• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
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 #define HILOG_TAG "Dump"
16 
17 #include "subcommand_dump.h"
18 
19 #include <cerrno>
20 #include <cinttypes>
21 #include <cstring>
22 #include <iostream>
23 #include <memory>
24 
25 #include "debug_logger.h"
26 #include "hiperf_hilog.h"
27 #include "option.h"
28 #include "perf_event_record.h"
29 #include "perf_events.h"
30 #include "register.h"
31 #include "spe_decoder.h"
32 #include "symbols_file.h"
33 #include "utilities.h"
34 #include "virtual_runtime.h"
35 
36 namespace OHOS {
37 namespace Developtools {
38 namespace HiPerf {
39 using namespace OHOS::HiviewDFX;
40 
41 static const std::string DEFAULT_DUMP_FILENAME = "perf.data";
42 
CheckInputFile()43 bool SubCommandDump::CheckInputFile()
44 {
45     if (!dumpFileName_.empty()) {
46         if (elfFileName_.empty() && protobufDumpFileName_.empty()) {
47             return true;
48         }
49     } else if (!elfFileName_.empty()) {
50         if (protobufDumpFileName_.empty()) {
51             return true;
52         }
53     } else if (!protobufDumpFileName_.empty()) {
54         return true;
55     } else { // all is empty
56         dumpFileName_ = DEFAULT_DUMP_FILENAME;
57         return true;
58     }
59 
60     printf("options conflict, please check usage\n");
61     return false;
62 }
63 
ParseOption(std::vector<std::string> & args)64 bool SubCommandDump::ParseOption(std::vector<std::string> &args)
65 {
66     if (!Option::GetOptionValue(args, "--head", dumpHeader_)) {
67         HLOGD("get option --head failed");
68         return false;
69     }
70     if (!Option::GetOptionValue(args, "-f", dumpFeatures_)) {
71         HLOGD("get option -f failed");
72         return false;
73     }
74     if (!Option::GetOptionValue(args, "-d", dumpData_)) {
75         HLOGD("get option -d failed");
76         return false;
77     }
78     if (!Option::GetOptionValue(args, "--sympath", dumpSymbolsPaths_)) {
79         HLOGD("get option --sympath failed");
80         return false;
81     }
82     if (!Option::GetOptionValue(args, "--elf", elfFileName_)) {
83         HLOGD("get option --elf failed");
84         return false;
85     }
86     if (!Option::GetOptionValue(args, "-i", dumpFileName_)) {
87         return false;
88     }
89 #if defined(HAVE_PROTOBUF) && HAVE_PROTOBUF
90     if (!Option::GetOptionValue(args, "--proto", protobufDumpFileName_)) {
91         HLOGD("get option --proto failed");
92         return false;
93     }
94 #endif
95     if (!Option::GetOptionValue(args, "-o", outputFilename_)) {
96         return false;
97     }
98     if (!Option::GetOptionValue(args, "--export", exportSampleIndex_)) {
99         HLOGD("get option --export failed");
100         return false;
101     }
102 
103     if (dumpHeader_ || dumpFeatures_ || dumpData_) {
104         dumpAll_ = false;
105     }
106     if (!args.empty()) {
107         printf("'%s' option usage error, please check usage.\n", VectorToString(args).c_str());
108         return false;
109     }
110 
111     return CheckInputFile();
112 }
113 
PrepareDumpOutput()114 bool SubCommandDump::PrepareDumpOutput()
115 {
116     if (outputFilename_.empty()) {
117         return true;
118     }
119     std::string resolvedPath = CanonicalizeSpecPath(outputFilename_.c_str());
120     g_outputDump = fopen(resolvedPath.c_str(), "w");
121     if (g_outputDump == nullptr) {
122         printf("unable open file to '%s' because '%d'\n", outputFilename_.c_str(), errno);
123         return false;
124     }
125     printf("dump result will save at '%s'\n", outputFilename_.c_str());
126     return true;
127 }
128 
~SubCommandDump()129 SubCommandDump::~SubCommandDump()
130 {
131     if (g_outputDump != nullptr && g_outputDump != stdout) {
132         fclose(g_outputDump);
133     }
134     SymbolsFile::onRecording_ = true; // back to default for UT
135 }
136 
OnSubCommand(std::vector<std::string> & args)137 HiperfError SubCommandDump::OnSubCommand(std::vector<std::string>& args)
138 {
139     RETURN_IF(!PrepareDumpOutput(), HiperfError::PREPARE_DUMP_OUTPUT_FAIL);
140 
141     if (!elfFileName_.empty()) {
142         return DumpElfFile() ? HiperfError::NO_ERR : HiperfError::DUMP_ELF_FILE_ERROR;
143     }
144 
145 #if defined(HAVE_PROTOBUF) && HAVE_PROTOBUF
146     if (!protobufDumpFileName_.empty()) {
147         return DumpProtoFile() ? HiperfError::NO_ERR : HiperfError::DUMP_PROTO_FILE_ERROR;
148     }
149 #endif
150 
151     if (access(dumpFileName_.c_str(), F_OK) != 0) {
152         printf("Can not access data file %s\n", dumpFileName_.c_str());
153         return HiperfError::ACCESS_DATA_FILE_FAIL;
154     }
155     // only one file should created
156     HLOG_ASSERT_MESSAGE(reader_ == nullptr, " perf file reader for %s\n", dumpFileName_.c_str());
157     reader_ = PerfFileReader::Instance(dumpFileName_);
158     if (reader_ == nullptr) {
159         HLOGE("HiperfFileReader::Instance(%s) return null", dumpFileName_.c_str());
160         return HiperfError::OPEN_DATA_FILE_FAIL;
161     }
162 
163     // any way tell symbols this is not on device
164     SymbolsFile::onRecording_ = false;
165     // we need unwind it (for function name match) even not give us path
166     vr_.SetDisableUnwind(false);
167 
168     if (!dumpSymbolsPaths_.empty()) {
169         // user give us path , we enable unwind
170         if (!vr_.SetSymbolsPaths(dumpSymbolsPaths_)) {
171             printf("Failed to set symbol path(%s)\n", VectorToString(dumpSymbolsPaths_).c_str());
172             return HiperfError::SET_SYMBOLS_PATH_FAIL;
173         }
174     }
175 
176     if (dumpHeader_ || dumpAll_) {
177         DumpPrintFileHeader(indent_);
178         DumpAttrPortion(indent_);
179     }
180 
181     if (dumpAll_ || dumpData_) {
182         // before load data section
183         SetHM();
184         DumpDataPortion(indent_);
185         DumpSpeReport();
186     }
187 
188     if (dumpFeatures_ || dumpAll_) {
189         DumpFeaturePortion(indent_);
190     }
191 
192     return HiperfError::NO_ERR;
193 }
194 
DumpElfFile()195 bool SubCommandDump::DumpElfFile()
196 {
197     printf("dump elf: '%s'\n", elfFileName_.c_str());
198     auto elf = SymbolsFile::CreateSymbolsFile(elfFileName_);
199     if (!elf->LoadSymbols(nullptr, "")) {
200         printf("load elf failed.\n");
201         return false;
202     } else {
203         printf("load elf succeed.\n");
204     }
205     return true;
206 }
207 #if defined(HAVE_PROTOBUF) && HAVE_PROTOBUF
DumpProtoFile()208 bool SubCommandDump::DumpProtoFile()
209 {
210     printf("dump protobuf file: '%s'\n", protobufDumpFileName_.c_str());
211     protobufInputFileReader_ = std::make_unique<ReportProtobufFileReader>();
212     if (!protobufInputFileReader_->Dump(protobufDumpFileName_)) {
213         printf("load proto failed.\n");
214         return false;
215     }
216     return true;
217 }
218 #endif
219 
PrintHeaderInfo(const int & indent)220 void SubCommandDump::PrintHeaderInfo(const int &indent)
221 {
222     const perf_file_header &header = reader_->GetHeader();
223     // magic
224     PRINT_INDENT(indent, "magic: ");
225     for (size_t i = 0; i < sizeof(header.magic); ++i) {
226         PRINT_INDENT(indent, "%c", header.magic[i]);
227     }
228     PRINT_INDENT(indent, "\n");
229     PRINT_INDENT(indent, "header_size: %" PRId64 "\n", header.size);
230     if (header.size != sizeof(header)) {
231         HLOGW("record file header size doesn't match");
232     }
233     PRINT_INDENT(indent, "attr_size: %" PRId64 "\n", header.attrSize);
234     if (header.attrSize != sizeof(perf_file_attr)) {
235         HLOGW("attr size doesn't match");
236     }
237     // attr
238     PRINT_INDENT(indent, "attrs[file section]: offset %" PRId64 ", size %" PRId64 "\n",
239                  header.attrs.offset, header.attrs.size);
240     // data
241     PRINT_INDENT(indent, "data[file section]: offset %" PRId64 ", size %" PRId64 "\n",
242                  header.data.offset, header.data.size);
243     PRINT_INDENT(indent, "event_types[file section]: offset %" PRId64 ", size %" PRId64 "\n",
244                  header.eventTypes.offset, header.eventTypes.size);
245     // feature
246     PRINT_INDENT(indent,
247                  "adds_features[]: 0x%" PRIX64 " 0x%" PRIX64 " 0x%" PRIX64 " 0x%" PRIX64 "\n",
248                  *(reinterpret_cast<const uint64_t *>(&header.features[0])),
249                  *(reinterpret_cast<const uint64_t *>(&header.features[8])),
250                  *(reinterpret_cast<const uint64_t *>(&header.features[16])),
251                  *(reinterpret_cast<const uint64_t *>(&header.features[24])));
252 }
253 
DumpPrintFileHeader(int indent)254 void SubCommandDump::DumpPrintFileHeader(int indent)
255 {
256     // print header
257     PrintHeaderInfo(indent);
258 
259     // print feature
260     auto features = reader_->GetFeatures();
261     for (auto feature : features) {
262         PRINT_INDENT(indent, "feature: %s\n", PerfFileSection::GetFeatureName(feature).c_str());
263     }
264 
265     // read here , because we need found symbols
266     reader_->ReadFeatureSection();
267 
268     SetDeviceArch(GetArchTypeFromUname(reader_->GetFeatureString(FEATURE::ARCH)));
269 
270     // found symbols in file
271     for (auto &featureSection : reader_->GetFeatureSections()) {
272         if (featureSection.get()->featureId_ == FEATURE::HIPERF_FILES_SYMBOL) {
273             const PerfFileSectionSymbolsFiles *sectionSymbolsFiles =
274                 static_cast<const PerfFileSectionSymbolsFiles *>(featureSection.get());
275             vr_.UpdateFromPerfData(sectionSymbolsFiles->symbolFileStructs_);
276         } else if (featureSection.get()->featureId_ == FEATURE::HIPERF_FILES_UNISTACK_TABLE) {
277             const PerfFileSectionUniStackTable *sectionUniStackTable  =
278                 static_cast<const PerfFileSectionUniStackTable *>(featureSection.get());
279             vr_.ImportUniqueStackNodes(sectionUniStackTable->uniStackTableInfos_);
280             vr_.SetDedupStack();
281         }
282     }
283 }
284 
285 static std::map<int, std::string> g_sampleTypeNames = {
286     {PERF_SAMPLE_IP, "ip"},
287     {PERF_SAMPLE_TID, "tid"},
288     {PERF_SAMPLE_TIME, "time"},
289     {PERF_SAMPLE_ADDR, "addr"},
290     {PERF_SAMPLE_READ, "read"},
291     {PERF_SAMPLE_CALLCHAIN, "callchain"},
292     {PERF_SAMPLE_ID, "id"},
293     {PERF_SAMPLE_CPU, "cpu"},
294     {PERF_SAMPLE_PERIOD, "period"},
295     {PERF_SAMPLE_STREAM_ID, "stream_id"},
296     {PERF_SAMPLE_RAW, "raw"},
297     {PERF_SAMPLE_BRANCH_STACK, "stack"},
298     {PERF_SAMPLE_REGS_USER, "regs_user"},
299     {PERF_SAMPLE_STACK_USER, "stack_user"},
300     {PERF_SAMPLE_WEIGHT, "weight"},
301     {PERF_SAMPLE_DATA_SRC, "data_src"},
302     {PERF_SAMPLE_IDENTIFIER, "identifier"},
303     {PERF_SAMPLE_TRANSACTION, "transaction"},
304     {PERF_SAMPLE_REGS_INTR, "reg_intr"},
305     {PERF_SAMPLE_SERVER_PID, "server_pid"},
306 };
307 
DumpSampleType(uint64_t sampleType,int indent)308 void SubCommandDump::DumpSampleType(uint64_t sampleType, int indent)
309 {
310     std::string names;
311     for (auto &pair : g_sampleTypeNames) {
312         if (sampleType & pair.first) {
313             if (!names.empty()) {
314                 names.append(",");
315             }
316             names.append(pair.second);
317         }
318     }
319     PRINT_INDENT(indent + 1, "sample_type names: %s\n", names.c_str());
320 }
321 
DumpPrintEventAttr(const perf_event_attr & attr,int indent)322 void SubCommandDump::DumpPrintEventAttr(const perf_event_attr &attr, int indent)
323 {
324     PRINT_INDENT(indent, "event_attr: \n");
325 
326     PRINT_INDENT(indent + 1, "type %u, size %u, config %llu\n", attr.type, attr.size, attr.config);
327 
328     if (attr.freq != 0) {
329         PRINT_INDENT(indent + 1, "sample_freq %llu\n", attr.sample_freq);
330     } else {
331         PRINT_INDENT(indent + 1, "sample_period %llu\n", attr.sample_period);
332     }
333 
334     PRINT_INDENT(indent + 1, "sample_type (0x%llx) \n", attr.sample_type);
335     DumpSampleType(attr.sample_type, indent);
336 
337     PRINT_INDENT(indent + 1, "read_format (0x%llx) \n", attr.read_format);
338 
339     PRINT_INDENT(indent + 1, "disabled %u, inherit %u, pinned %u, exclusive %u\n", attr.disabled,
340                  attr.inherit, attr.pinned, attr.exclusive);
341 
342     PRINT_INDENT(indent + 1, "exclude_user %u, exclude_kernel %u, exclude_hv %u, exclude_idle %u\n",
343                  attr.exclude_user, attr.exclude_kernel, attr.exclude_hv, attr.exclude_idle);
344 
345     PRINT_INDENT(indent + 1, "mmap %u, mmap2 %u, comm %u, comm_exec %u, freq %u\n", attr.mmap,
346                  attr.mmap2, attr.comm, attr.comm_exec, attr.freq);
347 
348     PRINT_INDENT(indent + 1, "inherit_stat %u, enable_on_exec %u, task %u, use_clockid %u\n",
349                  attr.inherit_stat, attr.enable_on_exec, attr.task, attr.use_clockid);
350 
351     PRINT_INDENT(indent + 1, "watermark %u, precise_ip %u, mmap_data %u, clockid %d\n", attr.watermark,
352                  attr.precise_ip, attr.mmap_data, attr.clockid);
353 
354     PRINT_INDENT(indent + 1, "sample_id_all %u, exclude_host %u, exclude_guest %u\n", attr.sample_id_all,
355                  attr.exclude_host, attr.exclude_guest);
356     PRINT_INDENT(indent + 1, "branch_sample_type 0x%llx\n", attr.branch_sample_type);
357     PRINT_INDENT(indent + 1, "exclude_callchain_kernel %u, exclude_callchain_user %u\n",
358                  attr.exclude_callchain_kernel, attr.exclude_callchain_user);
359     PRINT_INDENT(indent + 1, "sample_regs_user 0x%llx\n", attr.sample_regs_user);
360     PRINT_INDENT(indent + 1, "sample_stack_user 0x%x\n", attr.sample_stack_user);
361 }
362 
DumpAttrPortion(int indent)363 void SubCommandDump::DumpAttrPortion(int indent)
364 {
365     attrIds_ = reader_->GetAttrSection();
366     for (size_t i = 0; i < attrIds_.size(); ++i) {
367         const AttrWithId &attr = attrIds_[i];
368         PRINT_INDENT(indent, "attr %zu:\n", i + 1);
369         DumpPrintEventAttr(attr.attr, indent_ + 1);
370         if (!attr.ids.empty()) {
371             PRINT_INDENT(indent, "  ids:");
372             for (const auto &id : attr.ids) {
373                 PRINT_INDENT(indent, " %" PRId64, id);
374             }
375             PRINT_INDENT(indent, "\n");
376         }
377     }
378 }
379 
ExportUserStack(const PerfRecordSample & recordSample)380 void SubCommandDump::ExportUserStack(const PerfRecordSample &recordSample)
381 {
382     if (recordSample.data_.reg_nr > 0 && recordSample.data_.dyn_size > 0) {
383         // <pid>_<tid>_user_regs_<time>
384         std::string userRegs =
385             StringPrintf("hiperf_%d_%d_user_regs_%zu.dump", recordSample.data_.pid,
386                          recordSample.data_.tid, exportSampleIndex_);
387         std::string resolvedPath = CanonicalizeSpecPath(userRegs.c_str());
388         FILE *userRegsFp = fopen(resolvedPath.c_str(), "wb");
389         CHECK_TRUE(userRegsFp == nullptr, NO_RETVAL, 1, "open userRegs failed");
390         std::unique_ptr<FILE, decltype(&fclose)> fpUserRegs(userRegsFp, fclose);
391         fwrite(recordSample.data_.user_regs, sizeof(u64), recordSample.data_.reg_nr,
392                fpUserRegs.get());
393 
394         std::string userData =
395             StringPrintf("hiperf_%d_%d_user_data_%zu.dump", recordSample.data_.pid,
396                          recordSample.data_.tid, exportSampleIndex_);
397         std::string resolvePath = CanonicalizeSpecPath(userData.c_str());
398         FILE *UserDataFp = fopen(resolvePath.c_str(), "wb");
399         CHECK_TRUE(UserDataFp == nullptr, NO_RETVAL, 1, "open UserData failed");
400         std::unique_ptr<FILE, decltype(&fclose)> fpUserData(UserDataFp, fclose);
401         fwrite(recordSample.data_.stack_data, sizeof(u8), recordSample.data_.dyn_size,
402                fpUserData.get());
403     }
404 }
405 
ExportUserData(PerfEventRecord & record)406 void SubCommandDump::ExportUserData(PerfEventRecord& record)
407 {
408     if (record.GetType() == PERF_RECORD_SAMPLE) {
409         if (currectSampleIndex_++ != exportSampleIndex_) {
410             return;
411         }
412         PerfRecordSample* recordSample = static_cast<PerfRecordSample*>(&record);
413         ExportUserStack(*recordSample);
414 
415         std::string userData =
416             StringPrintf("hiperf_%d_%d_sample_record_%zu_%" PRIu64 ".dump", recordSample->data_.pid,
417                          recordSample->data_.tid, exportSampleIndex_, recordSample->data_.time);
418         std::string resolvedPath = CanonicalizeSpecPath(userData.c_str());
419         std::unique_ptr<FILE, decltype(&fclose)> fpUserData(fopen(resolvedPath.c_str(), "wb"), fclose);
420         static std::vector<u8> buf(RECORD_SIZE_LIMIT);
421         CHECK_TRUE(!recordSample->GetBinary(buf), NO_RETVAL, 1, "export user sample data failed");
422         fwrite(buf.data(), sizeof(u8), recordSample->GetSize(), fpUserData.get());
423 
424         HLOGD("export user data index %d time %llu", exportSampleIndex_, recordSample->data_.time);
425     }
426 }
427 
DumpCallChain(int indent,const PerfRecordSample & sample)428 void SubCommandDump::DumpCallChain(int indent, const PerfRecordSample& sample)
429 {
430     PRINT_INDENT(indent, "\n callchain: %zu\n", sample.callFrames_.size());
431     if (sample.callFrames_.size() > 0) {
432         indent += indent + 1;
433         for (auto frameIt = sample.callFrames_.begin(); frameIt != sample.callFrames_.end();
434              frameIt++) {
435             PRINT_INDENT(indent, "%02zd:%s\n", std::distance(frameIt, sample.callFrames_.end()),
436                          frameIt->ToSymbolString().c_str());
437         }
438     }
439 }
440 
DumpDataPortion(int indent)441 void SubCommandDump::DumpDataPortion(int indent)
442 {
443     int recordCount = 0;
444     auto recordcCallback = [&](PerfEventRecord& record) {
445         CHECK_TRUE(record.GetName() == nullptr, false, 0, ""); // return false in callback can stop the read process
446 
447         // for UT
448         if (exportSampleIndex_ > 0) {
449             ExportUserData(record);
450         }
451 
452         // tell process tree what happend for rebuild symbols
453         vr_.UpdateFromRecord(record);
454 
455         recordCount++;
456         record.Dump(indent, outputFilename_, g_outputDump);
457 
458         if (record.GetType() == PERF_RECORD_SAMPLE) {
459             DumpCallChain(indent, static_cast<PerfRecordSample&>(record));
460         }
461 
462         return true;
463     };
464 
465     reader_->ReadDataSection(recordcCallback);
466 
467     PRINT_INDENT(indent, "\n ======= there are %d records ======== \n", recordCount);
468 }
469 
PrintSymbolFile(const int & indent,const SymbolFileStruct & symbolFileStruct)470 void SubCommandDump::PrintSymbolFile(const int &indent, const SymbolFileStruct &symbolFileStruct)
471 {
472     PRINT_INDENT(indent + INDENT_TWO, "filePath:%s\n", symbolFileStruct.filePath_.c_str());
473     PRINT_INDENT(indent + INDENT_TWO, "symbolType:%u\n", symbolFileStruct.symbolType_);
474     PRINT_INDENT(indent + INDENT_TWO, "minExecAddr:0x%" PRIx64 "\n", symbolFileStruct.textExecVaddr_);
475     PRINT_INDENT(indent + INDENT_TWO, "minExecAddrFileOffset:0x%08" PRIx64 "\n",
476                 symbolFileStruct.textExecVaddrFileOffset_);
477     if (!symbolFileStruct.buildId_.empty()) {
478         PRINT_INDENT(indent + INDENT_TWO, "buildId:'%s'\n", symbolFileStruct.buildId_.c_str());
479     }
480     PRINT_INDENT(indent + INDENT_TWO, "symbol number: %zu\n", symbolFileStruct.symbolStructs_.size());
481     int symbolid = 0;
482     for (auto &symbolStruct : symbolFileStruct.symbolStructs_) {
483         PRINT_INDENT(indent + 3, "%05d [0x%016" PRIx64 "@0x%08x]  %s\n", symbolid, symbolStruct.vaddr_,
484                      symbolStruct.len_, symbolStruct.symbolName_.c_str());
485         symbolid++;
486     }
487 }
488 
PrintFeatureEventdesc(int indent,const PerfFileSectionEventDesc & sectionEventdesc)489 void SubCommandDump::PrintFeatureEventdesc(int indent,
490                                            const PerfFileSectionEventDesc &sectionEventdesc)
491 {
492     PRINT_INDENT(indent + INDENT_TWO, "Event descriptions: %zu\n", sectionEventdesc.eventDesces_.size());
493     for (size_t i = 0; i < sectionEventdesc.eventDesces_.size(); i++) {
494         const AttrWithId &desc = sectionEventdesc.eventDesces_[i];
495         PRINT_INDENT(indent + INDENT_TWO, "event name[%zu]: %s ids: %s\n", i, desc.name.c_str(),
496                      VectorToString(desc.ids).c_str());
497 
498         // attr is duplicated the attrs section
499     }
500     PRINT_INDENT(indent + INDENT_TWO, "\n");
501 }
502 
DumpFeaturePortion(int indent)503 void SubCommandDump::DumpFeaturePortion(int indent)
504 {
505     PRINT_INDENT(indent, "\n ==== features ====\n");
506     auto features = reader_->GetFeatures();
507     for (auto feature : features) {
508         PRINT_INDENT(indent + 1, "feature %d:%s\n", feature,
509                      PerfFileSection::GetFeatureName(feature).c_str());
510     }
511 
512     const auto &featureSections = reader_->GetFeatureSections();
513     HLOGV("featureSections: %zu ", featureSections.size());
514 
515     PRINT_INDENT(indent, "\n ==== feature sections ====\n");
516 
517     for (auto &featureSection : featureSections) {
518         PRINT_INDENT(indent + 1, "feature %d:%s content: \n", featureSection.get()->featureId_,
519                      PerfFileSection::GetFeatureName(featureSection.get()->featureId_).c_str());
520         if (reader_->IsFeatrureStringSection(featureSection.get()->featureId_)) {
521             const PerfFileSectionString *sectionString =
522                 static_cast<const PerfFileSectionString *>(featureSection.get());
523             PRINT_INDENT(indent + INDENT_TWO, "%s\n", sectionString->ToString().c_str());
524             continue;
525         } else if (featureSection.get()->featureId_ == FEATURE::EVENT_DESC) {
526             PrintFeatureEventdesc(
527                 indent, *static_cast<const PerfFileSectionEventDesc *>(featureSection.get()));
528             continue;
529         } else if (featureSection.get()->featureId_ == FEATURE::HIPERF_FILES_SYMBOL) {
530             const PerfFileSectionSymbolsFiles *sectionSymbolsFiles =
531                 static_cast<const PerfFileSectionSymbolsFiles *>(featureSection.get());
532             if (sectionSymbolsFiles != nullptr) {
533                 PRINT_INDENT(indent + INDENT_TWO, "SymbolFiles:%zu\n",
534                              sectionSymbolsFiles->symbolFileStructs_.size());
535 
536                 int fileid = 0;
537                 for (auto &symbolFileStruct : sectionSymbolsFiles->symbolFileStructs_) {
538                     PRINT_INDENT(indent + INDENT_TWO, "\n");
539                     PRINT_INDENT(indent + INDENT_TWO, "fileid:%d\n", fileid);
540                     fileid++;
541                     // symbol file info
542                     PrintSymbolFile(indent, symbolFileStruct);
543                 }
544             } else {
545                 PRINT_INDENT(indent + INDENT_TWO, "get SymbolFiles failed\n");
546             }
547             continue;
548         } else if (featureSection.get()->featureId_ == FEATURE::HIPERF_FILES_UNISTACK_TABLE) {
549             const PerfFileSectionUniStackTable *sectioniStackTable =
550                 static_cast<PerfFileSectionUniStackTable *>(const_cast<PerfFileSection *>(featureSection.get()));
551             if (sectioniStackTable != nullptr) {
552                 DumpUniqueStackTableNode(indent + 1, *sectioniStackTable);
553             } else {
554                 PRINT_INDENT(indent + INDENT_TWO, "get StackTable failed\n");
555             }
556             continue;
557         } else {
558             PRINT_INDENT(indent + INDENT_TWO, "not support dump this feature(%d).\n", featureSection.get()->featureId_);
559         }
560     }
561 }
562 
DumpUniqueStackTableNode(int indent,const PerfFileSectionUniStackTable & uniStackTable)563 void SubCommandDump::DumpUniqueStackTableNode(int indent, const PerfFileSectionUniStackTable &uniStackTable)
564 {
565     int tableid = 0;
566     PRINT_INDENT(indent + 1, "TableNums: %zu\n\n", uniStackTable.uniStackTableInfos_.size());
567     for (const auto& uniStackTableInfo : uniStackTable.uniStackTableInfos_) {
568         PRINT_INDENT(indent + INDENT_TWO, "tableid: %d\n", tableid);
569         PRINT_INDENT(indent + INDENT_TWO, "pid: %" PRIu32 "\n", uniStackTableInfo.pid);
570         PRINT_INDENT(indent + INDENT_TWO, "tableSize: %" PRIu32 "\n", uniStackTableInfo.tableSize);
571         PRINT_INDENT(indent + INDENT_TWO, "numNodes: %" PRIu32 "\n", uniStackTableInfo.numNodes);
572         PRINT_INDENT(indent + INDENT_TWO, "%-7s %-7s %-8s\n", "no", "index", "node");
573         for (size_t i = 0; i < uniStackTableInfo.nodes.size(); i++) {
574             UniStackNode node = uniStackTableInfo.nodes[i];
575             PRINT_INDENT(indent + INDENT_TWO, "%-7zu %-7" PRIu32 " 0x%-8" PRIx64 "\n", i, node.index, node.node.value);
576         }
577         tableid++;
578     }
579 }
580 
RegisterSubCommandDump()581 bool SubCommandDump::RegisterSubCommandDump()
582 {
583     return SubCommand::RegisterSubCommand("dump", SubCommandDump::GetInstance);
584 }
585 
SetHM()586 void SubCommandDump::SetHM()
587 {
588     std::string os = reader_->GetFeatureString(FEATURE::OSRELEASE);
589     isHM_ = os.find(HMKERNEL) != std::string::npos;
590     vr_.SetHM(isHM_);
591     HLOGD("Set isHM_: %d", isHM_);
592     if (isHM_) {
593         pid_t devhost = -1;
594         std::string str = reader_->GetFeatureString(FEATURE::HIPERF_HM_DEVHOST);
595         if (IsNumeric(str)) {
596             devhost = std::stoll(str);
597         }
598         vr_.SetDevhostPid(devhost);
599     }
600 }
601 
DumpSpeReport()602 void SubCommandDump::DumpSpeReport()
603 {
604 #if defined(is_ohos) && is_ohos
605     std::string cmdline = reader_->GetFeatureString(FEATURE::CMDLINE);
606     if (cmdline.find("-e arm_spe_0") != std::string::npos) {
607         HLOGD("dump spe report data");
608         UpdateHeating();
609         DumpSpeReportData(indent_, g_outputDump);
610     }
611 #endif
612 }
613 
GetInstance()614 SubCommand& SubCommandDump::GetInstance()
615 {
616     static SubCommandDump subCommand;
617     return subCommand;
618 }
619 
620 } // namespace HiPerf
621 } // namespace Developtools
622 } // namespace OHOS
623