1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. All rights reserved.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 *
15 * Description: FlowController implements
16 */
17 #include "flow_controller.h"
18
19 #include <algorithm>
20 #include <cinttypes>
21 #include <set>
22 #include <sstream>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include <regex>
27
28 #include "common.h"
29 #include "file_utils.h"
30 #include "ftrace_field_parser.h"
31 #include "ftrace_fs_ops.h"
32 #include "logging.h"
33 #include "parameters.h"
34
35 namespace {
36 using namespace OHOS::Developtools::Profiler;
37 #ifndef PAGE_SIZE
38 constexpr uint32_t PAGE_SIZE = 4096;
39 #endif
40 constexpr int KB_PER_PAGE = PAGE_SIZE / 1024;
41 constexpr uint32_t BYTE_PER_KB = 1024;
42 constexpr uint32_t MAX_FLUSH_INTERVAL = 1800 * 1000;
43 constexpr uint32_t MAX_FLUSH_THRESHOLD = 128 * 1024 * 1024;
44 constexpr uint32_t MAX_TRACE_PERIOD_MS = 720 * 1000;
45 constexpr uint32_t MAX_BUFFER_SIZE_KB = 64 * 1024; // 64MB
46 constexpr uint32_t HM_MAX_BUFFER_SIZE_KB = 512 * 1024; // 512MB
47 constexpr uint32_t MIN_BUFFER_SIZE_KB = 1024; // 1 MB
48 constexpr uint32_t DEFAULT_TRACE_PERIOD_MS = 250; // 250 ms
49 constexpr uint32_t MAX_BLOCK_SIZE_PAGES = 4096; // 16 MB
50 constexpr uint32_t MIN_BLOCK_SIZE_PAGES = 256; // 1 MB
51 constexpr uint32_t PARSE_CMDLINE_COUNT = 1000;
52 const std::set<std::string> g_availableClocks = { "boot", "global", "local", "mono" };
53 constexpr uint32_t SAVED_CMDLINE_SIZE_SMALL = 1024; // save cmdline sizes for cpu num less than 8
54 constexpr uint32_t SAVED_CMDLINE_SIZE_LARGE = 4096; // save cmdline sizes for cpu num no less than 8
55 constexpr int OCTA_CORE_CPU = 8; // 8 core
56 constexpr unsigned int RMQ_ENTRY_ALIGN_MASK = (1U << 2) - 1;
57 const std::string TRACE_PROPERTY = "debug.hitrace.tags.enableflags";
58 const std::string BGSRV_PROPERTY = "5456538433256433664";
59 } // namespace
60
61 FTRACE_NS_BEGIN
FlowController()62 FlowController::FlowController()
63 {
64 ftraceParser_ = std::make_unique<FtraceParser>();
65 ksymsParser_ = std::make_unique<KernelSymbolsParser>();
66 ftraceSupported_ = FtraceFsOps::GetInstance().GetFtraceRoot().size() > 0;
67 traceCollector_ = OHOS::HiviewDFX::UCollectClient::TraceCollector::Create();
68 osVersion_ = FtraceFsOps::GetInstance().GetKernelVersion();
69 }
70
~FlowController(void)71 FlowController::~FlowController(void)
72 {
73 PROFILER_LOG_INFO(LOG_CORE, "FlowController destroy!");
74 }
75
SetWriter(const WriterStructPtr & writer)76 int FlowController::SetWriter(const WriterStructPtr& writer)
77 {
78 CHECK_TRUE(ftraceSupported_, -1, "current kernel not support ftrace!");
79 CHECK_TRUE(resultWriter_ == nullptr, 0, "writer already setted!");
80
81 CHECK_NOTNULL(writer, -1, "writer null!");
82 auto transmiter = std::make_unique<ResultTransporter>("Transporter", writer);
83 CHECK_NOTNULL(transmiter, -1, "create ResultTransporter FAILED!");
84
85 // get CPU core numbers
86 int nprocs = static_cast<int>(sysconf(_SC_NPROCESSORS_ONLN));
87 CHECK_TRUE(nprocs > 0, -1, "get processor number failed!");
88 platformCpuNum_ = nprocs;
89
90 // init FtraceParser
91 CHECK_NOTNULL(ftraceParser_, 0, "FtraceParser create FAILED!");
92 CHECK_TRUE(ftraceParser_->Init(), -1, "ftrace parser init failed!");
93
94 // init KernelSymbolsParser
95 CHECK_NOTNULL(ksymsParser_, 0, "KernelSymbolsParser create FAILED!");
96 ksymsParser_->Parse(FtraceFsOps::GetInstance().GetKernelSymbols());
97
98 CHECK_TRUE(AddPlatformEventsToParser(), -1, "add platform events to parser failed!");
99 // disable all trace events
100 DisableAllCategories();
101
102 resultWriter_ = writer;
103 tansporter_ = std::move(transmiter);
104 return 0;
105 }
106
CreateRawDataReaders()107 bool FlowController::CreateRawDataReaders()
108 {
109 if (FtraceFsOps::GetInstance().IsHmKernel()) {
110 auto reader = std::make_unique<FtraceDataReader>(FtraceFsOps::GetInstance().GetHmRawTracePath());
111 CHECK_NOTNULL(reader, false, "create hm raw trace reader FAILED!");
112 ftraceReaders_.emplace_back(std::move(reader));
113 return true;
114 }
115
116 for (int i = 0; i < platformCpuNum_; i++) {
117 auto rawPath = FtraceFsOps::GetInstance().GetRawTracePath(i);
118 if (fakePath_ != "") {
119 rawPath = fakePath_ + "test_raw_" + std::to_string(i);
120 CHECK_NOTNULL(ftraceParser_, false, "create FtraceParser FAILED!");
121 ftraceParser_->ParseSavedCmdlines(FileUtils::ReadFile(fakePath_ + "test_comm"));
122 ftraceParser_->ParseSavedTgid(FileUtils::ReadFile(fakePath_ + "test_tgid"));
123 }
124 auto reader = std::make_unique<FtraceDataReader>(rawPath);
125 CHECK_NOTNULL(reader, false, "create reader %d FAILED!", i);
126 ftraceReaders_.emplace_back(std::move(reader));
127 }
128 return true;
129 }
130
CreatePagedMemoryPool()131 bool FlowController::CreatePagedMemoryPool()
132 {
133 PROFILER_LOG_INFO(LOG_CORE, "create memory pool, buffer_size_kb = %u", bufferSizeKb_);
134 if (KB_PER_PAGE == 0 || platformCpuNum_ == 0) {
135 return false;
136 }
137 size_t bufferSizePages = bufferSizeKb_ / KB_PER_PAGE;
138 size_t pagesPerBlock = bufferSizePages / static_cast<size_t>(platformCpuNum_);
139 if (pagesPerBlock < MIN_BLOCK_SIZE_PAGES) {
140 pagesPerBlock = MIN_BLOCK_SIZE_PAGES;
141 }
142 if (pagesPerBlock > MAX_BLOCK_SIZE_PAGES) {
143 pagesPerBlock = MAX_BLOCK_SIZE_PAGES;
144 }
145
146 if (FtraceFsOps::GetInstance().IsHmKernel()) {
147 memPool_ = std::make_unique<PagedMemPool>(bufferSizePages, 1);
148 } else {
149 memPool_ = std::make_unique<PagedMemPool>(pagesPerBlock, platformCpuNum_);
150 }
151 CHECK_NOTNULL(memPool_, false, "create PagedMemPool FAILED!");
152 return true;
153 }
154
CreateRawDataBuffers()155 bool FlowController::CreateRawDataBuffers()
156 {
157 int num = platformCpuNum_;
158 if (FtraceFsOps::GetInstance().IsHmKernel()) {
159 num = 1;
160 }
161 for (int i = 0; i < num; i++) {
162 using u8ptr = std::unique_ptr<uint8_t>::pointer;
163 auto buffer = std::shared_ptr<uint8_t>(reinterpret_cast<u8ptr>(memPool_->Allocate()),
164 [&](u8ptr block) { this->memPool_->Recycle(block); });
165 CHECK_NOTNULL(buffer, false, "create buffer %d failed!", i);
166 ftraceBuffers_.push_back(buffer);
167 };
168 return true;
169 }
170
CreateRawDataCaches()171 bool FlowController::CreateRawDataCaches()
172 {
173 char fileName[] = "/data/local/tmp/ftrace_rawdata.XXXXXX";
174 CHECK_TRUE(mkstemp(fileName) >= 0, false, "Create temp file failed!");
175 rawDataFile_ = std::shared_ptr<FILE>(fopen(fileName, "wb+"), [](FILE* fp) { fclose(fp); });
176 unlink(fileName);
177 return true;
178 }
179
ParseBasicData()180 bool FlowController::ParseBasicData()
181 {
182 CHECK_NOTNULL(resultWriter_, false, "%s: resultWriter_ nullptr", __func__);
183 // get clock times
184 if (getClockTimes_) {
185 if (resultWriter_->isProtobufSerialize) {
186 auto traceResult = std::make_unique<TracePluginResult>();
187 CHECK_TRUE(ReportClockTimes(traceResult), false, "parse clock times FAILED!");
188 CHECK_TRUE(tansporter_->Submit(std::move(traceResult)), false, "report clock times FAILED!");
189 } else {
190 auto ctx = resultWriter_->startReport(resultWriter_);
191 CHECK_NOTNULL(ctx, false, "%s: get RandomWriteCtx FAILED!", __func__);
192 auto traceResult = std::make_unique<ProtoEncoder::TracePluginResult>(ctx);
193 CHECK_TRUE(ReportClockTimes(traceResult), false, "parse clock times FAILED!");
194 int32_t msgSize = traceResult->Finish();
195 resultWriter_->finishReport(resultWriter_, msgSize);
196 tansporter_->Report(static_cast<size_t>(msgSize));
197 }
198 }
199
200 // parse kernel symbols
201 if (parseKsyms_) {
202 if (resultWriter_->isProtobufSerialize) {
203 auto traceResult = std::make_unique<TracePluginResult>();
204 CHECK_TRUE(ParseKernelSymbols(traceResult), false, "parse kernel symbols FAILED!");
205 CHECK_TRUE(tansporter_->Submit(std::move(traceResult)), false, "report kernel symbols FAILED!");
206 } else {
207 auto ctx = resultWriter_->startReport(resultWriter_);
208 CHECK_NOTNULL(ctx, false, "%s: get RandomWriteCtx FAILED!", __func__);
209 auto traceResult = std::make_unique<ProtoEncoder::TracePluginResult>(ctx);
210 CHECK_TRUE(ParseKernelSymbols(traceResult), false, "parse kernel symbols FAILED!");
211 int32_t msgSize = traceResult->Finish();
212 resultWriter_->finishReport(resultWriter_, msgSize);
213 tansporter_->Report(static_cast<size_t>(msgSize));
214 }
215 }
216 if (resultWriter_->isProtobufSerialize) {
217 auto traceResult = std::make_unique<TracePluginResult>();
218 CHECK_TRUE(ParsePerCpuStatus(traceResult, TRACE_START), false, "parse TRACE_START stats failed!");
219 CHECK_TRUE(tansporter_->Submit(std::move(traceResult)), false, "report TRACE_START stats failed!");
220 } else {
221 auto ctx = resultWriter_->startReport(resultWriter_);
222 CHECK_NOTNULL(ctx, false, "%s: get RandomWriteCtx FAILED!", __func__);
223 auto traceResult = std::make_unique<ProtoEncoder::TracePluginResult>(ctx);
224 CHECK_TRUE(ParsePerCpuStatus(traceResult, TRACE_START), false, "parse TRACE_START stats failed!");
225 int32_t msgSize = traceResult->Finish();
226 resultWriter_->finishReport(resultWriter_, msgSize);
227 tansporter_->Report(static_cast<size_t>(msgSize));
228 }
229 return true;
230 }
231
ReloadTraceArgs()232 std::string FlowController::ReloadTraceArgs()
233 {
234 std::string args;
235 for (size_t i = 0; i < traceCategories_.size(); i++) {
236 if (i == 0) {
237 args += ("tags:" + traceCategories_[i]);
238 } else {
239 args += ("," + traceCategories_[i]);
240 }
241 }
242 int appNum = 0;
243 for (size_t i = 0; i < traceApps_.size(); i++) {
244 int pidval = 0;
245 if (COMMON::IsProcessExist(traceApps_[i], pidval)) {
246 if (appNum == 0) {
247 args += (" filterPids:" + std::to_string(pidval));
248 } else {
249 args += ("," + std::to_string(pidval));
250 }
251 appNum += 1;
252 } else {
253 PROFILER_LOG_ERROR(LOG_CORE, "ReloadTraceArgs process %s doesn't exist", traceApps_[i].c_str());
254 }
255 }
256
257 if (traceClock_.size() > 0) {
258 args += (" clockType:" + traceClock_);
259 }
260
261 if (bufferSizeKb_ > 0) {
262 args += (" bufferSize:" + std::to_string(bufferSizeKb_));
263 }
264 PROFILER_LOG_INFO(LOG_CORE, "trace args: %s", args.c_str());
265 return args;
266 }
267
StartCapture(void)268 int FlowController::StartCapture(void)
269 {
270 CHECK_TRUE(ftraceSupported_, -1, "current kernel not support ftrace!");
271 CHECK_NOTNULL(ftraceParser_, -1, "create FtraceParser FAILED!");
272 CHECK_NOTNULL(ksymsParser_, -1, "create KernelSymbolsParser FAILED!");
273 CHECK_NOTNULL(tansporter_, -1, "create ResultTransporter FAILED!");
274 CHECK_NOTNULL(traceCollector_, -1, "create TraceCollector FAILED!");
275 CHECK_NOTNULL(resultWriter_, -1, "%s: resultWriter_ nullptr", __func__);
276
277 CHECK_TRUE(ParseBasicData(), -1, "parse basic data failed!");
278
279 // create memory pool, and raw data readers, buffers, caches.
280 CHECK_TRUE(CreatePagedMemoryPool(), -1, "create paged memory pool failed!");
281 CHECK_TRUE(CreateRawDataReaders(), -1, "create raw data readers failed!");
282 CHECK_TRUE(CreateRawDataBuffers(), -1, "create raw data buffers failed!");
283
284 // clear old trace
285 FtraceFsOps::GetInstance().ClearTraceBuffer();
286 // recover the hitrace
287 std::string param = OHOS::system::GetParameter(TRACE_PROPERTY, "");
288 if (param != "0" && param != BGSRV_PROPERTY) {
289 traceCollector_->Close();
290 }
291
292 uint32_t savedCmdlinesSize = platformCpuNum_ < OCTA_CORE_CPU ? SAVED_CMDLINE_SIZE_SMALL : SAVED_CMDLINE_SIZE_LARGE;
293 if (!FtraceFsOps::GetInstance().SetSavedCmdLinesSize(savedCmdlinesSize)) {
294 PROFILER_LOG_ERROR(LOG_CORE, "SetSavedCmdLinesSize %u fail.", savedCmdlinesSize);
295 }
296
297 // enable additional record options
298 FtraceFsOps::GetInstance().SetRecordCmdOption(true);
299 FtraceFsOps::GetInstance().SetRecordTgidOption(true);
300
301 // start ftrace event data polling thread
302 keepRunning_ = true;
303
304 if (parseMode_ == TracePluginConfig_ParseMode_NORMAL) {
305 pollThread_ = std::thread([this] { this->CaptureWorkOnNomalMode(); });
306 } else if (parseMode_ == TracePluginConfig_ParseMode_DELAY_PARSE) {
307 CHECK_TRUE(CreateRawDataCaches(), -1, "create raw data caches failed!");
308 pollThread_ = std::thread([this] { this->CaptureWorkOnDelayMode(); });
309 } else {
310 PROFILER_LOG_ERROR(LOG_CORE, "ParseMode is Illegal parameter!");
311 return -1;
312 }
313
314 // set trace_clock and enable all tag categories with hiview::TraceCollector
315 auto openRet = traceCollector_->OpenRecording(ReloadTraceArgs());
316 if (openRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
317 PROFILER_LOG_ERROR(LOG_CORE, "Enable tag categories failed, trace error code is %d!", openRet.retCode);
318 return -1;
319 }
320 EnableTraceEvents();
321 return 0;
322 }
323
CaptureWorkOnNomalModeInner()324 void FlowController::CaptureWorkOnNomalModeInner()
325 {
326 pthread_setname_np(pthread_self(), "TraceReader");
327 PROFILER_LOG_INFO(LOG_CORE, "FlowController::CaptureWorkOnNomalMode start!");
328 auto tracePeriod = std::chrono::milliseconds(tracePeriodMs_);
329 std::vector<long> rawDataBytes(platformCpuNum_, 0);
330 while (keepRunning_) {
331 std::this_thread::sleep_for(tracePeriod);
332 // read data from percpu trace_pipe_raw, consume kernel ring buffers
333 for (size_t i = 0; i < rawDataBytes.size(); i++) {
334 if (flushCacheData_ && !keepRunning_) {
335 PROFILER_LOG_INFO(LOG_CORE, "flushCacheData_ is true, return");
336 return;
337 }
338 long nbytes = ReadEventData(i);
339 rawDataBytes[i] = nbytes;
340 }
341 // parse ftrace percpu event data
342 for (size_t i = 0; i < rawDataBytes.size(); i++) {
343 if (flushCacheData_ && !keepRunning_) {
344 PROFILER_LOG_INFO(LOG_CORE, "flushCacheData_ is true, return");
345 return;
346 }
347 if (rawDataBytes[i] == 0) {
348 PROFILER_LOG_INFO(LOG_CORE, "Get raw data from CPU%zu is 0 bytes.", i);
349 continue;
350 }
351 if (!ParseEventDataOnNomalMode(i, rawDataBytes[i])) {
352 PROFILER_LOG_ERROR(LOG_CORE, "%s:ParseEventData failed!", __func__);
353 }
354 }
355 if (isReportBasicData_.load()) {
356 ParseBasicData();
357 isReportBasicData_ = false;
358 }
359 }
360 tansporter_->Flush();
361 PROFILER_LOG_DEBUG(LOG_CORE, "FlowController::CaptureWorkOnNomalMode done!");
362 }
363
HmReadEventData()364 long FlowController::HmReadEventData()
365 {
366 auto buffer = ftraceBuffers_[0].get();
367 auto reader = ftraceReaders_[0].get();
368 auto bufferSize = static_cast<long>(memPool_->GetBlockSize());
369
370 long nbytes = 0;
371 long used = 0;
372 long rest = bufferSize;
373 while ((nbytes = reader->Read(&buffer[used], rest)) > 0 && used < bufferSize) {
374 used += nbytes;
375 rest -= nbytes;
376 }
377 if (used == bufferSize) {
378 PROFILER_LOG_WARN(LOG_CORE, "hm trace raw data may overwrite. current buffer size = %u.",
379 (unsigned int)bufferSize);
380 }
381 return used;
382 }
383
HmCaptureWorkOnNomalModeInner()384 void FlowController::HmCaptureWorkOnNomalModeInner()
385 {
386 pthread_setname_np(pthread_self(), "HmTraceReader");
387 PROFILER_LOG_INFO(LOG_CORE, "FlowController::HmCaptureWorkOnNomalMode start!");
388 auto tracePeriod = std::chrono::milliseconds(tracePeriodMs_);
389 ftraceParser_->ParseTidGid();
390 while (keepRunning_) {
391 std::this_thread::sleep_for(tracePeriod);
392 if (flushCacheData_ && !keepRunning_) {
393 PROFILER_LOG_INFO(LOG_CORE, "flushCacheData_ is true, return");
394 return;
395 }
396 long rawDataBytes = HmReadEventData();
397 if (flushCacheData_ && !keepRunning_) {
398 PROFILER_LOG_INFO(LOG_CORE, "flushCacheData_ is true, return");
399 return;
400 }
401 if (rawDataBytes == 0) {
402 PROFILER_LOG_INFO(LOG_CORE, "Get hm raw data is 0 bytes.");
403 continue;
404 }
405 if (!HmParseEventDataOnNomalMode(rawDataBytes)) {
406 PROFILER_LOG_ERROR(LOG_CORE, "HmParseEventData failed!");
407 }
408 }
409 tansporter_->Flush();
410 PROFILER_LOG_INFO(LOG_CORE, "FlowController::HmCaptureWorkOnNomalMode done!");
411 }
412
CaptureWorkOnNomalMode()413 void FlowController::CaptureWorkOnNomalMode()
414 {
415 if (FtraceFsOps::GetInstance().IsHmKernel()) {
416 HmCaptureWorkOnNomalModeInner();
417 } else {
418 CaptureWorkOnNomalModeInner();
419 }
420 }
421
CaptureWorkOnDelayMode()422 void FlowController::CaptureWorkOnDelayMode()
423 {
424 pthread_setname_np(pthread_self(), "TraceReader");
425 PROFILER_LOG_INFO(LOG_CORE, "FlowController::CaptureWorkOnDelayMode start!");
426
427 auto tracePeriod = std::chrono::milliseconds(tracePeriodMs_);
428 int writeDataCount = 0;
429 while (keepRunning_) {
430 std::this_thread::sleep_for(tracePeriod);
431
432 // read data from percpu trace_pipe_raw, consume kernel ring buffers
433 for (int cpuIdx = 0; cpuIdx < platformCpuNum_; cpuIdx++) {
434 if (flushCacheData_ && !keepRunning_) {
435 PROFILER_LOG_INFO(LOG_CORE, "flushCacheData_ is true, return");
436 return;
437 }
438 long nbytes = ReadEventData(cpuIdx);
439 if (nbytes == 0) {
440 PROFILER_LOG_INFO(LOG_CORE, "Get raw data from CPU%d is 0 bytes.", cpuIdx);
441 continue;
442 }
443 fwrite(&cpuIdx, sizeof(uint8_t), 1, rawDataFile_.get());
444 fwrite(&nbytes, sizeof(long), 1, rawDataFile_.get());
445 fwrite(ftraceBuffers_[cpuIdx].get(), sizeof(uint8_t), nbytes, rawDataFile_.get());
446 }
447 writeDataCount++;
448 if (writeDataCount == PARSE_CMDLINE_COUNT) {
449 writeDataCount = 0;
450 }
451 }
452
453 CHECK_TRUE(ParseEventDataOnDelayMode(), NO_RETVAL, "ParseEventData failed!");
454 tansporter_->Flush();
455 PROFILER_LOG_DEBUG(LOG_CORE, "FlowController::CaptureWorkOnDelayMode done!");
456 }
457
RmqEntryTotalSize(unsigned int size)458 static inline int RmqEntryTotalSize(unsigned int size)
459 {
460 return sizeof(struct RmqEntry) + ((size + RMQ_ENTRY_ALIGN_MASK) & (~RMQ_ENTRY_ALIGN_MASK));
461 }
462
463 template <typename T, typename E>
HmParseEventData(T * traceResult,uint8_t * & data,E * ftraceEvent)464 bool FlowController::HmParseEventData(T* traceResult, uint8_t*& data, E* ftraceEvent)
465 {
466 struct RmqConsumerData* rmqData = reinterpret_cast<struct RmqConsumerData*>(data);
467 uint64_t timeStampBase = rmqData->timeStamp;
468 auto cpuDetailMsg = traceResult->add_ftrace_cpu_detail();
469 struct RmqEntry* event;
470 cpuDetailMsg->set_cpu(rmqData->coreId);
471 cpuDetailMsg->set_overwrite(0);
472 auto curPtr = rmqData->data;
473 auto endPtr = rmqData->data + rmqData->length;
474 while (curPtr < endPtr) {
475 event = reinterpret_cast<struct RmqEntry*>(curPtr);
476 unsigned int evtSize = event->size;
477 if (evtSize == 0U) {
478 break;
479 }
480 struct HmTraceHeader* header = reinterpret_cast<struct HmTraceHeader*>(event->data);
481 auto parseEventCtx = SubEventParser<E>::GetInstance().GetParseEventCtx(header->commonType);
482 if (parseEventCtx == NULL) {
483 curPtr += RmqEntryTotalSize(evtSize);
484 continue;
485 }
486 ftraceEvent = cpuDetailMsg->add_event();
487 ftraceEvent->set_timestamp(event->timeStampOffset + timeStampBase);
488 if (!ftraceParser_->HmParseFtraceEvent(*ftraceEvent, reinterpret_cast<uint8_t*>(header), evtSize,
489 parseEventCtx)) {
490 PROFILER_LOG_ERROR(LOG_CORE, "hm parse event failed!");
491 }
492 curPtr += RmqEntryTotalSize(evtSize);
493 }
494 data += PAGE_SIZE;
495 return true;
496 }
497
HmParseEventDataOnNomalMode(long dataSize)498 bool FlowController::HmParseEventDataOnNomalMode(long dataSize)
499 {
500 CHECK_NOTNULL(resultWriter_, false, "%s: resultWriter_ nullptr", __func__);
501 auto buffer = ftraceBuffers_[0].get();
502 auto endPtr = buffer + dataSize;
503
504 for (auto data = buffer; data < endPtr;) {
505 if (resultWriter_->isProtobufSerialize) {
506 auto traceResult = std::make_unique<TracePluginResult>();
507 FtraceEvent* event = nullptr;
508 CHECK_TRUE(HmParseEventData(traceResult.get(), data, event), false, "hm parse raw data failed!");
509 CHECK_TRUE(tansporter_->Submit(std::move(traceResult)), false, "report hm raw event failed!");
510 } else {
511 auto ctx = resultWriter_->startReport(resultWriter_);
512 CHECK_NOTNULL(ctx, false, "%s: get RandomWriteCtx FAILED!", __func__);
513 static ProtoEncoder::MessagePool msgPool;
514 static ProtoEncoder::TracePluginResult traceResult;
515 msgPool.Reset();
516 traceResult.Reset(ctx, &msgPool);
517 ProtoEncoder::FtraceEvent* event = nullptr;
518 CHECK_TRUE(HmParseEventData(&traceResult, data, event), false, "hm parse raw data failed!");
519 int32_t msgSize = traceResult.Finish();
520 resultWriter_->finishReport(resultWriter_, msgSize);
521 tansporter_->Report(static_cast<size_t>(msgSize));
522 }
523 }
524 if (!dataReady_) {
525 dataReady_ = true;
526 }
527
528 return true;
529 }
530
ReadEventData(int cpuid)531 long FlowController::ReadEventData(int cpuid)
532 {
533 auto buffer = ftraceBuffers_[cpuid].get();
534 auto reader = ftraceReaders_[cpuid].get();
535 auto bufferSize = static_cast<long>(memPool_->GetBlockSize());
536
537 long nbytes = 0;
538 long used = 0;
539 long rest = bufferSize;
540 while ((nbytes = reader->Read(&buffer[used], rest)) > 0 && used < bufferSize) {
541 CHECK_TRUE(used % PAGE_SIZE == 0, used, "used invalid!");
542 used += nbytes;
543 rest -= nbytes;
544 }
545
546 if (used == bufferSize) {
547 PROFILER_LOG_INFO(LOG_CORE,
548 "used(%ld) equals bufferSize(%ld), please expand buffer_size_kb, otherwise the kernel may lose data\n",
549 used, bufferSize);
550 }
551 return used;
552 }
553
ParseEventData(int cpuid,uint8_t * page)554 bool FlowController::ParseEventData(int cpuid, uint8_t* page)
555 {
556 if (resultWriter_->isProtobufSerialize) {
557 auto traceResult = std::make_unique<TracePluginResult>();
558 traceResult->set_version(osVersion_);
559 FtraceEvent* event = nullptr; // Used to distinguish between SubEventParser instance types.
560 CHECK_TRUE(ParseFtraceEvent(traceResult.get(), cpuid, page, event), false, "parse raw event for cpu-%d failed!",
561 cpuid);
562 CHECK_TRUE(tansporter_->Submit(std::move(traceResult)), false, "report raw event for cpu-%d failed!", cpuid);
563 } else {
564 auto ctx = resultWriter_->startReport(resultWriter_);
565 CHECK_NOTNULL(ctx, false, "%s: get RandomWriteCtx FAILED!", __func__);
566 static ProtoEncoder::MessagePool msgPool;
567 static ProtoEncoder::TracePluginResult traceResult;
568 msgPool.Reset();
569 traceResult.Reset(ctx, &msgPool);
570 traceResult.set_version(osVersion_);
571 ProtoEncoder::FtraceEvent* event = nullptr; // Used to distinguish between SubEventParser instance types.
572 CHECK_TRUE(ParseFtraceEvent(&traceResult, cpuid, page, event), false, "parse raw event for cpu-%d failed!",
573 cpuid);
574 int32_t msgSize = traceResult.Finish();
575 resultWriter_->finishReport(resultWriter_, msgSize);
576 tansporter_->Report(static_cast<size_t>(msgSize));
577 }
578 if (!dataReady_) {
579 dataReady_ = true;
580 }
581 return true;
582 }
583
ParseEventDataOnNomalMode(int cpuid,long dataSize)584 bool FlowController::ParseEventDataOnNomalMode(int cpuid, long dataSize)
585 {
586 CHECK_NOTNULL(resultWriter_, false, "%s: resultWriter_ nullptr", __func__);
587 auto buffer = ftraceBuffers_[cpuid].get();
588 auto endPtr = buffer + dataSize;
589 for (auto page = buffer; page < endPtr; page += PAGE_SIZE) {
590 if (!ParseEventData(cpuid, page)) {
591 PROFILER_LOG_ERROR(LOG_CORE, "%s:ParseEventData for cpu-%d failed!", __func__, cpuid);
592 }
593 }
594 return true;
595 }
596
ParseEventDataOnDelayMode()597 bool FlowController::ParseEventDataOnDelayMode()
598 {
599 CHECK_TRUE(fseek(rawDataFile_.get(), 0, SEEK_SET) == 0, false, "fseek failed!");
600 while (!feof(rawDataFile_.get())) {
601 uint8_t cpuId = 0;
602 long dataBytes = 0;
603 fread(&cpuId, sizeof(uint8_t), 1, rawDataFile_.get());
604 fread(&dataBytes, sizeof(long), 1, rawDataFile_.get());
605 for (long i = 0; i < dataBytes; i += PAGE_SIZE) {
606 uint8_t page[PAGE_SIZE] = {0};
607 fread(page, sizeof(uint8_t), PAGE_SIZE, rawDataFile_.get());
608 if (!ParseEventData(cpuId, page)) {
609 PROFILER_LOG_ERROR(LOG_CORE, "%s:ParseEventData for cpu-%d failed!", __func__, cpuId);
610 }
611 }
612 }
613 return true;
614 }
615
StopCapture(void)616 int FlowController::StopCapture(void)
617 {
618 CHECK_TRUE(ftraceSupported_, -1, "current kernel not support ftrace!");
619 CHECK_NOTNULL(tansporter_, -1, "crate ResultTransporter FAILED!");
620
621 CHECK_TRUE(requestEvents_.size() != 0 || traceApps_.size() != 0 || traceCategories_.size() != 0, -1,
622 "StopCapture: ftrace event is not set, return false");
623
624 // disable ftrace event switches
625 DisableTraceEvents();
626
627 // stop ftrace event data polling thread
628 keepRunning_ = false;
629 if (pollThread_.joinable()) {
630 PROFILER_LOG_INFO(LOG_CORE, "join thread start!\n");
631 pollThread_.join();
632 PROFILER_LOG_INFO(LOG_CORE, "join thread done!\n");
633 }
634 // parse per cpu stats
635 if (resultWriter_->isProtobufSerialize) {
636 auto traceResult = std::make_unique<TracePluginResult>();
637 CHECK_TRUE(ParsePerCpuStatus(traceResult, TRACE_END), -1, "parse TRACE_END stats FAILED!");
638 CHECK_TRUE(tansporter_->Submit(std::move(traceResult)), -1, "report TRACE_END stats FAILED!");
639 } else {
640 auto ctx = resultWriter_->startReport(resultWriter_);
641 CHECK_NOTNULL(ctx, -1, "%s: get RandomWriteCtx FAILED!", __func__);
642 auto traceResult = std::make_unique<ProtoEncoder::TracePluginResult>(ctx);
643 CHECK_TRUE(ParsePerCpuStatus(traceResult, TRACE_END), -1, "parse TRACE_END stats FAILED!");
644 int32_t msgSize = traceResult->Finish();
645 resultWriter_->finishReport(resultWriter_, msgSize);
646 tansporter_->Report(static_cast<size_t>(msgSize));
647 }
648
649 // disable userspace trace triggers
650 // because trace cmd will read trace buffer,
651 // so we to this action after polling thread exit.
652 traceCollector_->Close();
653 tansporter_->Flush();
654
655 // release resources
656 ftraceReaders_.clear(); // release ftrace data readers
657 ftraceBuffers_.clear(); // release ftrace event read buffers
658 memPool_.reset(); // release memory pool
659 return 0;
660 }
661
ParsePerCpuStatus(T & tracePluginResult,int stage)662 template <typename T> bool FlowController::ParsePerCpuStatus(T& tracePluginResult, int stage)
663 {
664 CHECK_NOTNULL(tracePluginResult, false, "create TracePluginResult FAILED!");
665
666 auto cpuStatsMsg = tracePluginResult->add_ftrace_cpu_stats();
667 if (stage == TRACE_START) {
668 cpuStatsMsg->set_status(FtraceCpuStatsMsg_Status_TRACE_START);
669 } else {
670 cpuStatsMsg->set_status(FtraceCpuStatsMsg_Status_TRACE_END);
671 }
672
673 std::string traceClock = FtraceFsOps::GetInstance().GetTraceClock();
674 if (traceClock.size() > 0) {
675 cpuStatsMsg->set_trace_clock(traceClock);
676 }
677
678 for (int i = 0; i < platformCpuNum_; i++) {
679 PROFILER_LOG_INFO(LOG_CORE, "[%d] ParsePerCpuStatus %d!", i, stage);
680 PerCpuStats stats = {};
681 stats.cpuIndex = i;
682 ftraceParser_->ParsePerCpuStatus(stats, FtraceFsOps::GetInstance().GetPerCpuStats(i));
683 auto perCpuMsg = cpuStatsMsg->add_per_cpu_stats();
684 perCpuMsg->set_cpu(stats.cpuIndex);
685 perCpuMsg->set_entries(stats.entries);
686 perCpuMsg->set_overrun(stats.overrun);
687 perCpuMsg->set_commit_overrun(stats.commitOverrun);
688 perCpuMsg->set_bytes(stats.bytes);
689 perCpuMsg->set_oldest_event_ts(stats.oldestEventTs);
690 perCpuMsg->set_now_ts(stats.nowTs);
691 perCpuMsg->set_dropped_events(stats.droppedEvents);
692 perCpuMsg->set_read_events(stats.readEvents);
693 }
694
695 return true;
696 }
697
ReportClockTimes(T & tracePluginResult)698 template <typename T> bool FlowController::ReportClockTimes(T& tracePluginResult)
699 {
700 CHECK_NOTNULL(tracePluginResult, false, "create TracePluginResult FAILED!");
701
702 std::map<clockid_t, ClockDetailMsg::ClockId> clocksMap = {
703 {CLOCK_REALTIME, ClockDetailMsg::REALTIME},
704 {CLOCK_REALTIME_COARSE, ClockDetailMsg::REALTIME_COARSE},
705 {CLOCK_MONOTONIC, ClockDetailMsg::MONOTONIC},
706 {CLOCK_MONOTONIC_COARSE, ClockDetailMsg::MONOTONIC_COARSE},
707 {CLOCK_MONOTONIC_RAW, ClockDetailMsg::MONOTONIC_RAW},
708 {CLOCK_BOOTTIME, ClockDetailMsg::BOOTTIME},
709 };
710 for (auto& entry : clocksMap) {
711 struct timespec ts = {};
712 clock_gettime(entry.first, &ts);
713 auto clockMsg = tracePluginResult->add_clocks_detail();
714 CHECK_NOTNULL(clockMsg, false, "add clock_detail failed for %d!", entry.first);
715 clockMsg->set_id(entry.second);
716 auto timeMsg = clockMsg->mutable_time();
717 timeMsg->set_tv_sec(ts.tv_sec);
718 timeMsg->set_tv_nsec(ts.tv_nsec);
719
720 struct timespec tsResolution = {};
721 clock_getres(entry.first, &tsResolution);
722 auto resolutionMsg = clockMsg->mutable_resolution();
723 resolutionMsg->set_tv_sec(tsResolution.tv_sec);
724 resolutionMsg->set_tv_nsec(tsResolution.tv_nsec);
725 }
726 return true;
727 }
728
ParseKernelSymbols(T & tracePluginResult)729 template <typename T> bool FlowController::ParseKernelSymbols(T& tracePluginResult)
730 {
731 CHECK_NOTNULL(tracePluginResult, false, "create TracePluginResult FAILED!");
732
733 ksymsParser_->Accept([&tracePluginResult](const KernelSymbol& symbol) {
734 auto symbolDetail = tracePluginResult->add_symbols_detail();
735 symbolDetail->set_symbol_addr(symbol.addr);
736 symbolDetail->set_symbol_name(symbol.name);
737 });
738 PROFILER_LOG_INFO(LOG_CORE, "parse kernel symbol message done!");
739 return true;
740 }
741
742 template <typename T, typename E>
ParseFtraceEvent(T * tracePluginResult,int cpuid,uint8_t page[],E * ftraceEvent)743 bool FlowController::ParseFtraceEvent(T* tracePluginResult, int cpuid, uint8_t page[], E* ftraceEvent)
744 {
745 CHECK_NOTNULL(tracePluginResult, false, "create TracePluginResult FAILED!");
746
747 auto cpudetail = tracePluginResult->add_ftrace_cpu_detail();
748 cpudetail->set_cpu(static_cast<uint32_t>(cpuid));
749
750 CHECK_TRUE(ftraceParser_->ParsePage(*cpudetail, page, PAGE_SIZE, ftraceEvent), false, "parse page failed!");
751 return true;
752 }
753
AddPlatformEventsToParser(void)754 bool FlowController::AddPlatformEventsToParser(void)
755 {
756 CHECK_TRUE(ftraceSupported_, false, "current kernel not support ftrace!");
757
758 PROFILER_LOG_INFO(LOG_CORE, "Add platform events to parser start!");
759 for (auto& typeName : FtraceFsOps::GetInstance().GetPlatformEvents()) {
760 std::string type = typeName.first;
761 std::string name = typeName.second;
762 if (ftraceParser_->SetupEvent(type, name)) {
763 supportedEvents_.push_back(typeName);
764 }
765 }
766 PROFILER_LOG_INFO(LOG_CORE, "Add platform events to parser done, events: %zu!", supportedEvents_.size());
767 return true;
768 }
769
GetCmdArgs(const TracePluginConfig & traceConfig)770 std::string FlowController::GetCmdArgs(const TracePluginConfig& traceConfig)
771 {
772 std::stringstream args;
773 for (const auto& event : traceConfig.ftrace_events()) {
774 args << "ftrace_events: " << event << ", ";
775 }
776 for (const auto& category : traceConfig.hitrace_categories()) {
777 args << "hitrace_categories: " << category << ", ";
778 }
779 for (const auto& app : traceConfig.hitrace_apps()) {
780 args << "hitrace_apps: " << app << ", ";
781 }
782 args << "buffer_size_kb: " << std::to_string(traceConfig.buffer_size_kb()) << ", ";
783 args << "flush_interval_ms: " << std::to_string(traceConfig.flush_interval_ms()) << ", ";
784 args << "flush_threshold_kb: " << std::to_string(traceConfig.flush_threshold_kb()) << ", ";
785 args << "trace_period_ms: " << std::to_string(traceConfig.trace_period_ms()) << ", ";
786 args << "trace_duration_ms: " << std::to_string(traceConfig.trace_duration_ms()) << ", ";
787 args << "hitrace_time: " << std::to_string(traceConfig.hitrace_time()) << ", ";
788 args << "parse_ksyms: " << (traceConfig.parse_ksyms() ? "true" : "false") << ", ";
789 args << "clock: " << traceConfig.clock() << ", ";
790 args << "raw_data_prefix: " << traceConfig.raw_data_prefix() << ", ";
791 args << "debug_on: " << (traceConfig.debug_on() ? "true" : "false") << ", ";
792 args << "discard_cache_data: " << (traceConfig.discard_cache_data() ? "true" : "false") << ", ";
793 args << "parse_mode: " << std::to_string(traceConfig.parse_mode());
794 return args.str();
795 }
796
LoadConfig(const uint8_t configData[],uint32_t size)797 int FlowController::LoadConfig(const uint8_t configData[], uint32_t size)
798 {
799 CHECK_TRUE(size > 0, -1, "config data size is zero!");
800 CHECK_NOTNULL(configData, -1, "config data is null!");
801 CHECK_TRUE(ftraceSupported_, -1, "current kernel not support ftrace!");
802 CHECK_NOTNULL(tansporter_, -1, "ResultTransporter crated FAILED!");
803
804 TracePluginConfig traceConfig;
805 CHECK_TRUE(traceConfig.ParseFromArray(configData, size), -1, "parse %u bytes configData failed!", size);
806
807 // sort and save user requested trace events
808 std::set<std::string> events(traceConfig.ftrace_events().begin(), traceConfig.ftrace_events().end());
809 for (auto ftraceEvent : events) {
810 requestEvents_.push_back(ftraceEvent);
811 }
812
813 traceApps_.assign(traceConfig.hitrace_apps().begin(), traceConfig.hitrace_apps().end());
814 traceCategories_.assign(traceConfig.hitrace_categories().begin(), traceConfig.hitrace_categories().end());
815
816 CHECK_TRUE(requestEvents_.size() != 0 || traceApps_.size() != 0 || traceCategories_.size() != 0, -1,
817 "LoadConfig: ftrace event is not set, return false");
818
819 // setup trace clock
820 if (g_availableClocks.count(traceConfig.clock()) > 0) {
821 traceClock_ = traceConfig.clock();
822 FtraceFsOps::GetInstance().SetTraceClock(traceConfig.clock());
823 }
824
825 // setup parse kernel symbol option
826 parseKsyms_ = traceConfig.parse_ksyms();
827 parseMode_ = traceConfig.parse_mode();
828 // setup trace buffer size
829 SetupTraceBufferSize(traceConfig.buffer_size_kb());
830
831 // setup transporter flush params
832 SetupTransporterFlushParams(traceConfig.flush_interval_ms(), traceConfig.flush_threshold_kb());
833
834 // generate raw data file names
835 GenerateRawDataFileNames(traceConfig.raw_data_prefix());
836
837 // setup trace period param
838 SetupTraceReadPeriod(traceConfig.trace_period_ms());
839 flushCacheData_ = traceConfig.discard_cache_data();
840 hitraceTime_ = traceConfig.hitrace_time();
841
842 int ret = COMMON::PluginWriteToHisysevent("ftrace_plugin", "sh", GetCmdArgs(traceConfig),
843 COMMON::ErrorType::RET_SUCC, "success");
844 PROFILER_LOG_INFO(LOG_CORE, "hisysevent report ftrace_plugin result: %d", ret);
845 return 0;
846 }
847
SetupTraceBufferSize(uint32_t sizeKb)848 void FlowController::SetupTraceBufferSize(uint32_t sizeKb)
849 {
850 uint32_t maxBufferSizeKb = MAX_BUFFER_SIZE_KB;
851 if (FtraceFsOps::GetInstance().IsHmKernel()) {
852 maxBufferSizeKb = HM_MAX_BUFFER_SIZE_KB;
853 }
854 if (sizeKb < MIN_BUFFER_SIZE_KB) {
855 bufferSizeKb_ = MIN_BUFFER_SIZE_KB;
856 } else if (sizeKb > maxBufferSizeKb) {
857 bufferSizeKb_ = maxBufferSizeKb;
858 } else {
859 bufferSizeKb_ = sizeKb / KB_PER_PAGE * KB_PER_PAGE;
860 }
861 }
862
SetupTransporterFlushParams(uint32_t flushInterval,uint32_t flushThresholdKb)863 void FlowController::SetupTransporterFlushParams(uint32_t flushInterval, uint32_t flushThresholdKb)
864 {
865 if (flushInterval > 0 && flushInterval <= MAX_FLUSH_INTERVAL) {
866 tansporter_->SetFlushInterval(flushInterval);
867 }
868 if (flushThresholdKb > 0 && flushThresholdKb <= MAX_FLUSH_THRESHOLD) {
869 tansporter_->SetFlushThreshold(flushThresholdKb * BYTE_PER_KB);
870 }
871 }
872
GenerateRawDataFileNames(const std::string & prefix)873 void FlowController::GenerateRawDataFileNames(const std::string& prefix)
874 {
875 if (prefix.size() > 0) {
876 for (int i = 0; i < platformCpuNum_; i++) {
877 std::string path = prefix + std::to_string(i);
878 rawDataDumpPath_.push_back(path);
879 }
880 }
881 }
882
SetupTraceReadPeriod(uint32_t tracePeriod)883 void FlowController::SetupTraceReadPeriod(uint32_t tracePeriod)
884 {
885 if (tracePeriod > 0 && tracePeriod <= MAX_TRACE_PERIOD_MS) {
886 tracePeriodMs_ = tracePeriod;
887 } else {
888 tracePeriodMs_ = DEFAULT_TRACE_PERIOD_MS;
889 }
890 }
891
EnableTraceEvents(void)892 void FlowController::EnableTraceEvents(void)
893 {
894 std::unordered_set<std::string> userEventSet(requestEvents_.begin(), requestEvents_.end());
895 for (auto& event : supportedEvents_) {
896 std::string type = event.first;
897 std::string name = event.second;
898 std::string fmtType = type;
899 if (type == "power_kernel") {
900 fmtType = "power";
901 }
902 if (userEventSet.count(fmtType + "/" + name)) { // user config format
903 if (FtraceFsOps::GetInstance().EnableEvent(type, name)) {
904 FtraceFsOps::GetInstance().AppendSetEvent(type, name);
905 enabledEvents_.push_back(event);
906 }
907 }
908 }
909 FtraceFsOps::GetInstance().EnableTracing();
910 }
911
DisableTraceEvents(void)912 void FlowController::DisableTraceEvents(void)
913 {
914 FtraceFsOps::GetInstance().DisableTracing();
915 for (auto& event : enabledEvents_) {
916 std::string type = event.first;
917 std::string name = event.second;
918 FtraceFsOps::GetInstance().DisableEvent(type, name);
919 }
920 enabledEvents_.clear();
921 }
922
DisableAllCategories(void)923 void FlowController::DisableAllCategories(void)
924 {
925 for (auto& event : supportedEvents_) {
926 std::string type = event.first;
927 std::string name = event.second;
928 FtraceFsOps::GetInstance().DisableCategories(type);
929 }
930 }
931
SetReportBasicData(bool isReportBasicData)932 void FlowController::SetReportBasicData(bool isReportBasicData)
933 {
934 isReportBasicData_ = isReportBasicData;
935 }
936 FTRACE_NS_END
937