• 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 <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 
243     if (traceClock_.size() > 0) {
244         args += (" clockType:" + traceClock_);
245     }
246 
247     if (bufferSizeKb_ > 0) {
248         args += (" bufferSize:" + std::to_string(bufferSizeKb_));
249     }
250     PROFILER_LOG_INFO(LOG_CORE, "trace args: %s", args.c_str());
251     return args;
252 }
253 
StartCapture(void)254 int FlowController::StartCapture(void)
255 {
256     CHECK_TRUE(ftraceSupported_, -1, "current kernel not support ftrace!");
257     CHECK_NOTNULL(ftraceParser_, -1, "create FtraceParser FAILED!");
258     CHECK_NOTNULL(ksymsParser_, -1, "create KernelSymbolsParser FAILED!");
259     CHECK_NOTNULL(tansporter_, -1, "create ResultTransporter FAILED!");
260     CHECK_NOTNULL(traceCollector_, -1, "create TraceCollector FAILED!");
261     CHECK_NOTNULL(resultWriter_, -1, "%s: resultWriter_ nullptr", __func__);
262 
263     CHECK_TRUE(ParseBasicData(), -1, "parse basic data failed!");
264 
265     // create memory pool, and raw data readers, buffers, caches.
266     CHECK_TRUE(CreatePagedMemoryPool(), -1, "create paged memory pool failed!");
267     CHECK_TRUE(CreateRawDataReaders(), -1, "create raw data readers failed!");
268     CHECK_TRUE(CreateRawDataBuffers(), -1, "create raw data buffers failed!");
269 
270     // clear old trace
271     FtraceFsOps::GetInstance().ClearTraceBuffer();
272     // recover the hitrace
273     std::string param = OHOS::system::GetParameter(TRACE_PROPERTY, "");
274     if (param != "0" && param != BGSRV_PROPERTY) {
275         traceCollector_->Close();
276     }
277 
278     uint32_t savedCmdlinesSize = platformCpuNum_ < OCTA_CORE_CPU ? SAVED_CMDLINE_SIZE_SMALL : SAVED_CMDLINE_SIZE_LARGE;
279     if (!FtraceFsOps::GetInstance().SetSavedCmdLinesSize(savedCmdlinesSize)) {
280         PROFILER_LOG_ERROR(LOG_CORE, "SetSavedCmdLinesSize %u fail.", savedCmdlinesSize);
281     }
282 
283     // enable additional record options
284     FtraceFsOps::GetInstance().SetRecordCmdOption(true);
285     FtraceFsOps::GetInstance().SetRecordTgidOption(true);
286 
287     // start ftrace event data polling thread
288     keepRunning_ = true;
289 
290     if (parseMode_ == TracePluginConfig_ParseMode_NORMAL) {
291         pollThread_ = std::thread([this] { this->CaptureWorkOnNomalMode(); });
292     } else if (parseMode_ == TracePluginConfig_ParseMode_DELAY_PARSE) {
293         CHECK_TRUE(CreateRawDataCaches(), -1, "create raw data caches failed!");
294         pollThread_ = std::thread([this] { this->CaptureWorkOnDelayMode(); });
295     } else {
296         PROFILER_LOG_ERROR(LOG_CORE, "ParseMode is Illegal parameter!");
297         return -1;
298     }
299 
300     // set trace_clock and enable all tag categories with hiview::TraceCollector
301     auto openRet = traceCollector_->OpenRecording(ReloadTraceArgs());
302     if (openRet.retCode != OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
303         PROFILER_LOG_ERROR(LOG_CORE, "Enable tag categories failed, trace error code is %d!", openRet.retCode);
304         return -1;
305     }
306     EnableTraceEvents();
307     return 0;
308 }
309 
CaptureWorkOnNomalModeInner()310 void FlowController::CaptureWorkOnNomalModeInner()
311 {
312     pthread_setname_np(pthread_self(), "TraceReader");
313     PROFILER_LOG_INFO(LOG_CORE, "FlowController::CaptureWorkOnNomalMode start!");
314     auto tracePeriod = std::chrono::milliseconds(tracePeriodMs_);
315     std::vector<long> rawDataBytes(platformCpuNum_, 0);
316     while (keepRunning_) {
317         std::this_thread::sleep_for(tracePeriod);
318         // read data from percpu trace_pipe_raw, consume kernel ring buffers
319         for (size_t i = 0; i < rawDataBytes.size(); i++) {
320             if (flushCacheData_ && !keepRunning_) {
321                 PROFILER_LOG_INFO(LOG_CORE, "flushCacheData_ is true, return");
322                 return;
323             }
324             long nbytes = ReadEventData(i);
325             rawDataBytes[i] = nbytes;
326         }
327         // parse ftrace metadata
328         ftraceParser_->ParseSavedCmdlines(FtraceFsOps::GetInstance().GetSavedCmdLines());
329         // parse ftrace percpu event data
330         for (size_t i = 0; i < rawDataBytes.size(); i++) {
331             if (flushCacheData_ && !keepRunning_) {
332                 PROFILER_LOG_INFO(LOG_CORE, "flushCacheData_ is true, return");
333                 return;
334             }
335             if (rawDataBytes[i] == 0) {
336                 PROFILER_LOG_INFO(LOG_CORE, "Get raw data from CPU%zu is 0 bytes.", i);
337                 continue;
338             }
339             if (!ParseEventDataOnNomalMode(i, rawDataBytes[i])) {
340                 PROFILER_LOG_ERROR(LOG_CORE, "%s:ParseEventData failed!", __func__);
341             }
342         }
343         if (isReportBasicData_.load()) {
344             ParseBasicData();
345             isReportBasicData_ = false;
346         }
347     }
348     tansporter_->Flush();
349     PROFILER_LOG_DEBUG(LOG_CORE, "FlowController::CaptureWorkOnNomalMode done!");
350 }
351 
HmReadEventData()352 long FlowController::HmReadEventData()
353 {
354     auto buffer = ftraceBuffers_[0].get();
355     auto reader = ftraceReaders_[0].get();
356     auto bufferSize = static_cast<long>(memPool_->GetBlockSize());
357 
358     long nbytes = 0;
359     long used = 0;
360     long rest = bufferSize;
361     while ((nbytes = reader->Read(&buffer[used], rest)) > 0 && used < bufferSize) {
362         used += nbytes;
363         rest -= nbytes;
364     }
365     if (used == bufferSize) {
366         PROFILER_LOG_WARN(LOG_CORE, "hm trace raw data may overwrite. current buffer size = %u.",
367                           (unsigned int)bufferSize);
368     }
369     return used;
370 }
371 
HmCaptureWorkOnNomalModeInner()372 void FlowController::HmCaptureWorkOnNomalModeInner()
373 {
374     pthread_setname_np(pthread_self(), "HmTraceReader");
375     PROFILER_LOG_INFO(LOG_CORE, "FlowController::HmCaptureWorkOnNomalMode start!");
376     auto tracePeriod = std::chrono::milliseconds(tracePeriodMs_);
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         long rawDataBytes = HmReadEventData();
384         ftraceParser_->ParseSavedCmdlines(FtraceFsOps::GetInstance().GetSavedCmdLines());
385         if (flushCacheData_ && !keepRunning_) {
386             PROFILER_LOG_INFO(LOG_CORE, "flushCacheData_ is true, return");
387             return;
388         }
389         if (rawDataBytes == 0) {
390             PROFILER_LOG_INFO(LOG_CORE, "Get hm raw data is 0 bytes.");
391             continue;
392         }
393         if (!HmParseEventDataOnNomalMode(rawDataBytes)) {
394             PROFILER_LOG_ERROR(LOG_CORE, "HmParseEventData failed!");
395         }
396     }
397     tansporter_->Flush();
398     PROFILER_LOG_INFO(LOG_CORE, "FlowController::HmCaptureWorkOnNomalMode done!");
399 }
400 
CaptureWorkOnNomalMode()401 void FlowController::CaptureWorkOnNomalMode()
402 {
403     if (FtraceFsOps::GetInstance().IsHmKernel()) {
404         HmCaptureWorkOnNomalModeInner();
405     } else {
406         CaptureWorkOnNomalModeInner();
407     }
408 }
409 
CaptureWorkOnDelayMode()410 void FlowController::CaptureWorkOnDelayMode()
411 {
412     pthread_setname_np(pthread_self(), "TraceReader");
413     PROFILER_LOG_INFO(LOG_CORE, "FlowController::CaptureWorkOnDelayMode start!");
414 
415     auto tracePeriod = std::chrono::milliseconds(tracePeriodMs_);
416     int writeDataCount = 0;
417     while (keepRunning_) {
418         std::this_thread::sleep_for(tracePeriod);
419 
420         // read data from percpu trace_pipe_raw, consume kernel ring buffers
421         for (int cpuIdx = 0; cpuIdx < platformCpuNum_; cpuIdx++) {
422             if (flushCacheData_ && !keepRunning_) {
423                 PROFILER_LOG_INFO(LOG_CORE, "flushCacheData_ is true, return");
424                 return;
425             }
426             long nbytes = ReadEventData(cpuIdx);
427             if (nbytes == 0) {
428                 PROFILER_LOG_INFO(LOG_CORE, "Get raw data from CPU%d is 0 bytes.", cpuIdx);
429                 continue;
430             }
431             fwrite(&cpuIdx, sizeof(uint8_t), 1, rawDataFile_.get());
432             fwrite(&nbytes, sizeof(long), 1, rawDataFile_.get());
433             fwrite(ftraceBuffers_[cpuIdx].get(), sizeof(uint8_t), nbytes, rawDataFile_.get());
434         }
435         writeDataCount++;
436         if (writeDataCount == PARSE_CMDLINE_COUNT) {
437             // parse ftrace metadata
438             ftraceParser_->ParseSavedCmdlines(FtraceFsOps::GetInstance().GetSavedCmdLines());
439             writeDataCount = 0;
440         }
441     }
442 
443     CHECK_TRUE(ParseEventDataOnDelayMode(), NO_RETVAL, "ParseEventData failed!");
444     tansporter_->Flush();
445     PROFILER_LOG_DEBUG(LOG_CORE, "FlowController::CaptureWorkOnDelayMode done!");
446 }
447 
RmqEntryTotalSize(unsigned int size)448 static inline int RmqEntryTotalSize(unsigned int size)
449 {
450     return sizeof(struct RmqEntry) + ((size + RMQ_ENTRY_ALIGN_MASK) & (~RMQ_ENTRY_ALIGN_MASK));
451 }
452 
453 template <typename T, typename E>
HmParseEventData(T * traceResult,uint8_t * & data,E * ftraceEvent)454 bool FlowController::HmParseEventData(T* traceResult, uint8_t*& data, E* ftraceEvent)
455 {
456     struct RmqConsumerData* rmqData = reinterpret_cast<struct RmqConsumerData*>(data);
457     uint64_t timeStampBase = rmqData->timeStamp;
458     auto cpuDetailMsg = traceResult->add_ftrace_cpu_detail();
459     struct RmqEntry* event;
460     cpuDetailMsg->set_cpu(rmqData->coreId);
461     cpuDetailMsg->set_overwrite(0);
462     auto curPtr = rmqData->data;
463     auto endPtr = rmqData->data + rmqData->length;
464     while (curPtr < endPtr) {
465         event = reinterpret_cast<struct RmqEntry*>(curPtr);
466         unsigned int evtSize = event->size;
467         if (evtSize == 0U) {
468             break;
469         }
470         struct HmTraceHeader* header = reinterpret_cast<struct HmTraceHeader*>(event->data);
471         auto parseEventCtx = SubEventParser<E>::GetInstance().GetParseEventCtx(header->commonType);
472         if (parseEventCtx == NULL) {
473             curPtr += RmqEntryTotalSize(evtSize);
474             continue;
475         }
476         ftraceEvent = cpuDetailMsg->add_event();
477         ftraceEvent->set_timestamp(event->timeStampOffset + timeStampBase);
478         if (!ftraceParser_->HmParseFtraceEvent(*ftraceEvent, reinterpret_cast<uint8_t*>(header), evtSize,
479                                                parseEventCtx)) {
480             PROFILER_LOG_ERROR(LOG_CORE, "hm parse event failed!");
481         }
482         curPtr += RmqEntryTotalSize(evtSize);
483     }
484     data += PAGE_SIZE;
485     return true;
486 }
487 
HmParseEventDataOnNomalMode(long dataSize)488 bool FlowController::HmParseEventDataOnNomalMode(long dataSize)
489 {
490     CHECK_NOTNULL(resultWriter_, false, "%s: resultWriter_ nullptr", __func__);
491     auto buffer = ftraceBuffers_[0].get();
492     auto endPtr = buffer + dataSize;
493 
494     for (auto data = buffer; data < endPtr;) {
495         if (resultWriter_->isProtobufSerialize) {
496             auto traceResult = std::make_unique<TracePluginResult>();
497             FtraceEvent* event = nullptr;
498             CHECK_TRUE(HmParseEventData(traceResult.get(), data, event), false, "hm parse raw data failed!");
499             CHECK_TRUE(tansporter_->Submit(std::move(traceResult)), false, "report hm raw event failed!");
500         } else {
501             auto ctx = resultWriter_->startReport(resultWriter_);
502             CHECK_NOTNULL(ctx, false, "%s: get RandomWriteCtx FAILED!", __func__);
503             static ProtoEncoder::MessagePool msgPool;
504             static ProtoEncoder::TracePluginResult traceResult;
505             msgPool.Reset();
506             traceResult.Reset(ctx, &msgPool);
507             ProtoEncoder::FtraceEvent* event = nullptr;
508             CHECK_TRUE(HmParseEventData(&traceResult, data, event), false, "hm parse raw data failed!");
509             int32_t msgSize = traceResult.Finish();
510             resultWriter_->finishReport(resultWriter_, msgSize);
511             tansporter_->Report(static_cast<size_t>(msgSize));
512         }
513     }
514     if (!dataReady_) {
515         dataReady_ = true;
516     }
517 
518     return true;
519 }
520 
ReadEventData(int cpuid)521 long FlowController::ReadEventData(int cpuid)
522 {
523     auto buffer = ftraceBuffers_[cpuid].get();
524     auto reader = ftraceReaders_[cpuid].get();
525     auto bufferSize = static_cast<long>(memPool_->GetBlockSize());
526 
527     long nbytes = 0;
528     long used = 0;
529     long rest = bufferSize;
530     while ((nbytes = reader->Read(&buffer[used], rest)) > 0 && used < bufferSize) {
531         CHECK_TRUE(used % PAGE_SIZE == 0, used, "used invalid!");
532         used += nbytes;
533         rest -= nbytes;
534     }
535 
536     if (used == bufferSize) {
537         PROFILER_LOG_INFO(LOG_CORE,
538             "used(%ld) equals bufferSize(%ld), please expand buffer_size_kb, otherwise the kernel may lose data\n",
539             used, bufferSize);
540     }
541     return used;
542 }
543 
ParseEventData(int cpuid,uint8_t * page)544 bool FlowController::ParseEventData(int cpuid, uint8_t* page)
545 {
546     if (resultWriter_->isProtobufSerialize) {
547         auto traceResult = std::make_unique<TracePluginResult>();
548         traceResult->set_version(osVersion_);
549         FtraceEvent* event = nullptr;  // Used to distinguish between SubEventParser instance types.
550         CHECK_TRUE(ParseFtraceEvent(traceResult.get(), cpuid, page, event), false, "parse raw event for cpu-%d failed!",
551                    cpuid);
552         CHECK_TRUE(tansporter_->Submit(std::move(traceResult)), false, "report raw event for cpu-%d failed!", cpuid);
553     } else {
554         auto ctx = resultWriter_->startReport(resultWriter_);
555         CHECK_NOTNULL(ctx, false, "%s: get RandomWriteCtx FAILED!", __func__);
556         static ProtoEncoder::MessagePool msgPool;
557         static ProtoEncoder::TracePluginResult traceResult;
558         msgPool.Reset();
559         traceResult.Reset(ctx, &msgPool);
560         traceResult.set_version(osVersion_);
561         ProtoEncoder::FtraceEvent* event = nullptr;  // Used to distinguish between SubEventParser instance types.
562         CHECK_TRUE(ParseFtraceEvent(&traceResult, cpuid, page, event), false, "parse raw event for cpu-%d failed!",
563                    cpuid);
564         int32_t msgSize = traceResult.Finish();
565         resultWriter_->finishReport(resultWriter_, msgSize);
566         tansporter_->Report(static_cast<size_t>(msgSize));
567     }
568     if (!dataReady_) {
569         dataReady_ = true;
570     }
571     return true;
572 }
573 
ParseEventDataOnNomalMode(int cpuid,long dataSize)574 bool FlowController::ParseEventDataOnNomalMode(int cpuid, long dataSize)
575 {
576     CHECK_NOTNULL(resultWriter_, false, "%s: resultWriter_ nullptr", __func__);
577     auto buffer = ftraceBuffers_[cpuid].get();
578     auto endPtr = buffer + dataSize;
579     for (auto page = buffer; page < endPtr; page += PAGE_SIZE) {
580         if (!ParseEventData(cpuid, page)) {
581             PROFILER_LOG_ERROR(LOG_CORE, "%s:ParseEventData for cpu-%d failed!", __func__, cpuid);
582         }
583     }
584     return true;
585 }
586 
ParseEventDataOnDelayMode()587 bool FlowController::ParseEventDataOnDelayMode()
588 {
589     CHECK_TRUE(fseek(rawDataFile_.get(), 0, SEEK_SET) == 0, false, "fseek failed!");
590     while (!feof(rawDataFile_.get())) {
591         uint8_t cpuId = 0;
592         long dataBytes = 0;
593         fread(&cpuId, sizeof(uint8_t), 1, rawDataFile_.get());
594         fread(&dataBytes, sizeof(long), 1, rawDataFile_.get());
595         for (long i = 0; i < dataBytes; i += PAGE_SIZE) {
596             uint8_t page[PAGE_SIZE] = {0};
597             fread(page, sizeof(uint8_t), PAGE_SIZE, rawDataFile_.get());
598             if (!ParseEventData(cpuId, page)) {
599                 PROFILER_LOG_ERROR(LOG_CORE, "%s:ParseEventData for cpu-%d failed!", __func__, cpuId);
600             }
601         }
602     }
603     return true;
604 }
605 
StopCapture(void)606 int FlowController::StopCapture(void)
607 {
608     CHECK_TRUE(ftraceSupported_, -1, "current kernel not support ftrace!");
609     CHECK_NOTNULL(tansporter_, -1, "crate ResultTransporter FAILED!");
610 
611     CHECK_TRUE(requestEvents_.size() != 0 || traceApps_.size() != 0 || traceCategories_.size() != 0, -1,
612                "StopCapture: ftrace event is not set, return false");
613 
614     // disable ftrace event switches
615     DisableTraceEvents();
616 
617     // stop ftrace event data polling thread
618     keepRunning_ = false;
619     if (pollThread_.joinable()) {
620         PROFILER_LOG_INFO(LOG_CORE, "join thread start!\n");
621         pollThread_.join();
622         PROFILER_LOG_INFO(LOG_CORE, "join thread  done!\n");
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         CHECK_TRUE(ParsePerCpuStatus(traceResult, TRACE_END), -1, "parse TRACE_END stats FAILED!");
634         int32_t msgSize = traceResult->Finish();
635         resultWriter_->finishReport(resultWriter_, msgSize);
636         tansporter_->Report(static_cast<size_t>(msgSize));
637     }
638 
639     // disable userspace trace triggers
640     // because trace cmd will read trace buffer,
641     // so we to this action after polling thread exit.
642     traceCollector_->Close();
643     tansporter_->Flush();
644 
645     // release resources
646     ftraceReaders_.clear();   // release ftrace data readers
647     ftraceBuffers_.clear();   // release ftrace event read buffers
648     memPool_.reset();         // release memory pool
649     return 0;
650 }
651 
ParsePerCpuStatus(T & tracePluginResult,int stage)652 template <typename T> bool FlowController::ParsePerCpuStatus(T& tracePluginResult, int stage)
653 {
654     CHECK_NOTNULL(tracePluginResult, false, "create TracePluginResult FAILED!");
655 
656     auto cpuStatsMsg = tracePluginResult->add_ftrace_cpu_stats();
657     if (stage == TRACE_START) {
658         cpuStatsMsg->set_status(FtraceCpuStatsMsg_Status_TRACE_START);
659     } else {
660         cpuStatsMsg->set_status(FtraceCpuStatsMsg_Status_TRACE_END);
661     }
662 
663     std::string traceClock = FtraceFsOps::GetInstance().GetTraceClock();
664     if (traceClock.size() > 0) {
665         cpuStatsMsg->set_trace_clock(traceClock);
666     }
667 
668     for (int i = 0; i < platformCpuNum_; i++) {
669         PROFILER_LOG_INFO(LOG_CORE, "[%d] ParsePerCpuStatus %d!", i, stage);
670         PerCpuStats stats = {};
671         stats.cpuIndex = i;
672         ftraceParser_->ParsePerCpuStatus(stats, FtraceFsOps::GetInstance().GetPerCpuStats(i));
673         auto perCpuMsg = cpuStatsMsg->add_per_cpu_stats();
674         perCpuMsg->set_cpu(stats.cpuIndex);
675         perCpuMsg->set_entries(stats.entries);
676         perCpuMsg->set_overrun(stats.overrun);
677         perCpuMsg->set_commit_overrun(stats.commitOverrun);
678         perCpuMsg->set_bytes(stats.bytes);
679         perCpuMsg->set_oldest_event_ts(stats.oldestEventTs);
680         perCpuMsg->set_now_ts(stats.nowTs);
681         perCpuMsg->set_dropped_events(stats.droppedEvents);
682         perCpuMsg->set_read_events(stats.readEvents);
683     }
684 
685     return true;
686 }
687 
ReportClockTimes(T & tracePluginResult)688 template <typename T> bool FlowController::ReportClockTimes(T& tracePluginResult)
689 {
690     CHECK_NOTNULL(tracePluginResult, false, "create TracePluginResult FAILED!");
691 
692     std::map<clockid_t, ClockDetailMsg::ClockId> clocksMap = {
693         {CLOCK_REALTIME, ClockDetailMsg::REALTIME},
694         {CLOCK_REALTIME_COARSE, ClockDetailMsg::REALTIME_COARSE},
695         {CLOCK_MONOTONIC, ClockDetailMsg::MONOTONIC},
696         {CLOCK_MONOTONIC_COARSE, ClockDetailMsg::MONOTONIC_COARSE},
697         {CLOCK_MONOTONIC_RAW, ClockDetailMsg::MONOTONIC_RAW},
698         {CLOCK_BOOTTIME, ClockDetailMsg::BOOTTIME},
699     };
700     for (auto& entry : clocksMap) {
701         struct timespec ts = {};
702         clock_gettime(entry.first, &ts);
703         auto clockMsg = tracePluginResult->add_clocks_detail();
704         CHECK_NOTNULL(clockMsg, false, "add clock_detail failed for %d!", entry.first);
705         clockMsg->set_id(entry.second);
706         auto timeMsg = clockMsg->mutable_time();
707         timeMsg->set_tv_sec(ts.tv_sec);
708         timeMsg->set_tv_nsec(ts.tv_nsec);
709 
710         struct timespec tsResolution = {};
711         clock_getres(entry.first, &tsResolution);
712         auto resolutionMsg = clockMsg->mutable_resolution();
713         resolutionMsg->set_tv_sec(tsResolution.tv_sec);
714         resolutionMsg->set_tv_nsec(tsResolution.tv_nsec);
715     }
716     return true;
717 }
718 
ParseKernelSymbols(T & tracePluginResult)719 template <typename T> bool FlowController::ParseKernelSymbols(T& tracePluginResult)
720 {
721     CHECK_NOTNULL(tracePluginResult, false, "create TracePluginResult FAILED!");
722 
723     ksymsParser_->Accept([&tracePluginResult](const KernelSymbol& symbol) {
724         auto symbolDetail = tracePluginResult->add_symbols_detail();
725         symbolDetail->set_symbol_addr(symbol.addr);
726         symbolDetail->set_symbol_name(symbol.name);
727     });
728     PROFILER_LOG_INFO(LOG_CORE, "parse kernel symbol message done!");
729     return true;
730 }
731 
732 template <typename T, typename E>
ParseFtraceEvent(T * tracePluginResult,int cpuid,uint8_t page[],E * ftraceEvent)733 bool FlowController::ParseFtraceEvent(T* tracePluginResult, int cpuid, uint8_t page[], E* ftraceEvent)
734 {
735     CHECK_NOTNULL(tracePluginResult, false, "create TracePluginResult FAILED!");
736 
737     auto cpudetail = tracePluginResult->add_ftrace_cpu_detail();
738     cpudetail->set_cpu(static_cast<uint32_t>(cpuid));
739 
740     CHECK_TRUE(ftraceParser_->ParsePage(*cpudetail, page, PAGE_SIZE, ftraceEvent), false, "parse page failed!");
741     return true;
742 }
743 
AddPlatformEventsToParser(void)744 bool FlowController::AddPlatformEventsToParser(void)
745 {
746     CHECK_TRUE(ftraceSupported_, false, "current kernel not support ftrace!");
747 
748     PROFILER_LOG_INFO(LOG_CORE, "Add platform events to parser start!");
749     for (auto& typeName : FtraceFsOps::GetInstance().GetPlatformEvents()) {
750         std::string type = typeName.first;
751         std::string name = typeName.second;
752         if (ftraceParser_->SetupEvent(type, name)) {
753             supportedEvents_.push_back(typeName);
754         }
755     }
756     PROFILER_LOG_INFO(LOG_CORE, "Add platform events to parser done, events: %zu!", supportedEvents_.size());
757     return true;
758 }
759 
GetCmdArgs(const TracePluginConfig & traceConfig)760 std::string FlowController::GetCmdArgs(const TracePluginConfig& traceConfig)
761 {
762     std::stringstream args;
763     for (const auto& event : traceConfig.ftrace_events()) {
764         args << "ftrace_events: " << event << ", ";
765     }
766     for (const auto& category : traceConfig.hitrace_categories()) {
767         args << "hitrace_categories: " << category << ", ";
768     }
769     for (const auto& app : traceConfig.hitrace_apps()) {
770         args << "hitrace_apps: " << app << ", ";
771     }
772     args << "buffer_size_kb: " << std::to_string(traceConfig.buffer_size_kb()) << ", ";
773     args << "flush_interval_ms: " << std::to_string(traceConfig.flush_interval_ms()) << ", ";
774     args << "flush_threshold_kb: " << std::to_string(traceConfig.flush_threshold_kb()) << ", ";
775     args << "trace_period_ms: " << std::to_string(traceConfig.trace_period_ms()) << ", ";
776     args << "trace_duration_ms: " << std::to_string(traceConfig.trace_duration_ms()) << ", ";
777     args << "hitrace_time: " << std::to_string(traceConfig.hitrace_time()) << ", ";
778     args << "parse_ksyms: " << (traceConfig.parse_ksyms() ? "true" : "false") << ", ";
779     args << "clock: " << traceConfig.clock() << ", ";
780     args << "raw_data_prefix: " << traceConfig.raw_data_prefix() << ", ";
781     args << "debug_on: " << (traceConfig.debug_on() ? "true" : "false") << ", ";
782     args << "discard_cache_data: " << (traceConfig.discard_cache_data() ? "true" : "false") << ", ";
783     args << "parse_mode: " << std::to_string(traceConfig.parse_mode());
784     return args.str();
785 }
786 
LoadConfig(const uint8_t configData[],uint32_t size)787 int FlowController::LoadConfig(const uint8_t configData[], uint32_t size)
788 {
789     CHECK_TRUE(size > 0, -1, "config data size is zero!");
790     CHECK_NOTNULL(configData, -1, "config data is null!");
791     CHECK_TRUE(ftraceSupported_, -1, "current kernel not support ftrace!");
792     CHECK_NOTNULL(tansporter_, -1, "ResultTransporter crated FAILED!");
793 
794     TracePluginConfig traceConfig;
795     CHECK_TRUE(traceConfig.ParseFromArray(configData, size), -1, "parse %u bytes configData failed!", size);
796 
797     // sort and save user requested trace events
798     std::set<std::string> events(traceConfig.ftrace_events().begin(), traceConfig.ftrace_events().end());
799     for (auto ftraceEvent : events) {
800         requestEvents_.push_back(ftraceEvent);
801     }
802 
803     traceApps_.assign(traceConfig.hitrace_apps().begin(), traceConfig.hitrace_apps().end());
804     traceCategories_.assign(traceConfig.hitrace_categories().begin(), traceConfig.hitrace_categories().end());
805 
806     CHECK_TRUE(requestEvents_.size() != 0 || traceApps_.size() != 0 || traceCategories_.size() != 0, -1,
807                "LoadConfig: ftrace event is not set, return false");
808 
809     // setup trace clock
810     if (g_availableClocks.count(traceConfig.clock()) > 0) {
811         traceClock_ = traceConfig.clock();
812         FtraceFsOps::GetInstance().SetTraceClock(traceConfig.clock());
813     }
814 
815     // setup parse kernel symbol option
816     parseKsyms_ = traceConfig.parse_ksyms();
817     parseMode_ = traceConfig.parse_mode();
818     // setup trace buffer size
819     SetupTraceBufferSize(traceConfig.buffer_size_kb());
820 
821     // setup transporter flush params
822     SetupTransporterFlushParams(traceConfig.flush_interval_ms(), traceConfig.flush_threshold_kb());
823 
824     // generate raw data file names
825     GenerateRawDataFileNames(traceConfig.raw_data_prefix());
826 
827     // setup trace period param
828     SetupTraceReadPeriod(traceConfig.trace_period_ms());
829     flushCacheData_ = traceConfig.discard_cache_data();
830     hitraceTime_ = traceConfig.hitrace_time();
831 
832     int ret = COMMON::PluginWriteToHisysevent("ftrace_plugin", "sh", GetCmdArgs(traceConfig),
833         COMMON::ErrorType::RET_SUCC, "success");
834     PROFILER_LOG_INFO(LOG_CORE, "hisysevent report ftrace_plugin result: %d", ret);
835     return 0;
836 }
837 
SetupTraceBufferSize(uint32_t sizeKb)838 void FlowController::SetupTraceBufferSize(uint32_t sizeKb)
839 {
840     uint32_t maxBufferSizeKb = MAX_BUFFER_SIZE_KB;
841     if (FtraceFsOps::GetInstance().IsHmKernel()) {
842         maxBufferSizeKb = HM_MAX_BUFFER_SIZE_KB;
843     }
844     if (sizeKb < MIN_BUFFER_SIZE_KB) {
845         bufferSizeKb_ = MIN_BUFFER_SIZE_KB;
846     } else if (sizeKb > maxBufferSizeKb) {
847         bufferSizeKb_ = maxBufferSizeKb;
848     } else {
849         bufferSizeKb_ = sizeKb / KB_PER_PAGE * KB_PER_PAGE;
850     }
851 }
852 
SetupTransporterFlushParams(uint32_t flushInterval,uint32_t flushThresholdKb)853 void FlowController::SetupTransporterFlushParams(uint32_t flushInterval, uint32_t flushThresholdKb)
854 {
855     if (flushInterval > 0 && flushInterval <= MAX_FLUSH_INTERVAL) {
856         tansporter_->SetFlushInterval(flushInterval);
857     }
858     if (flushThresholdKb > 0 && flushThresholdKb <= MAX_FLUSH_THRESHOLD) {
859         tansporter_->SetFlushThreshold(flushThresholdKb * BYTE_PER_KB);
860     }
861 }
862 
GenerateRawDataFileNames(const std::string & prefix)863 void FlowController::GenerateRawDataFileNames(const std::string& prefix)
864 {
865     if (prefix.size() > 0) {
866         for (int i = 0; i < platformCpuNum_; i++) {
867             std::string path = prefix + std::to_string(i);
868             rawDataDumpPath_.push_back(path);
869         }
870     }
871 }
872 
SetupTraceReadPeriod(uint32_t tracePeriod)873 void FlowController::SetupTraceReadPeriod(uint32_t tracePeriod)
874 {
875     if (tracePeriod > 0 && tracePeriod <= MAX_TRACE_PERIOD_MS) {
876         tracePeriodMs_ = tracePeriod;
877     } else {
878         tracePeriodMs_ = DEFAULT_TRACE_PERIOD_MS;
879     }
880 }
881 
EnableTraceEvents(void)882 void FlowController::EnableTraceEvents(void)
883 {
884     std::unordered_set<std::string> userEventSet(requestEvents_.begin(), requestEvents_.end());
885     for (auto& event : supportedEvents_) {
886         std::string type = event.first;
887         std::string name = event.second;
888         std::string fmtType = type;
889         if (type == "power_kernel") {
890             fmtType = "power";
891         }
892         if (userEventSet.count(fmtType + "/" + name)) { // user config format
893             if (FtraceFsOps::GetInstance().EnableEvent(type, name)) {
894                 FtraceFsOps::GetInstance().AppendSetEvent(type, name);
895                 enabledEvents_.push_back(event);
896             }
897         }
898     }
899     FtraceFsOps::GetInstance().EnableTracing();
900 }
901 
DisableTraceEvents(void)902 void FlowController::DisableTraceEvents(void)
903 {
904     FtraceFsOps::GetInstance().DisableTracing();
905     for (auto& event : enabledEvents_) {
906         std::string type = event.first;
907         std::string name = event.second;
908         FtraceFsOps::GetInstance().DisableEvent(type, name);
909     }
910     enabledEvents_.clear();
911 }
912 
DisableAllCategories(void)913 void FlowController::DisableAllCategories(void)
914 {
915     for (auto& event : supportedEvents_) {
916         std::string type = event.first;
917         std::string name = event.second;
918         FtraceFsOps::GetInstance().DisableCategories(type);
919     }
920 }
921 
SetReportBasicData(bool isReportBasicData)922 void FlowController::SetReportBasicData(bool isReportBasicData)
923 {
924     isReportBasicData_ = isReportBasicData;
925 }
926 FTRACE_NS_END
927