Home | History | Annotate | Download | only in quipper
      1 // Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #define LOG_TAG "perf_reader"
      6 
      7 #include "perf_utils.h"
      8 
      9 #include <sys/stat.h>
     10 
     11 #include <cctype>
     12 #include <cstddef>
     13 #include <cstdlib>
     14 #include <cstring>
     15 #include <fstream>  // NOLINT(readability/streams)
     16 #include <iomanip>
     17 #include <sstream>
     18 
     19 #include "base/logging.h"
     20 #include "base/macros.h"
     21 
     22 namespace {
     23 
     24 // Number of hex digits in a byte.
     25 const int kNumHexDigitsInByte = 2;
     26 
     27 }  // namespace
     28 
     29 namespace quipper {
     30 
     31 event_t* CallocMemoryForEvent(size_t size) {
     32   event_t* event = reinterpret_cast<event_t*>(calloc(1, size));
     33   CHECK(event);
     34   return event;
     35 }
     36 
     37 build_id_event* CallocMemoryForBuildID(size_t size) {
     38   build_id_event* event = reinterpret_cast<build_id_event*>(calloc(1, size));
     39   CHECK(event);
     40   return event;
     41 }
     42 
     43 string HexToString(const u8* array, size_t length) {
     44   // Convert the bytes to hex digits one at a time.
     45   // There will be kNumHexDigitsInByte hex digits, and 1 char for NUL.
     46   char buffer[kNumHexDigitsInByte + 1];
     47   string result = "";
     48   for (size_t i = 0; i < length; ++i) {
     49     snprintf(buffer, sizeof(buffer), "%02x", array[i]);
     50     result += buffer;
     51   }
     52   return result;
     53 }
     54 
     55 bool StringToHex(const string& str, u8* array, size_t length) {
     56   const int kHexRadix = 16;
     57   char* err;
     58   // Loop through kNumHexDigitsInByte characters at a time (to get one byte)
     59   // Stop when there are no more characters, or the array has been filled.
     60   for (size_t i = 0;
     61        (i + 1) * kNumHexDigitsInByte <= str.size() && i < length;
     62        ++i) {
     63     string one_byte = str.substr(i * kNumHexDigitsInByte, kNumHexDigitsInByte);
     64     array[i] = strtol(one_byte.c_str(), &err, kHexRadix);
     65     if (*err)
     66       return false;
     67   }
     68   return true;
     69 }
     70 
     71 uint64_t AlignSize(uint64_t size, uint32_t align_size) {
     72   return ((size + align_size - 1) / align_size) * align_size;
     73 }
     74 
     75 // In perf data, strings are packed into the smallest number of 8-byte blocks
     76 // possible, including the null terminator.
     77 // e.g.
     78 //    "0123"                ->  5 bytes -> packed into  8 bytes
     79 //    "0123456"             ->  8 bytes -> packed into  8 bytes
     80 //    "01234567"            ->  9 bytes -> packed into 16 bytes
     81 //    "0123456789abcd"      -> 15 bytes -> packed into 16 bytes
     82 //    "0123456789abcde"     -> 16 bytes -> packed into 16 bytes
     83 //    "0123456789abcdef"    -> 17 bytes -> packed into 24 bytes
     84 //
     85 // Returns the size of the 8-byte-aligned memory for storing |string|.
     86 size_t GetUint64AlignedStringLength(const string& str) {
     87   return AlignSize(str.size() + 1, sizeof(uint64_t));
     88 }
     89 
     90 uint64_t GetSampleFieldsForEventType(uint32_t event_type,
     91                                      uint64_t sample_type) {
     92   uint64_t mask = kuint64max;
     93   switch (event_type) {
     94   case PERF_RECORD_MMAP:
     95   case PERF_RECORD_LOST:
     96   case PERF_RECORD_COMM:
     97   case PERF_RECORD_EXIT:
     98   case PERF_RECORD_THROTTLE:
     99   case PERF_RECORD_UNTHROTTLE:
    100   case PERF_RECORD_FORK:
    101   case PERF_RECORD_READ:
    102   case PERF_RECORD_MMAP2:
    103     // See perf_event.h "struct" sample_id and sample_id_all.
    104     mask = PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_ID |
    105            PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER;
    106     break;
    107   case PERF_RECORD_SAMPLE:
    108     break;
    109   default:
    110     LOG(FATAL) << "Unknown event type " << event_type;
    111   }
    112   return sample_type & mask;
    113 }
    114 
    115 uint64_t GetPerfSampleDataOffset(const event_t& event) {
    116   uint64_t offset = kuint64max;
    117   switch (event.header.type) {
    118   case PERF_RECORD_SAMPLE:
    119     offset = offsetof(event_t, sample.array);
    120     break;
    121   case PERF_RECORD_MMAP:
    122     offset = sizeof(event.mmap) - sizeof(event.mmap.filename) +
    123              GetUint64AlignedStringLength(event.mmap.filename);
    124     break;
    125   case PERF_RECORD_FORK:
    126   case PERF_RECORD_EXIT:
    127     offset = sizeof(event.fork);
    128     break;
    129   case PERF_RECORD_COMM:
    130     offset = sizeof(event.comm) - sizeof(event.comm.comm) +
    131              GetUint64AlignedStringLength(event.comm.comm);
    132     break;
    133   case PERF_RECORD_LOST:
    134     offset = sizeof(event.lost);
    135     break;
    136   case PERF_RECORD_READ:
    137     offset = sizeof(event.read);
    138     break;
    139   case PERF_RECORD_MMAP2:
    140     offset = sizeof(event.mmap2) - sizeof(event.mmap2.filename) +
    141              GetUint64AlignedStringLength(event.mmap2.filename);
    142     break;
    143   default:
    144     LOG(FATAL) << "Unknown/unsupported event type " << event.header.type;
    145     break;
    146   }
    147   // Make sure the offset was valid
    148   CHECK_NE(offset, kuint64max);
    149   CHECK_EQ(offset % sizeof(uint64_t), 0U);
    150   return offset;
    151 }
    152 
    153 bool ReadFileToData(const string& filename, std::vector<char>* data) {
    154   std::ifstream in(filename.c_str(), std::ios::binary);
    155   if (!in.good()) {
    156     LOG(ERROR) << "Failed to open file " << filename;
    157     return false;
    158   }
    159   in.seekg(0, in.end);
    160   size_t length = in.tellg();
    161   in.seekg(0, in.beg);
    162   data->resize(length);
    163 
    164   in.read(&(*data)[0], length);
    165 
    166   if (!in.good()) {
    167     LOG(ERROR) << "Error reading from file " << filename;
    168     return false;
    169   }
    170   return true;
    171 }
    172 
    173 bool WriteDataToFile(const std::vector<char>& data, const string& filename) {
    174   std::ofstream out(filename.c_str(), std::ios::binary);
    175   out.seekp(0, std::ios::beg);
    176   out.write(&data[0], data.size());
    177   return out.good();
    178 }
    179 
    180 }  // namespace quipper
    181