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