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 <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