• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef CHROMIUMOS_WIDE_PROFILING_TEST_PERF_DATA_H_
6 #define CHROMIUMOS_WIDE_PROFILING_TEST_PERF_DATA_H_
7 
8 #include <memory>
9 #include <ostream>
10 #include <vector>
11 
12 #include "binary_data_utils.h"
13 #include "compat/string.h"
14 #include "kernel/perf_internals.h"
15 
16 namespace quipper {
17 namespace testing {
18 
19 // Union for punning 32-bit words into a 64-bit word.
20 union PunU32U64 {
21   u32 v32[2];
22   u64 v64;
23 };
24 
25 class StreamWriteable {
26  public:
StreamWriteable()27   StreamWriteable() : is_cross_endian_(false) {}
~StreamWriteable()28   virtual ~StreamWriteable() {}
29 
30   virtual void WriteTo(std::ostream* out) const = 0;
31 
WithCrossEndianness(bool value)32   virtual StreamWriteable& WithCrossEndianness(bool value) {
33     is_cross_endian_ = value;
34     return *this;
35   }
36 
37   // Do not call MaybeSwap() directly. The syntax of test data structure
38   // initialization makes data sizes ambiguous, so these force the caller to
39   // explicitly specify value sizes.
MaybeSwap16(uint16_t value)40   uint16_t MaybeSwap16(uint16_t value) const { return MaybeSwap(value); }
MaybeSwap32(uint32_t value)41   uint32_t MaybeSwap32(uint32_t value) const { return MaybeSwap(value); }
MaybeSwap64(uint64_t value)42   uint64_t MaybeSwap64(uint64_t value) const { return MaybeSwap(value); }
43 
44  protected:
45   // Derived classes can call this to determine the cross-endianness. However,
46   // the actual implementation of cross-endianness is up to the derived class,
47   // if it supports it at all.
is_cross_endian()48   bool is_cross_endian() const { return is_cross_endian_; }
49 
50  private:
51   template <typename T>
MaybeSwap(T value)52   T MaybeSwap(T value) const {
53     if (is_cross_endian()) ByteSwap(&value);
54     return value;
55   }
56 
57   bool is_cross_endian_;
58 };
59 
60 // Normal mode header
61 class ExamplePerfDataFileHeader : public StreamWriteable {
62  public:
63   typedef ExamplePerfDataFileHeader SelfT;
64   explicit ExamplePerfDataFileHeader(const unsigned long features);
65 
66   SelfT& WithAttrIdsCount(size_t n);
67   SelfT& WithAttrCount(size_t n);
68   SelfT& WithDataSize(size_t sz);
69 
70   // Used for testing compatibility w.r.t. sizeof(perf_event_attr)
71   SelfT& WithCustomPerfEventAttrSize(size_t sz);
72 
header()73   const struct perf_file_header& header() const { return header_; }
74 
data_end_offset()75   u64 data_end_offset() const {
76     return header_.data.offset + header_.data.size;
77   }
data_end()78   ssize_t data_end() const { return static_cast<ssize_t>(data_end_offset()); }
79 
80   void WriteTo(std::ostream* out) const override;
81 
82  protected:
83   struct perf_file_header header_;
84   size_t attr_ids_count_ = 0;
85 
86  private:
87   void UpdateSectionOffsets();
88 };
89 
90 // Produces the pipe-mode file header.
91 class ExamplePipedPerfDataFileHeader : public StreamWriteable {
92  public:
ExamplePipedPerfDataFileHeader()93   ExamplePipedPerfDataFileHeader() {}
94   void WriteTo(std::ostream* out) const override;
95 };
96 
97 // Produces a PERF_RECORD_HEADER_ATTR event with struct perf_event_attr
98 // describing a hardware event. The sample_type mask and the sample_id_all
99 // bit are paramatized.
100 class ExamplePerfEventAttrEvent_Hardware : public StreamWriteable {
101  public:
102   typedef ExamplePerfEventAttrEvent_Hardware SelfT;
ExamplePerfEventAttrEvent_Hardware(u64 sample_type,bool sample_id_all)103   explicit ExamplePerfEventAttrEvent_Hardware(u64 sample_type,
104                                               bool sample_id_all)
105       : attr_size_(sizeof(perf_event_attr)),
106         sample_type_(sample_type),
107         read_format_(0),
108         sample_id_all_(sample_id_all),
109         config_(0) {}
WithConfig(u64 config)110   SelfT& WithConfig(u64 config) {
111     config_ = config;
112     return *this;
113   }
WithAttrSize(u32 size)114   SelfT& WithAttrSize(u32 size) {
115     attr_size_ = size;
116     return *this;
117   }
WithReadFormat(u64 format)118   SelfT& WithReadFormat(u64 format) {
119     read_format_ = format;
120     return *this;
121   }
122 
WithId(u64 id)123   SelfT& WithId(u64 id) {
124     ids_.push_back(id);
125     return *this;
126   }
WithIds(std::initializer_list<u64> ids)127   SelfT& WithIds(std::initializer_list<u64> ids) {
128     ids_.insert(ids_.end(), ids.begin(), ids.end());
129     return *this;
130   }
131   void WriteTo(std::ostream* out) const override;
132 
133  private:
134   u32 attr_size_;
135   const u64 sample_type_;
136   u64 read_format_;
137   const bool sample_id_all_;
138   u64 config_;
139   std::vector<u64> ids_;
140 };
141 
142 class AttrIdsSection : public StreamWriteable {
143  public:
AttrIdsSection(size_t initial_offset)144   explicit AttrIdsSection(size_t initial_offset) : offset_(initial_offset) {}
145 
AddId(u64 id)146   perf_file_section AddId(u64 id) { return AddIds({id}); }
AddIds(std::initializer_list<u64> ids)147   perf_file_section AddIds(std::initializer_list<u64> ids) {
148     ids_.insert(ids_.end(), ids.begin(), ids.end());
149     perf_file_section s = {
150         .offset = offset_,
151         .size = ids.size() * sizeof(decltype(ids)::value_type),
152     };
153     offset_ += s.size;
154     return s;
155   }
156   void WriteTo(std::ostream* out) const override;
157 
158  private:
159   u64 offset_;
160   std::vector<u64> ids_;
161 };
162 
163 // Produces a struct perf_file_attr with a perf_event_attr describing a
164 // hardware event.
165 class ExamplePerfFileAttr_Hardware : public StreamWriteable {
166  public:
167   typedef ExamplePerfFileAttr_Hardware SelfT;
ExamplePerfFileAttr_Hardware(u64 sample_type,bool sample_id_all)168   explicit ExamplePerfFileAttr_Hardware(u64 sample_type, bool sample_id_all)
169       : attr_size_(sizeof(perf_event_attr)),
170         sample_type_(sample_type),
171         sample_id_all_(sample_id_all),
172         config_(0),
173         ids_section_({.offset = MaybeSwap64(104), .size = MaybeSwap64(0)}) {}
WithAttrSize(u32 size)174   SelfT& WithAttrSize(u32 size) {
175     attr_size_ = size;
176     return *this;
177   }
WithConfig(u64 config)178   SelfT& WithConfig(u64 config) {
179     config_ = config;
180     return *this;
181   }
WithIds(const perf_file_section & section)182   SelfT& WithIds(const perf_file_section& section) {
183     ids_section_ = section;
184     return *this;
185   }
186   void WriteTo(std::ostream* out) const override;
187 
188  private:
189   u32 attr_size_;
190   const u64 sample_type_;
191   const bool sample_id_all_;
192   u64 config_;
193   perf_file_section ids_section_;
194 };
195 
196 // Produces a struct perf_file_attr with a perf_event_attr describing a
197 // tracepoint event.
198 class ExamplePerfFileAttr_Tracepoint : public StreamWriteable {
199  public:
ExamplePerfFileAttr_Tracepoint(const u64 tracepoint_event_id)200   explicit ExamplePerfFileAttr_Tracepoint(const u64 tracepoint_event_id)
201       : tracepoint_event_id_(tracepoint_event_id) {}
202   void WriteTo(std::ostream* out) const override;
203 
204  private:
205   const u64 tracepoint_event_id_;
206 };
207 
208 // Produces a sample field array that can be used with either SAMPLE events
209 // or as the sample_id of another event.
210 // NB: This class simply places the fields in the order called. It does not
211 // enforce that they are in the correct order, or match the sample type.
212 // See enum perf_event_type in perf_event.h.
213 class SampleInfo {
214  public:
Ip(u64 ip)215   SampleInfo& Ip(u64 ip) { return AddField(ip); }
Tid(u32 pid,u32 tid)216   SampleInfo& Tid(u32 pid, u32 tid) {
217     return AddField(PunU32U64{.v32 = {pid, tid}}.v64);
218   }
Tid(u32 pid)219   SampleInfo& Tid(u32 pid) {
220     return AddField(PunU32U64{.v32 = {pid, pid}}.v64);
221   }
Time(u64 time)222   SampleInfo& Time(u64 time) { return AddField(time); }
Id(u64 id)223   SampleInfo& Id(u64 id) { return AddField(id); }
BranchStack_nr(u64 nr)224   SampleInfo& BranchStack_nr(u64 nr) { return AddField(nr); }
BranchStack_lbr(u64 from,u64 to,u64 flags)225   SampleInfo& BranchStack_lbr(u64 from, u64 to, u64 flags) {
226     AddField(from);
227     AddField(to);
228     AddField(flags);
229     return *this;
230   }
231 
data()232   const char* data() const {
233     return reinterpret_cast<const char*>(fields_.data());
234   }
size()235   const size_t size() const {
236     return fields_.size() * sizeof(decltype(fields_)::value_type);
237   }
238 
239  private:
AddField(u64 value)240   SampleInfo& AddField(u64 value) {
241     fields_.push_back(value);
242     return *this;
243   }
244 
245   std::vector<u64> fields_;
246 };
247 
248 // Produces a PERF_RECORD_MMAP event with the given file and mapping.
249 class ExampleMmapEvent : public StreamWriteable {
250  public:
ExampleMmapEvent(u32 pid,u64 start,u64 len,u64 pgoff,string filename,const SampleInfo & sample_id)251   ExampleMmapEvent(u32 pid, u64 start, u64 len, u64 pgoff, string filename,
252                    const SampleInfo& sample_id)
253       : pid_(pid),
254         start_(start),
255         len_(len),
256         pgoff_(pgoff),
257         filename_(filename),
258         sample_id_(sample_id) {}
259   size_t GetSize() const;
260   void WriteTo(std::ostream* out) const override;
261 
262  private:
263   const u32 pid_;
264   const u64 start_;
265   const u64 len_;
266   const u64 pgoff_;
267   const string filename_;
268   const SampleInfo sample_id_;
269 };
270 
271 // Produces a PERF_RECORD_MMAP2 event with the given file and mapping.
272 class ExampleMmap2Event : public StreamWriteable {
273  public:
274   typedef ExampleMmap2Event SelfT;
275   // pid is used as both pid and tid.
ExampleMmap2Event(u32 pid,u64 start,u64 len,u64 pgoff,string filename,const SampleInfo & sample_id)276   ExampleMmap2Event(u32 pid, u64 start, u64 len, u64 pgoff, string filename,
277                     const SampleInfo& sample_id)
278       : ExampleMmap2Event(pid, pid, start, len, pgoff, filename, sample_id) {}
ExampleMmap2Event(u32 pid,u32 tid,u64 start,u64 len,u64 pgoff,string filename,const SampleInfo & sample_id)279   ExampleMmap2Event(u32 pid, u32 tid, u64 start, u64 len, u64 pgoff,
280                     string filename, const SampleInfo& sample_id)
281       : pid_(pid),
282         tid_(tid),
283         start_(start),
284         len_(len),
285         pgoff_(pgoff),
286         maj_(6),
287         min_(7),
288         ino_(8),
289         filename_(filename),
290         sample_id_(sample_id) {}
291 
WithDeviceInfo(u32 maj,u32 min,u64 ino)292   SelfT& WithDeviceInfo(u32 maj, u32 min, u64 ino) {
293     maj_ = maj;
294     min_ = min;
295     ino_ = ino;
296     return *this;
297   }
298 
299   void WriteTo(std::ostream* out) const override;
300 
301  private:
302   const u32 pid_;
303   const u32 tid_;
304   const u64 start_;
305   const u64 len_;
306   const u64 pgoff_;
307   u32 maj_;
308   u32 min_;
309   u64 ino_;
310   const string filename_;
311   const SampleInfo sample_id_;
312 };
313 
314 // Produces a PERF_RECORD_FORK or PERF_RECORD_EXIT event.
315 // Cannot be instantiated directly; use a derived class.
316 class ExampleForkExitEvent : public StreamWriteable {
317  public:
318   void WriteTo(std::ostream* out) const override;
319 
320  protected:
ExampleForkExitEvent(u32 type,u32 pid,u32 ppid,u32 tid,u32 ptid,u64 time,const SampleInfo & sample_id)321   ExampleForkExitEvent(u32 type, u32 pid, u32 ppid, u32 tid, u32 ptid, u64 time,
322                        const SampleInfo& sample_id)
323       : type_(type),
324         pid_(pid),
325         ppid_(ppid),
326         tid_(tid),
327         ptid_(ptid),
328         time_(time),
329         sample_id_(sample_id) {}
330   const u32 type_;  // Either PERF_RECORD_FORK or PERF_RECORD_EXIT.
331  private:
332   const u32 pid_;
333   const u32 ppid_;
334   const u32 tid_;
335   const u32 ptid_;
336   const u64 time_;
337   const SampleInfo sample_id_;
338 };
339 
340 // Produces a PERF_RECORD_FORK event.
341 class ExampleForkEvent : public ExampleForkExitEvent {
342  public:
ExampleForkEvent(u32 pid,u32 ppid,u32 tid,u32 ptid,u64 time,const SampleInfo & sample_id)343   ExampleForkEvent(u32 pid, u32 ppid, u32 tid, u32 ptid, u64 time,
344                    const SampleInfo& sample_id)
345       : ExampleForkExitEvent(PERF_RECORD_FORK, pid, ppid, tid, ptid, time,
346                              sample_id) {}
347 };
348 
349 // Produces a PERF_RECORD_EXIT event.
350 class ExampleExitEvent : public ExampleForkExitEvent {
351  public:
ExampleExitEvent(u32 pid,u32 ppid,u32 tid,u32 ptid,u64 time,const SampleInfo & sample_id)352   ExampleExitEvent(u32 pid, u32 ppid, u32 tid, u32 ptid, u64 time,
353                    const SampleInfo& sample_id)
354       : ExampleForkExitEvent(PERF_RECORD_EXIT, pid, ppid, tid, ptid, time,
355                              sample_id) {}
356 };
357 
358 // Produces the PERF_RECORD_FINISHED_ROUND event. This event is just a header.
359 class FinishedRoundEvent : public StreamWriteable {
360  public:
361   void WriteTo(std::ostream* out) const override;
362 };
363 
364 // Produces a simple PERF_RECORD_SAMPLE event with the given sample info.
365 // NB: The sample_info must match the sample_type of the relevant attr.
366 class ExamplePerfSampleEvent : public StreamWriteable {
367  public:
ExamplePerfSampleEvent(const SampleInfo & sample_info)368   explicit ExamplePerfSampleEvent(const SampleInfo& sample_info)
369       : sample_info_(sample_info) {}
370   size_t GetSize() const;
371   void WriteTo(std::ostream* out) const override;
372 
373  private:
374   const SampleInfo sample_info_;
375 };
376 
377 class ExamplePerfSampleEvent_BranchStack : public ExamplePerfSampleEvent {
378  public:
379   ExamplePerfSampleEvent_BranchStack();
380   static const size_t kEventSize;
381 };
382 
383 // Produces a struct sample_event matching ExamplePerfFileAttr_Tracepoint.
384 class ExamplePerfSampleEvent_Tracepoint : public StreamWriteable {
385  public:
ExamplePerfSampleEvent_Tracepoint()386   ExamplePerfSampleEvent_Tracepoint() {}
387   void WriteTo(std::ostream* out) const override;
388   static const size_t kEventSize;
389 };
390 
391 // Produces a struct perf_file_section suitable for use in the metadata index.
392 class MetadataIndexEntry : public StreamWriteable {
393  public:
MetadataIndexEntry(u64 offset,u64 size)394   MetadataIndexEntry(u64 offset, u64 size)
395       : index_entry_{.offset = offset, .size = size} {}
WriteTo(std::ostream * out)396   void WriteTo(std::ostream* out) const override {
397     struct perf_file_section entry = {
398         .offset = MaybeSwap64(index_entry_.offset),
399         .size = MaybeSwap64(index_entry_.size),
400     };
401     out->write(reinterpret_cast<const char*>(&entry), sizeof(entry));
402   }
403 
404  public:
405   const perf_file_section index_entry_;
406 };
407 
408 // Produces sample string metadata, and corresponding metadata index entry.
409 class ExampleStringMetadata : public StreamWriteable {
410  public:
411   // The input string gets zero-padded/truncated to |kStringAlignSize| bytes if
412   // it is shorter/longer, respectively.
ExampleStringMetadata(const string & data,size_t offset)413   explicit ExampleStringMetadata(const string& data, size_t offset)
414       : data_(data), index_entry_(offset, sizeof(u32) + kStringAlignSize) {
415     data_.resize(kStringAlignSize);
416   }
417   void WriteTo(std::ostream* out) const override;
418 
index_entry()419   const MetadataIndexEntry& index_entry() { return index_entry_; }
size()420   size_t size() const { return sizeof(u32) + data_.size(); }
421 
WithCrossEndianness(bool value)422   StreamWriteable& WithCrossEndianness(bool value) override {
423     // Set index_entry_'s endianness since it is owned by this class.
424     index_entry_.WithCrossEndianness(value);
425     return StreamWriteable::WithCrossEndianness(value);
426   }
427 
428  private:
429   string data_;
430   MetadataIndexEntry index_entry_;
431 
432   static const int kStringAlignSize = 64;
433 };
434 
435 // Produces sample string metadata event for piped mode.
436 class ExampleStringMetadataEvent : public StreamWriteable {
437  public:
438   // The input string gets aligned to |kStringAlignSize|.
ExampleStringMetadataEvent(u32 type,const string & data)439   explicit ExampleStringMetadataEvent(u32 type, const string& data)
440       : type_(type), data_(data) {
441     data_.resize(kStringAlignSize);
442   }
443   void WriteTo(std::ostream* out) const override;
444 
445  private:
446   u32 type_;
447   string data_;
448 
449   static const int kStringAlignSize = 64;
450 };
451 
452 // Produces sample tracing metadata, and corresponding metadata index entry.
453 class ExampleTracingMetadata {
454  public:
455   class Data : public StreamWriteable {
456    public:
457     static const string kTraceMetadata;
458 
Data(ExampleTracingMetadata * parent)459     explicit Data(ExampleTracingMetadata* parent) : parent_(parent) {}
460 
value()461     const string& value() const { return kTraceMetadata; }
462 
463     void WriteTo(std::ostream* out) const override;
464 
465    private:
466     ExampleTracingMetadata* parent_;
467   };
468 
ExampleTracingMetadata(size_t offset)469   explicit ExampleTracingMetadata(size_t offset)
470       : data_(this), index_entry_(offset, data_.value().size()) {}
471 
data()472   const Data& data() { return data_; }
index_entry()473   const MetadataIndexEntry& index_entry() { return index_entry_; }
474 
475  private:
476   friend class Data;
477   Data data_;
478   MetadataIndexEntry index_entry_;
479 };
480 
481 // Produces a PERF_RECORD_AUXTRACE event.
482 class ExampleAuxtraceEvent : public StreamWriteable {
483  public:
ExampleAuxtraceEvent(u64 size,u64 offset,u64 reference,u32 idx,u32 tid,u32 cpu,u32 reserved,string trace_data)484   ExampleAuxtraceEvent(u64 size, u64 offset, u64 reference, u32 idx, u32 tid,
485                        u32 cpu, u32 reserved, string trace_data)
486       : size_(size),
487         offset_(offset),
488         reference_(reference),
489         idx_(idx),
490         tid_(tid),
491         cpu_(cpu),
492         reserved_(reserved),
493         trace_data_(std::move(trace_data)) {}
494   size_t GetSize() const;
495   size_t GetTraceSize() const;
496   void WriteTo(std::ostream* out) const override;
497 
498  private:
499   const u64 size_;
500   const u64 offset_;
501   const u64 reference_;
502   const u32 idx_;
503   const u32 tid_;
504   const u32 cpu_;
505   const u32 reserved_;
506   const string trace_data_;
507 };
508 
509 }  // namespace testing
510 }  // namespace quipper
511 
512 #endif  // CHROMIUMOS_WIDE_PROFILING_TEST_PERF_DATA_H_
513