• 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     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