OSDN Git Service

Timetest: Clean up
[android-x86/system-extras.git] / simpleperf / record.cpp
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 }