2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
23 #include <android-base/logging.h>
24 #include <android-base/stringprintf.h>
25 #include <android-base/strings.h>
28 #include "event_attr.h"
29 #include "event_type.h"
30 #include "perf_regs.h"
32 #include "record_file.h"
35 using namespace PerfFileFormat;
37 class DumpRecordCommand : public Command {
40 : Command("dump", "dump perf record file",
41 "Usage: simpleperf dumprecord [options] [perf_record_file]\n"
42 " Dump different parts of a perf record file. Default file is perf.data.\n"),
43 record_filename_("perf.data"), record_file_arch_(GetBuildArch()) {
46 bool Run(const std::vector<std::string>& args);
49 bool ParseOptions(const std::vector<std::string>& args);
50 void DumpFileHeader();
51 void DumpAttrSection();
52 bool DumpDataSection();
53 bool DumpFeatureSection();
55 std::string record_filename_;
56 std::unique_ptr<RecordFileReader> record_file_reader_;
57 ArchType record_file_arch_;
60 bool DumpRecordCommand::Run(const std::vector<std::string>& args) {
61 if (!ParseOptions(args)) {
64 record_file_reader_ = RecordFileReader::CreateInstance(record_filename_);
65 if (record_file_reader_ == nullptr) {
68 std::string arch = record_file_reader_->ReadFeatureString(FEAT_ARCH);
70 record_file_arch_ = GetArchType(arch);
71 if (record_file_arch_ == ARCH_UNSUPPORTED) {
75 ScopedCurrentArch scoped_arch(record_file_arch_);
76 std::unique_ptr<ScopedEventTypes> scoped_event_types;
77 if (record_file_reader_->HasFeature(PerfFileFormat::FEAT_META_INFO)) {
78 std::unordered_map<std::string, std::string> meta_info;
79 if (!record_file_reader_->ReadMetaInfoFeature(&meta_info)) {
82 auto it = meta_info.find("event_type_info");
83 if (it != meta_info.end()) {
84 scoped_event_types.reset(new ScopedEventTypes(it->second));
89 if (!DumpDataSection()) {
92 return DumpFeatureSection();
95 bool DumpRecordCommand::ParseOptions(const std::vector<std::string>& args) {
96 if (args.size() == 1) {
97 record_filename_ = args[0];
98 } else if (args.size() > 1) {
99 ReportUnknownOption(args, 1);
105 static const std::string GetFeatureNameOrUnknown(int feature) {
106 std::string name = GetFeatureName(feature);
107 return name.empty() ? android::base::StringPrintf("unknown_feature(%d)", feature) : name;
110 void DumpRecordCommand::DumpFileHeader() {
111 const FileHeader& header = record_file_reader_->FileHeader();
113 for (size_t i = 0; i < 8; ++i) {
114 printf("%c", header.magic[i]);
117 printf("header_size: %" PRId64 "\n", header.header_size);
118 if (header.header_size != sizeof(header)) {
119 PLOG(WARNING) << "record file header size " << header.header_size
120 << "doesn't match expected header size " << sizeof(header);
122 printf("attr_size: %" PRId64 "\n", header.attr_size);
123 if (header.attr_size != sizeof(FileAttr)) {
124 PLOG(WARNING) << "record file attr size " << header.attr_size
125 << " doesn't match expected attr size " << sizeof(FileAttr);
127 printf("attrs[file section]: offset %" PRId64 ", size %" PRId64 "\n", header.attrs.offset,
129 printf("data[file section]: offset %" PRId64 ", size %" PRId64 "\n", header.data.offset,
131 printf("event_types[file section]: offset %" PRId64 ", size %" PRId64 "\n",
132 header.event_types.offset, header.event_types.size);
134 std::vector<int> features;
135 for (size_t i = 0; i < FEAT_MAX_NUM; ++i) {
138 if ((header.features[j] & (1 << k)) != 0) {
139 features.push_back(i);
142 for (auto& feature : features) {
143 printf("feature: %s\n", GetFeatureNameOrUnknown(feature).c_str());
147 void DumpRecordCommand::DumpAttrSection() {
148 std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection();
149 for (size_t i = 0; i < attrs.size(); ++i) {
150 const auto& attr = attrs[i];
151 printf("attr %zu:\n", i + 1);
152 DumpPerfEventAttr(*attr.attr, 1);
153 if (!attr.ids.empty()) {
155 for (const auto& id : attr.ids) {
156 printf(" %" PRId64, id);
163 bool DumpRecordCommand::DumpDataSection() {
164 ThreadTree thread_tree;
165 thread_tree.ShowIpForUnknownSymbol();
166 record_file_reader_->LoadBuildIdAndFileFeatures(thread_tree);
168 auto get_symbol_function = [&](uint32_t pid, uint32_t tid, uint64_t ip, std::string& dso_name,
169 std::string& symbol_name, uint64_t& vaddr_in_file) {
170 ThreadEntry* thread = thread_tree.FindThreadOrNew(pid, tid);
171 const MapEntry* map = thread_tree.FindMap(thread, ip);
173 const Symbol* symbol = thread_tree.FindSymbol(map, ip, &vaddr_in_file, &dso);
174 dso_name = dso->Path();
175 symbol_name = symbol->DemangledName();
178 auto record_callback = [&](std::unique_ptr<Record> r) {
180 thread_tree.Update(*r);
181 if (r->type() == PERF_RECORD_SAMPLE) {
182 SampleRecord& sr = *static_cast<SampleRecord*>(r.get());
183 if (sr.sample_type & PERF_SAMPLE_CALLCHAIN) {
184 PrintIndented(1, "callchain:\n");
185 for (size_t i = 0; i < sr.callchain_data.ip_nr; ++i) {
186 std::string dso_name;
187 std::string symbol_name;
188 uint64_t vaddr_in_file;
189 get_symbol_function(sr.tid_data.pid, sr.tid_data.tid, sr.callchain_data.ips[i],
190 dso_name, symbol_name, vaddr_in_file);
191 PrintIndented(2, "%s (%s[+%" PRIx64 "])\n", symbol_name.c_str(), dso_name.c_str(),
195 } else if (r->type() == SIMPLE_PERF_RECORD_CALLCHAIN) {
196 CallChainRecord& cr = *static_cast<CallChainRecord*>(r.get());
197 PrintIndented(1, "callchain:\n");
198 for (size_t i = 0; i < cr.ip_nr; ++i) {
199 std::string dso_name;
200 std::string symbol_name;
201 uint64_t vaddr_in_file;
202 get_symbol_function(cr.pid, cr.tid, cr.ips[i], dso_name, symbol_name, vaddr_in_file);
203 PrintIndented(2, "%s (%s[+%" PRIx64 "])\n", symbol_name.c_str(), dso_name.c_str(),
209 return record_file_reader_->ReadDataSection(record_callback, false);
212 bool DumpRecordCommand::DumpFeatureSection() {
213 std::map<int, SectionDesc> section_map = record_file_reader_->FeatureSectionDescriptors();
214 for (const auto& pair : section_map) {
215 int feature = pair.first;
216 const auto& section = pair.second;
217 printf("feature section for %s: offset %" PRId64 ", size %" PRId64 "\n",
218 GetFeatureNameOrUnknown(feature).c_str(), section.offset, section.size);
219 if (feature == FEAT_BUILD_ID) {
220 std::vector<BuildIdRecord> records = record_file_reader_->ReadBuildIdFeature();
221 for (auto& r : records) {
224 } else if (feature == FEAT_OSRELEASE) {
225 std::string s = record_file_reader_->ReadFeatureString(feature);
226 PrintIndented(1, "osrelease: %s\n", s.c_str());
227 } else if (feature == FEAT_ARCH) {
228 std::string s = record_file_reader_->ReadFeatureString(feature);
229 PrintIndented(1, "arch: %s\n", s.c_str());
230 } else if (feature == FEAT_CMDLINE) {
231 std::vector<std::string> cmdline = record_file_reader_->ReadCmdlineFeature();
232 PrintIndented(1, "cmdline: %s\n", android::base::Join(cmdline, ' ').c_str());
233 } else if (feature == FEAT_FILE) {
234 std::string file_path;
237 std::vector<Symbol> symbols;
239 PrintIndented(1, "file:\n");
240 while (record_file_reader_->ReadFileFeature(read_pos, &file_path,
241 &file_type, &min_vaddr,
243 PrintIndented(2, "file_path %s\n", file_path.c_str());
244 PrintIndented(2, "file_type %s\n", DsoTypeToString(static_cast<DsoType>(file_type)));
245 PrintIndented(2, "min_vaddr 0x%" PRIx64 "\n", min_vaddr);
246 PrintIndented(2, "symbols:\n");
247 for (const auto& symbol : symbols) {
248 PrintIndented(3, "%s [0x%" PRIx64 "-0x%" PRIx64 "]\n", symbol.DemangledName(),
249 symbol.addr, symbol.addr + symbol.len);
252 } else if (feature == FEAT_META_INFO) {
253 std::unordered_map<std::string, std::string> info_map;
254 if (!record_file_reader_->ReadMetaInfoFeature(&info_map)) {
257 PrintIndented(1, "meta_info:\n");
258 for (auto& pair : info_map) {
259 PrintIndented(2, "%s = %s\n", pair.first.c_str(), pair.second.c_str());
266 void RegisterDumpRecordCommand() {
267 RegisterCommand("dump", [] { return std::unique_ptr<Command>(new DumpRecordCommand); });