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 <base/logging.h>
24 #include <base/stringprintf.h>
27 #include "event_attr.h"
29 #include "record_file.h"
31 using namespace PerfFileFormat;
33 class DumpRecordCommandImpl {
35 DumpRecordCommandImpl() : record_filename_("perf.data") {
38 bool Run(const std::vector<std::string>& args);
41 bool ParseOptions(const std::vector<std::string>& args);
42 void DumpFileHeader();
43 void DumpAttrSection();
44 void DumpDataSection();
45 void DumpFeatureSection();
47 std::string record_filename_;
48 std::unique_ptr<RecordFileReader> record_file_reader_;
50 std::vector<int> features_;
53 bool DumpRecordCommandImpl::Run(const std::vector<std::string>& args) {
54 if (!ParseOptions(args)) {
57 record_file_reader_ = RecordFileReader::CreateInstance(record_filename_);
58 if (record_file_reader_ == nullptr) {
69 bool DumpRecordCommandImpl::ParseOptions(const std::vector<std::string>& args) {
70 if (args.size() == 2) {
71 record_filename_ = args[1];
76 static const std::string GetFeatureName(int feature);
78 void DumpRecordCommandImpl::DumpFileHeader() {
79 const FileHeader* header = record_file_reader_->FileHeader();
81 for (size_t i = 0; i < 8; ++i) {
82 printf("%c", header->magic[i]);
85 printf("header_size: %" PRId64 "\n", header->header_size);
86 if (header->header_size != sizeof(*header)) {
87 PLOG(WARNING) << "record file header size doesn't match expected header size "
90 printf("attr_size: %" PRId64 "\n", header->attr_size);
91 if (header->attr_size != sizeof(FileAttr)) {
92 PLOG(WARNING) << "record file attr size doesn't match expected attr size " << sizeof(FileAttr);
94 printf("attrs[file section]: offset %" PRId64 ", size %" PRId64 "\n", header->attrs.offset,
96 printf("data[file section]: offset %" PRId64 ", size %" PRId64 "\n", header->data.offset,
98 printf("event_types[file section]: offset %" PRId64 ", size %" PRId64 "\n",
99 header->event_types.offset, header->event_types.size);
102 for (size_t i = 0; i < FEAT_MAX_NUM; ++i) {
105 if ((header->features[j] & (1 << k)) != 0) {
106 features_.push_back(i);
109 for (auto& feature : features_) {
110 printf("feature: %s\n", GetFeatureName(feature).c_str());
114 static const std::string GetFeatureName(int feature) {
115 static std::map<int, std::string> feature_name_map = {
116 {FEAT_TRACING_DATA, "tracing_data"},
117 {FEAT_BUILD_ID, "build_id"},
118 {FEAT_HOSTNAME, "hostname"},
119 {FEAT_OSRELEASE, "osrelease"},
120 {FEAT_VERSION, "version"},
122 {FEAT_NRCPUS, "nrcpus"},
123 {FEAT_CPUDESC, "cpudesc"},
124 {FEAT_CPUID, "cpuid"},
125 {FEAT_TOTAL_MEM, "total_mem"},
126 {FEAT_CMDLINE, "cmdline"},
127 {FEAT_EVENT_DESC, "event_desc"},
128 {FEAT_CPU_TOPOLOGY, "cpu_topology"},
129 {FEAT_NUMA_TOPOLOGY, "numa_topology"},
130 {FEAT_BRANCH_STACK, "branck_stack"},
131 {FEAT_PMU_MAPPINGS, "pmu_mappings"},
132 {FEAT_GROUP_DESC, "group_desc"},
134 auto it = feature_name_map.find(feature);
135 if (it != feature_name_map.end()) {
138 return android::base::StringPrintf("unknown_feature(%d)", feature);
141 void DumpRecordCommandImpl::DumpAttrSection() {
142 std::vector<const FileAttr*> attrs = record_file_reader_->AttrSection();
143 for (size_t i = 0; i < attrs.size(); ++i) {
144 auto& attr = attrs[i];
145 printf("file_attr %zu:\n", i + 1);
146 DumpPerfEventAttr(attr->attr, 1);
147 printf(" ids[file_section]: offset %" PRId64 ", size %" PRId64 "\n", attr->ids.offset,
149 std::vector<uint64_t> ids = record_file_reader_->IdsForAttr(attr);
150 if (ids.size() > 0) {
152 for (auto& id : ids) {
153 printf(" %" PRId64, id);
160 void DumpRecordCommandImpl::DumpDataSection() {
161 std::vector<std::unique_ptr<const Record>> records = record_file_reader_->DataSection();
162 for (auto& record : records) {
167 void DumpRecordCommandImpl::DumpFeatureSection() {
168 std::vector<SectionDesc> sections = record_file_reader_->FeatureSectionDescriptors();
169 CHECK_EQ(sections.size(), features_.size());
170 for (size_t i = 0; i < features_.size(); ++i) {
171 int feature = features_[i];
172 SectionDesc& section = sections[i];
173 printf("feature section for %s: offset %" PRId64 ", size %" PRId64 "\n",
174 GetFeatureName(feature).c_str(), section.offset, section.size);
175 if (feature == FEAT_BUILD_ID) {
176 const char* p = record_file_reader_->DataAtOffset(section.offset);
177 const char* end = p + section.size;
179 const perf_event_header* header = reinterpret_cast<const perf_event_header*>(p);
180 CHECK_LE(p + header->size, end);
181 CHECK_EQ(PERF_RECORD_BUILD_ID, header->type);
182 BuildIdRecord record(header);
190 class DumpRecordCommand : public Command {
193 : Command("dump", "dump perf record file",
194 "Usage: simpleperf dumprecord [options] [perf_record_file]\n"
195 " Dump different parts of a perf record file. Default file is perf.data.\n") {
198 bool Run(const std::vector<std::string>& args) override {
199 DumpRecordCommandImpl impl;
200 return impl.Run(args);
204 DumpRecordCommand dumprecord_cmd;