OSDN Git Service

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