148f512ceSopenharmony_ci/*
248f512ceSopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
348f512ceSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
448f512ceSopenharmony_ci * you may not use this file except in compliance with the License.
548f512ceSopenharmony_ci * You may obtain a copy of the License at
648f512ceSopenharmony_ci *
748f512ceSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
848f512ceSopenharmony_ci *
948f512ceSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1048f512ceSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1148f512ceSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1248f512ceSopenharmony_ci * See the License for the specific language governing permissions and
1348f512ceSopenharmony_ci * limitations under the License.
1448f512ceSopenharmony_ci */
1548f512ceSopenharmony_ci#include "perf_file_reader.h"
1648f512ceSopenharmony_ci
1748f512ceSopenharmony_ci#include <bitset>
1848f512ceSopenharmony_ci#include <cinttypes>
1948f512ceSopenharmony_ci#include <cstdlib>
2048f512ceSopenharmony_ci#include <memory>
2148f512ceSopenharmony_ci
2248f512ceSopenharmony_ci#include <sys/stat.h>
2348f512ceSopenharmony_ci#include <unistd.h>
2448f512ceSopenharmony_ci
2548f512ceSopenharmony_ci#include "hiperf_hilog.h"
2648f512ceSopenharmony_ci#include "utilities.h"
2748f512ceSopenharmony_ci
2848f512ceSopenharmony_ciusing namespace std::chrono;
2948f512ceSopenharmony_cinamespace OHOS {
3048f512ceSopenharmony_cinamespace Developtools {
3148f512ceSopenharmony_cinamespace HiPerf {
3248f512ceSopenharmony_ciconst int FETURE_MAX = 256;
3348f512ceSopenharmony_ciconst int SIZE_FETURE_COUNT = 8;
3448f512ceSopenharmony_ci
3548f512ceSopenharmony_cistd::unique_ptr<PerfFileReader> PerfFileReader::Instance(const std::string &fileName)
3648f512ceSopenharmony_ci{
3748f512ceSopenharmony_ci    std::string resolvedPath = CanonicalizeSpecPath(fileName.c_str());
3848f512ceSopenharmony_ci    FILE *fp = fopen(resolvedPath.c_str(), "rb");
3948f512ceSopenharmony_ci    if (fp == nullptr) {
4048f512ceSopenharmony_ci        HLOGE("fail to open file %s", fileName.c_str());
4148f512ceSopenharmony_ci        return nullptr;
4248f512ceSopenharmony_ci    }
4348f512ceSopenharmony_ci
4448f512ceSopenharmony_ci    std::unique_ptr<PerfFileReader> reader = std::make_unique<PerfFileReader>(fileName, fp);
4548f512ceSopenharmony_ci    if (!reader->ReadFileHeader()) {
4648f512ceSopenharmony_ci        // Fail to read header, maybe its compressed
4748f512ceSopenharmony_ci        if (reader->IsGzipFile()) {
4848f512ceSopenharmony_ci            fclose(fp);
4948f512ceSopenharmony_ci            reader->fp_ = nullptr;
5048f512ceSopenharmony_ci
5148f512ceSopenharmony_ci            CHECK_TRUE(!UncompressFile(fileName, ".perf.data"), nullptr, 1,
5248f512ceSopenharmony_ci                       "Fail to UncompressFile(%s)", fileName.c_str());
5348f512ceSopenharmony_ci
5448f512ceSopenharmony_ci            // open the uncompressed hidden file .perf.data
5548f512ceSopenharmony_ci            FILE *fp2 = fopen(".perf.data", "rb");
5648f512ceSopenharmony_ci            if (fp2 == nullptr) {
5748f512ceSopenharmony_ci                HLOGE("fail to open uncompressed file .perf.data");
5848f512ceSopenharmony_ci                return nullptr;
5948f512ceSopenharmony_ci            }
6048f512ceSopenharmony_ci
6148f512ceSopenharmony_ci            reader->fp_ = fp2;
6248f512ceSopenharmony_ci            reader->compressData_ = true;
6348f512ceSopenharmony_ci
6448f512ceSopenharmony_ci            if (!reader->ReadFileHeader()) {
6548f512ceSopenharmony_ci                HLOGE("fail to read header of file .perf.data");
6648f512ceSopenharmony_ci                return nullptr;
6748f512ceSopenharmony_ci            }
6848f512ceSopenharmony_ci            goto end;
6948f512ceSopenharmony_ci        }
7048f512ceSopenharmony_ci        return nullptr;
7148f512ceSopenharmony_ci    }
7248f512ceSopenharmony_ciend:
7348f512ceSopenharmony_ci    CHECK_TRUE(!reader->ReadAttrSection(), nullptr, 0, "");
7448f512ceSopenharmony_ci    return reader;
7548f512ceSopenharmony_ci}
7648f512ceSopenharmony_ci
7748f512ceSopenharmony_ciPerfFileReader::PerfFileReader(const std::string &fileName, FILE *fp) : fp_(fp), fileName_(fileName)
7848f512ceSopenharmony_ci{
7948f512ceSopenharmony_ci    featureSectionOffset_ = 0;
8048f512ceSopenharmony_ci    struct stat fileStat;
8148f512ceSopenharmony_ci    if (fp != nullptr) {
8248f512ceSopenharmony_ci        if (fstat(fileno(fp), &fileStat) != -1 and fileStat.st_size > 0) {
8348f512ceSopenharmony_ci            fileSize_ = fileStat.st_size;
8448f512ceSopenharmony_ci        }
8548f512ceSopenharmony_ci    }
8648f512ceSopenharmony_ci}
8748f512ceSopenharmony_ci
8848f512ceSopenharmony_ciPerfFileReader::~PerfFileReader()
8948f512ceSopenharmony_ci{
9048f512ceSopenharmony_ci    // if file was not closed properly
9148f512ceSopenharmony_ci    if (fp_ != nullptr) {
9248f512ceSopenharmony_ci        fclose(fp_);
9348f512ceSopenharmony_ci        fp_ = nullptr;
9448f512ceSopenharmony_ci    }
9548f512ceSopenharmony_ci
9648f512ceSopenharmony_ci    // remove the uncompressed .perf.data
9748f512ceSopenharmony_ci    if (compressData_) {
9848f512ceSopenharmony_ci        if (remove(".perf.data") != 0) {
9948f512ceSopenharmony_ci            HLOGE("Fail to remove uncompressed file .perf.data");
10048f512ceSopenharmony_ci            perror("Fail to remove temp file");
10148f512ceSopenharmony_ci        }
10248f512ceSopenharmony_ci    }
10348f512ceSopenharmony_ci}
10448f512ceSopenharmony_ci
10548f512ceSopenharmony_cibool PerfFileReader::IsValidDataFile()
10648f512ceSopenharmony_ci{
10748f512ceSopenharmony_ci    return (memcmp(header_.magic, PERF_MAGIC, sizeof(header_.magic)) == 0);
10848f512ceSopenharmony_ci}
10948f512ceSopenharmony_ci
11048f512ceSopenharmony_cibool PerfFileReader::IsGzipFile()
11148f512ceSopenharmony_ci{
11248f512ceSopenharmony_ci    return header_.magic[0] == '\x1f' and header_.magic[1] == '\x8b';
11348f512ceSopenharmony_ci}
11448f512ceSopenharmony_ci
11548f512ceSopenharmony_cibool PerfFileReader::ReadFileHeader()
11648f512ceSopenharmony_ci{
11748f512ceSopenharmony_ci    if (Read(&header_, sizeof(header_))) {
11848f512ceSopenharmony_ci        dataSectionSize_ = header_.data.size;
11948f512ceSopenharmony_ci        if (IsValidDataFile()) {
12048f512ceSopenharmony_ci            featureSectionOffset_ = header_.data.offset + header_.data.size;
12148f512ceSopenharmony_ci            for (int i = 0; i < FETURE_MAX / SIZE_FETURE_COUNT; i++) {
12248f512ceSopenharmony_ci                std::bitset<SIZE_FETURE_COUNT> features(header_.features[i]);
12348f512ceSopenharmony_ci                for (int j = 0; j < SIZE_FETURE_COUNT; j++) {
12448f512ceSopenharmony_ci                    if (features.test(j)) {
12548f512ceSopenharmony_ci                        features_.emplace_back((FEATURE)(((uint64_t)i) * SIZE_FETURE_COUNT + j));
12648f512ceSopenharmony_ci                    }
12748f512ceSopenharmony_ci                }
12848f512ceSopenharmony_ci            }
12948f512ceSopenharmony_ci            return true;
13048f512ceSopenharmony_ci        }
13148f512ceSopenharmony_ci    }
13248f512ceSopenharmony_ci    return false;
13348f512ceSopenharmony_ci}
13448f512ceSopenharmony_ci
13548f512ceSopenharmony_cibool PerfFileReader::ReadAttrSection()
13648f512ceSopenharmony_ci{
13748f512ceSopenharmony_ci    if (header_.attrSize != sizeof(perf_file_attr)) {
13848f512ceSopenharmony_ci        // 4.19 and 5.1 use diff size , 128 vs 136
13948f512ceSopenharmony_ci        HLOGW("attr size %" PRId64 " doesn't match expected size %zu", header_.attrSize,
14048f512ceSopenharmony_ci              sizeof(perf_file_attr));
14148f512ceSopenharmony_ci    }
14248f512ceSopenharmony_ci    CHECK_TRUE(header_.attrSize == 0, false, 0, "");
14348f512ceSopenharmony_ci    int attrCount = header_.attrs.size / header_.attrSize;
14448f512ceSopenharmony_ci    CHECK_TRUE(attrCount == 0, false, 1, "no attr in file");
14548f512ceSopenharmony_ci    if (fseek(fp_, header_.attrs.offset, SEEK_SET) != 0) {
14648f512ceSopenharmony_ci        HLOGE("fseek() failed");
14748f512ceSopenharmony_ci        return false;
14848f512ceSopenharmony_ci    }
14948f512ceSopenharmony_ci    for (int i = 0; i < attrCount; ++i) {
15048f512ceSopenharmony_ci        std::vector<char> buf(header_.attrSize);
15148f512ceSopenharmony_ci        CHECK_TRUE(!Read(buf.data(), buf.size()), false, 0, "");
15248f512ceSopenharmony_ci        // size of perf_event_attr change between different linux kernel versions.
15348f512ceSopenharmony_ci        // can not memcpy to perf_file_attr as a whole
15448f512ceSopenharmony_ci        perf_file_attr attr {};
15548f512ceSopenharmony_ci        size_t attrSize = header_.attrSize - sizeof(attr.ids);
15648f512ceSopenharmony_ci
15748f512ceSopenharmony_ci        // If the size is smaller, you can use a pointer to point directly.
15848f512ceSopenharmony_ci        // Our UAPI is 4.19. is less than 5.1
15948f512ceSopenharmony_ci        if (header_.attrSize < sizeof(perf_event_attr)) {
16048f512ceSopenharmony_ci            HLOGE("size not match, ptr of perf_event_attr maybe overfollow %zu vs %zu",
16148f512ceSopenharmony_ci                  sizeof(perf_event_attr), attrSize);
16248f512ceSopenharmony_ci        }
16348f512ceSopenharmony_ci
16448f512ceSopenharmony_ci        attr.attr = *(reinterpret_cast<perf_event_attr *>(&buf[0]));
16548f512ceSopenharmony_ci        attr.ids = *(reinterpret_cast<perf_file_section *>(&buf[attrSize]));
16648f512ceSopenharmony_ci        vecAttr_.push_back(attr);
16748f512ceSopenharmony_ci    }
16848f512ceSopenharmony_ci
16948f512ceSopenharmony_ci    // read ids for attr
17048f512ceSopenharmony_ci    for (size_t i = 0; i < vecAttr_.size(); ++i) {
17148f512ceSopenharmony_ci        std::vector<uint64_t> ids;
17248f512ceSopenharmony_ci        CHECK_TRUE(!ReadIdsForAttr(vecAttr_[i], &ids), false, 0, "");
17348f512ceSopenharmony_ci        vecAttrIds_.push_back(ids);
17448f512ceSopenharmony_ci
17548f512ceSopenharmony_ci        // map ids to attr index
17648f512ceSopenharmony_ci        for (auto id : ids) {
17748f512ceSopenharmony_ci            mapId2Attr_[id] = i;
17848f512ceSopenharmony_ci        }
17948f512ceSopenharmony_ci    }
18048f512ceSopenharmony_ci
18148f512ceSopenharmony_ci    return true;
18248f512ceSopenharmony_ci}
18348f512ceSopenharmony_ci
18448f512ceSopenharmony_cibool PerfFileReader::ReadIdsForAttr(const perf_file_attr &attr, std::vector<uint64_t> *ids)
18548f512ceSopenharmony_ci{
18648f512ceSopenharmony_ci    if (attr.ids.size > 0) {
18748f512ceSopenharmony_ci        size_t count = attr.ids.size / sizeof(uint64_t);
18848f512ceSopenharmony_ci        if (fseek(fp_, attr.ids.offset, SEEK_SET) != 0) {
18948f512ceSopenharmony_ci            HLOGE("fseek() failed");
19048f512ceSopenharmony_ci            return false;
19148f512ceSopenharmony_ci        }
19248f512ceSopenharmony_ci        CHECK_TRUE(ids == nullptr, false, 0, "");
19348f512ceSopenharmony_ci        ids->resize(count);
19448f512ceSopenharmony_ci        CHECK_TRUE(!Read(ids->data(), attr.ids.size), false, 0, "");
19548f512ceSopenharmony_ci    }
19648f512ceSopenharmony_ci    return true;
19748f512ceSopenharmony_ci}
19848f512ceSopenharmony_ci
19948f512ceSopenharmony_cistd::vector<AttrWithId> PerfFileReader::GetAttrSection() const
20048f512ceSopenharmony_ci{
20148f512ceSopenharmony_ci    std::vector<AttrWithId> result(vecAttr_.size());
20248f512ceSopenharmony_ci
20348f512ceSopenharmony_ci    for (size_t i = 0; i < vecAttr_.size(); ++i) {
20448f512ceSopenharmony_ci        result[i].attr = vecAttr_[i].attr;
20548f512ceSopenharmony_ci        result[i].ids = vecAttrIds_[i];
20648f512ceSopenharmony_ci    }
20748f512ceSopenharmony_ci    return result;
20848f512ceSopenharmony_ci}
20948f512ceSopenharmony_ci
21048f512ceSopenharmony_cibool PerfFileReader::ReadDataSection(ProcessRecordCB &callback)
21148f512ceSopenharmony_ci{
21248f512ceSopenharmony_ci    if (fseek(fp_, header_.data.offset, SEEK_SET) != 0) {
21348f512ceSopenharmony_ci        HLOGE("fseek() failed");
21448f512ceSopenharmony_ci        return false;
21548f512ceSopenharmony_ci    }
21648f512ceSopenharmony_ci
21748f512ceSopenharmony_ci    HLOGD("dataSection_ at offset %" PRId64 " + %" PRId64 "", header_.data.offset,
21848f512ceSopenharmony_ci          header_.data.size);
21948f512ceSopenharmony_ci
22048f512ceSopenharmony_ci    CHECK_TRUE(!ReadRecord(callback), false, LOG_TYPE_PRINTF, "some record format is error!\n");
22148f512ceSopenharmony_ci
22248f512ceSopenharmony_ci#ifdef HIPERF_DEBUG_TIME
22348f512ceSopenharmony_ci    printf("readRecordTime: %" PRId64 " ms\n",
22448f512ceSopenharmony_ci           duration_cast<milliseconds>(readRecordTime_).count());
22548f512ceSopenharmony_ci    printf("readCallbackTime: %" PRId64 " ms\n",
22648f512ceSopenharmony_ci           duration_cast<milliseconds>(readCallbackTime_).count());
22748f512ceSopenharmony_ci#endif
22848f512ceSopenharmony_ci    return dataSectionSize_ == 0;
22948f512ceSopenharmony_ci}
23048f512ceSopenharmony_ci
23148f512ceSopenharmony_ciconst perf_event_attr *PerfFileReader::GetDefaultAttr()
23248f512ceSopenharmony_ci{
23348f512ceSopenharmony_ci    CHECK_TRUE(vecAttr_.empty(), nullptr, 0, "");
23448f512ceSopenharmony_ci    return &(vecAttr_[0].attr);
23548f512ceSopenharmony_ci}
23648f512ceSopenharmony_ci
23748f512ceSopenharmony_cibool PerfFileReader::ReadRecord(ProcessRecordCB &callback)
23848f512ceSopenharmony_ci{
23948f512ceSopenharmony_ci#ifdef HIPERF_DEBUG_TIME
24048f512ceSopenharmony_ci    const auto startReadTime = steady_clock::now();
24148f512ceSopenharmony_ci#endif
24248f512ceSopenharmony_ci    // record size can not exceed 64K
24348f512ceSopenharmony_ci    HIPERF_BUF_ALIGN static uint8_t buf[RECORD_SIZE_LIMIT_SPE];
24448f512ceSopenharmony_ci    // diff with reader
24548f512ceSopenharmony_ci    uint64_t remainingSize = header_.data.size;
24648f512ceSopenharmony_ci    size_t recordNumber = 0;
24748f512ceSopenharmony_ci    const perf_event_attr *attr = GetDefaultAttr();
24848f512ceSopenharmony_ci    CHECK_TRUE(attr == nullptr, false, 1, "attr is null");
24948f512ceSopenharmony_ci    while (remainingSize > 0) {
25048f512ceSopenharmony_ci        if (remainingSize < sizeof(perf_event_header)) {
25148f512ceSopenharmony_ci            HLOGW("not enough sizeof perf_event_header");
25248f512ceSopenharmony_ci            return false;
25348f512ceSopenharmony_ci        } else if (!Read(buf, sizeof(perf_event_header))) {
25448f512ceSopenharmony_ci            HLOGW("read perf_event_header failed.");
25548f512ceSopenharmony_ci            return false;
25648f512ceSopenharmony_ci        } else {
25748f512ceSopenharmony_ci            perf_event_header *header = reinterpret_cast<perf_event_header *>(buf);
25848f512ceSopenharmony_ci            if (header == nullptr) {
25948f512ceSopenharmony_ci                HLOGE("read record header is null");
26048f512ceSopenharmony_ci                return false;
26148f512ceSopenharmony_ci            } else if (header->size > RECORD_SIZE_LIMIT) {
26248f512ceSopenharmony_ci                HLOGE("read record header size error %hu", header->size);
26348f512ceSopenharmony_ci                return false;
26448f512ceSopenharmony_ci            }
26548f512ceSopenharmony_ci            if (remainingSize >= header->size) {
26648f512ceSopenharmony_ci                size_t headerSize = sizeof(perf_event_header);
26748f512ceSopenharmony_ci                if (Read(buf + headerSize, header->size - headerSize)) {
26848f512ceSopenharmony_ci                    size_t speSize = 0;
26948f512ceSopenharmony_ci                    if (header->type == PERF_RECORD_AUXTRACE) {
27048f512ceSopenharmony_ci                        struct PerfRecordAuxtraceData *auxtrace = reinterpret_cast<struct PerfRecordAuxtraceData *>
27148f512ceSopenharmony_ci                                                                  (header + 1);
27248f512ceSopenharmony_ci                        speSize = auxtrace->size;
27348f512ceSopenharmony_ci                        if (speSize > 0) {
27448f512ceSopenharmony_ci                            Read(buf + header->size, auxtrace->size);
27548f512ceSopenharmony_ci                        }
27648f512ceSopenharmony_ci                    }
27748f512ceSopenharmony_ci                    uint8_t *data = buf;
27848f512ceSopenharmony_ci                    std::unique_ptr<PerfEventRecord> record = GetPerfEventRecord(
27948f512ceSopenharmony_ci                        static_cast<perf_event_type>(header->type), data, *attr);
28048f512ceSopenharmony_ci                    // unknown record , break the process
28148f512ceSopenharmony_ci                    if (!record) {
28248f512ceSopenharmony_ci                        return false;
28348f512ceSopenharmony_ci                    } else {
28448f512ceSopenharmony_ci                        HLOGV("record type %u", record->GetType());
28548f512ceSopenharmony_ci                    }
28648f512ceSopenharmony_ci                    remainingSize = remainingSize - header->size - speSize;
28748f512ceSopenharmony_ci#ifdef HIPERF_DEBUG_TIME
28848f512ceSopenharmony_ci                    const auto startCallbackTime = steady_clock::now();
28948f512ceSopenharmony_ci#endif
29048f512ceSopenharmony_ci                    // call callback to process, then destroy record
29148f512ceSopenharmony_ci                    callback(std::move(record));
29248f512ceSopenharmony_ci                    recordNumber++;
29348f512ceSopenharmony_ci#ifdef HIPERF_DEBUG_TIME
29448f512ceSopenharmony_ci                    readCallbackTime_ +=
29548f512ceSopenharmony_ci                        duration_cast<microseconds>(steady_clock::now() - startCallbackTime);
29648f512ceSopenharmony_ci#endif
29748f512ceSopenharmony_ci                } else {
29848f512ceSopenharmony_ci                    HLOGE("read record data size failed %zu", header->size - headerSize);
29948f512ceSopenharmony_ci                    return false;
30048f512ceSopenharmony_ci                }
30148f512ceSopenharmony_ci            } else {
30248f512ceSopenharmony_ci                HLOGE("not enough header->size.");
30348f512ceSopenharmony_ci                return false;
30448f512ceSopenharmony_ci            }
30548f512ceSopenharmony_ci        }
30648f512ceSopenharmony_ci    }
30748f512ceSopenharmony_ci    HLOGD("read back %zu records", recordNumber);
30848f512ceSopenharmony_ci#ifdef HIPERF_DEBUG_TIME
30948f512ceSopenharmony_ci    readRecordTime_ += duration_cast<microseconds>(steady_clock::now() - startReadTime);
31048f512ceSopenharmony_ci#endif
31148f512ceSopenharmony_ci    return true;
31248f512ceSopenharmony_ci}
31348f512ceSopenharmony_ci
31448f512ceSopenharmony_cibool PerfFileReader::Read(void *buf, size_t len)
31548f512ceSopenharmony_ci{
31648f512ceSopenharmony_ci    if (buf == nullptr || len == 0) {
31748f512ceSopenharmony_ci        HLOG_ASSERT(buf != nullptr);
31848f512ceSopenharmony_ci        HLOG_ASSERT(len > 0);
31948f512ceSopenharmony_ci        return false;
32048f512ceSopenharmony_ci    }
32148f512ceSopenharmony_ci
32248f512ceSopenharmony_ci    if (fread(buf, len, 1, fp_) != 1) {
32348f512ceSopenharmony_ci        printf("failed to read file: %d", errno);
32448f512ceSopenharmony_ci        return false;
32548f512ceSopenharmony_ci    }
32648f512ceSopenharmony_ci    return true;
32748f512ceSopenharmony_ci}
32848f512ceSopenharmony_ci
32948f512ceSopenharmony_ciconst perf_file_header &PerfFileReader::GetHeader() const
33048f512ceSopenharmony_ci{
33148f512ceSopenharmony_ci    return header_;
33248f512ceSopenharmony_ci}
33348f512ceSopenharmony_ci
33448f512ceSopenharmony_cibool PerfFileReader::Read(char *buf, uint64_t offset, size_t len)
33548f512ceSopenharmony_ci{
33648f512ceSopenharmony_ci    if (buf == nullptr || len == 0) {
33748f512ceSopenharmony_ci        HLOG_ASSERT(buf != nullptr);
33848f512ceSopenharmony_ci        HLOG_ASSERT(len > 0);
33948f512ceSopenharmony_ci        return false;
34048f512ceSopenharmony_ci    }
34148f512ceSopenharmony_ci    if (fseek(fp_, offset, SEEK_SET) != 0) {
34248f512ceSopenharmony_ci        HLOGE("fseek() failed");
34348f512ceSopenharmony_ci        return false;
34448f512ceSopenharmony_ci    }
34548f512ceSopenharmony_ci
34648f512ceSopenharmony_ci    CHECK_TRUE(fread(buf, len, 1, fp_) != 1, false, LOG_TYPE_PRINTF, "failed to read file: %d", errno);
34748f512ceSopenharmony_ci    HLOGM("offset %" PRIx64 " len %zu buf %x %x %x %x", offset, len, buf[0], buf[1], buf[2],
34848f512ceSopenharmony_ci          buf[3]);
34948f512ceSopenharmony_ci    return true;
35048f512ceSopenharmony_ci}
35148f512ceSopenharmony_ciconst std::vector<FEATURE> &PerfFileReader::GetFeatures() const
35248f512ceSopenharmony_ci{
35348f512ceSopenharmony_ci    return features_;
35448f512ceSopenharmony_ci}
35548f512ceSopenharmony_ci
35648f512ceSopenharmony_ciconst std::vector<std::unique_ptr<PerfFileSection>> &PerfFileReader::GetFeatureSections() const
35748f512ceSopenharmony_ci{
35848f512ceSopenharmony_ci    return perfFileSections_;
35948f512ceSopenharmony_ci}
36048f512ceSopenharmony_ci
36148f512ceSopenharmony_ciconst std::string PerfFileReader::GetFeatureString(const FEATURE feature) const
36248f512ceSopenharmony_ci{
36348f512ceSopenharmony_ci    std::string featureName = PerfFileSection::GetFeatureName(feature);
36448f512ceSopenharmony_ci    HLOGV("GetFeatureSection %s", featureName.c_str());
36548f512ceSopenharmony_ci    if (!IsFeatrureStringSection(feature)) {
36648f512ceSopenharmony_ci        HLOGV("not a string feature: %s", featureName.c_str());
36748f512ceSopenharmony_ci    } else {
36848f512ceSopenharmony_ci        const PerfFileSection *featureSection = GetFeatureSection(feature);
36948f512ceSopenharmony_ci        if (featureSection != nullptr) {
37048f512ceSopenharmony_ci            const PerfFileSectionString *sectionString =
37148f512ceSopenharmony_ci                static_cast<const PerfFileSectionString *>(featureSection);
37248f512ceSopenharmony_ci            return sectionString->ToString();
37348f512ceSopenharmony_ci        } else {
37448f512ceSopenharmony_ci            HLOGV("have not found: %s", featureName.c_str());
37548f512ceSopenharmony_ci        }
37648f512ceSopenharmony_ci    }
37748f512ceSopenharmony_ci    return EMPTY_STRING;
37848f512ceSopenharmony_ci}
37948f512ceSopenharmony_ci
38048f512ceSopenharmony_ciconst PerfFileSection *PerfFileReader::GetFeatureSection(FEATURE feature) const
38148f512ceSopenharmony_ci{
38248f512ceSopenharmony_ci    for (auto const &it : perfFileSections_) {
38348f512ceSopenharmony_ci        HLOGV("perfFileSections");
38448f512ceSopenharmony_ci        if (it->featureId_ == feature) {
38548f512ceSopenharmony_ci            return it.get();
38648f512ceSopenharmony_ci        }
38748f512ceSopenharmony_ci    }
38848f512ceSopenharmony_ci    return nullptr;
38948f512ceSopenharmony_ci}
39048f512ceSopenharmony_ci
39148f512ceSopenharmony_cibool PerfFileReader::ReadFeatureSection()
39248f512ceSopenharmony_ci{
39348f512ceSopenharmony_ci    uint64_t featureSectionOffsetRead = featureSectionOffset_;
39448f512ceSopenharmony_ci    HLOGV(" ReadDataSection data offset '0x%" PRIx64 " ", featureSectionOffset_);
39548f512ceSopenharmony_ci
39648f512ceSopenharmony_ci    for (FEATURE feature : features_) {
39748f512ceSopenharmony_ci        perf_file_section sectionHeader;
39848f512ceSopenharmony_ci        // read failed ??
39948f512ceSopenharmony_ci        CHECK_TRUE(!Read((char *)&sectionHeader, featureSectionOffsetRead, sizeof(sectionHeader)),
40048f512ceSopenharmony_ci                   false, LOG_TYPE_PRINTF,
40148f512ceSopenharmony_ci                   "file format not correct. featureSectionOffsetRead '0x%" PRIx64 "\n", featureSectionOffsetRead);
40248f512ceSopenharmony_ci
40348f512ceSopenharmony_ci        HLOGV("process feature %d:%s", feature, PerfFileSection::GetFeatureName(feature).c_str());
40448f512ceSopenharmony_ci        HLOGV(" sectionHeader -> read offset '0x%" PRIx64 " size '0x%" PRIx64 "'",
40548f512ceSopenharmony_ci              sectionHeader.offset, sectionHeader.size);
40648f512ceSopenharmony_ci        CHECK_TRUE(sectionHeader.size == 0 or sectionHeader.size > fileSize_, false, 1,
40748f512ceSopenharmony_ci                   "sectionHeader.size %" PRIu64 " is not correct", sectionHeader.size);
40848f512ceSopenharmony_ci
40948f512ceSopenharmony_ci        std::vector<char> buf(sectionHeader.size);
41048f512ceSopenharmony_ci        // read failed ??
41148f512ceSopenharmony_ci        CHECK_TRUE(!Read(&buf[0], sectionHeader.offset, buf.size()), false, LOG_TYPE_PRINTF,
41248f512ceSopenharmony_ci                   "file format not correct. featureSectionDataOffset '0x%" PRIx64 "\n", sectionHeader.offset);
41348f512ceSopenharmony_ci        if (IsFeatrureStringSection(feature)) {
41448f512ceSopenharmony_ci            perfFileSections_.emplace_back(
41548f512ceSopenharmony_ci                std::make_unique<PerfFileSectionString>(feature, (char *)&buf[0], buf.size()));
41648f512ceSopenharmony_ci        } else if (feature == FEATURE::HIPERF_FILES_SYMBOL) {
41748f512ceSopenharmony_ci            perfFileSections_.emplace_back(std::make_unique<PerfFileSectionSymbolsFiles>(
41848f512ceSopenharmony_ci                feature, (char *)&buf[0], buf.size()));
41948f512ceSopenharmony_ci        } else if (feature == FEATURE::EVENT_DESC) {
42048f512ceSopenharmony_ci            perfFileSections_.emplace_back(
42148f512ceSopenharmony_ci                std::make_unique<PerfFileSectionEventDesc>(feature, (char *)&buf[0], buf.size()));
42248f512ceSopenharmony_ci        } else if (feature == FEATURE::HIPERF_FILES_UNISTACK_TABLE) {
42348f512ceSopenharmony_ci            perfFileSections_.emplace_back(
42448f512ceSopenharmony_ci                std::make_unique<PerfFileSectionUniStackTable>(feature, (char *)&buf[0], buf.size()));
42548f512ceSopenharmony_ci            PerfRecordSample::dumpRemoveStack_ = true;
42648f512ceSopenharmony_ci        } else {
42748f512ceSopenharmony_ci            HLOGW("still not imp how to process with feature %d", feature);
42848f512ceSopenharmony_ci        }
42948f512ceSopenharmony_ci
43048f512ceSopenharmony_ci        featureSectionOffsetRead += sizeof(sectionHeader); // next feaure
43148f512ceSopenharmony_ci    }
43248f512ceSopenharmony_ci    return true;
43348f512ceSopenharmony_ci}
43448f512ceSopenharmony_ci} // namespace HiPerf
43548f512ceSopenharmony_ci} // namespace Developtools
43648f512ceSopenharmony_ci} // namespace OHOS
437