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 <base/logging.h> 24 #include <base/stringprintf.h> 25 26 #include "command.h" 27 #include "event_attr.h" 28 #include "record.h" 29 #include "record_file.h" 30 31 using namespace PerfFileFormat; 32 33 class DumpRecordCommandImpl { 34 public: 35 DumpRecordCommandImpl() : record_filename_("perf.data") { 36 } 37 38 bool Run(const std::vector<std::string>& args); 39 40 private: 41 bool ParseOptions(const std::vector<std::string>& args); 42 void DumpFileHeader(); 43 void DumpAttrSection(); 44 void DumpDataSection(); 45 void DumpFeatureSection(); 46 47 std::string record_filename_; 48 std::unique_ptr<RecordFileReader> record_file_reader_; 49 50 std::vector<int> features_; 51 }; 52 53 bool DumpRecordCommandImpl::Run(const std::vector<std::string>& args) { 54 if (!ParseOptions(args)) { 55 return false; 56 } 57 record_file_reader_ = RecordFileReader::CreateInstance(record_filename_); 58 if (record_file_reader_ == nullptr) { 59 return false; 60 } 61 DumpFileHeader(); 62 DumpAttrSection(); 63 DumpDataSection(); 64 DumpFeatureSection(); 65 66 return true; 67 } 68 69 bool DumpRecordCommandImpl::ParseOptions(const std::vector<std::string>& args) { 70 if (args.size() == 2) { 71 record_filename_ = args[1]; 72 } 73 return true; 74 } 75 76 static const std::string GetFeatureName(int feature); 77 78 void DumpRecordCommandImpl::DumpFileHeader() { 79 const FileHeader* header = record_file_reader_->FileHeader(); 80 printf("magic: "); 81 for (size_t i = 0; i < 8; ++i) { 82 printf("%c", header->magic[i]); 83 } 84 printf("\n"); 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 " 88 << sizeof(*header); 89 } 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); 93 } 94 printf("attrs[file section]: offset %" PRId64 ", size %" PRId64 "\n", header->attrs.offset, 95 header->attrs.size); 96 printf("data[file section]: offset %" PRId64 ", size %" PRId64 "\n", header->data.offset, 97 header->data.size); 98 printf("event_types[file section]: offset %" PRId64 ", size %" PRId64 "\n", 99 header->event_types.offset, header->event_types.size); 100 101 features_.clear(); 102 for (size_t i = 0; i < FEAT_MAX_NUM; ++i) { 103 size_t j = i / 8; 104 size_t k = i % 8; 105 if ((header->features[j] & (1 << k)) != 0) { 106 features_.push_back(i); 107 } 108 } 109 for (auto& feature : features_) { 110 printf("feature: %s\n", GetFeatureName(feature).c_str()); 111 } 112 } 113 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"}, 121 {FEAT_ARCH, "arch"}, 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"}, 133 }; 134 auto it = feature_name_map.find(feature); 135 if (it != feature_name_map.end()) { 136 return it->second; 137 } 138 return android::base::StringPrintf("unknown_feature(%d)", feature); 139 } 140 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, 148 attr->ids.size); 149 std::vector<uint64_t> ids = record_file_reader_->IdsForAttr(attr); 150 if (ids.size() > 0) { 151 printf(" ids:"); 152 for (auto& id : ids) { 153 printf(" %" PRId64, id); 154 } 155 printf("\n"); 156 } 157 } 158 } 159 160 void DumpRecordCommandImpl::DumpDataSection() { 161 std::vector<std::unique_ptr<const Record>> records = record_file_reader_->DataSection(); 162 for (auto& record : records) { 163 record->Dump(); 164 } 165 } 166 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; 178 while (p < end) { 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); 183 record.Dump(1); 184 p += header->size; 185 } 186 } 187 } 188 } 189 190 class DumpRecordCommand : public Command { 191 public: 192 DumpRecordCommand() 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") { 196 } 197 198 bool Run(const std::vector<std::string>& args) override { 199 DumpRecordCommandImpl impl; 200 return impl.Run(args); 201 } 202 }; 203 204 DumpRecordCommand dumprecord_cmd; 205