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 "perf_regs.h"
     28 #include "tracing.h"
     29 #include "utils.h"
     30 
     31 static std::string RecordTypeToString(int record_type) {
     32   static std::unordered_map<int, std::string> record_type_names = {
     33       {PERF_RECORD_MMAP, "mmap"},
     34       {PERF_RECORD_LOST, "lost"},
     35       {PERF_RECORD_COMM, "comm"},
     36       {PERF_RECORD_EXIT, "exit"},
     37       {PERF_RECORD_THROTTLE, "throttle"},
     38       {PERF_RECORD_UNTHROTTLE, "unthrottle"},
     39       {PERF_RECORD_FORK, "fork"},
     40       {PERF_RECORD_READ, "read"},
     41       {PERF_RECORD_SAMPLE, "sample"},
     42       {PERF_RECORD_BUILD_ID, "build_id"},
     43       {PERF_RECORD_MMAP2, "mmap2"},
     44       {PERF_RECORD_TRACING_DATA, "tracing_data"},
     45       {SIMPLE_PERF_RECORD_KERNEL_SYMBOL, "kernel_symbol"},
     46       {SIMPLE_PERF_RECORD_DSO, "dso"},
     47       {SIMPLE_PERF_RECORD_SYMBOL, "symbol"},
     48       {SIMPLE_PERF_RECORD_EVENT_ID, "event_id"},
     49   };
     50 
     51   auto it = record_type_names.find(record_type);
     52   if (it != record_type_names.end()) {
     53     return it->second;
     54   }
     55   return android::base::StringPrintf("unknown(%d)", record_type);
     56 }
     57 
     58 template <>
     59 void MoveToBinaryFormat(const RecordHeader& data, char*& p) {
     60   data.MoveToBinaryFormat(p);
     61 }
     62 
     63 SampleId::SampleId() { memset(this, 0, sizeof(SampleId)); }
     64 
     65 // Return sample_id size in binary format.
     66 size_t SampleId::CreateContent(const perf_event_attr& attr, uint64_t event_id) {
     67   sample_id_all = attr.sample_id_all;
     68   sample_type = attr.sample_type;
     69   id_data.id = event_id;
     70   // Other data are not necessary. TODO: Set missing SampleId data.
     71   return Size();
     72 }
     73 
     74 void SampleId::ReadFromBinaryFormat(const perf_event_attr& attr, const char* p,
     75                                     const char* end) {
     76   sample_id_all = attr.sample_id_all;
     77   sample_type = attr.sample_type;
     78   if (sample_id_all) {
     79     if (sample_type & PERF_SAMPLE_TID) {
     80       MoveFromBinaryFormat(tid_data, p);
     81     }
     82     if (sample_type & PERF_SAMPLE_TIME) {
     83       MoveFromBinaryFormat(time_data, p);
     84     }
     85     if (sample_type & PERF_SAMPLE_ID) {
     86       MoveFromBinaryFormat(id_data, p);
     87     }
     88     if (sample_type & PERF_SAMPLE_STREAM_ID) {
     89       MoveFromBinaryFormat(stream_id_data, p);
     90     }
     91     if (sample_type & PERF_SAMPLE_CPU) {
     92       MoveFromBinaryFormat(cpu_data, p);
     93     }
     94     if (sample_type & PERF_SAMPLE_IDENTIFIER) {
     95       MoveFromBinaryFormat(id_data, p);
     96     }
     97   }
     98   CHECK_LE(p, end);
     99   if (p < end) {
    100     LOG(DEBUG) << "Record SampleId part has " << end - p << " bytes left\n";
    101   }
    102 }
    103 
    104 void SampleId::WriteToBinaryFormat(char*& p) const {
    105   if (sample_id_all) {
    106     if (sample_type & PERF_SAMPLE_TID) {
    107       MoveToBinaryFormat(tid_data, p);
    108     }
    109     if (sample_type & PERF_SAMPLE_TIME) {
    110       MoveToBinaryFormat(time_data, p);
    111     }
    112     if (sample_type & PERF_SAMPLE_ID) {
    113       MoveToBinaryFormat(id_data, p);
    114     }
    115     if (sample_type & PERF_SAMPLE_STREAM_ID) {
    116       MoveToBinaryFormat(stream_id_data, p);
    117     }
    118     if (sample_type & PERF_SAMPLE_CPU) {
    119       MoveToBinaryFormat(cpu_data, p);
    120     }
    121   }
    122 }
    123 
    124 void SampleId::Dump(size_t indent) const {
    125   if (sample_id_all) {
    126     if (sample_type & PERF_SAMPLE_TID) {
    127       PrintIndented(indent, "sample_id: pid %u, tid %u\n", tid_data.pid,
    128                     tid_data.tid);
    129     }
    130     if (sample_type & PERF_SAMPLE_TIME) {
    131       PrintIndented(indent, "sample_id: time %" PRId64 "\n", time_data.time);
    132     }
    133     if (sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
    134       PrintIndented(indent, "sample_id: id %" PRId64 "\n", id_data.id);
    135     }
    136     if (sample_type & PERF_SAMPLE_STREAM_ID) {
    137       PrintIndented(indent, "sample_id: stream_id %" PRId64 "\n",
    138                     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,
    142                     cpu_data.res);
    143     }
    144   }
    145 }
    146 
    147 size_t SampleId::Size() const {
    148   size_t size = 0;
    149   if (sample_id_all) {
    150     if (sample_type & PERF_SAMPLE_TID) {
    151       size += sizeof(PerfSampleTidType);
    152     }
    153     if (sample_type & PERF_SAMPLE_TIME) {
    154       size += sizeof(PerfSampleTimeType);
    155     }
    156     if (sample_type & PERF_SAMPLE_ID) {
    157       size += sizeof(PerfSampleIdType);
    158     }
    159     if (sample_type & PERF_SAMPLE_STREAM_ID) {
    160       size += sizeof(PerfSampleStreamIdType);
    161     }
    162     if (sample_type & PERF_SAMPLE_CPU) {
    163       size += sizeof(PerfSampleCpuType);
    164     }
    165     if (sample_type & PERF_SAMPLE_IDENTIFIER) {
    166       size += sizeof(PerfSampleIdType);
    167     }
    168   }
    169   return size;
    170 }
    171 
    172 Record::Record(Record&& other) {
    173   header = other.header;
    174   sample_id = other.sample_id;
    175   binary_ = other.binary_;
    176   own_binary_ = other.own_binary_;
    177   other.binary_ = nullptr;
    178   other.own_binary_ = false;
    179 }
    180 
    181 void Record::Dump(size_t indent) const {
    182   PrintIndented(indent, "record %s: type %u, misc %u, size %u\n",
    183                 RecordTypeToString(type()).c_str(), type(), misc(), size());
    184   DumpData(indent + 1);
    185   sample_id.Dump(indent + 1);
    186 }
    187 
    188 uint64_t Record::Timestamp() const { return sample_id.time_data.time; }
    189 uint32_t Record::Cpu() const { return sample_id.cpu_data.cpu; }
    190 uint64_t Record::Id() const { return sample_id.id_data.id; }
    191 
    192 void Record::UpdateBinary(const char* new_binary) {
    193   if (own_binary_) {
    194     delete[] binary_;
    195   }
    196   own_binary_ = true;
    197   binary_ = new_binary;
    198 }
    199 
    200 MmapRecord::MmapRecord(const perf_event_attr& attr, const char* p) : Record(p) {
    201   const char* end = p + size();
    202   p += header_size();
    203   data = reinterpret_cast<const MmapRecordDataType*>(p);
    204   p += sizeof(*data);
    205   filename = p;
    206   p += Align(strlen(filename) + 1, 8);
    207   CHECK_LE(p, end);
    208   sample_id.ReadFromBinaryFormat(attr, p, end);
    209 }
    210 
    211 MmapRecord::MmapRecord(const perf_event_attr& attr, bool in_kernel,
    212                        uint32_t pid, uint32_t tid, uint64_t addr, uint64_t len,
    213                        uint64_t pgoff, const std::string& filename,
    214                        uint64_t event_id, uint64_t time) {
    215   SetTypeAndMisc(PERF_RECORD_MMAP,
    216                  in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER);
    217   sample_id.CreateContent(attr, event_id);
    218   sample_id.time_data.time = time;
    219   MmapRecordDataType data;
    220   data.pid = pid;
    221   data.tid = tid;
    222   data.addr = addr;
    223   data.len = len;
    224   data.pgoff = pgoff;
    225   SetDataAndFilename(data, filename);
    226 }
    227 
    228 void MmapRecord::SetDataAndFilename(const MmapRecordDataType& data,
    229                                     const std::string& filename) {
    230   SetSize(header_size() + sizeof(data) + Align(filename.size() + 1, 8) +
    231           sample_id.Size());
    232   char* new_binary = new char[size()];
    233   char* p = new_binary;
    234   MoveToBinaryFormat(header, p);
    235   this->data = reinterpret_cast<MmapRecordDataType*>(p);
    236   MoveToBinaryFormat(data, p);
    237   this->filename = p;
    238   strcpy(p, filename.c_str());
    239   p += Align(filename.size() + 1, 8);
    240   sample_id.WriteToBinaryFormat(p);
    241   UpdateBinary(new_binary);
    242 }
    243 
    244 void MmapRecord::DumpData(size_t indent) const {
    245   PrintIndented(indent,
    246                 "pid %u, tid %u, addr 0x%" PRIx64 ", len 0x%" PRIx64 "\n",
    247                 data->pid, data->tid, data->addr, data->len);
    248   PrintIndented(indent, "pgoff 0x%" PRIx64 ", filename %s\n", data->pgoff,
    249                 filename);
    250 }
    251 
    252 Mmap2Record::Mmap2Record(const perf_event_attr& attr, const char* p)
    253     : Record(p) {
    254   const char* end = p + size();
    255   p += header_size();
    256   data = reinterpret_cast<const Mmap2RecordDataType*>(p);
    257   p += sizeof(*data);
    258   filename = p;
    259   p += Align(strlen(filename) + 1, 8);
    260   CHECK_LE(p, end);
    261   sample_id.ReadFromBinaryFormat(attr, p, end);
    262 }
    263 
    264 void Mmap2Record::SetDataAndFilename(const Mmap2RecordDataType& data,
    265                                      const std::string& filename) {
    266   SetSize(header_size() + sizeof(data) + Align(filename.size() + 1, 8) +
    267           sample_id.Size());
    268   char* new_binary = new char[size()];
    269   char* p = new_binary;
    270   MoveToBinaryFormat(header, p);
    271   this->data = reinterpret_cast<Mmap2RecordDataType*>(p);
    272   MoveToBinaryFormat(data, p);
    273   this->filename = p;
    274   strcpy(p, filename.c_str());
    275   p += Align(filename.size() + 1, 8);
    276   sample_id.WriteToBinaryFormat(p);
    277   UpdateBinary(new_binary);
    278 }
    279 
    280 void Mmap2Record::DumpData(size_t indent) const {
    281   PrintIndented(indent,
    282                 "pid %u, tid %u, addr 0x%" PRIx64 ", len 0x%" PRIx64 "\n",
    283                 data->pid, data->tid, data->addr, data->len);
    284   PrintIndented(indent, "pgoff 0x" PRIx64 ", maj %u, min %u, ino %" PRId64
    285                         ", ino_generation %" PRIu64 "\n",
    286                 data->pgoff, data->maj, data->min, data->ino,
    287                 data->ino_generation);
    288   PrintIndented(indent, "prot %u, flags %u, filenames %s\n", data->prot,
    289                 data->flags, filename);
    290 }
    291 
    292 CommRecord::CommRecord(const perf_event_attr& attr, const char* p) : Record(p) {
    293   const char* end = p + size();
    294   p += header_size();
    295   data = reinterpret_cast<const CommRecordDataType*>(p);
    296   p += sizeof(*data);
    297   comm = p;
    298   p += Align(strlen(p) + 1, 8);
    299   CHECK_LE(p, end);
    300   sample_id.ReadFromBinaryFormat(attr, p, end);
    301 }
    302 
    303 CommRecord::CommRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid,
    304                        const std::string& comm, uint64_t event_id, uint64_t time) {
    305   SetTypeAndMisc(PERF_RECORD_COMM, 0);
    306   CommRecordDataType data;
    307   data.pid = pid;
    308   data.tid = tid;
    309   size_t sample_id_size = sample_id.CreateContent(attr, event_id);
    310   sample_id.time_data.time = time;
    311   SetSize(header_size() + sizeof(data) + Align(comm.size() + 1, 8) +
    312           sample_id_size);
    313   char* new_binary = new char[size()];
    314   char* p = new_binary;
    315   MoveToBinaryFormat(header, p);
    316   this->data = reinterpret_cast<CommRecordDataType*>(p);
    317   MoveToBinaryFormat(data, p);
    318   this->comm = p;
    319   strcpy(p, comm.c_str());
    320   p += Align(comm.size() + 1, 8);
    321   sample_id.WriteToBinaryFormat(p);
    322   UpdateBinary(new_binary);
    323 }
    324 
    325 void CommRecord::DumpData(size_t indent) const {
    326   PrintIndented(indent, "pid %u, tid %u, comm %s\n", data->pid, data->tid,
    327                 comm);
    328 }
    329 
    330 ExitOrForkRecord::ExitOrForkRecord(const perf_event_attr& attr, const char* p)
    331     : Record(p) {
    332   const char* end = p + size();
    333   p += header_size();
    334   data = reinterpret_cast<const ExitOrForkRecordDataType*>(p);
    335   p += sizeof(*data);
    336   CHECK_LE(p, end);
    337   sample_id.ReadFromBinaryFormat(attr, p, end);
    338 }
    339 
    340 void ExitOrForkRecord::DumpData(size_t indent) const {
    341   PrintIndented(indent, "pid %u, ppid %u, tid %u, ptid %u\n", data->pid,
    342                 data->ppid, data->tid, data->ptid);
    343 }
    344 
    345 ForkRecord::ForkRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid,
    346                        uint32_t ppid, uint32_t ptid, uint64_t event_id) {
    347   SetTypeAndMisc(PERF_RECORD_FORK, 0);
    348   ExitOrForkRecordDataType data;
    349   data.pid = pid;
    350   data.ppid = ppid;
    351   data.tid = tid;
    352   data.ptid = ptid;
    353   data.time = 0;
    354   size_t sample_id_size = sample_id.CreateContent(attr, event_id);
    355   SetSize(header_size() + sizeof(data) + sample_id_size);
    356   char* new_binary = new char[size()];
    357   char* p = new_binary;
    358   MoveToBinaryFormat(header, p);
    359   this->data = reinterpret_cast<ExitOrForkRecordDataType*>(p);
    360   MoveToBinaryFormat(data, p);
    361   sample_id.WriteToBinaryFormat(p);
    362   UpdateBinary(new_binary);
    363 }
    364 
    365 LostRecord::LostRecord(const perf_event_attr& attr, const char* p) : Record(p) {
    366   const char* end = p + size();
    367   p += header_size();
    368   MoveFromBinaryFormat(id, p);
    369   MoveFromBinaryFormat(lost, p);
    370   CHECK_LE(p, end);
    371   sample_id.ReadFromBinaryFormat(attr, p, end);
    372 }
    373 
    374 void LostRecord::DumpData(size_t indent) const {
    375   PrintIndented(indent, "id %" PRIu64 ", lost %" PRIu64 "\n", id, lost);
    376 }
    377 
    378 SampleRecord::SampleRecord(const perf_event_attr& attr, const char* p)
    379     : Record(p) {
    380   const char* end = p + size();
    381   p += header_size();
    382   sample_type = attr.sample_type;
    383 
    384   // Set a default id value to report correctly even if ID is not recorded.
    385   id_data.id = 0;
    386   if (sample_type & PERF_SAMPLE_IDENTIFIER) {
    387     MoveFromBinaryFormat(id_data, p);
    388   }
    389   if (sample_type & PERF_SAMPLE_IP) {
    390     MoveFromBinaryFormat(ip_data, p);
    391   }
    392   if (sample_type & PERF_SAMPLE_TID) {
    393     MoveFromBinaryFormat(tid_data, p);
    394   }
    395   if (sample_type & PERF_SAMPLE_TIME) {
    396     MoveFromBinaryFormat(time_data, p);
    397   }
    398   if (sample_type & PERF_SAMPLE_ADDR) {
    399     MoveFromBinaryFormat(addr_data, p);
    400   }
    401   if (sample_type & PERF_SAMPLE_ID) {
    402     MoveFromBinaryFormat(id_data, p);
    403   }
    404   if (sample_type & PERF_SAMPLE_STREAM_ID) {
    405     MoveFromBinaryFormat(stream_id_data, p);
    406   }
    407   if (sample_type & PERF_SAMPLE_CPU) {
    408     MoveFromBinaryFormat(cpu_data, p);
    409   }
    410   if (sample_type & PERF_SAMPLE_PERIOD) {
    411     MoveFromBinaryFormat(period_data, p);
    412   }
    413   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
    414     MoveFromBinaryFormat(callchain_data.ip_nr, p);
    415     callchain_data.ips = reinterpret_cast<const uint64_t*>(p);
    416     p += callchain_data.ip_nr * sizeof(uint64_t);
    417   }
    418   if (sample_type & PERF_SAMPLE_RAW) {
    419     MoveFromBinaryFormat(raw_data.size, p);
    420     raw_data.data = p;
    421     p += raw_data.size;
    422   }
    423   if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
    424     MoveFromBinaryFormat(branch_stack_data.stack_nr, p);
    425     branch_stack_data.stack = reinterpret_cast<const BranchStackItemType*>(p);
    426     p += branch_stack_data.stack_nr * sizeof(BranchStackItemType);
    427   }
    428   if (sample_type & PERF_SAMPLE_REGS_USER) {
    429     MoveFromBinaryFormat(regs_user_data.abi, p);
    430     if (regs_user_data.abi == 0) {
    431       regs_user_data.reg_mask = 0;
    432     } else {
    433       regs_user_data.reg_mask = attr.sample_regs_user;
    434       size_t bit_nr = 0;
    435       for (size_t i = 0; i < 64; ++i) {
    436         if ((regs_user_data.reg_mask >> i) & 1) {
    437           bit_nr++;
    438         }
    439       }
    440       regs_user_data.reg_nr = bit_nr;
    441       regs_user_data.regs = reinterpret_cast<const uint64_t*>(p);
    442       p += bit_nr * sizeof(uint64_t);
    443     }
    444   }
    445   if (sample_type & PERF_SAMPLE_STACK_USER) {
    446     MoveFromBinaryFormat(stack_user_data.size, p);
    447     if (stack_user_data.size == 0) {
    448       stack_user_data.dyn_size = 0;
    449     } else {
    450       stack_user_data.data = p;
    451       p += stack_user_data.size;
    452       MoveFromBinaryFormat(stack_user_data.dyn_size, p);
    453     }
    454   }
    455   // TODO: Add parsing of other PERF_SAMPLE_*.
    456   CHECK_LE(p, end);
    457   if (p < end) {
    458     LOG(DEBUG) << "Record has " << end - p << " bytes left\n";
    459   }
    460 }
    461 
    462 SampleRecord::SampleRecord(const perf_event_attr& attr, uint64_t id,
    463                            uint64_t ip, uint32_t pid, uint32_t tid,
    464                            uint64_t time, uint32_t cpu, uint64_t period,
    465                            const std::vector<uint64_t>& ips) {
    466   SetTypeAndMisc(PERF_RECORD_SAMPLE, PERF_RECORD_MISC_USER);
    467   sample_type = attr.sample_type;
    468   CHECK_EQ(0u, sample_type & ~(PERF_SAMPLE_IP | PERF_SAMPLE_TID
    469       | PERF_SAMPLE_TIME | PERF_SAMPLE_ID | PERF_SAMPLE_CPU
    470       | PERF_SAMPLE_PERIOD | PERF_SAMPLE_CALLCHAIN | PERF_SAMPLE_REGS_USER
    471       | PERF_SAMPLE_STACK_USER));
    472   ip_data.ip = ip;
    473   tid_data.pid = pid;
    474   tid_data.tid = tid;
    475   time_data.time = time;
    476   id_data.id = id;
    477   cpu_data.cpu = cpu;
    478   cpu_data.res = 0;
    479   period_data.period = period;
    480   callchain_data.ip_nr = ips.size();
    481   raw_data.size = 0;
    482   branch_stack_data.stack_nr = 0;
    483   regs_user_data.abi = 0;
    484   regs_user_data.reg_mask = 0;
    485   stack_user_data.size = 0;
    486 
    487   uint32_t size = header_size();
    488   if (sample_type & PERF_SAMPLE_IP) {
    489     size += sizeof(ip_data);
    490   }
    491   if (sample_type & PERF_SAMPLE_TID) {
    492     size += sizeof(tid_data);
    493   }
    494   if (sample_type & PERF_SAMPLE_TIME) {
    495     size += sizeof(time_data);
    496   }
    497   if (sample_type & PERF_SAMPLE_ID) {
    498     size += sizeof(id_data);
    499   }
    500   if (sample_type & PERF_SAMPLE_CPU) {
    501     size += sizeof(cpu_data);
    502   }
    503   if (sample_type & PERF_SAMPLE_PERIOD) {
    504     size += sizeof(period_data);
    505   }
    506   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
    507     size += sizeof(uint64_t) * (ips.size() + 1);
    508   }
    509   if (sample_type & PERF_SAMPLE_REGS_USER) {
    510     size += sizeof(uint64_t);
    511   }
    512   if (sample_type & PERF_SAMPLE_STACK_USER) {
    513     size += sizeof(uint64_t);
    514   }
    515 
    516   SetSize(size);
    517   char* new_binary = new char[size];
    518   char* p = new_binary;
    519   MoveToBinaryFormat(header, p);
    520   if (sample_type & PERF_SAMPLE_IP) {
    521     MoveToBinaryFormat(ip_data, p);
    522   }
    523   if (sample_type & PERF_SAMPLE_TID) {
    524     MoveToBinaryFormat(tid_data, p);
    525   }
    526   if (sample_type & PERF_SAMPLE_TIME) {
    527     MoveToBinaryFormat(time_data, p);
    528   }
    529   if (sample_type & PERF_SAMPLE_ID) {
    530     MoveToBinaryFormat(id_data, p);
    531   }
    532   if (sample_type & PERF_SAMPLE_CPU) {
    533     MoveToBinaryFormat(cpu_data, p);
    534   }
    535   if (sample_type & PERF_SAMPLE_PERIOD) {
    536     MoveToBinaryFormat(period_data, p);
    537   }
    538   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
    539     MoveToBinaryFormat(callchain_data.ip_nr, p);
    540     callchain_data.ips = reinterpret_cast<uint64_t*>(p);
    541     MoveToBinaryFormat(ips.data(), ips.size(), p);
    542   }
    543   if (sample_type & PERF_SAMPLE_REGS_USER) {
    544     MoveToBinaryFormat(regs_user_data.abi, p);
    545   }
    546   if (sample_type & PERF_SAMPLE_STACK_USER) {
    547     MoveToBinaryFormat(stack_user_data.size, p);
    548   }
    549   CHECK_EQ(p, new_binary + size);
    550   UpdateBinary(new_binary);
    551 }
    552 
    553 void SampleRecord::ReplaceRegAndStackWithCallChain(
    554     const std::vector<uint64_t>& ips) {
    555   uint32_t size_added_in_callchain = sizeof(uint64_t) * (ips.size() + 1);
    556   uint32_t size_reduced_in_reg_stack =
    557       regs_user_data.reg_nr * sizeof(uint64_t) + stack_user_data.size +
    558       sizeof(uint64_t);
    559   CHECK_LE(size_added_in_callchain, size_reduced_in_reg_stack);
    560   uint32_t size_reduced = size_reduced_in_reg_stack - size_added_in_callchain;
    561   SetSize(size() - size_reduced);
    562   char* p = const_cast<char*>(binary_);
    563   MoveToBinaryFormat(header, p);
    564   p = const_cast<char*>(stack_user_data.data + stack_user_data.size +
    565                         sizeof(uint64_t)) -
    566       (size_reduced_in_reg_stack - size_added_in_callchain);
    567   stack_user_data.size = 0;
    568   regs_user_data.abi = 0;
    569   p -= sizeof(uint64_t);
    570   *reinterpret_cast<uint64_t*>(p) = stack_user_data.size;
    571   p -= sizeof(uint64_t);
    572   *reinterpret_cast<uint64_t*>(p) = regs_user_data.abi;
    573   if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
    574     p -= branch_stack_data.stack_nr * sizeof(BranchStackItemType);
    575     memmove(p, branch_stack_data.stack,
    576             branch_stack_data.stack_nr * sizeof(BranchStackItemType));
    577     p -= sizeof(uint64_t);
    578     *reinterpret_cast<uint64_t*>(p) = branch_stack_data.stack_nr;
    579   }
    580   if (sample_type & PERF_SAMPLE_RAW) {
    581     p -= raw_data.size;
    582     memmove(p, raw_data.data, raw_data.size);
    583     p -= sizeof(uint32_t);
    584     *reinterpret_cast<uint32_t*>(p) = raw_data.size;
    585   }
    586   p -= ips.size() * sizeof(uint64_t);
    587   memcpy(p, ips.data(), ips.size() * sizeof(uint64_t));
    588   p -= sizeof(uint64_t);
    589   *reinterpret_cast<uint64_t*>(p) = PERF_CONTEXT_USER;
    590   p -= sizeof(uint64_t) * (callchain_data.ip_nr);
    591   callchain_data.ips = reinterpret_cast<uint64_t*>(p);
    592   callchain_data.ip_nr += ips.size() + 1;
    593   p -= sizeof(uint64_t);
    594   *reinterpret_cast<uint64_t*>(p) = callchain_data.ip_nr;
    595 }
    596 
    597 void SampleRecord::DumpData(size_t indent) const {
    598   PrintIndented(indent, "sample_type: 0x%" PRIx64 "\n", sample_type);
    599   if (sample_type & PERF_SAMPLE_IP) {
    600     PrintIndented(indent, "ip %p\n", reinterpret_cast<void*>(ip_data.ip));
    601   }
    602   if (sample_type & PERF_SAMPLE_TID) {
    603     PrintIndented(indent, "pid %u, tid %u\n", tid_data.pid, tid_data.tid);
    604   }
    605   if (sample_type & PERF_SAMPLE_TIME) {
    606     PrintIndented(indent, "time %" PRId64 "\n", time_data.time);
    607   }
    608   if (sample_type & PERF_SAMPLE_ADDR) {
    609     PrintIndented(indent, "addr %p\n", reinterpret_cast<void*>(addr_data.addr));
    610   }
    611   if (sample_type & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) {
    612     PrintIndented(indent, "id %" PRId64 "\n", id_data.id);
    613   }
    614   if (sample_type & PERF_SAMPLE_STREAM_ID) {
    615     PrintIndented(indent, "stream_id %" PRId64 "\n", stream_id_data.stream_id);
    616   }
    617   if (sample_type & PERF_SAMPLE_CPU) {
    618     PrintIndented(indent, "cpu %u, res %u\n", cpu_data.cpu, cpu_data.res);
    619   }
    620   if (sample_type & PERF_SAMPLE_PERIOD) {
    621     PrintIndented(indent, "period %" PRId64 "\n", period_data.period);
    622   }
    623   if (sample_type & PERF_SAMPLE_CALLCHAIN) {
    624     PrintIndented(indent, "callchain nr=%" PRIu64 "\n", callchain_data.ip_nr);
    625     for (uint64_t i = 0; i < callchain_data.ip_nr; ++i) {
    626       PrintIndented(indent + 1, "0x%" PRIx64 "\n", callchain_data.ips[i]);
    627     }
    628   }
    629   if (sample_type & PERF_SAMPLE_RAW) {
    630     PrintIndented(indent, "raw size=%zu\n", raw_data.size);
    631     const uint32_t* data = reinterpret_cast<const uint32_t*>(raw_data.data);
    632     size_t size = raw_data.size / sizeof(uint32_t);
    633     for (size_t i = 0; i < size; ++i) {
    634       PrintIndented(indent + 1, "0x%08x (%zu)\n", data[i], data[i]);
    635     }
    636   }
    637   if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
    638     PrintIndented(indent, "branch_stack nr=%" PRIu64 "\n",
    639                   branch_stack_data.stack_nr);
    640     for (uint64_t i = 0; i < branch_stack_data.stack_nr; ++i) {
    641       auto& item = branch_stack_data.stack[i];
    642       PrintIndented(indent + 1, "from 0x%" PRIx64 ", to 0x%" PRIx64
    643                                 ", flags 0x%" PRIx64 "\n",
    644                     item.from, item.to, item.flags);
    645     }
    646   }
    647   if (sample_type & PERF_SAMPLE_REGS_USER) {
    648     PrintIndented(indent, "user regs: abi=%" PRId64 "\n", regs_user_data.abi);
    649     for (size_t i = 0, pos = 0; i < 64; ++i) {
    650       if ((regs_user_data.reg_mask >> i) & 1) {
    651         PrintIndented(
    652             indent + 1, "reg (%s) 0x%016" PRIx64 "\n",
    653             GetRegName(i, ScopedCurrentArch::GetCurrentArch()).c_str(),
    654             regs_user_data.regs[pos++]);
    655       }
    656     }
    657   }
    658   if (sample_type & PERF_SAMPLE_STACK_USER) {
    659     PrintIndented(indent, "user stack: size %zu dyn_size %" PRIu64 "\n",
    660                   stack_user_data.size, stack_user_data.dyn_size);
    661     const uint64_t* p = reinterpret_cast<const uint64_t*>(stack_user_data.data);
    662     const uint64_t* end = p + (stack_user_data.size / sizeof(uint64_t));
    663     while (p < end) {
    664       PrintIndented(indent + 1, "");
    665       for (size_t i = 0; i < 4 && p < end; ++i, ++p) {
    666         printf(" %016" PRIx64, *p);
    667       }
    668       printf("\n");
    669     }
    670     printf("\n");
    671   }
    672 }
    673 
    674 uint64_t SampleRecord::Timestamp() const { return time_data.time; }
    675 uint32_t SampleRecord::Cpu() const { return cpu_data.cpu; }
    676 uint64_t SampleRecord::Id() const { return id_data.id; }
    677 
    678 BuildIdRecord::BuildIdRecord(const char* p) : Record(p) {
    679   const char* end = p + size();
    680   p += header_size();
    681   MoveFromBinaryFormat(pid, p);
    682   build_id = BuildId(p, BUILD_ID_SIZE);
    683   p += Align(build_id.Size(), 8);
    684   filename = p;
    685   p += Align(strlen(filename) + 1, 64);
    686   CHECK_EQ(p, end);
    687 }
    688 
    689 void BuildIdRecord::DumpData(size_t indent) const {
    690   PrintIndented(indent, "pid %u\n", pid);
    691   PrintIndented(indent, "build_id %s\n", build_id.ToString().c_str());
    692   PrintIndented(indent, "filename %s\n", filename);
    693 }
    694 
    695 BuildIdRecord::BuildIdRecord(bool in_kernel, pid_t pid, const BuildId& build_id,
    696                              const std::string& filename) {
    697   SetTypeAndMisc(PERF_RECORD_BUILD_ID,
    698                  in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER);
    699   this->pid = pid;
    700   this->build_id = build_id;
    701   SetSize(header_size() + sizeof(pid) + Align(build_id.Size(), 8) +
    702           Align(filename.size() + 1, 64));
    703   char* new_binary = new char[size()];
    704   char* p = new_binary;
    705   MoveToBinaryFormat(header, p);
    706   MoveToBinaryFormat(pid, p);
    707   memcpy(p, build_id.Data(), build_id.Size());
    708   p += Align(build_id.Size(), 8);
    709   this->filename = p;
    710   strcpy(p, filename.c_str());
    711   UpdateBinary(new_binary);
    712 }
    713 
    714 KernelSymbolRecord::KernelSymbolRecord(const char* p) : Record(p) {
    715   const char* end = p + size();
    716   p += header_size();
    717   MoveFromBinaryFormat(kallsyms_size, p);
    718   kallsyms = p;
    719   p += Align(kallsyms_size, 8);
    720   CHECK_EQ(p, end);
    721 }
    722 
    723 void KernelSymbolRecord::DumpData(size_t indent) const {
    724   PrintIndented(indent, "kallsyms: %s\n",
    725                 std::string(kallsyms, kallsyms + kallsyms_size).c_str());
    726 }
    727 
    728 KernelSymbolRecord::KernelSymbolRecord(const std::string& kallsyms) {
    729   SetTypeAndMisc(SIMPLE_PERF_RECORD_KERNEL_SYMBOL, 0);
    730   kallsyms_size = kallsyms.size();
    731   SetSize(header_size() + 4 + Align(kallsyms.size(), 8));
    732   char* new_binary = new char[size()];
    733   char* p = new_binary;
    734   MoveToBinaryFormat(header, p);
    735   MoveToBinaryFormat(kallsyms_size, p);
    736   this->kallsyms = p;
    737   memcpy(p, kallsyms.data(), kallsyms_size);
    738   UpdateBinary(new_binary);
    739 }
    740 
    741 DsoRecord::DsoRecord(const char* p) : Record(p) {
    742   const char* end = p + size();
    743   p += header_size();
    744   MoveFromBinaryFormat(dso_type, p);
    745   MoveFromBinaryFormat(dso_id, p);
    746   MoveFromBinaryFormat(min_vaddr, p);
    747   dso_name = p;
    748   p += Align(strlen(dso_name) + 1, 8);
    749   CHECK_EQ(p, end);
    750 }
    751 
    752 DsoRecord::DsoRecord(uint64_t dso_type, uint64_t dso_id,
    753                      const std::string& dso_name, uint64_t min_vaddr) {
    754   SetTypeAndMisc(SIMPLE_PERF_RECORD_DSO, 0);
    755   this->dso_type = dso_type;
    756   this->dso_id = dso_id;
    757   this->min_vaddr = min_vaddr;
    758   SetSize(header_size() + 3 * sizeof(uint64_t) + Align(dso_name.size() + 1, 8));
    759   char* new_binary = new char[size()];
    760   char* p = new_binary;
    761   MoveToBinaryFormat(header, p);
    762   MoveToBinaryFormat(dso_type, p);
    763   MoveToBinaryFormat(dso_id, p);
    764   MoveToBinaryFormat(min_vaddr, p);
    765   this->dso_name = p;
    766   strcpy(p, dso_name.c_str());
    767   UpdateBinary(new_binary);
    768 }
    769 
    770 void DsoRecord::DumpData(size_t indent) const {
    771   PrintIndented(indent, "dso_type: %s(%" PRIu64 ")\n",
    772                 DsoTypeToString(static_cast<DsoType>(dso_type)), dso_type);
    773   PrintIndented(indent, "dso_id: %" PRIu64 "\n", dso_id);
    774   PrintIndented(indent, "min_vaddr: 0x%" PRIx64 "\n", min_vaddr);
    775   PrintIndented(indent, "dso_name: %s\n", dso_name);
    776 }
    777 
    778 SymbolRecord::SymbolRecord(const char* p) : Record(p) {
    779   const char* end = p + size();
    780   p += header_size();
    781   MoveFromBinaryFormat(addr, p);
    782   MoveFromBinaryFormat(len, p);
    783   MoveFromBinaryFormat(dso_id, p);
    784   name = p;
    785   p += Align(strlen(name) + 1, 8);
    786   CHECK_EQ(p, end);
    787 }
    788 
    789 SymbolRecord::SymbolRecord(uint64_t addr, uint64_t len, const std::string& name,
    790                            uint64_t dso_id) {
    791   SetTypeAndMisc(SIMPLE_PERF_RECORD_SYMBOL, 0);
    792   this->addr = addr;
    793   this->len = len;
    794   this->dso_id = dso_id;
    795   SetSize(header_size() + 3 * sizeof(uint64_t) + Align(name.size() + 1, 8));
    796   char* new_binary = new char[size()];
    797   char* p = new_binary;
    798   MoveToBinaryFormat(header, p);
    799   MoveToBinaryFormat(addr, p);
    800   MoveToBinaryFormat(len, p);
    801   MoveToBinaryFormat(dso_id, p);
    802   this->name = p;
    803   strcpy(p, name.c_str());
    804   UpdateBinary(new_binary);
    805 }
    806 
    807 void SymbolRecord::DumpData(size_t indent) const {
    808   PrintIndented(indent, "name: %s\n", name);
    809   PrintIndented(indent, "addr: 0x%" PRIx64 "\n", addr);
    810   PrintIndented(indent, "len: 0x%" PRIx64 "\n", len);
    811   PrintIndented(indent, "dso_id: %" PRIu64 "\n", dso_id);
    812 }
    813 
    814 TracingDataRecord::TracingDataRecord(const char* p) : Record(p) {
    815   const char* end = p + size();
    816   p += header_size();
    817   MoveFromBinaryFormat(data_size, p);
    818   data = p;
    819   p += Align(data_size, 64);
    820   CHECK_EQ(p, end);
    821 }
    822 
    823 TracingDataRecord::TracingDataRecord(const std::vector<char>& tracing_data) {
    824   SetTypeAndMisc(PERF_RECORD_TRACING_DATA, 0);
    825   data_size = tracing_data.size();
    826   SetSize(header_size() + sizeof(uint32_t) + Align(tracing_data.size(), 64));
    827   char* new_binary = new char[size()];
    828   char* p = new_binary;
    829   MoveToBinaryFormat(header, p);
    830   MoveToBinaryFormat(data_size, p);
    831   data = p;
    832   memcpy(p, tracing_data.data(), data_size);
    833   UpdateBinary(new_binary);
    834 }
    835 
    836 void TracingDataRecord::DumpData(size_t indent) const {
    837   Tracing tracing(std::vector<char>(data, data + data_size));
    838   tracing.Dump(indent);
    839 }
    840 
    841 EventIdRecord::EventIdRecord(const char* p) : Record(p) {
    842   const char* end = p + size();
    843   p += header_size();
    844   MoveFromBinaryFormat(count, p);
    845   data = reinterpret_cast<const EventIdData*>(p);
    846   p += sizeof(data[0]) * count;
    847   CHECK_EQ(p, end);
    848 }
    849 
    850 EventIdRecord::EventIdRecord(const std::vector<uint64_t>& data) {
    851   SetTypeAndMisc(SIMPLE_PERF_RECORD_EVENT_ID, 0);
    852   SetSize(header_size() + sizeof(uint64_t) * (1 + data.size()));
    853   char* new_binary = new char[size()];
    854   char* p = new_binary;
    855   MoveToBinaryFormat(header, p);
    856   count = data.size() / 2;
    857   MoveToBinaryFormat(count, p);
    858   this->data = reinterpret_cast<EventIdData*>(p);
    859   memcpy(p, data.data(), sizeof(uint64_t) * data.size());
    860   UpdateBinary(new_binary);
    861 }
    862 
    863 void EventIdRecord::DumpData(size_t indent) const {
    864   PrintIndented(indent, "count: %" PRIu64 "\n", count);
    865   for (size_t i = 0; i < count; ++i) {
    866     PrintIndented(indent, "attr_id[%" PRIu64 "]: %" PRIu64 "\n", i,
    867                   data[i].attr_id);
    868     PrintIndented(indent, "event_id[%" PRIu64 "]: %" PRIu64 "\n", i,
    869                   data[i].event_id);
    870   }
    871 }
    872 
    873 UnknownRecord::UnknownRecord(const char* p) : Record(p) {
    874   p += header_size();
    875   data = p;
    876 }
    877 
    878 void UnknownRecord::DumpData(size_t) const {}
    879 
    880 std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr,
    881                                              uint32_t type, const char* p) {
    882   switch (type) {
    883     case PERF_RECORD_MMAP:
    884       return std::unique_ptr<Record>(new MmapRecord(attr, p));
    885     case PERF_RECORD_MMAP2:
    886       return std::unique_ptr<Record>(new Mmap2Record(attr, p));
    887     case PERF_RECORD_COMM:
    888       return std::unique_ptr<Record>(new CommRecord(attr, p));
    889     case PERF_RECORD_EXIT:
    890       return std::unique_ptr<Record>(new ExitRecord(attr, p));
    891     case PERF_RECORD_FORK:
    892       return std::unique_ptr<Record>(new ForkRecord(attr, p));
    893     case PERF_RECORD_LOST:
    894       return std::unique_ptr<Record>(new LostRecord(attr, p));
    895     case PERF_RECORD_SAMPLE:
    896       return std::unique_ptr<Record>(new SampleRecord(attr, p));
    897     case PERF_RECORD_TRACING_DATA:
    898       return std::unique_ptr<Record>(new TracingDataRecord(p));
    899     case SIMPLE_PERF_RECORD_KERNEL_SYMBOL:
    900       return std::unique_ptr<Record>(new KernelSymbolRecord(p));
    901     case SIMPLE_PERF_RECORD_DSO:
    902       return std::unique_ptr<Record>(new DsoRecord(p));
    903     case SIMPLE_PERF_RECORD_SYMBOL:
    904       return std::unique_ptr<Record>(new SymbolRecord(p));
    905     case SIMPLE_PERF_RECORD_EVENT_ID:
    906       return std::unique_ptr<Record>(new EventIdRecord(p));
    907     default:
    908       return std::unique_ptr<Record>(new UnknownRecord(p));
    909   }
    910 }
    911 
    912 std::unique_ptr<Record> ReadRecordFromOwnedBuffer(const perf_event_attr& attr,
    913                                                   uint32_t type,
    914                                                   const char* p) {
    915   std::unique_ptr<Record> record = ReadRecordFromBuffer(attr, type, p);
    916   if (record != nullptr) {
    917     record->OwnBinary();
    918   } else {
    919     delete[] p;
    920   }
    921   return record;
    922 }
    923 
    924 std::vector<std::unique_ptr<Record>> ReadRecordsFromBuffer(
    925     const perf_event_attr& attr, const char* buf, size_t buf_size) {
    926   std::vector<std::unique_ptr<Record>> result;
    927   const char* p = buf;
    928   const char* end = buf + buf_size;
    929   while (p < end) {
    930     RecordHeader header(p);
    931     CHECK_LE(p + header.size, end);
    932     CHECK_NE(0u, header.size);
    933     result.push_back(ReadRecordFromBuffer(attr, header.type, p));
    934     p += header.size;
    935   }
    936   return result;
    937 }
    938 
    939 std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr,
    940                                              const char* p) {
    941   auto header = reinterpret_cast<const perf_event_header*>(p);
    942   return ReadRecordFromBuffer(attr, header->type, p);
    943 }
    944 
    945 bool RecordCache::RecordWithSeq::IsHappensBefore(
    946     const RecordWithSeq& other) const {
    947   bool is_sample = (record->type() == PERF_RECORD_SAMPLE);
    948   bool is_other_sample = (other.record->type() == PERF_RECORD_SAMPLE);
    949   uint64_t time = record->Timestamp();
    950   uint64_t other_time = other.record->Timestamp();
    951   // The record with smaller time happens first.
    952   if (time != other_time) {
    953     return time < other_time;
    954   }
    955   // If happening at the same time, make non-sample records before sample
    956   // records, because non-sample records may contain useful information to
    957   // parse sample records.
    958   if (is_sample != is_other_sample) {
    959     return is_sample ? false : true;
    960   }
    961   // Otherwise, use the same order as they enter the cache.
    962   return seq < other.seq;
    963 }
    964 
    965 bool RecordCache::RecordComparator::operator()(const RecordWithSeq& r1,
    966                                                const RecordWithSeq& r2) {
    967   return r2.IsHappensBefore(r1);
    968 }
    969 
    970 RecordCache::RecordCache(bool has_timestamp, size_t min_cache_size,
    971                          uint64_t min_time_diff_in_ns)
    972     : has_timestamp_(has_timestamp),
    973       min_cache_size_(min_cache_size),
    974       min_time_diff_in_ns_(min_time_diff_in_ns),
    975       last_time_(0),
    976       cur_seq_(0),
    977       queue_(RecordComparator()) {}
    978 
    979 RecordCache::~RecordCache() { PopAll(); }
    980 
    981 void RecordCache::Push(std::unique_ptr<Record> record) {
    982   if (has_timestamp_) {
    983     last_time_ = std::max(last_time_, record->Timestamp());
    984   }
    985   queue_.push(RecordWithSeq(cur_seq_++, record.release()));
    986 }
    987 
    988 void RecordCache::Push(std::vector<std::unique_ptr<Record>> records) {
    989   for (auto& r : records) {
    990     Push(std::move(r));
    991   }
    992 }
    993 
    994 std::unique_ptr<Record> RecordCache::Pop() {
    995   if (queue_.size() < min_cache_size_) {
    996     return nullptr;
    997   }
    998   Record* r = queue_.top().record;
    999   if (has_timestamp_) {
   1000     if (r->Timestamp() + min_time_diff_in_ns_ > last_time_) {
   1001       return nullptr;
   1002     }
   1003   }
   1004   queue_.pop();
   1005   return std::unique_ptr<Record>(r);
   1006 }
   1007 
   1008 std::vector<std::unique_ptr<Record>> RecordCache::PopAll() {
   1009   std::vector<std::unique_ptr<Record>> result;
   1010   while (!queue_.empty()) {
   1011     result.emplace_back(queue_.top().record);
   1012     queue_.pop();
   1013   }
   1014   return result;
   1015 }
   1016 
   1017 std::unique_ptr<Record> RecordCache::ForcedPop() {
   1018   if (queue_.empty()) {
   1019     return nullptr;
   1020   }
   1021   Record* r = queue_.top().record;
   1022   queue_.pop();
   1023   return std::unique_ptr<Record>(r);
   1024 }
   1025