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