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