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.h"
     18 
     19 #include <inttypes.h>
     20 #include <algorithm>
     21 #include <unordered_map>
     22 
     23 #include <android-base/logging.h>
     24 #include <android-base/stringprintf.h>
     25 
     26 #include "environment.h"
     27 #include "perf_regs.h"
     28 #include "utils.h"
     29 
     30 static std::string RecordTypeToString(int record_type) {
     31   static std::unordered_map<int, std::string> record_type_names = {
     32       {PERF_RECORD_MMAP, "mmap"},         {PERF_RECORD_LOST, "lost"},
     33       {PERF_RECORD_COMM, "comm"},         {PERF_RECORD_EXIT, "exit"},
     34       {PERF_RECORD_THROTTLE, "throttle"}, {PERF_RECORD_UNTHROTTLE, "unthrottle"},
     35       {PERF_RECORD_FORK, "fork"},         {PERF_RECORD_READ, "read"},
     36       {PERF_RECORD_SAMPLE, "sample"},     {PERF_RECORD_BUILD_ID, "build_id"},
     37       {PERF_RECORD_MMAP2, "mmap2"},
     38   };
     39 
     40   auto it = record_type_names.find(record_type);
     41   if (it != record_type_names.end()) {
     42     return it->second;
     43   }
     44   return android::base::StringPrintf("unknown(%d)", record_type);
     45 }
     46 
     47 template <class T>
     48 void MoveFromBinaryFormat(T* data_p, size_t n, const char*& p) {
     49   size_t size = n * sizeof(T);
     50   memcpy(data_p, p, size);
     51   p += size;
     52 }
     53 
     54 template <class T>
     55 void MoveToBinaryFormat(const T& data, char*& p) {
     56   *reinterpret_cast<T*>(p) = data;
     57   p += sizeof(T);
     58 }
     59 
     60 template <class T>
     61 void MoveToBinaryFormat(const T* data_p, size_t n, char*& p) {
     62   size_t size = n * sizeof(T);
     63   memcpy(p, data_p, size);
     64   p += size;
     65 }
     66 
     67 SampleId::SampleId() {
     68   memset(this, 0, sizeof(SampleId));
     69 }
     70 
     71 // Return sample_id size in binary format.
     72 size_t SampleId::CreateContent(const perf_event_attr& attr) {
     73   sample_id_all = attr.sample_id_all;
     74   sample_type = attr.sample_type;
     75   // Other data are not necessary. TODO: Set missing SampleId data.
     76   return Size();
     77 }
     78 
     79 void SampleId::ReadFromBinaryFormat(const perf_event_attr& attr, const char* p, const char* end) {
     80   sample_id_all = attr.sample_id_all;
     81   sample_type = attr.sample_type;
     82   if (sample_id_all) {
     83     if (sample_type & PERF_SAMPLE_TID) {
     84       MoveFromBinaryFormat(tid_data, p);
     85     }
     86     if (sample_type & PERF_SAMPLE_TIME) {
     87       MoveFromBinaryFormat(time_data, p);
     88     }
     89     if (sample_type & PERF_SAMPLE_ID) {
     90       MoveFromBinaryFormat(id_data, p);
     91     }
     92     if (sample_type & PERF_SAMPLE_STREAM_ID) {
     93       MoveFromBinaryFormat(stream_id_data, p);
     94     }
     95     if (sample_type & PERF_SAMPLE_CPU) {
     96       MoveFromBinaryFormat(cpu_data, p);
     97     }
     98     // TODO: Add parsing of PERF_SAMPLE_IDENTIFIER.
     99   }
    100   CHECK_LE(p, end);
    101   if (p < end) {
    102     LOG(DEBUG) << "Record SampleId part has " << end - p << " bytes left\n";
    103   }
    104 }
    105 
    106 void SampleId::WriteToBinaryFormat(char*& p) const {
    107   if (sample_id_all) {
    108     if (sample_type & PERF_SAMPLE_TID) {
    109       MoveToBinaryFormat(tid_data, p);
    110     }
    111     if (sample_type & PERF_SAMPLE_TIME) {
    112       MoveToBinaryFormat(time_data, p);
    113     }
    114     if (sample_type & PERF_SAMPLE_ID) {
    115       MoveToBinaryFormat(id_data, p);
    116     }
    117     if (sample_type & PERF_SAMPLE_STREAM_ID) {
    118       MoveToBinaryFormat(stream_id_data, p);
    119     }
    120     if (sample_type & PERF_SAMPLE_CPU) {
    121       MoveToBinaryFormat(cpu_data, p);
    122     }
    123   }
    124 }
    125 
    126 void SampleId::Dump(size_t indent) const {
    127   if (sample_id_all) {
    128     if (sample_type & PERF_SAMPLE_TID) {
    129       PrintIndented(indent, "sample_id: pid %u, tid %u\n", tid_data.pid, tid_data.tid);
    130     }
    131     if (sample_type & PERF_SAMPLE_TIME) {
    132       PrintIndented(indent, "sample_id: time %" PRId64 "\n", time_data.time);
    133     }
    134     if (sample_type & PERF_SAMPLE_ID) {
    135       PrintIndented(indent, "sample_id: stream_id %" PRId64 "\n", id_data.id);
    136     }
    137     if (sample_type & PERF_SAMPLE_STREAM_ID) {
    138       PrintIndented(indent, "sample_id: stream_id %" PRId64 "\n", stream_id_data.stream_id);
    139     }
    140     if (sample_type & PERF_SAMPLE_CPU) {
    141       PrintIndented(indent, "sample_id: cpu %u, res %u\n", cpu_data.cpu, cpu_data.res);
    142     }
    143   }
    144 }
    145 
    146 size_t SampleId::Size() const {
    147   size_t size = 0;
    148   if (sample_id_all) {
    149     if (sample_type & PERF_SAMPLE_TID) {
    150       size += sizeof(PerfSampleTidType);
    151     }
    152     if (sample_type & PERF_SAMPLE_TIME) {
    153       size += sizeof(PerfSampleTimeType);
    154     }
    155     if (sample_type & PERF_SAMPLE_ID) {
    156       size += sizeof(PerfSampleIdType);
    157     }
    158     if (sample_type & PERF_SAMPLE_STREAM_ID) {
    159       size += sizeof(PerfSampleStreamIdType);
    160     }
    161     if (sample_type & PERF_SAMPLE_CPU) {
    162       size += sizeof(PerfSampleCpuType);
    163     }
    164   }
    165   return size;
    166 }
    167 
    168 Record::Record() {
    169   memset(&header, 0, sizeof(header));
    170 }
    171 
    172 Record::Record(const perf_event_header* pheader) {
    173   header = *pheader;
    174 }
    175 
    176 void Record::Dump(size_t indent) const {
    177   PrintIndented(indent, "record %s: type %u, misc %u, size %u\n",
    178                 RecordTypeToString(header.type).c_str(), header.type, header.misc, header.size);
    179   DumpData(indent + 1);
    180   sample_id.Dump(indent + 1);
    181 }
    182 
    183 uint64_t Record::Timestamp() const {
    184   return sample_id.time_data.time;
    185 }
    186 
    187 MmapRecord::MmapRecord(const perf_event_attr& attr, const perf_event_header* pheader)
    188     : Record(pheader) {
    189   const char* p = reinterpret_cast<const char*>(pheader + 1);
    190   const char* end = reinterpret_cast<const char*>(pheader) + pheader->size;
    191   MoveFromBinaryFormat(data, p);
    192   filename = p;
    193   p += ALIGN(filename.size() + 1, 8);
    194   CHECK_LE(p, end);
    195   sample_id.ReadFromBinaryFormat(attr, p, end);
    196 }
    197 
    198 std::vector<char> MmapRecord::BinaryFormat() const {
    199   std::vector<char> buf(header.size);
    200   char* p = buf.data();
    201   MoveToBinaryFormat(header, p);
    202   MoveToBinaryFormat(data, p);
    203   strcpy(p, filename.c_str());
    204   p += ALIGN(filename.size() + 1, 8);
    205   sample_id.WriteToBinaryFormat(p);
    206   return buf;
    207 }
    208 
    209 void MmapRecord::AdjustSizeBasedOnData() {
    210   header.size = sizeof(header) + sizeof(data) + ALIGN(filename.size() + 1, 8) + sample_id.Size();
    211 }
    212 
    213 void MmapRecord::DumpData(size_t indent) const {
    214   PrintIndented(indent, "pid %u, tid %u, addr 0x%" PRIx64 ", len 0x%" PRIx64 "\n", data.pid,
    215                 data.tid, data.addr, data.len);
    216   PrintIndented(indent, "pgoff 0x%" PRIx64 ", filename %s\n", data.pgoff, filename.c_str());
    217 }
    218 
    219 Mmap2Record::Mmap2Record(const perf_event_attr& attr, const perf_event_header* pheader)
    220     : Record(pheader) {
    221   const char* p = reinterpret_cast<const char*>(pheader + 1);
    222   const char* end = reinterpret_cast<const char*>(pheader) + pheader->size;
    223   MoveFromBinaryFormat(data, p);
    224   filename = p;
    225   p += ALIGN(filename.size() + 1, 8);
    226   CHECK_LE(p, end);
    227   sample_id.ReadFromBinaryFormat(attr, p, end);
    228 }
    229 
    230 std::vector<char> Mmap2Record::BinaryFormat() const {
    231   std::vector<char> buf(header.size);
    232   char* p = buf.data();
    233   MoveToBinaryFormat(header, p);
    234   MoveToBinaryFormat(data, p);
    235   strcpy(p, filename.c_str());
    236   p += ALIGN(filename.size() + 1, 8);
    237   sample_id.WriteToBinaryFormat(p);
    238   return buf;
    239 }
    240 
    241 void Mmap2Record::AdjustSizeBasedOnData() {
    242   header.size = sizeof(header) + sizeof(data) + ALIGN(filename.size() + 1, 8) + sample_id.Size();
    243 }
    244 
    245 void Mmap2Record::DumpData(size_t indent) const {
    246   PrintIndented(indent, "pid %u, tid %u, addr 0x%" PRIx64 ", len 0x%" PRIx64 "\n", data.pid,
    247                 data.tid, data.addr, data.len);
    248   PrintIndented(indent,
    249                 "pgoff 0x" PRIx64 ", maj %u, min %u, ino %" PRId64 ", ino_generation %" PRIu64 "\n",
    250                 data.pgoff, data.maj, data.min, data.ino, data.ino_generation);
    251   PrintIndented(indent, "prot %u, flags %u, filenames %s\n", data.prot, data.flags,
    252                 filename.c_str());
    253 }
    254 
    255 CommRecord::CommRecord(const perf_event_attr& attr, const perf_event_header* pheader)
    256     : Record(pheader) {
    257   const char* p = reinterpret_cast<const char*>(pheader + 1);
    258   const char* end = reinterpret_cast<const char*>(pheader) + pheader->size;
    259   MoveFromBinaryFormat(data, p);
    260   comm = p;
    261   p += ALIGN(strlen(p) + 1, 8);
    262   CHECK_LE(p, end);
    263   sample_id.ReadFromBinaryFormat(attr, p, end);
    264 }
    265 
    266 std::vector<char> CommRecord::BinaryFormat() const {
    267   std::vector<char> buf(header.size);
    268   char* p = buf.data();
    269   MoveToBinaryFormat(header, p);
    270   MoveToBinaryFormat(data, p);
    271   strcpy(p, comm.c_str());
    272   p += ALIGN(comm.size() + 1, 8);
    273   sample_id.WriteToBinaryFormat(p);
    274   return buf;
    275 }
    276 
    277 void CommRecord::DumpData(size_t indent) const {
    278   PrintIndented(indent, "pid %u, tid %u, comm %s\n", data.pid, data.tid, comm.c_str());
    279 }
    280 
    281 ExitOrForkRecord::ExitOrForkRecord(const perf_event_attr& attr, const perf_event_header* pheader)
    282     : Record(pheader) {
    283   const char* p = reinterpret_cast<const char*>(pheader + 1);
    284   const char* end = reinterpret_cast<const char*>(pheader) + pheader->size;
    285   MoveFromBinaryFormat(data, p);
    286   CHECK_LE(p, end);
    287   sample_id.ReadFromBinaryFormat(attr, p, end);
    288 }
    289 
    290 std::vector<char> ExitOrForkRecord::BinaryFormat() const {
    291   std::vector<char> buf(header.size);
    292   char* p = buf.data();
    293   MoveToBinaryFormat(header, p);
    294   MoveToBinaryFormat(data, p);
    295   sample_id.WriteToBinaryFormat(p);
    296   return buf;
    297 }
    298 
    299 void ExitOrForkRecord::DumpData(size_t indent) const {
    300   PrintIndented(indent, "pid %u, ppid %u, tid %u, ptid %u\n", data.pid, data.ppid, data.tid,
    301                 data.ptid);
    302 }
    303 
    304 SampleRecord::SampleRecord(const perf_event_attr& attr, const perf_event_header* pheader)
    305     : Record(pheader) {
    306   const char* p = reinterpret_cast<const char*>(pheader + 1);
    307   const char* end = reinterpret_cast<const char*>(pheader) + pheader->size;
    308   sample_type = attr.sample_type;
    309 
    310   if (sample_type & PERF_SAMPLE_IP) {
    311     MoveFromBinaryFormat(ip_data, p);
    312   }
    313   if (sample_type & PERF_SAMPLE_TID) {
    314     MoveFromBinaryFormat(tid_data, p);
    315   }
    316   if (sample_type & PERF_SAMPLE_TIME) {
    317     MoveFromBinaryFormat(time_data, p);
    318   }
    319   if (sample_type & PERF_SAMPLE_ADDR) {
    320     MoveFromBinaryFormat(addr_data, p);
    321   }
    322   if (sample_type & PERF_SAMPLE_ID) {
    323     MoveFromBinaryFormat(id_data, p);
    324   }
    325   if (sample_type & PERF_SAMPLE_STREAM_ID) {
    326     MoveFromBinaryFormat(stream_id_data, p);
    327   }
    328   if (sample_type & PERF_SAMPLE_CPU) {
    329     MoveFromBinaryFormat(cpu_data, p);
    330   }
    331   if (sample_type & PERF_SAMPLE_PERIOD) {
    332     MoveFromBinaryFormat(period_data, p);
    333   }
    334   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
    335     uint64_t nr;
    336     MoveFromBinaryFormat(nr, p);
    337     callchain_data.ips.resize(nr);
    338     MoveFromBinaryFormat(callchain_data.ips.data(), nr, p);
    339   }
    340   if (sample_type & PERF_SAMPLE_RAW) {
    341     uint32_t size;
    342     MoveFromBinaryFormat(size, p);
    343     raw_data.data.resize(size);
    344     MoveFromBinaryFormat(raw_data.data.data(), size, p);
    345   }
    346   if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
    347     uint64_t nr;
    348     MoveFromBinaryFormat(nr, p);
    349     branch_stack_data.stack.resize(nr);
    350     MoveFromBinaryFormat(branch_stack_data.stack.data(), nr, p);
    351   }
    352   if (sample_type & PERF_SAMPLE_REGS_USER) {
    353     MoveFromBinaryFormat(regs_user_data.abi, p);
    354     if (regs_user_data.abi == 0) {
    355       regs_user_data.reg_mask = 0;
    356     } else {
    357       regs_user_data.reg_mask = attr.sample_regs_user;
    358       size_t bit_nr = 0;
    359       for (size_t i = 0; i < 64; ++i) {
    360         if ((regs_user_data.reg_mask >> i) & 1) {
    361           bit_nr++;
    362         }
    363       }
    364       regs_user_data.regs.resize(bit_nr);
    365       MoveFromBinaryFormat(regs_user_data.regs.data(), bit_nr, p);
    366     }
    367   }
    368   if (sample_type & PERF_SAMPLE_STACK_USER) {
    369     uint64_t size;
    370     MoveFromBinaryFormat(size, p);
    371     if (size == 0) {
    372       stack_user_data.dyn_size = 0;
    373     } else {
    374       stack_user_data.data.resize(size);
    375       MoveFromBinaryFormat(stack_user_data.data.data(), size, p);
    376       MoveFromBinaryFormat(stack_user_data.dyn_size, p);
    377     }
    378   }
    379   // TODO: Add parsing of other PERF_SAMPLE_*.
    380   CHECK_LE(p, end);
    381   if (p < end) {
    382     LOG(DEBUG) << "Record has " << end - p << " bytes left\n";
    383   }
    384 }
    385 
    386 std::vector<char> SampleRecord::BinaryFormat() const {
    387   std::vector<char> buf(header.size);
    388   char* p = buf.data();
    389   MoveToBinaryFormat(header, p);
    390   if (sample_type & PERF_SAMPLE_IP) {
    391     MoveToBinaryFormat(ip_data, p);
    392   }
    393   if (sample_type & PERF_SAMPLE_TID) {
    394     MoveToBinaryFormat(tid_data, p);
    395   }
    396   if (sample_type & PERF_SAMPLE_TIME) {
    397     MoveToBinaryFormat(time_data, p);
    398   }
    399   if (sample_type & PERF_SAMPLE_ADDR) {
    400     MoveToBinaryFormat(addr_data, p);
    401   }
    402   if (sample_type & PERF_SAMPLE_ID) {
    403     MoveToBinaryFormat(id_data, p);
    404   }
    405   if (sample_type & PERF_SAMPLE_STREAM_ID) {
    406     MoveToBinaryFormat(stream_id_data, p);
    407   }
    408   if (sample_type & PERF_SAMPLE_CPU) {
    409     MoveToBinaryFormat(cpu_data, p);
    410   }
    411   if (sample_type & PERF_SAMPLE_PERIOD) {
    412     MoveToBinaryFormat(period_data, p);
    413   }
    414   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
    415     uint64_t nr = callchain_data.ips.size();
    416     MoveToBinaryFormat(nr, p);
    417     MoveToBinaryFormat(callchain_data.ips.data(), nr, p);
    418   }
    419   if (sample_type & PERF_SAMPLE_RAW) {
    420     uint32_t size = raw_data.data.size();
    421     MoveToBinaryFormat(size, p);
    422     MoveToBinaryFormat(raw_data.data.data(), size, p);
    423   }
    424   if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
    425     uint64_t nr = branch_stack_data.stack.size();
    426     MoveToBinaryFormat(nr, p);
    427     MoveToBinaryFormat(branch_stack_data.stack.data(), nr, p);
    428   }
    429   if (sample_type & PERF_SAMPLE_REGS_USER) {
    430     MoveToBinaryFormat(regs_user_data.abi, p);
    431     if (regs_user_data.abi != 0) {
    432       MoveToBinaryFormat(regs_user_data.regs.data(), regs_user_data.regs.size(), p);
    433     }
    434   }
    435   if (sample_type & PERF_SAMPLE_STACK_USER) {
    436     uint64_t size = stack_user_data.data.size();
    437     MoveToBinaryFormat(size, p);
    438     if (size != 0) {
    439       MoveToBinaryFormat(stack_user_data.data.data(), size, p);
    440       MoveToBinaryFormat(stack_user_data.dyn_size, p);
    441     }
    442   }
    443 
    444   // If record command does stack unwinding, sample records' size may be decreased.
    445   // So we can't trust header.size here, and should adjust buffer size based on real need.
    446   buf.resize(p - buf.data());
    447   return buf;
    448 }
    449 
    450 void SampleRecord::AdjustSizeBasedOnData() {
    451   size_t size = BinaryFormat().size();
    452   LOG(DEBUG) << "Record (type " << RecordTypeToString(header.type) << ") size is changed from "
    453       << header.size << " to " << size;
    454   header.size = size;
    455 }
    456 
    457 void SampleRecord::DumpData(size_t indent) const {
    458   PrintIndented(indent, "sample_type: 0x%" PRIx64 "\n", sample_type);
    459   if (sample_type & PERF_SAMPLE_IP) {
    460     PrintIndented(indent, "ip %p\n", reinterpret_cast<void*>(ip_data.ip));
    461   }
    462   if (sample_type & PERF_SAMPLE_TID) {
    463     PrintIndented(indent, "pid %u, tid %u\n", tid_data.pid, tid_data.tid);
    464   }
    465   if (sample_type & PERF_SAMPLE_TIME) {
    466     PrintIndented(indent, "time %" PRId64 "\n", time_data.time);
    467   }
    468   if (sample_type & PERF_SAMPLE_ADDR) {
    469     PrintIndented(indent, "addr %p\n", reinterpret_cast<void*>(addr_data.addr));
    470   }
    471   if (sample_type & PERF_SAMPLE_ID) {
    472     PrintIndented(indent, "id %" PRId64 "\n", id_data.id);
    473   }
    474   if (sample_type & PERF_SAMPLE_STREAM_ID) {
    475     PrintIndented(indent, "stream_id %" PRId64 "\n", stream_id_data.stream_id);
    476   }
    477   if (sample_type & PERF_SAMPLE_CPU) {
    478     PrintIndented(indent, "cpu %u, res %u\n", cpu_data.cpu, cpu_data.res);
    479   }
    480   if (sample_type & PERF_SAMPLE_PERIOD) {
    481     PrintIndented(indent, "period %" PRId64 "\n", period_data.period);
    482   }
    483   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
    484     PrintIndented(indent, "callchain nr=%" PRIu64 "\n", callchain_data.ips.size());
    485     for (auto& ip : callchain_data.ips) {
    486       PrintIndented(indent + 1, "0x%" PRIx64 "\n", ip);
    487     }
    488   }
    489   if (sample_type & PERF_SAMPLE_RAW) {
    490     PrintIndented(indent, "raw size=%zu\n", raw_data.data.size());
    491     const uint32_t* data = reinterpret_cast<const uint32_t*>(raw_data.data.data());
    492     size_t size = raw_data.data.size() / sizeof(uint32_t);
    493     for (size_t i = 0; i < size; ++i) {
    494       PrintIndented(indent + 1, "0x%08x (%zu)\n", data[i], data[i]);
    495     }
    496   }
    497   if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
    498     PrintIndented(indent, "branch_stack nr=%" PRIu64 "\n", branch_stack_data.stack.size());
    499     for (auto& item : branch_stack_data.stack) {
    500       PrintIndented(indent + 1, "from 0x%" PRIx64 ", to 0x%" PRIx64 ", flags 0x%" PRIx64 "\n",
    501                     item.from, item.to, item.flags);
    502     }
    503   }
    504   if (sample_type & PERF_SAMPLE_REGS_USER) {
    505     PrintIndented(indent, "user regs: abi=%" PRId64 "\n", regs_user_data.abi);
    506     for (size_t i = 0, pos = 0; i < 64; ++i) {
    507       if ((regs_user_data.reg_mask >> i) & 1) {
    508         PrintIndented(indent + 1, "reg (%s) 0x%016" PRIx64 "\n",
    509                       GetRegName(i, ScopedCurrentArch::GetCurrentArch()).c_str(),
    510                       regs_user_data.regs[pos++]);
    511       }
    512     }
    513   }
    514   if (sample_type & PERF_SAMPLE_STACK_USER) {
    515     PrintIndented(indent, "user stack: size %zu dyn_size %" PRIu64 "\n",
    516                   stack_user_data.data.size(), stack_user_data.dyn_size);
    517     const uint64_t* p = reinterpret_cast<const uint64_t*>(stack_user_data.data.data());
    518     const uint64_t* end = p + (stack_user_data.data.size() / sizeof(uint64_t));
    519     while (p < end) {
    520       PrintIndented(indent + 1, "");
    521       for (size_t i = 0; i < 4 && p < end; ++i, ++p) {
    522         printf(" %016" PRIx64, *p);
    523       }
    524       printf("\n");
    525     }
    526     printf("\n");
    527   }
    528 }
    529 
    530 uint64_t SampleRecord::Timestamp() const {
    531   return time_data.time;
    532 }
    533 
    534 BuildIdRecord::BuildIdRecord(const perf_event_header* pheader) : Record(pheader) {
    535   const char* p = reinterpret_cast<const char*>(pheader + 1);
    536   const char* end = reinterpret_cast<const char*>(pheader) + pheader->size;
    537   MoveFromBinaryFormat(pid, p);
    538   build_id = BuildId(p, BUILD_ID_SIZE);
    539   p += ALIGN(build_id.Size(), 8);
    540   filename = p;
    541   p += ALIGN(filename.size() + 1, 64);
    542   CHECK_EQ(p, end);
    543 }
    544 
    545 std::vector<char> BuildIdRecord::BinaryFormat() const {
    546   std::vector<char> buf(header.size);
    547   char* p = buf.data();
    548   MoveToBinaryFormat(header, p);
    549   MoveToBinaryFormat(pid, p);
    550   memcpy(p, build_id.Data(), build_id.Size());
    551   p += ALIGN(build_id.Size(), 8);
    552   strcpy(p, filename.c_str());
    553   p += ALIGN(filename.size() + 1, 64);
    554   return buf;
    555 }
    556 
    557 void BuildIdRecord::DumpData(size_t indent) const {
    558   PrintIndented(indent, "pid %u\n", pid);
    559   PrintIndented(indent, "build_id %s\n", build_id.ToString().c_str());
    560   PrintIndented(indent, "filename %s\n", filename.c_str());
    561 }
    562 
    563 UnknownRecord::UnknownRecord(const perf_event_header* pheader) : Record(pheader) {
    564   const char* p = reinterpret_cast<const char*>(pheader + 1);
    565   const char* end = reinterpret_cast<const char*>(pheader) + pheader->size;
    566   data.insert(data.end(), p, end);
    567 }
    568 
    569 std::vector<char> UnknownRecord::BinaryFormat() const {
    570   std::vector<char> buf(header.size);
    571   char* p = buf.data();
    572   MoveToBinaryFormat(header, p);
    573   MoveToBinaryFormat(data.data(), data.size(), p);
    574   return buf;
    575 }
    576 
    577 void UnknownRecord::DumpData(size_t) const {
    578 }
    579 
    580 static std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr,
    581                                                     const perf_event_header* pheader) {
    582   switch (pheader->type) {
    583     case PERF_RECORD_MMAP:
    584       return std::unique_ptr<Record>(new MmapRecord(attr, pheader));
    585     case PERF_RECORD_MMAP2:
    586       return std::unique_ptr<Record>(new Mmap2Record(attr, pheader));
    587     case PERF_RECORD_COMM:
    588       return std::unique_ptr<Record>(new CommRecord(attr, pheader));
    589     case PERF_RECORD_EXIT:
    590       return std::unique_ptr<Record>(new ExitRecord(attr, pheader));
    591     case PERF_RECORD_FORK:
    592       return std::unique_ptr<Record>(new ForkRecord(attr, pheader));
    593     case PERF_RECORD_SAMPLE:
    594       return std::unique_ptr<Record>(new SampleRecord(attr, pheader));
    595     default:
    596       return std::unique_ptr<Record>(new UnknownRecord(pheader));
    597   }
    598 }
    599 
    600 std::vector<std::unique_ptr<Record>> ReadRecordsFromBuffer(const perf_event_attr& attr,
    601                                                            const char* buf, size_t buf_size) {
    602   std::vector<std::unique_ptr<Record>> result;
    603   const char* p = buf;
    604   const char* end = buf + buf_size;
    605   while (p < end) {
    606     const perf_event_header* header = reinterpret_cast<const perf_event_header*>(p);
    607     CHECK_LE(p + header->size, end);
    608     CHECK_NE(0u, header->size);
    609     result.push_back(ReadRecordFromBuffer(attr, header));
    610     p += header->size;
    611   }
    612   return result;
    613 }
    614 
    615 std::unique_ptr<Record> ReadRecordFromFile(const perf_event_attr& attr, FILE* fp) {
    616   std::vector<char> buf(sizeof(perf_event_header));
    617   perf_event_header* header = reinterpret_cast<perf_event_header*>(&buf[0]);
    618   if (fread(header, sizeof(perf_event_header), 1, fp) != 1) {
    619     PLOG(ERROR) << "Failed to read record file";
    620     return nullptr;
    621   }
    622   buf.resize(header->size);
    623   header = reinterpret_cast<perf_event_header*>(&buf[0]);
    624   if (fread(&buf[sizeof(perf_event_header)], buf.size() - sizeof(perf_event_header), 1, fp) != 1) {
    625     PLOG(ERROR) << "Failed to read record file";
    626     return nullptr;
    627   }
    628   return ReadRecordFromBuffer(attr, header);
    629 }
    630 
    631 MmapRecord CreateMmapRecord(const perf_event_attr& attr, bool in_kernel, uint32_t pid, uint32_t tid,
    632                             uint64_t addr, uint64_t len, uint64_t pgoff,
    633                             const std::string& filename) {
    634   MmapRecord record;
    635   record.header.type = PERF_RECORD_MMAP;
    636   record.header.misc = (in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER);
    637   record.data.pid = pid;
    638   record.data.tid = tid;
    639   record.data.addr = addr;
    640   record.data.len = len;
    641   record.data.pgoff = pgoff;
    642   record.filename = filename;
    643   size_t sample_id_size = record.sample_id.CreateContent(attr);
    644   record.header.size = sizeof(record.header) + sizeof(record.data) +
    645                        ALIGN(record.filename.size() + 1, 8) + sample_id_size;
    646   return record;
    647 }
    648 
    649 CommRecord CreateCommRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid,
    650                             const std::string& comm) {
    651   CommRecord record;
    652   record.header.type = PERF_RECORD_COMM;
    653   record.header.misc = 0;
    654   record.data.pid = pid;
    655   record.data.tid = tid;
    656   record.comm = comm;
    657   size_t sample_id_size = record.sample_id.CreateContent(attr);
    658   record.header.size = sizeof(record.header) + sizeof(record.data) +
    659                        ALIGN(record.comm.size() + 1, 8) + sample_id_size;
    660   return record;
    661 }
    662 
    663 ForkRecord CreateForkRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid, uint32_t ppid,
    664                             uint32_t ptid) {
    665   ForkRecord record;
    666   record.header.type = PERF_RECORD_FORK;
    667   record.header.misc = 0;
    668   record.data.pid = pid;
    669   record.data.ppid = ppid;
    670   record.data.tid = tid;
    671   record.data.ptid = ptid;
    672   record.data.time = 0;
    673   size_t sample_id_size = record.sample_id.CreateContent(attr);
    674   record.header.size = sizeof(record.header) + sizeof(record.data) + sample_id_size;
    675   return record;
    676 }
    677 
    678 BuildIdRecord CreateBuildIdRecord(bool in_kernel, pid_t pid, const BuildId& build_id,
    679                                   const std::string& filename) {
    680   BuildIdRecord record;
    681   record.header.type = PERF_RECORD_BUILD_ID;
    682   record.header.misc = (in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER);
    683   record.pid = pid;
    684   record.build_id = build_id;
    685   record.filename = filename;
    686   record.header.size = sizeof(record.header) + sizeof(record.pid) +
    687                        ALIGN(record.build_id.Size(), 8) + ALIGN(filename.size() + 1, 64);
    688   return record;
    689 }
    690 
    691 bool RecordCache::RecordWithSeq::IsHappensBefore(const RecordWithSeq& other) const {
    692   bool is_sample = (record->header.type == PERF_RECORD_SAMPLE);
    693   bool is_other_sample = (other.record->header.type == PERF_RECORD_SAMPLE);
    694   uint64_t time = record->Timestamp();
    695   uint64_t other_time = other.record->Timestamp();
    696   // The record with smaller time happens first.
    697   if (time != other_time) {
    698     return time < other_time;
    699   }
    700   // If happening at the same time, make non-sample records before sample records,
    701   // because non-sample records may contain useful information to parse sample records.
    702   if (is_sample != is_other_sample) {
    703     return is_sample ? false : true;
    704   }
    705   // Otherwise, use the same order as they enter the cache.
    706   return seq < other.seq;
    707 }
    708 
    709 bool RecordCache::RecordComparator::operator()(const RecordWithSeq& r1,
    710                                                const RecordWithSeq& r2) {
    711   return r2.IsHappensBefore(r1);
    712 }
    713 
    714 RecordCache::RecordCache(const perf_event_attr& attr, size_t min_cache_size,
    715                          uint64_t min_time_diff_in_ns)
    716     : attr_(attr),
    717       has_timestamp_(attr.sample_id_all && (attr.sample_type & PERF_SAMPLE_TIME)),
    718       min_cache_size_(min_cache_size),
    719       min_time_diff_in_ns_(min_time_diff_in_ns),
    720       last_time_(0),
    721       cur_seq_(0),
    722       queue_(RecordComparator()) {
    723 }
    724 
    725 RecordCache::~RecordCache() {
    726   PopAll();
    727 }
    728 
    729 void RecordCache::Push(const char* data, size_t size) {
    730   std::vector<std::unique_ptr<Record>> records = ReadRecordsFromBuffer(attr_, data, size);
    731   if (has_timestamp_) {
    732     for (const auto& r : records) {
    733       last_time_ = std::max(last_time_, r->Timestamp());
    734     }
    735   }
    736   for (auto& r : records) {
    737     queue_.push(CreateRecordWithSeq(r.release()));
    738   }
    739 }
    740 
    741 void RecordCache::Push(std::unique_ptr<Record> record) {
    742   queue_.push(CreateRecordWithSeq(record.release()));
    743 }
    744 
    745 std::unique_ptr<Record> RecordCache::Pop() {
    746   if (queue_.size() < min_cache_size_) {
    747     return nullptr;
    748   }
    749   Record* r = queue_.top().record;
    750   if (has_timestamp_) {
    751     if (r->Timestamp() + min_time_diff_in_ns_ > last_time_) {
    752       return nullptr;
    753     }
    754   }
    755   queue_.pop();
    756   return std::unique_ptr<Record>(r);
    757 }
    758 
    759 std::vector<std::unique_ptr<Record>> RecordCache::PopAll() {
    760   std::vector<std::unique_ptr<Record>> result;
    761   while (!queue_.empty()) {
    762     result.emplace_back(queue_.top().record);
    763     queue_.pop();
    764   }
    765   return result;
    766 }
    767 
    768 RecordCache::RecordWithSeq RecordCache::CreateRecordWithSeq(Record *r) {
    769   RecordWithSeq result;
    770   result.seq = cur_seq_++;
    771   result.record = r;
    772   return result;
    773 }
    774