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