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 "dso.h"
     27 #include "OfflineUnwinder.h"
     28 #include "perf_regs.h"
     29 #include "tracing.h"
     30 #include "utils.h"
     31 
     32 using namespace simpleperf;
     33 
     34 static std::string RecordTypeToString(int record_type) {
     35   static std::unordered_map<int, std::string> record_type_names = {
     36       {PERF_RECORD_MMAP, "mmap"},
     37       {PERF_RECORD_LOST, "lost"},
     38       {PERF_RECORD_COMM, "comm"},
     39       {PERF_RECORD_EXIT, "exit"},
     40       {PERF_RECORD_THROTTLE, "throttle"},
     41       {PERF_RECORD_UNTHROTTLE, "unthrottle"},
     42       {PERF_RECORD_FORK, "fork"},
     43       {PERF_RECORD_READ, "read"},
     44       {PERF_RECORD_SAMPLE, "sample"},
     45       {PERF_RECORD_BUILD_ID, "build_id"},
     46       {PERF_RECORD_MMAP2, "mmap2"},
     47       {PERF_RECORD_TRACING_DATA, "tracing_data"},
     48       {SIMPLE_PERF_RECORD_KERNEL_SYMBOL, "kernel_symbol"},
     49       {SIMPLE_PERF_RECORD_DSO, "dso"},
     50       {SIMPLE_PERF_RECORD_SYMBOL, "symbol"},
     51       {SIMPLE_PERF_RECORD_EVENT_ID, "event_id"},
     52       {SIMPLE_PERF_RECORD_CALLCHAIN, "callchain"},
     53       {SIMPLE_PERF_RECORD_UNWINDING_RESULT, "unwinding_result"},
     54   };
     55 
     56   auto it = record_type_names.find(record_type);
     57   if (it != record_type_names.end()) {
     58     return it->second;
     59   }
     60   return android::base::StringPrintf("unknown(%d)", record_type);
     61 }
     62 
     63 template <>
     64 void MoveToBinaryFormat(const RecordHeader& data, char*& p) {
     65   data.MoveToBinaryFormat(p);
     66 }
     67 
     68 SampleId::SampleId() { memset(this, 0, sizeof(SampleId)); }
     69 
     70 // Return sample_id size in binary format.
     71 size_t SampleId::CreateContent(const perf_event_attr& attr, uint64_t event_id) {
     72   sample_id_all = attr.sample_id_all;
     73   sample_type = attr.sample_type;
     74   id_data.id = event_id;
     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,
     80                                     const char* end) {
     81   sample_id_all = attr.sample_id_all;
     82   sample_type = attr.sample_type;
     83   if (sample_id_all) {
     84     if (sample_type & PERF_SAMPLE_TID) {
     85       MoveFromBinaryFormat(tid_data, p);
     86     }
     87     if (sample_type & PERF_SAMPLE_TIME) {
     88       MoveFromBinaryFormat(time_data, p);
     89     }
     90     if (sample_type & PERF_SAMPLE_ID) {
     91       MoveFromBinaryFormat(id_data, p);
     92     }
     93     if (sample_type & PERF_SAMPLE_STREAM_ID) {
     94       MoveFromBinaryFormat(stream_id_data, p);
     95     }
     96     if (sample_type & PERF_SAMPLE_CPU) {
     97       MoveFromBinaryFormat(cpu_data, p);
     98     }
     99     if (sample_type & PERF_SAMPLE_IDENTIFIER) {
    100       MoveFromBinaryFormat(id_data, p);
    101     }
    102   }
    103   CHECK_LE(p, end);
    104   if (p < end) {
    105     LOG(DEBUG) << "Record SampleId part has " << end - p << " bytes left\n";
    106   }
    107 }
    108 
    109 void SampleId::WriteToBinaryFormat(char*& p) const {
    110   if (sample_id_all) {
    111     if (sample_type & PERF_SAMPLE_TID) {
    112       MoveToBinaryFormat(tid_data, p);
    113     }
    114     if (sample_type & PERF_SAMPLE_TIME) {
    115       MoveToBinaryFormat(time_data, p);
    116     }
    117     if (sample_type & PERF_SAMPLE_ID) {
    118       MoveToBinaryFormat(id_data, p);
    119     }
    120     if (sample_type & PERF_SAMPLE_STREAM_ID) {
    121       MoveToBinaryFormat(stream_id_data, p);
    122     }
    123     if (sample_type & PERF_SAMPLE_CPU) {
    124       MoveToBinaryFormat(cpu_data, p);
    125     }
    126   }
    127 }
    128 
    129 void SampleId::Dump(size_t indent) const {
    130   if (sample_id_all) {
    131     if (sample_type & PERF_SAMPLE_TID) {
    132       PrintIndented(indent, "sample_id: pid %u, tid %u\n", tid_data.pid,
    133                     tid_data.tid);
    134     }
    135     if (sample_type & PERF_SAMPLE_TIME) {
    136       PrintIndented(indent, "sample_id: time %" PRId64 "\n", time_data.time);
    137     }
    138     if (sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
    139       PrintIndented(indent, "sample_id: id %" PRId64 "\n", id_data.id);
    140     }
    141     if (sample_type & PERF_SAMPLE_STREAM_ID) {
    142       PrintIndented(indent, "sample_id: stream_id %" PRId64 "\n",
    143                     stream_id_data.stream_id);
    144     }
    145     if (sample_type & PERF_SAMPLE_CPU) {
    146       PrintIndented(indent, "sample_id: cpu %u, res %u\n", cpu_data.cpu,
    147                     cpu_data.res);
    148     }
    149   }
    150 }
    151 
    152 size_t SampleId::Size() const {
    153   size_t size = 0;
    154   if (sample_id_all) {
    155     if (sample_type & PERF_SAMPLE_TID) {
    156       size += sizeof(PerfSampleTidType);
    157     }
    158     if (sample_type & PERF_SAMPLE_TIME) {
    159       size += sizeof(PerfSampleTimeType);
    160     }
    161     if (sample_type & PERF_SAMPLE_ID) {
    162       size += sizeof(PerfSampleIdType);
    163     }
    164     if (sample_type & PERF_SAMPLE_STREAM_ID) {
    165       size += sizeof(PerfSampleStreamIdType);
    166     }
    167     if (sample_type & PERF_SAMPLE_CPU) {
    168       size += sizeof(PerfSampleCpuType);
    169     }
    170     if (sample_type & PERF_SAMPLE_IDENTIFIER) {
    171       size += sizeof(PerfSampleIdType);
    172     }
    173   }
    174   return size;
    175 }
    176 
    177 Record::Record(Record&& other) {
    178   header = other.header;
    179   sample_id = other.sample_id;
    180   binary_ = other.binary_;
    181   own_binary_ = other.own_binary_;
    182   other.binary_ = nullptr;
    183   other.own_binary_ = false;
    184 }
    185 
    186 void Record::Dump(size_t indent) const {
    187   PrintIndented(indent, "record %s: type %u, misc %u, size %u\n",
    188                 RecordTypeToString(type()).c_str(), type(), misc(), size());
    189   DumpData(indent + 1);
    190   sample_id.Dump(indent + 1);
    191 }
    192 
    193 uint64_t Record::Timestamp() const { return sample_id.time_data.time; }
    194 uint32_t Record::Cpu() const { return sample_id.cpu_data.cpu; }
    195 uint64_t Record::Id() const { return sample_id.id_data.id; }
    196 
    197 void Record::UpdateBinary(char* new_binary) {
    198   if (own_binary_) {
    199     delete[] binary_;
    200   }
    201   own_binary_ = true;
    202   binary_ = new_binary;
    203 }
    204 
    205 MmapRecord::MmapRecord(const perf_event_attr& attr, char* p) : Record(p) {
    206   const char* end = p + size();
    207   p += header_size();
    208   data = reinterpret_cast<const MmapRecordDataType*>(p);
    209   p += sizeof(*data);
    210   filename = p;
    211   p += Align(strlen(filename) + 1, 8);
    212   CHECK_LE(p, end);
    213   sample_id.ReadFromBinaryFormat(attr, p, end);
    214 }
    215 
    216 MmapRecord::MmapRecord(const perf_event_attr& attr, bool in_kernel,
    217                        uint32_t pid, uint32_t tid, uint64_t addr, uint64_t len,
    218                        uint64_t pgoff, const std::string& filename,
    219                        uint64_t event_id, uint64_t time) {
    220   SetTypeAndMisc(PERF_RECORD_MMAP,
    221                  in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER);
    222   sample_id.CreateContent(attr, event_id);
    223   sample_id.time_data.time = time;
    224   MmapRecordDataType data;
    225   data.pid = pid;
    226   data.tid = tid;
    227   data.addr = addr;
    228   data.len = len;
    229   data.pgoff = pgoff;
    230   SetDataAndFilename(data, filename);
    231 }
    232 
    233 void MmapRecord::SetDataAndFilename(const MmapRecordDataType& data,
    234                                     const std::string& filename) {
    235   SetSize(header_size() + sizeof(data) + Align(filename.size() + 1, 8) +
    236           sample_id.Size());
    237   char* new_binary = new char[size()];
    238   char* p = new_binary;
    239   MoveToBinaryFormat(header, p);
    240   this->data = reinterpret_cast<MmapRecordDataType*>(p);
    241   MoveToBinaryFormat(data, p);
    242   this->filename = p;
    243   strcpy(p, filename.c_str());
    244   p += Align(filename.size() + 1, 8);
    245   sample_id.WriteToBinaryFormat(p);
    246   UpdateBinary(new_binary);
    247 }
    248 
    249 void MmapRecord::DumpData(size_t indent) const {
    250   PrintIndented(indent,
    251                 "pid %u, tid %u, addr 0x%" PRIx64 ", len 0x%" PRIx64 "\n",
    252                 data->pid, data->tid, data->addr, data->len);
    253   PrintIndented(indent, "pgoff 0x%" PRIx64 ", filename %s\n", data->pgoff,
    254                 filename);
    255 }
    256 
    257 Mmap2Record::Mmap2Record(const perf_event_attr& attr, char* p) : Record(p) {
    258   const char* end = p + size();
    259   p += header_size();
    260   data = reinterpret_cast<const Mmap2RecordDataType*>(p);
    261   p += sizeof(*data);
    262   filename = p;
    263   p += Align(strlen(filename) + 1, 8);
    264   CHECK_LE(p, end);
    265   sample_id.ReadFromBinaryFormat(attr, p, end);
    266 }
    267 
    268 void Mmap2Record::SetDataAndFilename(const Mmap2RecordDataType& data,
    269                                      const std::string& filename) {
    270   SetSize(header_size() + sizeof(data) + Align(filename.size() + 1, 8) +
    271           sample_id.Size());
    272   char* new_binary = new char[size()];
    273   char* p = new_binary;
    274   MoveToBinaryFormat(header, p);
    275   this->data = reinterpret_cast<Mmap2RecordDataType*>(p);
    276   MoveToBinaryFormat(data, p);
    277   this->filename = p;
    278   strcpy(p, filename.c_str());
    279   p += Align(filename.size() + 1, 8);
    280   sample_id.WriteToBinaryFormat(p);
    281   UpdateBinary(new_binary);
    282 }
    283 
    284 void Mmap2Record::DumpData(size_t indent) const {
    285   PrintIndented(indent,
    286                 "pid %u, tid %u, addr 0x%" PRIx64 ", len 0x%" PRIx64 "\n",
    287                 data->pid, data->tid, data->addr, data->len);
    288   PrintIndented(indent, "pgoff 0x" PRIx64 ", maj %u, min %u, ino %" PRId64
    289                         ", ino_generation %" PRIu64 "\n",
    290                 data->pgoff, data->maj, data->min, data->ino,
    291                 data->ino_generation);
    292   PrintIndented(indent, "prot %u, flags %u, filenames %s\n", data->prot,
    293                 data->flags, filename);
    294 }
    295 
    296 CommRecord::CommRecord(const perf_event_attr& attr, char* p) : Record(p) {
    297   const char* end = p + size();
    298   p += header_size();
    299   data = reinterpret_cast<const CommRecordDataType*>(p);
    300   p += sizeof(*data);
    301   comm = p;
    302   p += Align(strlen(p) + 1, 8);
    303   CHECK_LE(p, end);
    304   sample_id.ReadFromBinaryFormat(attr, p, end);
    305 }
    306 
    307 CommRecord::CommRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid,
    308                        const std::string& comm, uint64_t event_id, uint64_t time) {
    309   SetTypeAndMisc(PERF_RECORD_COMM, 0);
    310   CommRecordDataType data;
    311   data.pid = pid;
    312   data.tid = tid;
    313   size_t sample_id_size = sample_id.CreateContent(attr, event_id);
    314   sample_id.time_data.time = time;
    315   SetSize(header_size() + sizeof(data) + Align(comm.size() + 1, 8) +
    316           sample_id_size);
    317   char* new_binary = new char[size()];
    318   char* p = new_binary;
    319   MoveToBinaryFormat(header, p);
    320   this->data = reinterpret_cast<CommRecordDataType*>(p);
    321   MoveToBinaryFormat(data, p);
    322   this->comm = p;
    323   strcpy(p, comm.c_str());
    324   p += Align(comm.size() + 1, 8);
    325   sample_id.WriteToBinaryFormat(p);
    326   UpdateBinary(new_binary);
    327 }
    328 
    329 void CommRecord::DumpData(size_t indent) const {
    330   PrintIndented(indent, "pid %u, tid %u, comm %s\n", data->pid, data->tid,
    331                 comm);
    332 }
    333 
    334 ExitOrForkRecord::ExitOrForkRecord(const perf_event_attr& attr, char* p)
    335     : Record(p) {
    336   const char* end = p + size();
    337   p += header_size();
    338   data = reinterpret_cast<const ExitOrForkRecordDataType*>(p);
    339   p += sizeof(*data);
    340   CHECK_LE(p, end);
    341   sample_id.ReadFromBinaryFormat(attr, p, end);
    342 }
    343 
    344 void ExitOrForkRecord::DumpData(size_t indent) const {
    345   PrintIndented(indent, "pid %u, ppid %u, tid %u, ptid %u\n", data->pid,
    346                 data->ppid, data->tid, data->ptid);
    347 }
    348 
    349 ForkRecord::ForkRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid,
    350                        uint32_t ppid, uint32_t ptid, uint64_t event_id) {
    351   SetTypeAndMisc(PERF_RECORD_FORK, 0);
    352   ExitOrForkRecordDataType data;
    353   data.pid = pid;
    354   data.ppid = ppid;
    355   data.tid = tid;
    356   data.ptid = ptid;
    357   data.time = 0;
    358   size_t sample_id_size = sample_id.CreateContent(attr, event_id);
    359   SetSize(header_size() + sizeof(data) + sample_id_size);
    360   char* new_binary = new char[size()];
    361   char* p = new_binary;
    362   MoveToBinaryFormat(header, p);
    363   this->data = reinterpret_cast<ExitOrForkRecordDataType*>(p);
    364   MoveToBinaryFormat(data, p);
    365   sample_id.WriteToBinaryFormat(p);
    366   UpdateBinary(new_binary);
    367 }
    368 
    369 LostRecord::LostRecord(const perf_event_attr& attr, char* p) : Record(p) {
    370   const char* end = p + size();
    371   p += header_size();
    372   MoveFromBinaryFormat(id, p);
    373   MoveFromBinaryFormat(lost, p);
    374   CHECK_LE(p, end);
    375   sample_id.ReadFromBinaryFormat(attr, p, end);
    376 }
    377 
    378 void LostRecord::DumpData(size_t indent) const {
    379   PrintIndented(indent, "id %" PRIu64 ", lost %" PRIu64 "\n", id, lost);
    380 }
    381 
    382 SampleRecord::SampleRecord(const perf_event_attr& attr, char* p) : Record(p) {
    383   const char* end = p + size();
    384   p += header_size();
    385   sample_type = attr.sample_type;
    386 
    387   // Set a default id value to report correctly even if ID is not recorded.
    388   id_data.id = 0;
    389   if (sample_type & PERF_SAMPLE_IDENTIFIER) {
    390     MoveFromBinaryFormat(id_data, p);
    391   }
    392   if (sample_type & PERF_SAMPLE_IP) {
    393     MoveFromBinaryFormat(ip_data, p);
    394   }
    395   if (sample_type & PERF_SAMPLE_TID) {
    396     MoveFromBinaryFormat(tid_data, p);
    397   }
    398   if (sample_type & PERF_SAMPLE_TIME) {
    399     MoveFromBinaryFormat(time_data, p);
    400   }
    401   if (sample_type & PERF_SAMPLE_ADDR) {
    402     MoveFromBinaryFormat(addr_data, p);
    403   }
    404   if (sample_type & PERF_SAMPLE_ID) {
    405     MoveFromBinaryFormat(id_data, p);
    406   }
    407   if (sample_type & PERF_SAMPLE_STREAM_ID) {
    408     MoveFromBinaryFormat(stream_id_data, p);
    409   }
    410   if (sample_type & PERF_SAMPLE_CPU) {
    411     MoveFromBinaryFormat(cpu_data, p);
    412   }
    413   if (sample_type & PERF_SAMPLE_PERIOD) {
    414     MoveFromBinaryFormat(period_data, p);
    415   }
    416   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
    417     MoveFromBinaryFormat(callchain_data.ip_nr, p);
    418     callchain_data.ips = reinterpret_cast<uint64_t*>(p);
    419     p += callchain_data.ip_nr * sizeof(uint64_t);
    420   }
    421   if (sample_type & PERF_SAMPLE_RAW) {
    422     MoveFromBinaryFormat(raw_data.size, p);
    423     raw_data.data = p;
    424     p += raw_data.size;
    425   }
    426   if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
    427     MoveFromBinaryFormat(branch_stack_data.stack_nr, p);
    428     branch_stack_data.stack = reinterpret_cast<BranchStackItemType*>(p);
    429     p += branch_stack_data.stack_nr * sizeof(BranchStackItemType);
    430   }
    431   if (sample_type & PERF_SAMPLE_REGS_USER) {
    432     MoveFromBinaryFormat(regs_user_data.abi, p);
    433     if (regs_user_data.abi == 0) {
    434       regs_user_data.reg_mask = 0;
    435     } else {
    436       regs_user_data.reg_mask = attr.sample_regs_user;
    437       size_t bit_nr = 0;
    438       for (size_t i = 0; i < 64; ++i) {
    439         if ((regs_user_data.reg_mask >> i) & 1) {
    440           bit_nr++;
    441         }
    442       }
    443       regs_user_data.reg_nr = bit_nr;
    444       regs_user_data.regs = reinterpret_cast<uint64_t*>(p);
    445       p += bit_nr * sizeof(uint64_t);
    446     }
    447   }
    448   if (sample_type & PERF_SAMPLE_STACK_USER) {
    449     MoveFromBinaryFormat(stack_user_data.size, p);
    450     if (stack_user_data.size == 0) {
    451       stack_user_data.dyn_size = 0;
    452     } else {
    453       stack_user_data.data = p;
    454       p += stack_user_data.size;
    455       MoveFromBinaryFormat(stack_user_data.dyn_size, p);
    456     }
    457   }
    458   // TODO: Add parsing of other PERF_SAMPLE_*.
    459   CHECK_LE(p, end);
    460   if (p < end) {
    461     LOG(DEBUG) << "Record has " << end - p << " bytes left\n";
    462   }
    463 }
    464 
    465 SampleRecord::SampleRecord(const perf_event_attr& attr, uint64_t id,
    466                            uint64_t ip, uint32_t pid, uint32_t tid,
    467                            uint64_t time, uint32_t cpu, uint64_t period,
    468                            const std::vector<uint64_t>& ips) {
    469   SetTypeAndMisc(PERF_RECORD_SAMPLE, PERF_RECORD_MISC_USER);
    470   sample_type = attr.sample_type;
    471   CHECK_EQ(0u, sample_type & ~(PERF_SAMPLE_IP | PERF_SAMPLE_TID
    472       | PERF_SAMPLE_TIME | PERF_SAMPLE_ID | PERF_SAMPLE_CPU
    473       | PERF_SAMPLE_PERIOD | PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER
    474       | PERF_SAMPLE_STACK_USER));
    475   ip_data.ip = ip;
    476   tid_data.pid = pid;
    477   tid_data.tid = tid;
    478   time_data.time = time;
    479   id_data.id = id;
    480   cpu_data.cpu = cpu;
    481   cpu_data.res = 0;
    482   period_data.period = period;
    483   callchain_data.ip_nr = ips.size();
    484   raw_data.size = 0;
    485   branch_stack_data.stack_nr = 0;
    486   regs_user_data.abi = 0;
    487   regs_user_data.reg_mask = 0;
    488   stack_user_data.size = 0;
    489 
    490   uint32_t size = header_size();
    491   if (sample_type & PERF_SAMPLE_IP) {
    492     size += sizeof(ip_data);
    493   }
    494   if (sample_type & PERF_SAMPLE_TID) {
    495     size += sizeof(tid_data);
    496   }
    497   if (sample_type & PERF_SAMPLE_TIME) {
    498     size += sizeof(time_data);
    499   }
    500   if (sample_type & PERF_SAMPLE_ID) {
    501     size += sizeof(id_data);
    502   }
    503   if (sample_type & PERF_SAMPLE_CPU) {
    504     size += sizeof(cpu_data);
    505   }
    506   if (sample_type & PERF_SAMPLE_PERIOD) {
    507     size += sizeof(period_data);
    508   }
    509   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
    510     size += sizeof(uint64_t) * (ips.size() + 1);
    511   }
    512   if (sample_type & PERF_SAMPLE_REGS_USER) {
    513     size += sizeof(uint64_t);
    514   }
    515   if (sample_type & PERF_SAMPLE_STACK_USER) {
    516     size += sizeof(uint64_t);
    517   }
    518 
    519   SetSize(size);
    520   char* new_binary = new char[size];
    521   char* p = new_binary;
    522   MoveToBinaryFormat(header, p);
    523   if (sample_type & PERF_SAMPLE_IP) {
    524     MoveToBinaryFormat(ip_data, p);
    525   }
    526   if (sample_type & PERF_SAMPLE_TID) {
    527     MoveToBinaryFormat(tid_data, p);
    528   }
    529   if (sample_type & PERF_SAMPLE_TIME) {
    530     MoveToBinaryFormat(time_data, p);
    531   }
    532   if (sample_type & PERF_SAMPLE_ID) {
    533     MoveToBinaryFormat(id_data, p);
    534   }
    535   if (sample_type & PERF_SAMPLE_CPU) {
    536     MoveToBinaryFormat(cpu_data, p);
    537   }
    538   if (sample_type & PERF_SAMPLE_PERIOD) {
    539     MoveToBinaryFormat(period_data, p);
    540   }
    541   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
    542     MoveToBinaryFormat(callchain_data.ip_nr, p);
    543     callchain_data.ips = reinterpret_cast<uint64_t*>(p);
    544     MoveToBinaryFormat(ips.data(), ips.size(), p);
    545   }
    546   if (sample_type & PERF_SAMPLE_REGS_USER) {
    547     MoveToBinaryFormat(regs_user_data.abi, p);
    548   }
    549   if (sample_type & PERF_SAMPLE_STACK_USER) {
    550     MoveToBinaryFormat(stack_user_data.size, p);
    551   }
    552   CHECK_EQ(p, new_binary + size);
    553   UpdateBinary(new_binary);
    554 }
    555 
    556 void SampleRecord::ReplaceRegAndStackWithCallChain(
    557     const std::vector<uint64_t>& ips) {
    558   uint32_t size_added_in_callchain = sizeof(uint64_t) * (ips.size() + 1);
    559   uint32_t size_reduced_in_reg_stack =
    560       regs_user_data.reg_nr * sizeof(uint64_t) + stack_user_data.size +
    561       sizeof(uint64_t);
    562   CHECK_LE(size_added_in_callchain, size_reduced_in_reg_stack);
    563   uint32_t size_reduced = size_reduced_in_reg_stack - size_added_in_callchain;
    564   SetSize(size() - size_reduced);
    565   char* p = binary_;
    566   MoveToBinaryFormat(header, p);
    567   p = (stack_user_data.data + stack_user_data.size + sizeof(uint64_t)) -
    568       (size_reduced_in_reg_stack - size_added_in_callchain);
    569   stack_user_data.size = 0;
    570   regs_user_data.abi = 0;
    571   p -= sizeof(uint64_t);
    572   *reinterpret_cast<uint64_t*>(p) = stack_user_data.size;
    573   p -= sizeof(uint64_t);
    574   *reinterpret_cast<uint64_t*>(p) = regs_user_data.abi;
    575   if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
    576     p -= branch_stack_data.stack_nr * sizeof(BranchStackItemType);
    577     memmove(p, branch_stack_data.stack,
    578             branch_stack_data.stack_nr * sizeof(BranchStackItemType));
    579     p -= sizeof(uint64_t);
    580     *reinterpret_cast<uint64_t*>(p) = branch_stack_data.stack_nr;
    581   }
    582   if (sample_type & PERF_SAMPLE_RAW) {
    583     p -= raw_data.size;
    584     memmove(p, raw_data.data, raw_data.size);
    585     p -= sizeof(uint32_t);
    586     *reinterpret_cast<uint32_t*>(p) = raw_data.size;
    587   }
    588   p -= ips.size() * sizeof(uint64_t);
    589   memcpy(p, ips.data(), ips.size() * sizeof(uint64_t));
    590   p -= sizeof(uint64_t);
    591   *reinterpret_cast<uint64_t*>(p) = PERF_CONTEXT_USER;
    592   p -= sizeof(uint64_t) * (callchain_data.ip_nr);
    593   callchain_data.ips = reinterpret_cast<uint64_t*>(p);
    594   callchain_data.ip_nr += ips.size() + 1;
    595   p -= sizeof(uint64_t);
    596   *reinterpret_cast<uint64_t*>(p) = callchain_data.ip_nr;
    597 }
    598 
    599 size_t SampleRecord::ExcludeKernelCallChain() {
    600   size_t user_callchain_length = 0u;
    601   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
    602     size_t i;
    603     for (i = 0; i < callchain_data.ip_nr; ++i) {
    604       if (callchain_data.ips[i] == PERF_CONTEXT_USER) {
    605         i++;
    606         if (i < callchain_data.ip_nr) {
    607           ip_data.ip = callchain_data.ips[i];
    608           if (sample_type & PERF_SAMPLE_IP) {
    609             *reinterpret_cast<uint64_t*>(binary_ + header_size()) = ip_data.ip;
    610           }
    611           header.misc = (header.misc & ~PERF_RECORD_MISC_KERNEL) | PERF_RECORD_MISC_USER;
    612           reinterpret_cast<perf_event_header*>(binary_)->misc = header.misc;
    613         }
    614         break;
    615       } else {
    616         callchain_data.ips[i] = PERF_CONTEXT_USER;
    617       }
    618     }
    619     user_callchain_length = callchain_data.ip_nr - i;
    620   }
    621   return user_callchain_length;
    622 }
    623 
    624 bool SampleRecord::HasUserCallChain() const {
    625   if ((sample_type & PERF_SAMPLE_CALLCHAIN) == 0) {
    626     return false;
    627   }
    628   bool in_user_context = !InKernel();
    629   for (size_t i = 0; i < callchain_data.ip_nr; ++i) {
    630     if (in_user_context && callchain_data.ips[i] < PERF_CONTEXT_MAX) {
    631       return true;
    632     }
    633     if (callchain_data.ips[i] == PERF_CONTEXT_USER) {
    634       in_user_context = true;
    635     }
    636   }
    637   return false;
    638 }
    639 
    640 void SampleRecord::UpdateUserCallChain(const std::vector<uint64_t>& user_ips) {
    641   std::vector<uint64_t> kernel_ips;
    642   for (size_t i = 0; i < callchain_data.ip_nr; ++i) {
    643     if (callchain_data.ips[i] == PERF_CONTEXT_USER) {
    644       break;
    645     }
    646     kernel_ips.push_back(callchain_data.ips[i]);
    647   }
    648   kernel_ips.push_back(PERF_CONTEXT_USER);
    649   size_t new_size = size() - callchain_data.ip_nr * sizeof(uint64_t) +
    650                     (kernel_ips.size() + user_ips.size()) * sizeof(uint64_t);
    651   if (new_size == size()) {
    652     return;
    653   }
    654   char* new_binary = new char[new_size];
    655   char* p = new_binary;
    656   SetSize(new_size);
    657   MoveToBinaryFormat(header, p);
    658   if (sample_type & PERF_SAMPLE_IDENTIFIER) {
    659     MoveToBinaryFormat(id_data, p);
    660   }
    661   if (sample_type & PERF_SAMPLE_IP) {
    662     MoveToBinaryFormat(ip_data, p);
    663   }
    664   if (sample_type & PERF_SAMPLE_TID) {
    665     MoveToBinaryFormat(tid_data, p);
    666   }
    667   if (sample_type & PERF_SAMPLE_TIME) {
    668     MoveToBinaryFormat(time_data, p);
    669   }
    670   if (sample_type & PERF_SAMPLE_ADDR) {
    671     MoveToBinaryFormat(addr_data, p);
    672   }
    673   if (sample_type & PERF_SAMPLE_ID) {
    674     MoveToBinaryFormat(id_data, p);
    675   }
    676   if (sample_type & PERF_SAMPLE_STREAM_ID) {
    677     MoveToBinaryFormat(stream_id_data, p);
    678   }
    679   if (sample_type & PERF_SAMPLE_CPU) {
    680     MoveToBinaryFormat(cpu_data, p);
    681   }
    682   if (sample_type & PERF_SAMPLE_PERIOD) {
    683     MoveToBinaryFormat(period_data, p);
    684   }
    685   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
    686     callchain_data.ip_nr = kernel_ips.size() + user_ips.size();
    687     MoveToBinaryFormat(callchain_data.ip_nr, p);
    688     callchain_data.ips = reinterpret_cast<uint64_t*>(p);
    689     MoveToBinaryFormat(kernel_ips.data(), kernel_ips.size(), p);
    690     MoveToBinaryFormat(user_ips.data(), user_ips.size(), p);
    691   }
    692   if (sample_type & PERF_SAMPLE_RAW) {
    693     MoveToBinaryFormat(raw_data.size, p);
    694     MoveToBinaryFormat(raw_data.data, raw_data.size, p);
    695     raw_data.data = p - raw_data.size;
    696   }
    697   if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
    698     MoveToBinaryFormat(branch_stack_data.stack_nr, p);
    699     char* old_p = p;
    700     MoveToBinaryFormat(branch_stack_data.stack, branch_stack_data.stack_nr, p);
    701     branch_stack_data.stack = reinterpret_cast<BranchStackItemType*>(old_p);
    702   }
    703   if (sample_type & PERF_SAMPLE_REGS_USER) {
    704     MoveToBinaryFormat(regs_user_data.abi, p);
    705     CHECK_EQ(regs_user_data.abi, 0u);
    706   }
    707   if (sample_type & PERF_SAMPLE_STACK_USER) {
    708     MoveToBinaryFormat(stack_user_data.size, p);
    709     CHECK_EQ(stack_user_data.size, 0u);
    710   }
    711   CHECK_EQ(p, new_binary + new_size) << "sample_type = " << std::hex << sample_type;
    712   UpdateBinary(new_binary);
    713 }
    714 
    715 // When simpleperf requests the kernel to dump 64K stack per sample, it will allocate 64K space in
    716 // each sample to store stack data. However, a thread may use less stack than 64K. So not all the
    717 // 64K stack data in a sample is valid. And this function is used to remove invalid stack data in
    718 // a sample, which can save time and disk space when storing samples in file.
    719 void SampleRecord::RemoveInvalidStackData() {
    720   if (sample_type & PERF_SAMPLE_STACK_USER) {
    721     uint64_t valid_stack_size = GetValidStackSize();
    722     if (stack_user_data.size > valid_stack_size) {
    723       // Shrink stack size to valid_stack_size, and update it in binary.
    724       stack_user_data.size = valid_stack_size;
    725       char* p = stack_user_data.data - sizeof(stack_user_data.size);
    726       MoveToBinaryFormat(stack_user_data.size, p);
    727       p += valid_stack_size;
    728       // Update dyn_size in binary.
    729       if (valid_stack_size != 0u) {
    730         MoveToBinaryFormat(stack_user_data.dyn_size, p);
    731       }
    732       // Update sample size.
    733       header.size = p - binary_;
    734       p = binary_;
    735       header.MoveToBinaryFormat(p);
    736     }
    737   }
    738 }
    739 
    740 void SampleRecord::DumpData(size_t indent) const {
    741   PrintIndented(indent, "sample_type: 0x%" PRIx64 "\n", sample_type);
    742   if (sample_type & PERF_SAMPLE_IP) {
    743     PrintIndented(indent, "ip %p\n", reinterpret_cast<void*>(ip_data.ip));
    744   }
    745   if (sample_type & PERF_SAMPLE_TID) {
    746     PrintIndented(indent, "pid %u, tid %u\n", tid_data.pid, tid_data.tid);
    747   }
    748   if (sample_type & PERF_SAMPLE_TIME) {
    749     PrintIndented(indent, "time %" PRId64 "\n", time_data.time);
    750   }
    751   if (sample_type & PERF_SAMPLE_ADDR) {
    752     PrintIndented(indent, "addr %p\n", reinterpret_cast<void*>(addr_data.addr));
    753   }
    754   if (sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
    755     PrintIndented(indent, "id %" PRId64 "\n", id_data.id);
    756   }
    757   if (sample_type & PERF_SAMPLE_STREAM_ID) {
    758     PrintIndented(indent, "stream_id %" PRId64 "\n", stream_id_data.stream_id);
    759   }
    760   if (sample_type & PERF_SAMPLE_CPU) {
    761     PrintIndented(indent, "cpu %u, res %u\n", cpu_data.cpu, cpu_data.res);
    762   }
    763   if (sample_type & PERF_SAMPLE_PERIOD) {
    764     PrintIndented(indent, "period %" PRId64 "\n", period_data.period);
    765   }
    766   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
    767     PrintIndented(indent, "callchain nr=%" PRIu64 "\n", callchain_data.ip_nr);
    768     for (uint64_t i = 0; i < callchain_data.ip_nr; ++i) {
    769       PrintIndented(indent + 1, "0x%" PRIx64 "\n", callchain_data.ips[i]);
    770     }
    771   }
    772   if (sample_type & PERF_SAMPLE_RAW) {
    773     PrintIndented(indent, "raw size=%zu\n", raw_data.size);
    774     const uint32_t* data = reinterpret_cast<const uint32_t*>(raw_data.data);
    775     size_t size = raw_data.size / sizeof(uint32_t);
    776     for (size_t i = 0; i < size; ++i) {
    777       PrintIndented(indent + 1, "0x%08x (%zu)\n", data[i], data[i]);
    778     }
    779   }
    780   if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
    781     PrintIndented(indent, "branch_stack nr=%" PRIu64 "\n",
    782                   branch_stack_data.stack_nr);
    783     for (uint64_t i = 0; i < branch_stack_data.stack_nr; ++i) {
    784       auto& item = branch_stack_data.stack[i];
    785       PrintIndented(indent + 1, "from 0x%" PRIx64 ", to 0x%" PRIx64
    786                                 ", flags 0x%" PRIx64 "\n",
    787                     item.from, item.to, item.flags);
    788     }
    789   }
    790   if (sample_type & PERF_SAMPLE_REGS_USER) {
    791     PrintIndented(indent, "user regs: abi=%" PRId64 "\n", regs_user_data.abi);
    792     for (size_t i = 0, pos = 0; i < 64; ++i) {
    793       if ((regs_user_data.reg_mask >> i) & 1) {
    794         PrintIndented(
    795             indent + 1, "reg (%s) 0x%016" PRIx64 "\n",
    796             GetRegName(i, ScopedCurrentArch::GetCurrentArch()).c_str(),
    797             regs_user_data.regs[pos++]);
    798       }
    799     }
    800   }
    801   if (sample_type & PERF_SAMPLE_STACK_USER) {
    802     PrintIndented(indent, "user stack: size %zu dyn_size %" PRIu64 "\n",
    803                   stack_user_data.size, stack_user_data.dyn_size);
    804     const uint64_t* p = reinterpret_cast<const uint64_t*>(stack_user_data.data);
    805     const uint64_t* end = p + (stack_user_data.size / sizeof(uint64_t));
    806     while (p < end) {
    807       PrintIndented(indent + 1, "");
    808       for (size_t i = 0; i < 4 && p < end; ++i, ++p) {
    809         printf(" %016" PRIx64, *p);
    810       }
    811       printf("\n");
    812     }
    813     printf("\n");
    814   }
    815 }
    816 
    817 uint64_t SampleRecord::Timestamp() const { return time_data.time; }
    818 uint32_t SampleRecord::Cpu() const { return cpu_data.cpu; }
    819 uint64_t SampleRecord::Id() const { return id_data.id; }
    820 
    821 void SampleRecord::AdjustCallChainGeneratedByKernel() {
    822   // The kernel stores return addrs in the callchain, but we want the addrs of call instructions
    823   // along the callchain.
    824   uint64_t* ips = callchain_data.ips;
    825   bool first_frame = true;
    826   for (uint64_t i = 0; i < callchain_data.ip_nr; ++i) {
    827     if (ips[i] > 0 && ips[i] < PERF_CONTEXT_MAX) {
    828       if (first_frame) {
    829         first_frame = false;
    830       } else {
    831         // Here we want to change the return addr to the addr of the previous instruction. We don't
    832         // need to find the exact start addr of the previous instruction. A location in
    833         // [start_addr_of_call_inst, start_addr_of_next_inst) is enough.
    834 #if defined(__arm__) || defined(__aarch64__)
    835         // If we are built for arm/aarch64, this may be a callchain of thumb code. For thumb code,
    836         // the real instruction addr is (ip & ~1), and ip - 2 can used to hit the address range
    837         // of the previous instruction. For non thumb code, any addr in [ip - 4, ip - 1] is fine.
    838         ips[i] -= 2;
    839 #else
    840         ips[i]--;
    841 #endif
    842       }
    843     }
    844   }
    845 }
    846 
    847 BuildIdRecord::BuildIdRecord(char* p) : Record(p) {
    848   const char* end = p + size();
    849   p += header_size();
    850   MoveFromBinaryFormat(pid, p);
    851   build_id = BuildId(p, BUILD_ID_SIZE);
    852   p += Align(build_id.Size(), 8);
    853   filename = p;
    854   p += Align(strlen(filename) + 1, 64);
    855   CHECK_EQ(p, end);
    856 }
    857 
    858 void BuildIdRecord::DumpData(size_t indent) const {
    859   PrintIndented(indent, "pid %u\n", pid);
    860   PrintIndented(indent, "build_id %s\n", build_id.ToString().c_str());
    861   PrintIndented(indent, "filename %s\n", filename);
    862 }
    863 
    864 BuildIdRecord::BuildIdRecord(bool in_kernel, pid_t pid, const BuildId& build_id,
    865                              const std::string& filename) {
    866   SetTypeAndMisc(PERF_RECORD_BUILD_ID,
    867                  in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER);
    868   this->pid = pid;
    869   this->build_id = build_id;
    870   SetSize(header_size() + sizeof(pid) + Align(build_id.Size(), 8) +
    871           Align(filename.size() + 1, 64));
    872   char* new_binary = new char[size()];
    873   char* p = new_binary;
    874   MoveToBinaryFormat(header, p);
    875   MoveToBinaryFormat(pid, p);
    876   memcpy(p, build_id.Data(), build_id.Size());
    877   p += Align(build_id.Size(), 8);
    878   this->filename = p;
    879   strcpy(p, filename.c_str());
    880   UpdateBinary(new_binary);
    881 }
    882 
    883 KernelSymbolRecord::KernelSymbolRecord(char* p) : Record(p) {
    884   const char* end = p + size();
    885   p += header_size();
    886   MoveFromBinaryFormat(kallsyms_size, p);
    887   kallsyms = p;
    888   p += Align(kallsyms_size, 8);
    889   CHECK_EQ(p, end);
    890 }
    891 
    892 void KernelSymbolRecord::DumpData(size_t indent) const {
    893   PrintIndented(indent, "kallsyms: %s\n",
    894                 std::string(kallsyms, kallsyms + kallsyms_size).c_str());
    895 }
    896 
    897 KernelSymbolRecord::KernelSymbolRecord(const std::string& kallsyms) {
    898   SetTypeAndMisc(SIMPLE_PERF_RECORD_KERNEL_SYMBOL, 0);
    899   kallsyms_size = kallsyms.size();
    900   SetSize(header_size() + 4 + Align(kallsyms.size(), 8));
    901   char* new_binary = new char[size()];
    902   char* p = new_binary;
    903   MoveToBinaryFormat(header, p);
    904   MoveToBinaryFormat(kallsyms_size, p);
    905   this->kallsyms = p;
    906   memcpy(p, kallsyms.data(), kallsyms_size);
    907   UpdateBinary(new_binary);
    908 }
    909 
    910 DsoRecord::DsoRecord(char* p) : Record(p) {
    911   const char* end = p + size();
    912   p += header_size();
    913   MoveFromBinaryFormat(dso_type, p);
    914   MoveFromBinaryFormat(dso_id, p);
    915   MoveFromBinaryFormat(min_vaddr, p);
    916   dso_name = p;
    917   p += Align(strlen(dso_name) + 1, 8);
    918   CHECK_EQ(p, end);
    919 }
    920 
    921 DsoRecord::DsoRecord(uint64_t dso_type, uint64_t dso_id,
    922                      const std::string& dso_name, uint64_t min_vaddr) {
    923   SetTypeAndMisc(SIMPLE_PERF_RECORD_DSO, 0);
    924   this->dso_type = dso_type;
    925   this->dso_id = dso_id;
    926   this->min_vaddr = min_vaddr;
    927   SetSize(header_size() + 3 * sizeof(uint64_t) + Align(dso_name.size() + 1, 8));
    928   char* new_binary = new char[size()];
    929   char* p = new_binary;
    930   MoveToBinaryFormat(header, p);
    931   MoveToBinaryFormat(dso_type, p);
    932   MoveToBinaryFormat(dso_id, p);
    933   MoveToBinaryFormat(min_vaddr, p);
    934   this->dso_name = p;
    935   strcpy(p, dso_name.c_str());
    936   UpdateBinary(new_binary);
    937 }
    938 
    939 void DsoRecord::DumpData(size_t indent) const {
    940   PrintIndented(indent, "dso_type: %s(%" PRIu64 ")\n",
    941                 DsoTypeToString(static_cast<DsoType>(dso_type)), dso_type);
    942   PrintIndented(indent, "dso_id: %" PRIu64 "\n", dso_id);
    943   PrintIndented(indent, "min_vaddr: 0x%" PRIx64 "\n", min_vaddr);
    944   PrintIndented(indent, "dso_name: %s\n", dso_name);
    945 }
    946 
    947 SymbolRecord::SymbolRecord(char* p) : Record(p) {
    948   const char* end = p + size();
    949   p += header_size();
    950   MoveFromBinaryFormat(addr, p);
    951   MoveFromBinaryFormat(len, p);
    952   MoveFromBinaryFormat(dso_id, p);
    953   name = p;
    954   p += Align(strlen(name) + 1, 8);
    955   CHECK_EQ(p, end);
    956 }
    957 
    958 SymbolRecord::SymbolRecord(uint64_t addr, uint64_t len, const std::string& name,
    959                            uint64_t dso_id) {
    960   SetTypeAndMisc(SIMPLE_PERF_RECORD_SYMBOL, 0);
    961   this->addr = addr;
    962   this->len = len;
    963   this->dso_id = dso_id;
    964   SetSize(header_size() + 3 * sizeof(uint64_t) + Align(name.size() + 1, 8));
    965   char* new_binary = new char[size()];
    966   char* p = new_binary;
    967   MoveToBinaryFormat(header, p);
    968   MoveToBinaryFormat(addr, p);
    969   MoveToBinaryFormat(len, p);
    970   MoveToBinaryFormat(dso_id, p);
    971   this->name = p;
    972   strcpy(p, name.c_str());
    973   UpdateBinary(new_binary);
    974 }
    975 
    976 void SymbolRecord::DumpData(size_t indent) const {
    977   PrintIndented(indent, "name: %s\n", name);
    978   PrintIndented(indent, "addr: 0x%" PRIx64 "\n", addr);
    979   PrintIndented(indent, "len: 0x%" PRIx64 "\n", len);
    980   PrintIndented(indent, "dso_id: %" PRIu64 "\n", dso_id);
    981 }
    982 
    983 TracingDataRecord::TracingDataRecord(char* p) : Record(p) {
    984   const char* end = p + size();
    985   p += header_size();
    986   MoveFromBinaryFormat(data_size, p);
    987   data = p;
    988   p += Align(data_size, 64);
    989   CHECK_EQ(p, end);
    990 }
    991 
    992 TracingDataRecord::TracingDataRecord(const std::vector<char>& tracing_data) {
    993   SetTypeAndMisc(PERF_RECORD_TRACING_DATA, 0);
    994   data_size = tracing_data.size();
    995   SetSize(header_size() + sizeof(uint32_t) + Align(tracing_data.size(), 64));
    996   char* new_binary = new char[size()];
    997   char* p = new_binary;
    998   MoveToBinaryFormat(header, p);
    999   MoveToBinaryFormat(data_size, p);
   1000   data = p;
   1001   memcpy(p, tracing_data.data(), data_size);
   1002   UpdateBinary(new_binary);
   1003 }
   1004 
   1005 void TracingDataRecord::DumpData(size_t indent) const {
   1006   Tracing tracing(std::vector<char>(data, data + data_size));
   1007   tracing.Dump(indent);
   1008 }
   1009 
   1010 EventIdRecord::EventIdRecord(char* p) : Record(p) {
   1011   const char* end = p + size();
   1012   p += header_size();
   1013   MoveFromBinaryFormat(count, p);
   1014   data = reinterpret_cast<const EventIdData*>(p);
   1015   p += sizeof(data[0]) * count;
   1016   CHECK_EQ(p, end);
   1017 }
   1018 
   1019 EventIdRecord::EventIdRecord(const std::vector<uint64_t>& data) {
   1020   SetTypeAndMisc(SIMPLE_PERF_RECORD_EVENT_ID, 0);
   1021   SetSize(header_size() + sizeof(uint64_t) * (1 + data.size()));
   1022   char* new_binary = new char[size()];
   1023   char* p = new_binary;
   1024   MoveToBinaryFormat(header, p);
   1025   count = data.size() / 2;
   1026   MoveToBinaryFormat(count, p);
   1027   this->data = reinterpret_cast<EventIdData*>(p);
   1028   memcpy(p, data.data(), sizeof(uint64_t) * data.size());
   1029   UpdateBinary(new_binary);
   1030 }
   1031 
   1032 void EventIdRecord::DumpData(size_t indent) const {
   1033   PrintIndented(indent, "count: %" PRIu64 "\n", count);
   1034   for (size_t i = 0; i < count; ++i) {
   1035     PrintIndented(indent, "attr_id[%" PRIu64 "]: %" PRIu64 "\n", i,
   1036                   data[i].attr_id);
   1037     PrintIndented(indent, "event_id[%" PRIu64 "]: %" PRIu64 "\n", i,
   1038                   data[i].event_id);
   1039   }
   1040 }
   1041 
   1042 CallChainRecord::CallChainRecord(char* p) : Record(p) {
   1043   const char* end = p + size();
   1044   p += header_size();
   1045   MoveFromBinaryFormat(pid, p);
   1046   MoveFromBinaryFormat(tid, p);
   1047   MoveFromBinaryFormat(chain_type, p);
   1048   MoveFromBinaryFormat(time, p);
   1049   MoveFromBinaryFormat(ip_nr, p);
   1050   ips = reinterpret_cast<uint64_t*>(p);
   1051   p += ip_nr * sizeof(uint64_t);
   1052   sps = reinterpret_cast<uint64_t*>(p);
   1053   p += ip_nr * sizeof(uint64_t);
   1054   CHECK_EQ(p, end);
   1055 }
   1056 
   1057 CallChainRecord::CallChainRecord(pid_t pid, pid_t tid, CallChainJoiner::ChainType type,
   1058                                  uint64_t time, const std::vector<uint64_t>& ips,
   1059                                  const std::vector<uint64_t>& sps) {
   1060   CHECK_EQ(ips.size(), sps.size());
   1061   SetTypeAndMisc(SIMPLE_PERF_RECORD_CALLCHAIN, 0);
   1062   this->pid = pid;
   1063   this->tid = tid;
   1064   this->chain_type = static_cast<int>(type);
   1065   this->time = time;
   1066   this->ip_nr = ips.size();
   1067   SetSize(header_size() + (4 + ips.size() * 2) * sizeof(uint64_t));
   1068   char* new_binary = new char[size()];
   1069   char* p = new_binary;
   1070   MoveToBinaryFormat(header, p);
   1071   MoveToBinaryFormat(this->pid, p);
   1072   MoveToBinaryFormat(this->tid, p);
   1073   MoveToBinaryFormat(this->chain_type, p);
   1074   MoveToBinaryFormat(this->time, p);
   1075   MoveToBinaryFormat(this->ip_nr, p);
   1076   this->ips = reinterpret_cast<uint64_t*>(p);
   1077   MoveToBinaryFormat(ips.data(), ips.size(), p);
   1078   this->sps = reinterpret_cast<uint64_t*>(p);
   1079   MoveToBinaryFormat(sps.data(), sps.size(), p);
   1080   UpdateBinary(new_binary);
   1081 }
   1082 
   1083 void CallChainRecord::DumpData(size_t indent) const {
   1084   const char* type_name = "";
   1085   switch (chain_type) {
   1086     case CallChainJoiner::ORIGINAL_OFFLINE: type_name = "ORIGINAL_OFFLINE"; break;
   1087     case CallChainJoiner::ORIGINAL_REMOTE: type_name = "ORIGINAL_REMOTE"; break;
   1088     case CallChainJoiner::JOINED_OFFLINE: type_name = "JOINED_OFFLINE"; break;
   1089     case CallChainJoiner::JOINED_REMOTE: type_name = "JOINED_REMOTE"; break;
   1090   }
   1091   PrintIndented(indent, "pid %u\n", pid);
   1092   PrintIndented(indent, "tid %u\n", tid);
   1093   PrintIndented(indent, "chain_type %s\n", type_name);
   1094   PrintIndented(indent, "time %" PRIu64 "\n", time);
   1095   PrintIndented(indent, "ip_nr %" PRIu64 "\n", ip_nr);
   1096   for (size_t i = 0; i < ip_nr; ++i) {
   1097     PrintIndented(indent + 1, "ip 0x%" PRIx64 ", sp 0x%" PRIx64 "\n", ips[i], sps[i]);
   1098   }
   1099 }
   1100 
   1101 UnwindingResultRecord::UnwindingResultRecord(char* p) : Record(p) {
   1102   const char* end = p + size();
   1103   p += header_size();
   1104   MoveFromBinaryFormat(time, p);
   1105   MoveFromBinaryFormat(unwinding_result.used_time, p);
   1106   uint64_t stop_reason;
   1107   MoveFromBinaryFormat(stop_reason, p);
   1108   unwinding_result.stop_reason = static_cast<decltype(unwinding_result.stop_reason)>(stop_reason);
   1109   MoveFromBinaryFormat(unwinding_result.stop_info, p);
   1110   MoveFromBinaryFormat(unwinding_result.stack_start, p);
   1111   MoveFromBinaryFormat(unwinding_result.stack_end, p);
   1112   CHECK_EQ(p, end);
   1113 }
   1114 
   1115 UnwindingResultRecord::UnwindingResultRecord(uint64_t time,
   1116                                              const UnwindingResult& unwinding_result) {
   1117   SetTypeAndMisc(SIMPLE_PERF_RECORD_UNWINDING_RESULT, 0);
   1118   SetSize(header_size() + 6 * sizeof(uint64_t));
   1119   this->time = time;
   1120   this->unwinding_result = unwinding_result;
   1121   char* new_binary = new char[size()];
   1122   char* p = new_binary;
   1123   MoveToBinaryFormat(header, p);
   1124   MoveToBinaryFormat(this->time, p);
   1125   MoveToBinaryFormat(unwinding_result.used_time, p);
   1126   uint64_t stop_reason = unwinding_result.stop_reason;
   1127   MoveToBinaryFormat(stop_reason, p);
   1128   MoveToBinaryFormat(unwinding_result.stop_info, p);
   1129   MoveToBinaryFormat(unwinding_result.stack_start, p);
   1130   MoveToBinaryFormat(unwinding_result.stack_end, p);
   1131   UpdateBinary(new_binary);
   1132 }
   1133 
   1134 void UnwindingResultRecord::DumpData(size_t indent) const {
   1135   PrintIndented(indent, "time %" PRIu64 "\n", time);
   1136   PrintIndented(indent, "used_time %" PRIu64 "\n", unwinding_result.used_time);
   1137   static std::unordered_map<int, std::string> map = {
   1138       {UnwindingResult::UNKNOWN_REASON, "UNKNOWN_REASON"},
   1139       {UnwindingResult::EXCEED_MAX_FRAMES_LIMIT, "EXCEED_MAX_FRAME_LIMIT"},
   1140       {UnwindingResult::ACCESS_REG_FAILED, "ACCESS_REG_FAILED"},
   1141       {UnwindingResult::ACCESS_STACK_FAILED, "ACCESS_STACK_FAILED"},
   1142       {UnwindingResult::ACCESS_MEM_FAILED, "ACCESS_MEM_FAILED"},
   1143       {UnwindingResult::FIND_PROC_INFO_FAILED, "FIND_PROC_INFO_FAILED"},
   1144       {UnwindingResult::EXECUTE_DWARF_INSTRUCTION_FAILED, "EXECUTE_DWARF_INSTRUCTION_FAILED"},
   1145       {UnwindingResult::DIFFERENT_ARCH, "DIFFERENT_ARCH"},
   1146       {UnwindingResult::MAP_MISSING, "MAP_MISSING"},
   1147   };
   1148   PrintIndented(indent, "stop_reason %s\n", map[unwinding_result.stop_reason].c_str());
   1149   if (unwinding_result.stop_reason == UnwindingResult::ACCESS_REG_FAILED) {
   1150     PrintIndented(indent, "regno %" PRIu64 "\n", unwinding_result.stop_info);
   1151   } else if (unwinding_result.stop_reason == UnwindingResult::ACCESS_STACK_FAILED ||
   1152              unwinding_result.stop_reason == UnwindingResult::ACCESS_MEM_FAILED) {
   1153     PrintIndented(indent, "addr 0x%" PRIx64 "\n", unwinding_result.stop_info);
   1154   }
   1155   PrintIndented(indent, "stack_start 0x%" PRIx64 "\n", unwinding_result.stack_start);
   1156   PrintIndented(indent, "stack_end 0x%" PRIx64 "\n", unwinding_result.stack_end);
   1157 }
   1158 
   1159 UnknownRecord::UnknownRecord(char* p) : Record(p) {
   1160   p += header_size();
   1161   data = p;
   1162 }
   1163 
   1164 void UnknownRecord::DumpData(size_t) const {}
   1165 
   1166 std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr, uint32_t type, char* p) {
   1167   switch (type) {
   1168     case PERF_RECORD_MMAP:
   1169       return std::unique_ptr<Record>(new MmapRecord(attr, p));
   1170     case PERF_RECORD_MMAP2:
   1171       return std::unique_ptr<Record>(new Mmap2Record(attr, p));
   1172     case PERF_RECORD_COMM:
   1173       return std::unique_ptr<Record>(new CommRecord(attr, p));
   1174     case PERF_RECORD_EXIT:
   1175       return std::unique_ptr<Record>(new ExitRecord(attr, p));
   1176     case PERF_RECORD_FORK:
   1177       return std::unique_ptr<Record>(new ForkRecord(attr, p));
   1178     case PERF_RECORD_LOST:
   1179       return std::unique_ptr<Record>(new LostRecord(attr, p));
   1180     case PERF_RECORD_SAMPLE:
   1181       return std::unique_ptr<Record>(new SampleRecord(attr, p));
   1182     case PERF_RECORD_TRACING_DATA:
   1183       return std::unique_ptr<Record>(new TracingDataRecord(p));
   1184     case SIMPLE_PERF_RECORD_KERNEL_SYMBOL:
   1185       return std::unique_ptr<Record>(new KernelSymbolRecord(p));
   1186     case SIMPLE_PERF_RECORD_DSO:
   1187       return std::unique_ptr<Record>(new DsoRecord(p));
   1188     case SIMPLE_PERF_RECORD_SYMBOL:
   1189       return std::unique_ptr<Record>(new SymbolRecord(p));
   1190     case SIMPLE_PERF_RECORD_EVENT_ID:
   1191       return std::unique_ptr<Record>(new EventIdRecord(p));
   1192     case SIMPLE_PERF_RECORD_CALLCHAIN:
   1193       return std::unique_ptr<Record>(new CallChainRecord(p));
   1194     case SIMPLE_PERF_RECORD_UNWINDING_RESULT:
   1195       return std::unique_ptr<Record>(new UnwindingResultRecord(p));
   1196     default:
   1197       return std::unique_ptr<Record>(new UnknownRecord(p));
   1198   }
   1199 }
   1200 
   1201 std::unique_ptr<Record> ReadRecordFromOwnedBuffer(const perf_event_attr& attr,
   1202                                                   uint32_t type, char* p) {
   1203   std::unique_ptr<Record> record = ReadRecordFromBuffer(attr, type, p);
   1204   if (record != nullptr) {
   1205     record->OwnBinary();
   1206   } else {
   1207     delete[] p;
   1208   }
   1209   return record;
   1210 }
   1211 
   1212 std::vector<std::unique_ptr<Record>> ReadRecordsFromBuffer(
   1213     const perf_event_attr& attr, char* buf, size_t buf_size) {
   1214   std::vector<std::unique_ptr<Record>> result;
   1215   char* p = buf;
   1216   char* end = buf + buf_size;
   1217   while (p < end) {
   1218     RecordHeader header(p);
   1219     CHECK_LE(p + header.size, end);
   1220     CHECK_NE(0u, header.size);
   1221     result.push_back(ReadRecordFromBuffer(attr, header.type, p));
   1222     p += header.size;
   1223   }
   1224   return result;
   1225 }
   1226 
   1227 std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr, char* p) {
   1228   auto header = reinterpret_cast<const perf_event_header*>(p);
   1229   return ReadRecordFromBuffer(attr, header->type, p);
   1230 }
   1231 
   1232 bool RecordCache::RecordWithSeq::IsHappensBefore(
   1233     const RecordWithSeq& other) const {
   1234   bool is_sample = (record->type() == PERF_RECORD_SAMPLE);
   1235   bool is_other_sample = (other.record->type() == PERF_RECORD_SAMPLE);
   1236   uint64_t time = record->Timestamp();
   1237   uint64_t other_time = other.record->Timestamp();
   1238   // The record with smaller time happens first.
   1239   if (time != other_time) {
   1240     return time < other_time;
   1241   }
   1242   // If happening at the same time, make non-sample records before sample
   1243   // records, because non-sample records may contain useful information to
   1244   // parse sample records.
   1245   if (is_sample != is_other_sample) {
   1246     return is_sample ? false : true;
   1247   }
   1248   // Otherwise, use the same order as they enter the cache.
   1249   return seq < other.seq;
   1250 }
   1251 
   1252 bool RecordCache::RecordComparator::operator()(const RecordWithSeq& r1,
   1253                                                const RecordWithSeq& r2) {
   1254   return r2.IsHappensBefore(r1);
   1255 }
   1256 
   1257 RecordCache::RecordCache(bool has_timestamp, size_t min_cache_size,
   1258                          uint64_t min_time_diff_in_ns)
   1259     : has_timestamp_(has_timestamp),
   1260       min_cache_size_(min_cache_size),
   1261       min_time_diff_in_ns_(min_time_diff_in_ns),
   1262       last_time_(0),
   1263       cur_seq_(0),
   1264       queue_(RecordComparator()) {}
   1265 
   1266 RecordCache::~RecordCache() { PopAll(); }
   1267 
   1268 void RecordCache::Push(std::unique_ptr<Record> record) {
   1269   if (has_timestamp_) {
   1270     last_time_ = std::max(last_time_, record->Timestamp());
   1271   }
   1272   queue_.push(RecordWithSeq(cur_seq_++, record.release()));
   1273 }
   1274 
   1275 void RecordCache::Push(std::vector<std::unique_ptr<Record>> records) {
   1276   for (auto& r : records) {
   1277     Push(std::move(r));
   1278   }
   1279 }
   1280 
   1281 std::unique_ptr<Record> RecordCache::Pop() {
   1282   if (queue_.size() < min_cache_size_) {
   1283     return nullptr;
   1284   }
   1285   Record* r = queue_.top().record;
   1286   if (has_timestamp_) {
   1287     if (r->Timestamp() + min_time_diff_in_ns_ > last_time_) {
   1288       return nullptr;
   1289     }
   1290   }
   1291   queue_.pop();
   1292   return std::unique_ptr<Record>(r);
   1293 }
   1294 
   1295 std::vector<std::unique_ptr<Record>> RecordCache::PopAll() {
   1296   std::vector<std::unique_ptr<Record>> result;
   1297   while (!queue_.empty()) {
   1298     result.emplace_back(queue_.top().record);
   1299     queue_.pop();
   1300   }
   1301   return result;
   1302 }
   1303 
   1304 std::unique_ptr<Record> RecordCache::ForcedPop() {
   1305   if (queue_.empty()) {
   1306     return nullptr;
   1307   }
   1308   Record* r = queue_.top().record;
   1309   queue_.pop();
   1310   return std::unique_ptr<Record>(r);
   1311 }
   1312