• 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 #ifndef SIMPLE_PERF_RECORD_H_
18 #define SIMPLE_PERF_RECORD_H_
19 
20 #include <stdio.h>
21 #include <sys/types.h>
22 
23 #include <memory>
24 #include <queue>
25 #include <string>
26 #include <vector>
27 
28 #include <android-base/logging.h>
29 
30 #include "build_id.h"
31 #include "CallChainJoiner.h"
32 #include "OfflineUnwinder.h"
33 #include "perf_event.h"
34 
35 enum user_record_type {
36   PERF_RECORD_USER_DEFINED_TYPE_START = 64,
37   PERF_RECORD_ATTR = 64,
38   PERF_RECORD_EVENT_TYPE,
39   PERF_RECORD_TRACING_DATA,
40   PERF_RECORD_BUILD_ID,
41   PERF_RECORD_FINISHED_ROUND,
42 
43   SIMPLE_PERF_RECORD_TYPE_START = 32768,
44   SIMPLE_PERF_RECORD_KERNEL_SYMBOL,
45   // TODO: remove DsoRecord and SymbolRecord.
46   SIMPLE_PERF_RECORD_DSO,
47   SIMPLE_PERF_RECORD_SYMBOL,
48   SIMPLE_PERF_RECORD_SPLIT,
49   SIMPLE_PERF_RECORD_SPLIT_END,
50   SIMPLE_PERF_RECORD_EVENT_ID,
51   SIMPLE_PERF_RECORD_CALLCHAIN,
52   SIMPLE_PERF_RECORD_UNWINDING_RESULT,
53 };
54 
55 // perf_event_header uses u16 to store record size. However, that is not
56 // enough for storing records like KERNEL_SYMBOL or TRACING_DATA. So define
57 // a simpleperf_record_header struct to store record header for simpleperf
58 // defined records (type > SIMPLE_PERF_RECORD_TYPE_START).
59 struct simpleperf_record_header {
60   uint32_t type;
61   uint16_t size1;
62   uint16_t size0;
63 };
64 
65 static_assert(
66     sizeof(simpleperf_record_header) == sizeof(perf_event_header),
67     "simpleperf_record_header should have the same size as perf_event_header");
68 
69 struct PerfSampleIpType {
70   uint64_t ip;
71 };
72 
73 struct PerfSampleTidType {
74   uint32_t pid, tid;
75 };
76 
77 struct PerfSampleTimeType {
78   uint64_t time;
79 };
80 
81 struct PerfSampleAddrType {
82   uint64_t addr;
83 };
84 
85 struct PerfSampleIdType {
86   uint64_t id;
87 };
88 
89 struct PerfSampleStreamIdType {
90   uint64_t stream_id;
91 };
92 
93 struct PerfSampleCpuType {
94   uint32_t cpu, res;
95 };
96 
97 struct PerfSamplePeriodType {
98   uint64_t period;
99 };
100 
101 struct PerfSampleCallChainType {
102   uint64_t ip_nr;
103   uint64_t* ips;
104 };
105 
106 struct PerfSampleRawType {
107   uint32_t size;
108   const char* data;
109 };
110 
111 struct BranchStackItemType {
112   uint64_t from;
113   uint64_t to;
114   uint64_t flags;
115 };
116 
117 struct PerfSampleBranchStackType {
118   uint64_t stack_nr;
119   const BranchStackItemType* stack;
120 };
121 
122 struct PerfSampleRegsUserType {
123   uint64_t abi;
124   uint64_t reg_mask;
125   uint64_t reg_nr;
126   const uint64_t* regs;
127 };
128 
129 struct PerfSampleStackUserType {
130   uint64_t size;
131   char* data;
132   uint64_t dyn_size;
133 };
134 
135 struct RecordHeader {
136  public:
137   uint32_t type;
138   uint16_t misc;
139   uint32_t size;
140 
RecordHeaderRecordHeader141   RecordHeader() : type(0), misc(0), size(0) {}
142 
RecordHeaderRecordHeader143   explicit RecordHeader(const char* p) {
144     auto pheader = reinterpret_cast<const perf_event_header*>(p);
145     if (pheader->type < SIMPLE_PERF_RECORD_TYPE_START) {
146       type = pheader->type;
147       misc = pheader->misc;
148       size = pheader->size;
149     } else {
150       auto sheader = reinterpret_cast<const simpleperf_record_header*>(p);
151       type = sheader->type;
152       misc = 0;
153       size = (sheader->size1 << 16) | sheader->size0;
154     }
155   }
156 
MoveToBinaryFormatRecordHeader157   void MoveToBinaryFormat(char*& p) const {
158     if (type < SIMPLE_PERF_RECORD_TYPE_START) {
159       auto pheader = reinterpret_cast<perf_event_header*>(p);
160       pheader->type = type;
161       pheader->misc = misc;
162       CHECK_LT(size, 1u << 16);
163       pheader->size = static_cast<uint16_t>(size);
164     } else {
165       auto sheader = reinterpret_cast<simpleperf_record_header*>(p);
166       sheader->type = type;
167       CHECK_EQ(misc, 0u);
168       sheader->size1 = size >> 16;
169       sheader->size0 = size & 0xffff;
170     }
171     p += sizeof(perf_event_header);
172   }
173 };
174 
175 // SampleId is optional at the end of a record in binary format. Its content is
176 // determined by sample_id_all and sample_type in perf_event_attr. To avoid the
177 // complexity of referring to perf_event_attr each time, we copy sample_id_all
178 // and sample_type inside the SampleId structure.
179 struct SampleId {
180   bool sample_id_all;
181   uint64_t sample_type;
182 
183   PerfSampleTidType tid_data;    // Valid if sample_id_all && PERF_SAMPLE_TID.
184   PerfSampleTimeType time_data;  // Valid if sample_id_all && PERF_SAMPLE_TIME.
185   PerfSampleIdType id_data;      // Valid if sample_id_all && PERF_SAMPLE_ID.
186   PerfSampleStreamIdType
187       stream_id_data;  // Valid if sample_id_all && PERF_SAMPLE_STREAM_ID.
188   PerfSampleCpuType cpu_data;  // Valid if sample_id_all && PERF_SAMPLE_CPU.
189 
190   SampleId();
191 
192   // Create the content of sample_id. It depends on the attr we use.
193   size_t CreateContent(const perf_event_attr& attr, uint64_t event_id);
194 
195   // Parse sample_id from binary format in the buffer pointed by p.
196   void ReadFromBinaryFormat(const perf_event_attr& attr, const char* p,
197                             const char* end);
198 
199   // Write the binary format of sample_id to the buffer pointed by p.
200   void WriteToBinaryFormat(char*& p) const;
201   void Dump(size_t indent) const;
202   size_t Size() const;
203 };
204 
205 // Usually one record contains the following three parts in order in binary
206 // format:
207 //   RecordHeader (at the head of a record, containing type and size info)
208 //   data depends on the record type
209 //   SampleId (optional part at the end of a record)
210 // We hold the common parts (RecordHeader and SampleId) in the base class
211 // Record, and hold the type specific data part in classes derived from Record.
212 struct Record {
213   RecordHeader header;
214   SampleId sample_id;
215 
RecordRecord216   Record() : binary_(nullptr), own_binary_(false) {}
RecordRecord217   explicit Record(char* p) : header(p), binary_(p), own_binary_(false) {}
218   Record(Record&& other);
219 
~RecordRecord220   virtual ~Record() {
221     if (own_binary_) {
222       delete[] binary_;
223     }
224   }
225 
OwnBinaryRecord226   void OwnBinary() { own_binary_ = true; }
227 
typeRecord228   uint32_t type() const { return header.type; }
229 
miscRecord230   uint16_t misc() const { return header.misc; }
231 
sizeRecord232   uint32_t size() const { return header.size; }
233 
header_sizeRecord234   static uint32_t header_size() { return sizeof(perf_event_header); }
235 
InKernelRecord236   bool InKernel() const {
237     return (header.misc & PERF_RECORD_MISC_CPUMODE_MASK) ==
238            PERF_RECORD_MISC_KERNEL;
239   }
240 
SetTypeAndMiscRecord241   void SetTypeAndMisc(uint32_t type, uint16_t misc) {
242     header.type = type;
243     header.misc = misc;
244   }
245 
SetSizeRecord246   void SetSize(uint32_t size) { header.size = size; }
247 
248   void Dump(size_t indent = 0) const;
249 
BinaryRecord250   const char* Binary() const { return binary_; }
BinaryForTestingOnlyRecord251   char* BinaryForTestingOnly() { return binary_; }
252 
253   virtual uint64_t Timestamp() const;
254   virtual uint32_t Cpu() const;
255   virtual uint64_t Id() const;
256 
257  protected:
258   void UpdateBinary(char* new_binary);
259   virtual void DumpData(size_t) const = 0;
260 
261   char* binary_;
262   bool own_binary_;
263 
264   DISALLOW_COPY_AND_ASSIGN(Record);
265 };
266 
267 struct MmapRecord : public Record {
268   struct MmapRecordDataType {
269     uint32_t pid, tid;
270     uint64_t addr;
271     uint64_t len;
272     uint64_t pgoff;
273   };
274   const MmapRecordDataType* data;
275   const char* filename;
276 
277   MmapRecord(const perf_event_attr& attr, char* p);
278 
279   MmapRecord(const perf_event_attr& attr, bool in_kernel, uint32_t pid,
280              uint32_t tid, uint64_t addr, uint64_t len, uint64_t pgoff,
281              const std::string& filename, uint64_t event_id, uint64_t time = 0);
282 
283   void SetDataAndFilename(const MmapRecordDataType& data,
284                           const std::string& filename);
285 
286  protected:
287   void DumpData(size_t indent) const override;
288 };
289 
290 struct Mmap2Record : public Record {
291   struct Mmap2RecordDataType {
292     uint32_t pid, tid;
293     uint64_t addr;
294     uint64_t len;
295     uint64_t pgoff;
296     uint32_t maj;
297     uint32_t min;
298     uint64_t ino;
299     uint64_t ino_generation;
300     uint32_t prot, flags;
301   };
302   const Mmap2RecordDataType* data;
303   const char* filename;
304 
305   Mmap2Record(const perf_event_attr& attr, char* p);
306 
307   void SetDataAndFilename(const Mmap2RecordDataType& data,
308                           const std::string& filename);
309 
310  protected:
311   void DumpData(size_t indent) const override;
312 };
313 
314 struct CommRecord : public Record {
315   struct CommRecordDataType {
316     uint32_t pid, tid;
317   };
318   const CommRecordDataType* data;
319   const char* comm;
320 
321   CommRecord(const perf_event_attr& attr, char* p);
322 
323   CommRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid,
324              const std::string& comm, uint64_t event_id, uint64_t time);
325 
326  protected:
327   void DumpData(size_t indent) const override;
328 };
329 
330 struct ExitOrForkRecord : public Record {
331   struct ExitOrForkRecordDataType {
332     uint32_t pid, ppid;
333     uint32_t tid, ptid;
334     uint64_t time;
335   };
336   const ExitOrForkRecordDataType* data;
337 
338   ExitOrForkRecord(const perf_event_attr& attr, char* p);
339 
ExitOrForkRecordExitOrForkRecord340   ExitOrForkRecord() : data(nullptr) {}
341 
342  protected:
343   void DumpData(size_t indent) const override;
344 };
345 
346 struct ExitRecord : public ExitOrForkRecord {
ExitRecordExitRecord347   ExitRecord(const perf_event_attr& attr, char* p)
348       : ExitOrForkRecord(attr, p) {}
349 };
350 
351 struct ForkRecord : public ExitOrForkRecord {
ForkRecordForkRecord352   ForkRecord(const perf_event_attr& attr, char* p)
353       : ExitOrForkRecord(attr, p) {}
354 
355   ForkRecord(const perf_event_attr& attr, uint32_t pid, uint32_t tid,
356              uint32_t ppid, uint32_t ptid, uint64_t event_id);
357 };
358 
359 struct LostRecord : public Record {
360   uint64_t id;
361   uint64_t lost;
362 
363   LostRecord(const perf_event_attr& attr, char* p);
364 
365  protected:
366   void DumpData(size_t indent) const override;
367 };
368 
369 struct SampleRecord : public Record {
370   uint64_t sample_type;  // sample_type is a bit mask determining which fields
371                          // below are valid.
372 
373   PerfSampleIpType ip_data;               // Valid if PERF_SAMPLE_IP.
374   PerfSampleTidType tid_data;             // Valid if PERF_SAMPLE_TID.
375   PerfSampleTimeType time_data;           // Valid if PERF_SAMPLE_TIME.
376   PerfSampleAddrType addr_data;           // Valid if PERF_SAMPLE_ADDR.
377   PerfSampleIdType id_data;               // Valid if PERF_SAMPLE_ID.
378   PerfSampleStreamIdType stream_id_data;  // Valid if PERF_SAMPLE_STREAM_ID.
379   PerfSampleCpuType cpu_data;             // Valid if PERF_SAMPLE_CPU.
380   PerfSamplePeriodType period_data;       // Valid if PERF_SAMPLE_PERIOD.
381 
382   PerfSampleCallChainType callchain_data;  // Valid if PERF_SAMPLE_CALLCHAIN.
383   PerfSampleRawType raw_data;              // Valid if PERF_SAMPLE_RAW.
384   PerfSampleBranchStackType
385       branch_stack_data;                  // Valid if PERF_SAMPLE_BRANCH_STACK.
386   PerfSampleRegsUserType regs_user_data;  // Valid if PERF_SAMPLE_REGS_USER.
387   PerfSampleStackUserType stack_user_data;  // Valid if PERF_SAMPLE_STACK_USER.
388 
389   SampleRecord(const perf_event_attr& attr, char* p);
390   SampleRecord(const perf_event_attr& attr, uint64_t id, uint64_t ip,
391                uint32_t pid, uint32_t tid, uint64_t time, uint32_t cpu,
392                uint64_t period, const std::vector<uint64_t>& ips);
393 
394   void ReplaceRegAndStackWithCallChain(const std::vector<uint64_t>& ips);
395   size_t ExcludeKernelCallChain();
396   bool HasUserCallChain() const;
397   void UpdateUserCallChain(const std::vector<uint64_t>& user_ips);
398   void RemoveInvalidStackData();
399 
400   uint64_t Timestamp() const override;
401   uint32_t Cpu() const override;
402   uint64_t Id() const override;
403 
GetValidStackSizeSampleRecord404   uint64_t GetValidStackSize() const {
405     // If stack_user_data.dyn_size == 0, it may be because the kernel misses
406     // the patch to update dyn_size, like in N9 (See b/22612370). So assume
407     // all stack data is valid if dyn_size == 0.
408     if (stack_user_data.dyn_size == 0) {
409       return stack_user_data.size;
410     }
411     return stack_user_data.dyn_size;
412   }
413 
414   void AdjustCallChainGeneratedByKernel();
415 
416  protected:
417   void DumpData(size_t indent) const override;
418 };
419 
420 // BuildIdRecord is defined in user-space, stored in BuildId feature section in
421 // record file.
422 struct BuildIdRecord : public Record {
423   uint32_t pid;
424   BuildId build_id;
425   const char* filename;
426 
427   explicit BuildIdRecord(char* p);
428 
429   BuildIdRecord(bool in_kernel, pid_t pid, const BuildId& build_id,
430                 const std::string& filename);
431 
432  protected:
433   void DumpData(size_t indent) const override;
434 };
435 
436 struct KernelSymbolRecord : public Record {
437   uint32_t kallsyms_size;
438   const char* kallsyms;
439 
440   explicit KernelSymbolRecord(char* p);
441 
442   explicit KernelSymbolRecord(const std::string& kallsyms);
443 
444  protected:
445   void DumpData(size_t indent) const override;
446 };
447 
448 struct DsoRecord : public Record {
449   uint64_t dso_type;
450   uint64_t dso_id;
451   uint64_t min_vaddr;
452   const char* dso_name;
453 
454   explicit DsoRecord(char* p);
455 
456   DsoRecord(uint64_t dso_type, uint64_t dso_id, const std::string& dso_name,
457             uint64_t min_vaddr);
458 
459  protected:
460   void DumpData(size_t indent) const override;
461 };
462 
463 struct SymbolRecord : public Record {
464   uint64_t addr;
465   uint64_t len;
466   uint64_t dso_id;
467   const char* name;
468 
469   explicit SymbolRecord(char* p);
470 
471   SymbolRecord(uint64_t addr, uint64_t len, const std::string& name,
472                uint64_t dso_id);
473 
474  protected:
475   void DumpData(size_t indent) const override;
476 };
477 
478 struct TracingDataRecord : public Record {
479   uint32_t data_size;
480   const char* data;
481 
482   explicit TracingDataRecord(char* p);
483 
484   explicit TracingDataRecord(const std::vector<char>& tracing_data);
485 
486  protected:
487   void DumpData(size_t indent) const override;
488 };
489 
490 struct EventIdRecord : public Record {
491   uint64_t count;
492   struct EventIdData {
493     uint64_t attr_id;
494     uint64_t event_id;
495   } const* data;
496 
497   explicit EventIdRecord(char* p);
498 
499   explicit EventIdRecord(const std::vector<uint64_t>& data);
500 
501  protected:
502   void DumpData(size_t indent) const override;
503 };
504 
505 struct CallChainRecord : public Record {
506   uint32_t pid;
507   uint32_t tid;
508   uint64_t chain_type;
509   uint64_t time;
510   uint64_t ip_nr;
511   uint64_t* ips;
512   uint64_t* sps;
513 
514   explicit CallChainRecord(char* p);
515 
516   CallChainRecord(pid_t pid, pid_t tid, simpleperf::CallChainJoiner::ChainType type, uint64_t time,
517                   const std::vector<uint64_t>& ips, const std::vector<uint64_t>& sps);
518 
TimestampCallChainRecord519   uint64_t Timestamp() const override {
520     return time;
521   }
522 
523  protected:
524   void DumpData(size_t indent) const override;
525 };
526 
527 struct UnwindingResultRecord : public Record {
528   uint64_t time;
529   simpleperf::UnwindingResult unwinding_result;
530 
531   explicit UnwindingResultRecord(char* p);
532 
533   UnwindingResultRecord(uint64_t time, const simpleperf::UnwindingResult& unwinding_result);
534 
TimestampUnwindingResultRecord535   uint64_t Timestamp() const override {
536     return time;
537   }
538 
539  protected:
540   void DumpData(size_t indent) const override;
541 };
542 
543 // UnknownRecord is used for unknown record types, it makes sure all unknown
544 // records are not changed when modifying perf.data.
545 struct UnknownRecord : public Record {
546   const char* data;
547 
548   explicit UnknownRecord(char* p);
549 
550  protected:
551   void DumpData(size_t indent) const override;
552 };
553 
554 // Read record from the buffer pointed by [p]. But the record doesn't own
555 // the buffer.
556 std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr, uint32_t type, char* p);
557 
558 // Read record from the buffer pointed by [p]. And the record owns the buffer.
559 std::unique_ptr<Record> ReadRecordFromOwnedBuffer(const perf_event_attr& attr,
560                                                   uint32_t type, char* p);
561 
562 // Read records from the buffer pointed by [buf]. None of the records own
563 // the buffer.
564 std::vector<std::unique_ptr<Record>> ReadRecordsFromBuffer(
565     const perf_event_attr& attr, char* buf, size_t buf_size);
566 
567 // Read one record from the buffer pointed by [p]. But the record doesn't
568 // own the buffer.
569 std::unique_ptr<Record> ReadRecordFromBuffer(const perf_event_attr& attr, char* p);
570 
571 // RecordCache is a cache used when receiving records from the kernel.
572 // It sorts received records based on type and timestamp, and pops records
573 // in sorted order. Records from the kernel need to be sorted because
574 // records may come from different cpus at the same time, and it is affected
575 // by the order in which we collect records from different cpus.
576 // RecordCache pushes records and pops sorted record online. It uses two checks
577 // to help ensure that records are popped in order. Each time we pop a record A,
578 // it is the earliest record among all records in the cache. In addition, we
579 // have checks for min_cache_size and min_time_diff. For min_cache_size check,
580 // we check if the cache size >= min_cache_size, which is based on the
581 // assumption that if we have received (min_cache_size - 1) records after
582 // record A, we are not likely to receive a record earlier than A. For
583 // min_time_diff check, we check if record A is generated min_time_diff ns
584 // earlier than the latest record, which is based on the assumption that if we
585 // have received a record for time t, we are not likely to receive a record for
586 // time (t - min_time_diff) or earlier.
587 class RecordCache {
588  public:
589   explicit RecordCache(bool has_timestamp, size_t min_cache_size = 1000u,
590                        uint64_t min_time_diff_in_ns = 1000000u);
591   ~RecordCache();
592   void Push(std::unique_ptr<Record> record);
593   void Push(std::vector<std::unique_ptr<Record>> records);
594   std::unique_ptr<Record> Pop();
595   std::vector<std::unique_ptr<Record>> PopAll();
596   std::unique_ptr<Record> ForcedPop();
597 
598  private:
599   struct RecordWithSeq {
600     uint32_t seq;
601     Record* record;
602 
RecordWithSeqRecordWithSeq603     RecordWithSeq(uint32_t seq, Record* record) : seq(seq), record(record) {}
604     bool IsHappensBefore(const RecordWithSeq& other) const;
605   };
606 
607   struct RecordComparator {
608     bool operator()(const RecordWithSeq& r1, const RecordWithSeq& r2);
609   };
610 
611   bool has_timestamp_;
612   size_t min_cache_size_;
613   uint64_t min_time_diff_in_ns_;
614   uint64_t last_time_;
615   uint32_t cur_seq_;
616   std::priority_queue<RecordWithSeq, std::vector<RecordWithSeq>,
617                       RecordComparator> queue_;
618 };
619 
620 #endif  // SIMPLE_PERF_RECORD_H_
621