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   void 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   DumpFeatureSection();
     79 
     80   return true;
     81 }
     82 
     83 bool 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 
     93 static const std::string GetFeatureName(int feature);
     94 
     95 void 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 
    132 static 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       {FEAT_FILE, "file"},
    152   };
    153   auto it = feature_name_map.find(feature);
    154   if (it != feature_name_map.end()) {
    155     return it->second;
    156   }
    157   return android::base::StringPrintf("unknown_feature(%d)", feature);
    158 }
    159 
    160 void DumpRecordCommand::DumpAttrSection() {
    161   std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection();
    162   for (size_t i = 0; i < attrs.size(); ++i) {
    163     const auto& attr = attrs[i];
    164     printf("attr %zu:\n", i + 1);
    165     DumpPerfEventAttr(*attr.attr, 1);
    166     if (!attr.ids.empty()) {
    167       printf("  ids:");
    168       for (const auto& id : attr.ids) {
    169         printf(" %" PRId64, id);
    170       }
    171       printf("\n");
    172     }
    173   }
    174 }
    175 
    176 void DumpRecordCommand::DumpDataSection() {
    177   record_file_reader_->ReadDataSection([](std::unique_ptr<Record> record) {
    178     record->Dump();
    179     return true;
    180   }, false);
    181 }
    182 
    183 void DumpRecordCommand::DumpFeatureSection() {
    184   std::map<int, SectionDesc> section_map = record_file_reader_->FeatureSectionDescriptors();
    185   for (const auto& pair : section_map) {
    186     int feature = pair.first;
    187     const auto& section = pair.second;
    188     printf("feature section for %s: offset %" PRId64 ", size %" PRId64 "\n",
    189            GetFeatureName(feature).c_str(), section.offset, section.size);
    190     if (feature == FEAT_BUILD_ID) {
    191       std::vector<BuildIdRecord> records = record_file_reader_->ReadBuildIdFeature();
    192       for (auto& r : records) {
    193         r.Dump(1);
    194       }
    195     } else if (feature == FEAT_OSRELEASE) {
    196       std::string s = record_file_reader_->ReadFeatureString(feature);
    197       PrintIndented(1, "osrelease: %s\n", s.c_str());
    198     } else if (feature == FEAT_ARCH) {
    199       std::string s = record_file_reader_->ReadFeatureString(feature);
    200       PrintIndented(1, "arch: %s\n", s.c_str());
    201     } else if (feature == FEAT_CMDLINE) {
    202       std::vector<std::string> cmdline = record_file_reader_->ReadCmdlineFeature();
    203       PrintIndented(1, "cmdline: %s\n", android::base::Join(cmdline, ' ').c_str());
    204     } else if (feature == FEAT_FILE) {
    205       std::string file_path;
    206       uint32_t file_type;
    207       uint64_t min_vaddr;
    208       std::vector<Symbol> symbols;
    209       size_t read_pos = 0;
    210       PrintIndented(1, "file:\n");
    211       while (record_file_reader_->ReadFileFeature(read_pos, &file_path,
    212                                                   &file_type, &min_vaddr,
    213                                                   &symbols)) {
    214         PrintIndented(2, "file_path %s\n", file_path.c_str());
    215         PrintIndented(2, "file_type %s\n", DsoTypeToString(static_cast<DsoType>(file_type)));
    216         PrintIndented(2, "min_vaddr 0x%" PRIx64 "\n", min_vaddr);
    217         PrintIndented(2, "symbols:\n");
    218         for (const auto& symbol : symbols) {
    219           PrintIndented(3, "%s [0x%" PRIx64 "-0x%" PRIx64 "]\n", symbol.DemangledName(),
    220                         symbol.addr, symbol.addr + symbol.len);
    221         }
    222       }
    223     }
    224   }
    225 }
    226 
    227 void RegisterDumpRecordCommand() {
    228   RegisterCommand("dump", [] { return std::unique_ptr<Command>(new DumpRecordCommand); });
    229 }
    230