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