Home | History | Annotate | Download | only in simpleperf
      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 
     34 using namespace PerfFileFormat;
     35 
     36 class 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   bool DumpFeatureSection();
     53 
     54   std::string record_filename_;
     55   std::unique_ptr<RecordFileReader> record_file_reader_;
     56   ArchType record_file_arch_;
     57 };
     58 
     59 bool 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   if (!DumpFeatureSection()) {
     79     return false;
     80   }
     81 
     82   return true;
     83 }
     84 
     85 bool DumpRecordCommand::ParseOptions(const std::vector<std::string>& args) {
     86   if (args.size() == 1) {
     87     record_filename_ = args[0];
     88   } else if (args.size() > 1) {
     89     ReportUnknownOption(args, 1);
     90     return false;
     91   }
     92   return true;
     93 }
     94 
     95 static const std::string GetFeatureName(int feature);
     96 
     97 void DumpRecordCommand::DumpFileHeader() {
     98   const FileHeader& header = record_file_reader_->FileHeader();
     99   printf("magic: ");
    100   for (size_t i = 0; i < 8; ++i) {
    101     printf("%c", header.magic[i]);
    102   }
    103   printf("\n");
    104   printf("header_size: %" PRId64 "\n", header.header_size);
    105   if (header.header_size != sizeof(header)) {
    106     PLOG(WARNING) << "record file header size " << header.header_size
    107                   << "doesn't match expected header size " << sizeof(header);
    108   }
    109   printf("attr_size: %" PRId64 "\n", header.attr_size);
    110   if (header.attr_size != sizeof(FileAttr)) {
    111     PLOG(WARNING) << "record file attr size " << header.attr_size
    112                   << " doesn't match expected attr size " << sizeof(FileAttr);
    113   }
    114   printf("attrs[file section]: offset %" PRId64 ", size %" PRId64 "\n", header.attrs.offset,
    115          header.attrs.size);
    116   printf("data[file section]: offset %" PRId64 ", size %" PRId64 "\n", header.data.offset,
    117          header.data.size);
    118   printf("event_types[file section]: offset %" PRId64 ", size %" PRId64 "\n",
    119          header.event_types.offset, header.event_types.size);
    120 
    121   std::vector<int> features;
    122   for (size_t i = 0; i < FEAT_MAX_NUM; ++i) {
    123     size_t j = i / 8;
    124     size_t k = i % 8;
    125     if ((header.features[j] & (1 << k)) != 0) {
    126       features.push_back(i);
    127     }
    128   }
    129   for (auto& feature : features) {
    130     printf("feature: %s\n", GetFeatureName(feature).c_str());
    131   }
    132 }
    133 
    134 static const std::string GetFeatureName(int feature) {
    135   static std::map<int, std::string> feature_name_map = {
    136       {FEAT_TRACING_DATA, "tracing_data"},
    137       {FEAT_BUILD_ID, "build_id"},
    138       {FEAT_HOSTNAME, "hostname"},
    139       {FEAT_OSRELEASE, "osrelease"},
    140       {FEAT_VERSION, "version"},
    141       {FEAT_ARCH, "arch"},
    142       {FEAT_NRCPUS, "nrcpus"},
    143       {FEAT_CPUDESC, "cpudesc"},
    144       {FEAT_CPUID, "cpuid"},
    145       {FEAT_TOTAL_MEM, "total_mem"},
    146       {FEAT_CMDLINE, "cmdline"},
    147       {FEAT_EVENT_DESC, "event_desc"},
    148       {FEAT_CPU_TOPOLOGY, "cpu_topology"},
    149       {FEAT_NUMA_TOPOLOGY, "numa_topology"},
    150       {FEAT_BRANCH_STACK, "branch_stack"},
    151       {FEAT_PMU_MAPPINGS, "pmu_mappings"},
    152       {FEAT_GROUP_DESC, "group_desc"},
    153       {FEAT_FILE, "file"},
    154   };
    155   auto it = feature_name_map.find(feature);
    156   if (it != feature_name_map.end()) {
    157     return it->second;
    158   }
    159   return android::base::StringPrintf("unknown_feature(%d)", feature);
    160 }
    161 
    162 void DumpRecordCommand::DumpAttrSection() {
    163   std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection();
    164   for (size_t i = 0; i < attrs.size(); ++i) {
    165     const auto& attr = attrs[i];
    166     printf("attr %zu:\n", i + 1);
    167     DumpPerfEventAttr(*attr.attr, 1);
    168     if (!attr.ids.empty()) {
    169       printf("  ids:");
    170       for (const auto& id : attr.ids) {
    171         printf(" %" PRId64, id);
    172       }
    173       printf("\n");
    174     }
    175   }
    176 }
    177 
    178 void DumpRecordCommand::DumpDataSection() {
    179   record_file_reader_->ReadDataSection([](std::unique_ptr<Record> record) {
    180     record->Dump();
    181     return true;
    182   }, false);
    183 }
    184 
    185 bool DumpRecordCommand::DumpFeatureSection() {
    186   std::map<int, SectionDesc> section_map = record_file_reader_->FeatureSectionDescriptors();
    187   for (const auto& pair : section_map) {
    188     int feature = pair.first;
    189     const auto& section = pair.second;
    190     printf("feature section for %s: offset %" PRId64 ", size %" PRId64 "\n",
    191            GetFeatureName(feature).c_str(), section.offset, section.size);
    192     if (feature == FEAT_BUILD_ID) {
    193       std::vector<BuildIdRecord> records = record_file_reader_->ReadBuildIdFeature();
    194       for (auto& r : records) {
    195         r.Dump(1);
    196       }
    197     } else if (feature == FEAT_OSRELEASE) {
    198       std::string s = record_file_reader_->ReadFeatureString(feature);
    199       PrintIndented(1, "osrelease: %s\n", s.c_str());
    200     } else if (feature == FEAT_ARCH) {
    201       std::string s = record_file_reader_->ReadFeatureString(feature);
    202       PrintIndented(1, "arch: %s\n", s.c_str());
    203     } else if (feature == FEAT_CMDLINE) {
    204       std::vector<std::string> cmdline = record_file_reader_->ReadCmdlineFeature();
    205       PrintIndented(1, "cmdline: %s\n", android::base::Join(cmdline, ' ').c_str());
    206     } else if (feature == FEAT_FILE) {
    207       std::string file_path;
    208       uint32_t file_type;
    209       uint64_t min_vaddr;
    210       std::vector<Symbol> symbols;
    211       size_t read_pos = 0;
    212       PrintIndented(1, "file:\n");
    213       while (record_file_reader_->ReadFileFeature(read_pos, &file_path,
    214                                                   &file_type, &min_vaddr,
    215                                                   &symbols)) {
    216         PrintIndented(2, "file_path %s\n", file_path.c_str());
    217         PrintIndented(2, "file_type %s\n", DsoTypeToString(static_cast<DsoType>(file_type)));
    218         PrintIndented(2, "min_vaddr 0x%" PRIx64 "\n", min_vaddr);
    219         PrintIndented(2, "symbols:\n");
    220         for (const auto& symbol : symbols) {
    221           PrintIndented(3, "%s [0x%" PRIx64 "-0x%" PRIx64 "]\n", symbol.DemangledName(),
    222                         symbol.addr, symbol.addr + symbol.len);
    223         }
    224       }
    225     } else if (feature == FEAT_META_INFO) {
    226       std::unordered_map<std::string, std::string> info_map;
    227       if (!record_file_reader_->ReadMetaInfoFeature(&info_map)) {
    228         return false;
    229       }
    230       PrintIndented(1, "meta_info:\n");
    231       for (auto& pair : info_map) {
    232         PrintIndented(2, "%s = %s\n", pair.first.c_str(), pair.second.c_str());
    233       }
    234     }
    235   }
    236   return true;
    237 }
    238 
    239 void RegisterDumpRecordCommand() {
    240   RegisterCommand("dump", [] { return std::unique_ptr<Command>(new DumpRecordCommand); });
    241 }
    242