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 <sys/mman.h>
     22 #include <unistd.h>
     23 #include <set>
     24 #include <string>
     25 #include <vector>
     26 
     27 #include <android-base/file.h>
     28 #include <android-base/logging.h>
     29 
     30 #include "perf_event.h"
     31 #include "record.h"
     32 #include "utils.h"
     33 
     34 using namespace PerfFileFormat;
     35 
     36 std::unique_ptr<RecordFileWriter> RecordFileWriter::CreateInstance(const std::string& filename) {
     37   // Remove old perf.data to avoid file ownership problems.
     38   std::string err;
     39   if (!android::base::RemoveFileIfExists(filename, &err)) {
     40     LOG(ERROR) << "failed to remove file " << filename << ": " << err;
     41     return nullptr;
     42   }
     43   FILE* fp = fopen(filename.c_str(), "web+");
     44   if (fp == nullptr) {
     45     PLOG(ERROR) << "failed to open record file '" << filename << "'";
     46     return nullptr;
     47   }
     48 
     49   return std::unique_ptr<RecordFileWriter>(new RecordFileWriter(filename, fp));
     50 }
     51 
     52 RecordFileWriter::RecordFileWriter(const std::string& filename, FILE* fp)
     53     : filename_(filename),
     54       record_fp_(fp),
     55       attr_section_offset_(0),
     56       attr_section_size_(0),
     57       data_section_offset_(0),
     58       data_section_size_(0),
     59       feature_count_(0),
     60       current_feature_index_(0) {
     61 }
     62 
     63 RecordFileWriter::~RecordFileWriter() {
     64   if (record_fp_ != nullptr) {
     65     Close();
     66   }
     67 }
     68 
     69 bool RecordFileWriter::WriteAttrSection(const std::vector<AttrWithId>& attr_ids) {
     70   if (attr_ids.empty()) {
     71     return false;
     72   }
     73 
     74   // Skip file header part.
     75   if (fseek(record_fp_, sizeof(FileHeader), SEEK_SET) == -1) {
     76     return false;
     77   }
     78 
     79   // Write id section.
     80   long id_section_offset = ftell(record_fp_);
     81   if (id_section_offset == -1) {
     82     return false;
     83   }
     84   for (auto& attr_id : attr_ids) {
     85     if (!Write(attr_id.ids.data(), attr_id.ids.size() * sizeof(uint64_t))) {
     86       return false;
     87     }
     88   }
     89 
     90   // Write attr section.
     91   long attr_section_offset = ftell(record_fp_);
     92   if (attr_section_offset == -1) {
     93     return false;
     94   }
     95   for (auto& attr_id : attr_ids) {
     96     FileAttr file_attr;
     97     file_attr.attr = *attr_id.attr;
     98     file_attr.ids.offset = id_section_offset;
     99     file_attr.ids.size = attr_id.ids.size() * sizeof(uint64_t);
    100     id_section_offset += file_attr.ids.size;
    101     if (!Write(&file_attr, sizeof(file_attr))) {
    102       return false;
    103     }
    104   }
    105 
    106   long data_section_offset = ftell(record_fp_);
    107   if (data_section_offset == -1) {
    108     return false;
    109   }
    110 
    111   attr_section_offset_ = attr_section_offset;
    112   attr_section_size_ = data_section_offset - attr_section_offset;
    113   data_section_offset_ = data_section_offset;
    114 
    115   // Save event_attr for use when reading records.
    116   event_attr_ = *attr_ids[0].attr;
    117   return true;
    118 }
    119 
    120 bool RecordFileWriter::WriteData(const void* buf, size_t len) {
    121   if (!Write(buf, len)) {
    122     return false;
    123   }
    124   data_section_size_ += len;
    125   return true;
    126 }
    127 
    128 bool RecordFileWriter::Write(const void* buf, size_t len) {
    129   if (fwrite(buf, len, 1, record_fp_) != 1) {
    130     PLOG(ERROR) << "failed to write to record file '" << filename_ << "'";
    131     return false;
    132   }
    133   return true;
    134 }
    135 
    136 bool RecordFileWriter::SeekFileEnd(uint64_t* file_end) {
    137   if (fseek(record_fp_, 0, SEEK_END) == -1) {
    138     PLOG(ERROR) << "fseek() failed";
    139     return false;
    140   }
    141   long offset = ftell(record_fp_);
    142   if (offset == -1) {
    143     PLOG(ERROR) << "ftell() failed";
    144     return false;
    145   }
    146   *file_end = static_cast<uint64_t>(offset);
    147   return true;
    148 }
    149 
    150 bool RecordFileWriter::WriteFeatureHeader(size_t feature_count) {
    151   feature_count_ = feature_count;
    152   current_feature_index_ = 0;
    153   uint64_t feature_header_size = feature_count * sizeof(SectionDesc);
    154 
    155   // Reserve enough space in the record file for the feature header.
    156   std::vector<unsigned char> zero_data(feature_header_size);
    157   if (fseek(record_fp_, data_section_offset_ + data_section_size_, SEEK_SET) == -1) {
    158     PLOG(ERROR) << "fseek() failed";
    159     return false;
    160   }
    161   return Write(zero_data.data(), zero_data.size());
    162 }
    163 
    164 bool RecordFileWriter::WriteBuildIdFeature(const std::vector<BuildIdRecord>& build_id_records) {
    165   uint64_t start_offset;
    166   if (!WriteFeatureBegin(&start_offset)) {
    167     return false;
    168   }
    169   for (auto& record : build_id_records) {
    170     std::vector<char> data = record.BinaryFormat();
    171     if (!Write(data.data(), data.size())) {
    172       return false;
    173     }
    174   }
    175   return WriteFeatureEnd(FEAT_BUILD_ID, start_offset);
    176 }
    177 
    178 bool RecordFileWriter::WriteFeatureString(int feature, const std::string& s) {
    179   uint64_t start_offset;
    180   if (!WriteFeatureBegin(&start_offset)) {
    181     return false;
    182   }
    183   uint32_t len = static_cast<uint32_t>(ALIGN(s.size() + 1, 64));
    184   if (!Write(&len, sizeof(len))) {
    185     return false;
    186   }
    187   std::vector<char> v(len, '\0');
    188   std::copy(s.begin(), s.end(), v.begin());
    189   if (!Write(v.data(), v.size())) {
    190     return false;
    191   }
    192   return WriteFeatureEnd(feature, start_offset);
    193 }
    194 
    195 bool RecordFileWriter::WriteCmdlineFeature(const std::vector<std::string>& cmdline) {
    196   uint64_t start_offset;
    197   if (!WriteFeatureBegin(&start_offset)) {
    198     return false;
    199   }
    200   uint32_t arg_count = cmdline.size();
    201   if (!Write(&arg_count, sizeof(arg_count))) {
    202     return false;
    203   }
    204   for (auto& arg : cmdline) {
    205     uint32_t len = static_cast<uint32_t>(ALIGN(arg.size() + 1, 64));
    206     if (!Write(&len, sizeof(len))) {
    207       return false;
    208     }
    209     std::vector<char> array(len, '\0');
    210     std::copy(arg.begin(), arg.end(), array.begin());
    211     if (!Write(array.data(), array.size())) {
    212       return false;
    213     }
    214   }
    215   return WriteFeatureEnd(FEAT_CMDLINE, start_offset);
    216 }
    217 
    218 bool RecordFileWriter::WriteBranchStackFeature() {
    219   uint64_t start_offset;
    220   if (!WriteFeatureBegin(&start_offset)) {
    221     return false;
    222   }
    223   return WriteFeatureEnd(FEAT_BRANCH_STACK, start_offset);
    224 }
    225 
    226 bool RecordFileWriter::WriteFeatureBegin(uint64_t* start_offset) {
    227   CHECK_LT(current_feature_index_, feature_count_);
    228   if (!SeekFileEnd(start_offset)) {
    229     return false;
    230   }
    231   return true;
    232 }
    233 
    234 bool RecordFileWriter::WriteFeatureEnd(int feature, uint64_t start_offset) {
    235   uint64_t end_offset;
    236   if (!SeekFileEnd(&end_offset)) {
    237     return false;
    238   }
    239   SectionDesc desc;
    240   desc.offset = start_offset;
    241   desc.size = end_offset - start_offset;
    242   uint64_t feature_offset = data_section_offset_ + data_section_size_;
    243   if (fseek(record_fp_, feature_offset + current_feature_index_ * sizeof(SectionDesc), SEEK_SET) ==
    244       -1) {
    245     PLOG(ERROR) << "fseek() failed";
    246     return false;
    247   }
    248   if (!Write(&desc, sizeof(SectionDesc))) {
    249     return false;
    250   }
    251   ++current_feature_index_;
    252   features_.push_back(feature);
    253   return true;
    254 }
    255 
    256 bool RecordFileWriter::WriteFileHeader() {
    257   FileHeader header;
    258   memset(&header, 0, sizeof(header));
    259   memcpy(header.magic, PERF_MAGIC, sizeof(header.magic));
    260   header.header_size = sizeof(header);
    261   header.attr_size = sizeof(FileAttr);
    262   header.attrs.offset = attr_section_offset_;
    263   header.attrs.size = attr_section_size_;
    264   header.data.offset = data_section_offset_;
    265   header.data.size = data_section_size_;
    266   for (auto& feature : features_) {
    267     int i = feature / 8;
    268     int j = feature % 8;
    269     header.features[i] |= (1 << j);
    270   }
    271 
    272   if (fseek(record_fp_, 0, SEEK_SET) == -1) {
    273     return false;
    274   }
    275   if (!Write(&header, sizeof(header))) {
    276     return false;
    277   }
    278   return true;
    279 }
    280 
    281 bool RecordFileWriter::Close() {
    282   CHECK(record_fp_ != nullptr);
    283   bool result = true;
    284 
    285   // Write file header. We gather enough information to write file header only after
    286   // writing data section and feature section.
    287   if (!WriteFileHeader()) {
    288     result = false;
    289   }
    290 
    291   if (fclose(record_fp_) != 0) {
    292     PLOG(ERROR) << "failed to close record file '" << filename_ << "'";
    293     result = false;
    294   }
    295   record_fp_ = nullptr;
    296   return result;
    297 }
    298