1/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <inttypes.h>
18
19#include <map>
20#include <string>
21#include <vector>
22
23#include <android-base/logging.h>
24#include <android-base/stringprintf.h>
25#include <android-base/strings.h>
26
27#include "command.h"
28#include "event_attr.h"
29#include "perf_regs.h"
30#include "record.h"
31#include "record_file.h"
32#include "utils.h"
33
34using namespace PerfFileFormat;
35
36class DumpRecordCommand : public Command {
37 public:
38  DumpRecordCommand()
39      : Command("dump", "dump perf record file",
40                "Usage: simpleperf dumprecord [options] [perf_record_file]\n"
41                "    Dump different parts of a perf record file. Default file is perf.data.\n"),
42        record_filename_("perf.data"), record_file_arch_(GetBuildArch()) {
43  }
44
45  bool Run(const std::vector<std::string>& args);
46
47 private:
48  bool ParseOptions(const std::vector<std::string>& args);
49  void DumpFileHeader();
50  void DumpAttrSection();
51  void DumpDataSection();
52  void DumpFeatureSection();
53
54  std::string record_filename_;
55  std::unique_ptr<RecordFileReader> record_file_reader_;
56  ArchType record_file_arch_;
57};
58
59bool DumpRecordCommand::Run(const std::vector<std::string>& args) {
60  if (!ParseOptions(args)) {
61    return false;
62  }
63  record_file_reader_ = RecordFileReader::CreateInstance(record_filename_);
64  if (record_file_reader_ == nullptr) {
65    return false;
66  }
67  std::string arch = record_file_reader_->ReadFeatureString(FEAT_ARCH);
68  if (!arch.empty()) {
69    record_file_arch_ = GetArchType(arch);
70    if (record_file_arch_ == ARCH_UNSUPPORTED) {
71      return false;
72    }
73  }
74  ScopedCurrentArch scoped_arch(record_file_arch_);
75  DumpFileHeader();
76  DumpAttrSection();
77  DumpDataSection();
78  DumpFeatureSection();
79
80  return true;
81}
82
83bool DumpRecordCommand::ParseOptions(const std::vector<std::string>& args) {
84  if (args.size() == 1) {
85    record_filename_ = args[0];
86  } else if (args.size() > 1) {
87    ReportUnknownOption(args, 1);
88    return false;
89  }
90  return true;
91}
92
93static const std::string GetFeatureName(int feature);
94
95void DumpRecordCommand::DumpFileHeader() {
96  const FileHeader& header = record_file_reader_->FileHeader();
97  printf("magic: ");
98  for (size_t i = 0; i < 8; ++i) {
99    printf("%c", header.magic[i]);
100  }
101  printf("\n");
102  printf("header_size: %" PRId64 "\n", header.header_size);
103  if (header.header_size != sizeof(header)) {
104    PLOG(WARNING) << "record file header size " << header.header_size
105                  << "doesn't match expected header size " << sizeof(header);
106  }
107  printf("attr_size: %" PRId64 "\n", header.attr_size);
108  if (header.attr_size != sizeof(FileAttr)) {
109    PLOG(WARNING) << "record file attr size " << header.attr_size
110                  << " doesn't match expected attr size " << sizeof(FileAttr);
111  }
112  printf("attrs[file section]: offset %" PRId64 ", size %" PRId64 "\n", header.attrs.offset,
113         header.attrs.size);
114  printf("data[file section]: offset %" PRId64 ", size %" PRId64 "\n", header.data.offset,
115         header.data.size);
116  printf("event_types[file section]: offset %" PRId64 ", size %" PRId64 "\n",
117         header.event_types.offset, header.event_types.size);
118
119  std::vector<int> features;
120  for (size_t i = 0; i < FEAT_MAX_NUM; ++i) {
121    size_t j = i / 8;
122    size_t k = i % 8;
123    if ((header.features[j] & (1 << k)) != 0) {
124      features.push_back(i);
125    }
126  }
127  for (auto& feature : features) {
128    printf("feature: %s\n", GetFeatureName(feature).c_str());
129  }
130}
131
132static const std::string GetFeatureName(int feature) {
133  static std::map<int, std::string> feature_name_map = {
134      {FEAT_TRACING_DATA, "tracing_data"},
135      {FEAT_BUILD_ID, "build_id"},
136      {FEAT_HOSTNAME, "hostname"},
137      {FEAT_OSRELEASE, "osrelease"},
138      {FEAT_VERSION, "version"},
139      {FEAT_ARCH, "arch"},
140      {FEAT_NRCPUS, "nrcpus"},
141      {FEAT_CPUDESC, "cpudesc"},
142      {FEAT_CPUID, "cpuid"},
143      {FEAT_TOTAL_MEM, "total_mem"},
144      {FEAT_CMDLINE, "cmdline"},
145      {FEAT_EVENT_DESC, "event_desc"},
146      {FEAT_CPU_TOPOLOGY, "cpu_topology"},
147      {FEAT_NUMA_TOPOLOGY, "numa_topology"},
148      {FEAT_BRANCH_STACK, "branch_stack"},
149      {FEAT_PMU_MAPPINGS, "pmu_mappings"},
150      {FEAT_GROUP_DESC, "group_desc"},
151  };
152  auto it = feature_name_map.find(feature);
153  if (it != feature_name_map.end()) {
154    return it->second;
155  }
156  return android::base::StringPrintf("unknown_feature(%d)", feature);
157}
158
159void DumpRecordCommand::DumpAttrSection() {
160  const std::vector<FileAttr>& attrs = record_file_reader_->AttrSection();
161  for (size_t i = 0; i < attrs.size(); ++i) {
162    const auto& attr = attrs[i];
163    printf("file_attr %zu:\n", i + 1);
164    DumpPerfEventAttr(attr.attr, 1);
165    printf("  ids[file_section]: offset %" PRId64 ", size %" PRId64 "\n", attr.ids.offset,
166           attr.ids.size);
167    std::vector<uint64_t> ids;
168    if (!record_file_reader_->ReadIdsForAttr(attr, &ids)) {
169      return;
170    }
171    if (!ids.empty()) {
172      printf("  ids:");
173      for (const auto& id : ids) {
174        printf(" %" PRId64, id);
175      }
176      printf("\n");
177    }
178  }
179}
180
181void DumpRecordCommand::DumpDataSection() {
182  record_file_reader_->ReadDataSection([](std::unique_ptr<Record> record) {
183    record->Dump();
184    return true;
185  }, false);
186}
187
188void DumpRecordCommand::DumpFeatureSection() {
189  std::map<int, SectionDesc> section_map = record_file_reader_->FeatureSectionDescriptors();
190  for (const auto& pair : section_map) {
191    int feature = pair.first;
192    const auto& section = pair.second;
193    printf("feature section for %s: offset %" PRId64 ", size %" PRId64 "\n",
194           GetFeatureName(feature).c_str(), section.offset, section.size);
195    if (feature == FEAT_BUILD_ID) {
196      std::vector<BuildIdRecord> records = record_file_reader_->ReadBuildIdFeature();
197      for (auto& r : records) {
198        r.Dump(1);
199      }
200    } else if (feature == FEAT_OSRELEASE) {
201      std::string s = record_file_reader_->ReadFeatureString(feature);
202      PrintIndented(1, "osrelease: %s\n", s.c_str());
203    } else if (feature == FEAT_ARCH) {
204      std::string s = record_file_reader_->ReadFeatureString(feature);
205      PrintIndented(1, "arch: %s\n", s.c_str());
206    } else if (feature == FEAT_CMDLINE) {
207      std::vector<std::string> cmdline = record_file_reader_->ReadCmdlineFeature();
208      PrintIndented(1, "cmdline: %s\n", android::base::Join(cmdline, ' ').c_str());
209    }
210  }
211}
212
213void RegisterDumpRecordCommand() {
214  RegisterCommand("dump", [] { return std::unique_ptr<Command>(new DumpRecordCommand); });
215}
216