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 bool SubCommandDump::OnSubCommand(std::vector<std::string> &args)
138 {
139 if (!PrepareDumpOutput()) {
140 return false;
141 }
142
143 if (!elfFileName_.empty()) {
144 return DumpElfFile();
145 }
146
147 #if defined(HAVE_PROTOBUF) && HAVE_PROTOBUF
148 if (!protobufDumpFileName_.empty()) {
149 return DumpProtoFile();
150 }
151 #endif
152
153 if (access(dumpFileName_.c_str(), F_OK) != 0) {
154 printf("Can not access data file %s\n", dumpFileName_.c_str());
155 return false;
156 }
157 // only one file should created
158 HLOG_ASSERT_MESSAGE(reader_ == nullptr, " perf file reader for %s\n", dumpFileName_.c_str());
159 reader_ = PerfFileReader::Instance(dumpFileName_);
160 if (reader_ == nullptr) {
161 HLOGE("HiperfFileReader::Instance(%s) return null", dumpFileName_.c_str());
162 return false;
163 }
164
165 // any way tell symbols this is not on device
166 SymbolsFile::onRecording_ = false;
167 // we need unwind it (for function name match) even not give us path
168 vr_.SetDisableUnwind(false);
169
170 if (!dumpSymbolsPaths_.empty()) {
171 // user give us path , we enable unwind
172 if (!vr_.SetSymbolsPaths(dumpSymbolsPaths_)) {
173 printf("Failed to set symbol path(%s)\n", VectorToString(dumpSymbolsPaths_).c_str());
174 return false;
175 }
176 }
177
178 if (dumpHeader_ || dumpAll_) {
179 DumpPrintFileHeader(indent_);
180 DumpAttrPortion(indent_);
181 }
182
183 if (dumpAll_ || dumpData_) {
184 // before load data section
185 SetHM();
186 DumpDataPortion(indent_);
187 DumpSpeReport();
188 }
189
190 if (dumpFeatures_ || dumpAll_) {
191 DumpFeaturePortion(indent_);
192 }
193
194 return true;
195 }
196
DumpElfFile()197 bool SubCommandDump::DumpElfFile()
198 {
199 printf("dump elf: '%s'\n", elfFileName_.c_str());
200 auto elf = SymbolsFile::CreateSymbolsFile(elfFileName_);
201 if (!elf->LoadSymbols(nullptr, "")) {
202 printf("load elf failed.\n");
203 return false;
204 } else {
205 printf("load elf succeed.\n");
206 }
207 return true;
208 }
209 #if defined(HAVE_PROTOBUF) && HAVE_PROTOBUF
DumpProtoFile()210 bool SubCommandDump::DumpProtoFile()
211 {
212 printf("dump protobuf file: '%s'\n", protobufDumpFileName_.c_str());
213 protobufInputFileReader_ = std::make_unique<ReportProtobufFileReader>();
214 if (!protobufInputFileReader_->Dump(protobufDumpFileName_)) {
215 printf("load proto failed.\n");
216 return false;
217 }
218 return true;
219 }
220 #endif
221
PrintHeaderInfo(const int &indent)222 void SubCommandDump::PrintHeaderInfo(const int &indent)
223 {
224 const perf_file_header &header = reader_->GetHeader();
225 // magic
226 PRINT_INDENT(indent, "magic: ");
227 for (size_t i = 0; i < sizeof(header.magic); ++i) {
228 PRINT_INDENT(indent, "%c", header.magic[i]);
229 }
230 PRINT_INDENT(indent, "\n");
231 PRINT_INDENT(indent, "header_size: %" PRId64 "\n", header.size);
232 if (header.size != sizeof(header)) {
233 HLOGW("record file header size doesn't match");
234 }
235 PRINT_INDENT(indent, "attr_size: %" PRId64 "\n", header.attrSize);
236 if (header.attrSize != sizeof(perf_file_attr)) {
237 HLOGW("attr size doesn't match");
238 }
239 // attr
240 PRINT_INDENT(indent, "attrs[file section]: offset %" PRId64 ", size %" PRId64 "\n",
241 header.attrs.offset, header.attrs.size);
242 // data
243 PRINT_INDENT(indent, "data[file section]: offset %" PRId64 ", size %" PRId64 "\n",
244 header.data.offset, header.data.size);
245 PRINT_INDENT(indent, "event_types[file section]: offset %" PRId64 ", size %" PRId64 "\n",
246 header.eventTypes.offset, header.eventTypes.size);
247 // feature
248 PRINT_INDENT(indent,
249 "adds_features[]: 0x%" PRIX64 " 0x%" PRIX64 " 0x%" PRIX64 " 0x%" PRIX64 "\n",
250 *(reinterpret_cast<const uint64_t *>(&header.features[0])),
251 *(reinterpret_cast<const uint64_t *>(&header.features[8])),
252 *(reinterpret_cast<const uint64_t *>(&header.features[16])),
253 *(reinterpret_cast<const uint64_t *>(&header.features[24])));
254 }
255
DumpPrintFileHeader(int indent)256 void SubCommandDump::DumpPrintFileHeader(int indent)
257 {
258 // print header
259 PrintHeaderInfo(indent);
260
261 // print feature
262 auto features = reader_->GetFeatures();
263 for (auto feature : features) {
264 PRINT_INDENT(indent, "feature: %s\n", PerfFileSection::GetFeatureName(feature).c_str());
265 }
266
267 // read here , because we need found symbols
268 reader_->ReadFeatureSection();
269
270 SetDeviceArch(GetArchTypeFromUname(reader_->GetFeatureString(FEATURE::ARCH)));
271
272 // found symbols in file
273 for (auto &featureSection : reader_->GetFeatureSections()) {
274 if (featureSection.get()->featureId_ == FEATURE::HIPERF_FILES_SYMBOL) {
275 const PerfFileSectionSymbolsFiles *sectionSymbolsFiles =
276 static_cast<const PerfFileSectionSymbolsFiles *>(featureSection.get());
277 vr_.UpdateFromPerfData(sectionSymbolsFiles->symbolFileStructs_);
278 } else if (featureSection.get()->featureId_ == FEATURE::HIPERF_FILES_UNISTACK_TABLE) {
279 const PerfFileSectionUniStackTable *sectionUniStackTable =
280 static_cast<const PerfFileSectionUniStackTable *>(featureSection.get());
281 vr_.ImportUniqueStackNodes(sectionUniStackTable->uniStackTableInfos_);
282 vr_.SetDedupStack();
283 }
284 }
285 }
286
287 static std::map<int, std::string> g_sampleTypeNames = {
288 {PERF_SAMPLE_IP, "ip"},
289 {PERF_SAMPLE_TID, "tid"},
290 {PERF_SAMPLE_TIME, "time"},
291 {PERF_SAMPLE_ADDR, "addr"},
292 {PERF_SAMPLE_READ, "read"},
293 {PERF_SAMPLE_CALLCHAIN, "callchain"},
294 {PERF_SAMPLE_ID, "id"},
295 {PERF_SAMPLE_CPU, "cpu"},
296 {PERF_SAMPLE_PERIOD, "period"},
297 {PERF_SAMPLE_STREAM_ID, "stream_id"},
298 {PERF_SAMPLE_RAW, "raw"},
299 {PERF_SAMPLE_BRANCH_STACK, "stack"},
300 {PERF_SAMPLE_REGS_USER, "regs_user"},
301 {PERF_SAMPLE_STACK_USER, "stack_user"},
302 {PERF_SAMPLE_WEIGHT, "weight"},
303 {PERF_SAMPLE_DATA_SRC, "data_src"},
304 {PERF_SAMPLE_IDENTIFIER, "identifier"},
305 {PERF_SAMPLE_TRANSACTION, "transaction"},
306 {PERF_SAMPLE_REGS_INTR, "reg_intr"},
307 {PERF_SAMPLE_SERVER_PID, "server_pid"},
308 };
309
DumpSampleType(uint64_t sampleType, int indent)310 void SubCommandDump::DumpSampleType(uint64_t sampleType, int indent)
311 {
312 std::string names;
313 for (auto &pair : g_sampleTypeNames) {
314 if (sampleType & pair.first) {
315 if (!names.empty()) {
316 names.append(",");
317 }
318 names.append(pair.second);
319 }
320 }
321 PRINT_INDENT(indent + 1, "sample_type names: %s\n", names.c_str());
322 }
323
DumpPrintEventAttr(const perf_event_attr &attr, int indent)324 void SubCommandDump::DumpPrintEventAttr(const perf_event_attr &attr, int indent)
325 {
326 PRINT_INDENT(indent, "event_attr: \n");
327
328 PRINT_INDENT(indent + 1, "type %u, size %u, config %llu\n", attr.type, attr.size, attr.config);
329
330 if (attr.freq != 0) {
331 PRINT_INDENT(indent + 1, "sample_freq %llu\n", attr.sample_freq);
332 } else {
333 PRINT_INDENT(indent + 1, "sample_period %llu\n", attr.sample_period);
334 }
335
336 PRINT_INDENT(indent + 1, "sample_type (0x%llx) \n", attr.sample_type);
337 DumpSampleType(attr.sample_type, indent);
338
339 PRINT_INDENT(indent + 1, "read_format (0x%llx) \n", attr.read_format);
340
341 PRINT_INDENT(indent + 1, "disabled %u, inherit %u, pinned %u, exclusive %u\n", attr.disabled,
342 attr.inherit, attr.pinned, attr.exclusive);
343
344 PRINT_INDENT(indent + 1, "exclude_user %u, exclude_kernel %u, exclude_hv %u, exclude_idle %u\n",
345 attr.exclude_user, attr.exclude_kernel, attr.exclude_hv, attr.exclude_idle);
346
347 PRINT_INDENT(indent + 1, "mmap %u, mmap2 %u, comm %u, comm_exec %u, freq %u\n", attr.mmap,
348 attr.mmap2, attr.comm, attr.comm_exec, attr.freq);
349
350 PRINT_INDENT(indent + 1, "inherit_stat %u, enable_on_exec %u, task %u, use_clockid %u\n",
351 attr.inherit_stat, attr.enable_on_exec, attr.task, attr.use_clockid);
352
353 PRINT_INDENT(indent + 1, "watermark %u, precise_ip %u, mmap_data %u, clockid %d\n", attr.watermark,
354 attr.precise_ip, attr.mmap_data, attr.clockid);
355
356 PRINT_INDENT(indent + 1, "sample_id_all %u, exclude_host %u, exclude_guest %u\n", attr.sample_id_all,
357 attr.exclude_host, attr.exclude_guest);
358 PRINT_INDENT(indent + 1, "branch_sample_type 0x%llx\n", attr.branch_sample_type);
359 PRINT_INDENT(indent + 1, "exclude_callchain_kernel %u, exclude_callchain_user %u\n",
360 attr.exclude_callchain_kernel, attr.exclude_callchain_user);
361 PRINT_INDENT(indent + 1, "sample_regs_user 0x%llx\n", attr.sample_regs_user);
362 PRINT_INDENT(indent + 1, "sample_stack_user 0x%x\n", attr.sample_stack_user);
363 }
364
DumpAttrPortion(int indent)365 void SubCommandDump::DumpAttrPortion(int indent)
366 {
367 attrIds_ = reader_->GetAttrSection();
368 for (size_t i = 0; i < attrIds_.size(); ++i) {
369 const AttrWithId &attr = attrIds_[i];
370 PRINT_INDENT(indent, "attr %zu:\n", i + 1);
371 DumpPrintEventAttr(attr.attr, indent_ + 1);
372 if (!attr.ids.empty()) {
373 PRINT_INDENT(indent, " ids:");
374 for (const auto &id : attr.ids) {
375 PRINT_INDENT(indent, " %" PRId64, id);
376 }
377 PRINT_INDENT(indent, "\n");
378 }
379 }
380 }
381
ExprotUserStack(const PerfRecordSample &recordSample)382 void SubCommandDump::ExprotUserStack(const PerfRecordSample &recordSample)
383 {
384 if (recordSample.data_.reg_nr > 0 and recordSample.data_.dyn_size > 0) {
385 // <pid>_<tid>_user_regs_<time>
386 std::string userRegs =
387 StringPrintf("hiperf_%d_%d_user_regs_%zu.dump", recordSample.data_.pid,
388 recordSample.data_.tid, exportSampleIndex_);
389 std::string resolvedPath = CanonicalizeSpecPath(userRegs.c_str());
390 std::unique_ptr<FILE, decltype(&fclose)> fpUserRegs(fopen(resolvedPath.c_str(), "wb"), 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 std::unique_ptr<FILE, decltype(&fclose)> fpUserData(fopen(resolvePath.c_str(), "wb"), fclose);
399 fwrite(recordSample.data_.stack_data, sizeof(u8), recordSample.data_.dyn_size,
400 fpUserData.get());
401 }
402 }
403
ExprotUserData(std::unique_ptr<PerfEventRecord> &record)404 void SubCommandDump::ExprotUserData(std::unique_ptr<PerfEventRecord> &record)
405 {
406 if (record->GetType() == PERF_RECORD_SAMPLE) {
407 if (currectSampleIndex_++ != exportSampleIndex_) {
408 return;
409 }
410 PerfRecordSample *recordSample = static_cast<PerfRecordSample *>(record.get());
411 ExprotUserStack(*recordSample);
412
413 std::string userData =
414 StringPrintf("hiperf_%d_%d_sample_record_%zu_%" PRIu64 ".dump", recordSample->data_.pid,
415 recordSample->data_.tid, exportSampleIndex_, recordSample->data_.time);
416 std::string resolvedPath = CanonicalizeSpecPath(userData.c_str());
417 std::unique_ptr<FILE, decltype(&fclose)> fpUserData(fopen(resolvedPath.c_str(), "wb"), fclose);
418 static std::vector<u8> buf(RECORD_SIZE_LIMIT);
419 CHECK_TRUE(!recordSample->GetBinary(buf), NO_RETVAL, 1, "export user sample data failed");
420 fwrite(buf.data(), sizeof(u8), recordSample->GetSize(), fpUserData.get());
421
422 HLOGD("export user data index %d time %llu", exportSampleIndex_, recordSample->data_.time);
423 }
424 }
425
DumpCallChain(int indent, std::unique_ptr<PerfRecordSample> &sample)426 void SubCommandDump::DumpCallChain(int indent, std::unique_ptr<PerfRecordSample> &sample)
427 {
428 PRINT_INDENT(indent, "\n callchain: %zu\n", sample->callFrames_.size());
429 if (sample->callFrames_.size() > 0) {
430 indent += indent + 1;
431 for (auto frameIt = sample->callFrames_.begin(); frameIt != sample->callFrames_.end();
432 frameIt++) {
433 PRINT_INDENT(indent, "%02zd:%s\n", std::distance(frameIt, sample->callFrames_.end()),
434 frameIt->ToSymbolString().c_str());
435 }
436 }
437 }
438
DumpDataPortion(int indent)439 void SubCommandDump::DumpDataPortion(int indent)
440 {
441 int recordCount = 0;
442 auto recordcCallback = [&](std::unique_ptr<PerfEventRecord> record) {
443 CHECK_TRUE(record == nullptr, false, 0, ""); // return false in callback can stop the read process
444
445 // for UT
446 if (exportSampleIndex_ > 0) {
447 ExprotUserData(record);
448 }
449
450 // tell process tree what happend for rebuild symbols
451 vr_.UpdateFromRecord(*record);
452
453 recordCount++;
454 record->Dump(indent, outputFilename_, g_outputDump);
455
456 if (record->GetType() == PERF_RECORD_SAMPLE) {
457 std::unique_ptr<PerfRecordSample> sample(
458 static_cast<PerfRecordSample *>(record.release()));
459 DumpCallChain(indent, sample);
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 §ionEventdesc)489 void SubCommandDump::PrintFeatureEventdesc(int indent,
490 const PerfFileSectionEventDesc §ionEventdesc)
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", std::make_unique<SubCommandDump>());
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 (str != EMPTY_STRING) {
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
614 } // namespace HiPerf
615 } // namespace Developtools
616 } // namespace OHOS
617