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 "record_file.h"
     18 
     19 #include <fcntl.h>
     20 #include <string.h>
     21 #include <set>
     22 #include <vector>
     23 
     24 #include <android-base/logging.h>
     25 
     26 #include "event_attr.h"
     27 #include "record.h"
     28 #include "utils.h"
     29 
     30 using namespace PerfFileFormat;
     31 
     32 namespace PerfFileFormat {
     33 
     34 static const std::map<int, std::string> feature_name_map = {
     35     {FEAT_TRACING_DATA, "tracing_data"},
     36     {FEAT_BUILD_ID, "build_id"},
     37     {FEAT_HOSTNAME, "hostname"},
     38     {FEAT_OSRELEASE, "osrelease"},
     39     {FEAT_VERSION, "version"},
     40     {FEAT_ARCH, "arch"},
     41     {FEAT_NRCPUS, "nrcpus"},
     42     {FEAT_CPUDESC, "cpudesc"},
     43     {FEAT_CPUID, "cpuid"},
     44     {FEAT_TOTAL_MEM, "total_mem"},
     45     {FEAT_CMDLINE, "cmdline"},
     46     {FEAT_EVENT_DESC, "event_desc"},
     47     {FEAT_CPU_TOPOLOGY, "cpu_topology"},
     48     {FEAT_NUMA_TOPOLOGY, "numa_topology"},
     49     {FEAT_BRANCH_STACK, "branch_stack"},
     50     {FEAT_PMU_MAPPINGS, "pmu_mappings"},
     51     {FEAT_GROUP_DESC, "group_desc"},
     52     {FEAT_FILE, "file"},
     53     {FEAT_META_INFO, "meta_info"},
     54 };
     55 
     56 std::string GetFeatureName(int feature_id) {
     57   auto it = feature_name_map.find(feature_id);
     58   return it == feature_name_map.end() ? "" : it->second;
     59 }
     60 
     61 int GetFeatureId(const std::string& feature_name) {
     62   for (auto& pair : feature_name_map) {
     63     if (pair.second == feature_name) {
     64       return pair.first;
     65     }
     66   }
     67   return -1;
     68 }
     69 
     70 } // namespace PerfFileFormat
     71 
     72 std::unique_ptr<RecordFileReader> RecordFileReader::CreateInstance(const std::string& filename) {
     73   std::string mode = std::string("rb") + CLOSE_ON_EXEC_MODE;
     74   FILE* fp = fopen(filename.c_str(), mode.c_str());
     75   if (fp == nullptr) {
     76     PLOG(ERROR) << "failed to open record file '" << filename << "'";
     77     return nullptr;
     78   }
     79   auto reader = std::unique_ptr<RecordFileReader>(new RecordFileReader(filename, fp));
     80   if (!reader->ReadHeader() || !reader->ReadAttrSection() ||
     81       !reader->ReadFeatureSectionDescriptors()) {
     82     return nullptr;
     83   }
     84   return reader;
     85 }
     86 
     87 RecordFileReader::RecordFileReader(const std::string& filename, FILE* fp)
     88     : filename_(filename), record_fp_(fp), event_id_pos_in_sample_records_(0),
     89       event_id_reverse_pos_in_non_sample_records_(0), read_record_size_(0) {
     90 }
     91 
     92 RecordFileReader::~RecordFileReader() {
     93   if (record_fp_ != nullptr) {
     94     Close();
     95   }
     96 }
     97 
     98 bool RecordFileReader::Close() {
     99   bool result = true;
    100   if (fclose(record_fp_) != 0) {
    101     PLOG(ERROR) << "failed to close record file '" << filename_ << "'";
    102     result = false;
    103   }
    104   record_fp_ = nullptr;
    105   return result;
    106 }
    107 
    108 bool RecordFileReader::ReadHeader() {
    109   if (!Read(&header_, sizeof(header_))) {
    110     return false;
    111   }
    112   if (memcmp(header_.magic, PERF_MAGIC, sizeof(header_.magic)) != 0) {
    113     LOG(ERROR) << filename_ << " is not a valid profiling record file.";
    114     return false;
    115   }
    116   return true;
    117 }
    118 
    119 bool RecordFileReader::ReadAttrSection() {
    120   size_t attr_count = header_.attrs.size / header_.attr_size;
    121   if (header_.attr_size != sizeof(FileAttr)) {
    122     LOG(DEBUG) << "attr size (" << header_.attr_size << ") in " << filename_
    123                  << " doesn't match expected size (" << sizeof(FileAttr) << ")";
    124   }
    125   if (attr_count == 0) {
    126     LOG(ERROR) << "no attr in file " << filename_;
    127     return false;
    128   }
    129   if (fseek(record_fp_, header_.attrs.offset, SEEK_SET) != 0) {
    130     PLOG(ERROR) << "fseek() failed";
    131     return false;
    132   }
    133   for (size_t i = 0; i < attr_count; ++i) {
    134     std::vector<char> buf(header_.attr_size);
    135     if (!Read(buf.data(), buf.size())) {
    136       return false;
    137     }
    138     // The size of perf_event_attr is changing between different linux kernel versions.
    139     // Make sure we copy correct data to memory.
    140     FileAttr attr;
    141     memset(&attr, 0, sizeof(attr));
    142     size_t section_desc_size = sizeof(attr.ids);
    143     size_t perf_event_attr_size = header_.attr_size - section_desc_size;
    144     memcpy(&attr.attr, &buf[0], std::min(sizeof(attr.attr), perf_event_attr_size));
    145     memcpy(&attr.ids, &buf[perf_event_attr_size], section_desc_size);
    146     file_attrs_.push_back(attr);
    147   }
    148   if (file_attrs_.size() > 1) {
    149     std::vector<perf_event_attr> attrs;
    150     for (const auto& file_attr : file_attrs_) {
    151       attrs.push_back(file_attr.attr);
    152     }
    153     if (!GetCommonEventIdPositionsForAttrs(attrs, &event_id_pos_in_sample_records_,
    154                                                &event_id_reverse_pos_in_non_sample_records_)) {
    155       return false;
    156     }
    157   }
    158   for (size_t i = 0; i < file_attrs_.size(); ++i) {
    159     std::vector<uint64_t> ids;
    160     if (!ReadIdsForAttr(file_attrs_[i], &ids)) {
    161       return false;
    162     }
    163     event_ids_for_file_attrs_.push_back(ids);
    164     for (auto id : ids) {
    165       event_id_to_attr_map_[id] = i;
    166     }
    167   }
    168   return true;
    169 }
    170 
    171 bool RecordFileReader::ReadFeatureSectionDescriptors() {
    172   std::vector<int> features;
    173   for (size_t i = 0; i < sizeof(header_.features); ++i) {
    174     for (size_t j = 0; j < 8; ++j) {
    175       if (header_.features[i] & (1 << j)) {
    176         features.push_back(i * 8 + j);
    177       }
    178     }
    179   }
    180   uint64_t feature_section_offset = header_.data.offset + header_.data.size;
    181   if (fseek(record_fp_, feature_section_offset, SEEK_SET) != 0) {
    182     PLOG(ERROR) << "fseek() failed";
    183     return false;
    184   }
    185   for (const auto& id : features) {
    186     SectionDesc desc;
    187     if (!Read(&desc, sizeof(desc))) {
    188       return false;
    189     }
    190     feature_section_descriptors_.emplace(id, desc);
    191   }
    192   return true;
    193 }
    194 
    195 bool RecordFileReader::ReadIdsForAttr(const FileAttr& attr, std::vector<uint64_t>* ids) {
    196   size_t id_count = attr.ids.size / sizeof(uint64_t);
    197   if (fseek(record_fp_, attr.ids.offset, SEEK_SET) != 0) {
    198     PLOG(ERROR) << "fseek() failed";
    199     return false;
    200   }
    201   ids->resize(id_count);
    202   if (!Read(ids->data(), attr.ids.size)) {
    203     return false;
    204   }
    205   return true;
    206 }
    207 
    208 bool RecordFileReader::ReadDataSection(
    209     const std::function<bool(std::unique_ptr<Record>)>& callback, bool sorted) {
    210   std::unique_ptr<Record> record;
    211   while (ReadRecord(record, sorted)) {
    212     if (record == nullptr) {
    213       return true;
    214     }
    215     if (!callback(std::move(record))) {
    216       return false;
    217     }
    218   }
    219   return false;
    220 }
    221 
    222 bool RecordFileReader::ReadRecord(std::unique_ptr<Record>& record,
    223                                   bool sorted) {
    224   if (read_record_size_ == 0) {
    225     if (fseek(record_fp_, header_.data.offset, SEEK_SET) != 0) {
    226       PLOG(ERROR) << "fseek() failed";
    227       return false;
    228     }
    229     bool has_timestamp = true;
    230     for (const auto& attr : file_attrs_) {
    231       if (!IsTimestampSupported(attr.attr)) {
    232         has_timestamp = false;
    233         break;
    234       }
    235     }
    236     record_cache_.reset(new RecordCache(has_timestamp));
    237   }
    238   record = nullptr;
    239   while (read_record_size_ < header_.data.size && record == nullptr) {
    240     record = ReadRecord(&read_record_size_);
    241     if (record == nullptr) {
    242       return false;
    243     }
    244     if (record->type() == SIMPLE_PERF_RECORD_EVENT_ID) {
    245       ProcessEventIdRecord(*static_cast<EventIdRecord*>(record.get()));
    246     } else if (record->type() == PERF_RECORD_SAMPLE) {
    247       SampleRecord* r = static_cast<SampleRecord*>(record.get());
    248       // Although we have removed ip == 0 callchains when recording dwarf based callgraph,
    249       // stack frame based callgraph can also generate ip == 0 callchains. Remove them here
    250       // to avoid caller's effort.
    251       if (r->sample_type & PERF_SAMPLE_CALLCHAIN) {
    252         size_t i;
    253         for (i = 0; i < r->callchain_data.ip_nr; ++i) {
    254           if (r->callchain_data.ips[i] == 0) {
    255             break;
    256           }
    257         }
    258         r->callchain_data.ip_nr = i;
    259       }
    260     }
    261     if (sorted) {
    262       record_cache_->Push(std::move(record));
    263       record = record_cache_->Pop();
    264     }
    265   }
    266   if (record == nullptr) {
    267     record = record_cache_->ForcedPop();
    268   }
    269   return true;
    270 }
    271 
    272 std::unique_ptr<Record> RecordFileReader::ReadRecord(uint64_t* nbytes_read) {
    273   char header_buf[Record::header_size()];
    274   if (!Read(header_buf, Record::header_size())) {
    275     return nullptr;
    276   }
    277   RecordHeader header(header_buf);
    278   std::unique_ptr<char[]> p;
    279   if (header.type == SIMPLE_PERF_RECORD_SPLIT) {
    280     // Read until meeting a RECORD_SPLIT_END record.
    281     std::vector<char> buf;
    282     size_t cur_size = 0;
    283     char header_buf[Record::header_size()];
    284     while (header.type == SIMPLE_PERF_RECORD_SPLIT) {
    285       size_t bytes_to_read = header.size - Record::header_size();
    286       buf.resize(cur_size + bytes_to_read);
    287       if (!Read(&buf[cur_size], bytes_to_read)) {
    288         return nullptr;
    289       }
    290       cur_size += bytes_to_read;
    291       *nbytes_read += header.size;
    292       if (!Read(header_buf, Record::header_size())) {
    293         return nullptr;
    294       }
    295       header = RecordHeader(header_buf);
    296     }
    297     if (header.type != SIMPLE_PERF_RECORD_SPLIT_END) {
    298       LOG(ERROR) << "SPLIT records are not followed by a SPLIT_END record.";
    299       return nullptr;
    300     }
    301     *nbytes_read += header.size;
    302     header = RecordHeader(buf.data());
    303     p.reset(new char[header.size]);
    304     memcpy(p.get(), buf.data(), buf.size());
    305   } else {
    306     p.reset(new char[header.size]);
    307     memcpy(p.get(), header_buf, Record::header_size());
    308     if (header.size > Record::header_size()) {
    309       if (!Read(p.get() + Record::header_size(), header.size - Record::header_size())) {
    310         return nullptr;
    311       }
    312     }
    313     *nbytes_read += header.size;
    314   }
    315 
    316   const perf_event_attr* attr = &file_attrs_[0].attr;
    317   if (file_attrs_.size() > 1 && header.type < PERF_RECORD_USER_DEFINED_TYPE_START) {
    318     bool has_event_id = false;
    319     uint64_t event_id;
    320     if (header.type == PERF_RECORD_SAMPLE) {
    321       if (header.size > event_id_pos_in_sample_records_ + sizeof(uint64_t)) {
    322         has_event_id = true;
    323         event_id = *reinterpret_cast<uint64_t*>(p.get() + event_id_pos_in_sample_records_);
    324       }
    325     } else {
    326       if (header.size > event_id_reverse_pos_in_non_sample_records_) {
    327         has_event_id = true;
    328         event_id = *reinterpret_cast<uint64_t*>(p.get() + header.size - event_id_reverse_pos_in_non_sample_records_);
    329       }
    330     }
    331     if (has_event_id) {
    332       auto it = event_id_to_attr_map_.find(event_id);
    333       if (it != event_id_to_attr_map_.end()) {
    334         attr = &file_attrs_[it->second].attr;
    335       }
    336     }
    337   }
    338   return ReadRecordFromOwnedBuffer(*attr, header.type, p.release());
    339 }
    340 
    341 bool RecordFileReader::Read(void* buf, size_t len) {
    342   if (len != 0 && fread(buf, len, 1, record_fp_) != 1) {
    343     PLOG(FATAL) << "failed to read file " << filename_;
    344     return false;
    345   }
    346   return true;
    347 }
    348 
    349 void RecordFileReader::ProcessEventIdRecord(const EventIdRecord& r) {
    350   for (size_t i = 0; i < r.count; ++i) {
    351     event_ids_for_file_attrs_[r.data[i].attr_id].push_back(r.data[i].event_id);
    352     event_id_to_attr_map_[r.data[i].event_id] = r.data[i].attr_id;
    353   }
    354 }
    355 
    356 size_t RecordFileReader::GetAttrIndexOfRecord(const Record* record) {
    357   auto it = event_id_to_attr_map_.find(record->Id());
    358   if (it != event_id_to_attr_map_.end()) {
    359     return it->second;
    360   }
    361   return 0;
    362 }
    363 
    364 bool RecordFileReader::ReadFeatureSection(int feature, std::vector<char>* data) {
    365   const std::map<int, SectionDesc>& section_map = FeatureSectionDescriptors();
    366   auto it = section_map.find(feature);
    367   if (it == section_map.end()) {
    368     return false;
    369   }
    370   SectionDesc section = it->second;
    371   data->resize(section.size);
    372   if (section.size == 0) {
    373     return true;
    374   }
    375   if (fseek(record_fp_, section.offset, SEEK_SET) != 0) {
    376     PLOG(ERROR) << "fseek() failed";
    377     return false;
    378   }
    379   if (!Read(data->data(), data->size())) {
    380     return false;
    381   }
    382   return true;
    383 }
    384 
    385 std::vector<std::string> RecordFileReader::ReadCmdlineFeature() {
    386   std::vector<char> buf;
    387   if (!ReadFeatureSection(FEAT_CMDLINE, &buf)) {
    388     return std::vector<std::string>();
    389   }
    390   const char* p = buf.data();
    391   const char* end = buf.data() + buf.size();
    392   std::vector<std::string> cmdline;
    393   uint32_t arg_count;
    394   MoveFromBinaryFormat(arg_count, p);
    395   CHECK_LE(p, end);
    396   for (size_t i = 0; i < arg_count; ++i) {
    397     uint32_t len;
    398     MoveFromBinaryFormat(len, p);
    399     CHECK_LE(p + len, end);
    400     cmdline.push_back(p);
    401     p += len;
    402   }
    403   return cmdline;
    404 }
    405 
    406 std::vector<BuildIdRecord> RecordFileReader::ReadBuildIdFeature() {
    407   std::vector<char> buf;
    408   if (!ReadFeatureSection(FEAT_BUILD_ID, &buf)) {
    409     return std::vector<BuildIdRecord>();
    410   }
    411   const char* p = buf.data();
    412   const char* end = buf.data() + buf.size();
    413   std::vector<BuildIdRecord> result;
    414   while (p < end) {
    415     auto header = reinterpret_cast<const perf_event_header*>(p);
    416     CHECK_LE(p + header->size, end);
    417     char* binary = new char[header->size];
    418     memcpy(binary, p, header->size);
    419     p += header->size;
    420     BuildIdRecord record(binary);
    421     record.OwnBinary();
    422     // Set type explicitly as the perf.data produced by perf doesn't set it.
    423     record.SetTypeAndMisc(PERF_RECORD_BUILD_ID, record.misc());
    424     result.push_back(std::move(record));
    425   }
    426   return result;
    427 }
    428 
    429 std::string RecordFileReader::ReadFeatureString(int feature) {
    430   std::vector<char> buf;
    431   if (!ReadFeatureSection(feature, &buf)) {
    432     return std::string();
    433   }
    434   const char* p = buf.data();
    435   const char* end = buf.data() + buf.size();
    436   uint32_t len;
    437   MoveFromBinaryFormat(len, p);
    438   CHECK_LE(p + len, end);
    439   return p;
    440 }
    441 
    442 bool RecordFileReader::ReadFileFeature(size_t& read_pos,
    443                                        std::string* file_path,
    444                                        uint32_t* file_type,
    445                                        uint64_t* min_vaddr,
    446                                        std::vector<Symbol>* symbols) {
    447   auto it = feature_section_descriptors_.find(FEAT_FILE);
    448   if (it == feature_section_descriptors_.end()) {
    449     return false;
    450   }
    451   if (read_pos >= it->second.size) {
    452     return false;
    453   }
    454   if (read_pos == 0) {
    455     if (fseek(record_fp_, it->second.offset, SEEK_SET) != 0) {
    456       PLOG(ERROR) << "fseek() failed";
    457       return false;
    458     }
    459   }
    460   uint32_t size;
    461   if (!Read(&size, 4)) {
    462     return false;
    463   }
    464   std::vector<char> buf(size);
    465   if (!Read(buf.data(), size)) {
    466     return false;
    467   }
    468   read_pos += 4 + size;
    469   const char* p = buf.data();
    470   *file_path = p;
    471   p += file_path->size() + 1;
    472   MoveFromBinaryFormat(*file_type, p);
    473   MoveFromBinaryFormat(*min_vaddr, p);
    474   uint32_t symbol_count;
    475   MoveFromBinaryFormat(symbol_count, p);
    476   symbols->clear();
    477   symbols->reserve(symbol_count);
    478   for (uint32_t i = 0; i < symbol_count; ++i) {
    479     uint64_t start_vaddr;
    480     uint32_t len;
    481     MoveFromBinaryFormat(start_vaddr, p);
    482     MoveFromBinaryFormat(len, p);
    483     std::string name = p;
    484     p += name.size() + 1;
    485     symbols->emplace_back(name, start_vaddr, len);
    486   }
    487   CHECK_EQ(size, static_cast<size_t>(p - buf.data()));
    488   return true;
    489 }
    490 
    491 bool RecordFileReader::ReadMetaInfoFeature(std::unordered_map<std::string, std::string>* info_map) {
    492   std::vector<char> buf;
    493   if (!ReadFeatureSection(FEAT_META_INFO, &buf)) {
    494     return false;
    495   }
    496   const char* p = buf.data();
    497   const char* end = buf.data() + buf.size();
    498   while (p < end) {
    499     const char* key = p;
    500     const char* value = key + strlen(key) + 1;
    501     CHECK(value < end);
    502     (*info_map)[p] = value;
    503     p = value + strlen(value) + 1;
    504   }
    505   return true;
    506 }
    507 
    508 void RecordFileReader::LoadBuildIdAndFileFeatures(ThreadTree& thread_tree) {
    509   std::vector<BuildIdRecord> records = ReadBuildIdFeature();
    510   std::vector<std::pair<std::string, BuildId>> build_ids;
    511   for (auto& r : records) {
    512     build_ids.push_back(std::make_pair(r.filename, r.build_id));
    513   }
    514   Dso::SetBuildIds(build_ids);
    515 
    516   if (HasFeature(PerfFileFormat::FEAT_FILE)) {
    517     std::string file_path;
    518     uint32_t file_type;
    519     uint64_t min_vaddr;
    520     std::vector<Symbol> symbols;
    521     size_t read_pos = 0;
    522     while (ReadFileFeature(
    523         read_pos, &file_path, &file_type, &min_vaddr, &symbols)) {
    524       thread_tree.AddDsoInfo(file_path, file_type, min_vaddr, &symbols);
    525     }
    526   }
    527 }
    528 
    529 std::vector<std::unique_ptr<Record>> RecordFileReader::DataSection() {
    530   std::vector<std::unique_ptr<Record>> records;
    531   ReadDataSection([&](std::unique_ptr<Record> record) {
    532     records.push_back(std::move(record));
    533     return true;
    534   });
    535   return records;
    536 }
    537