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