Home | History | Annotate | Download | only in quipper
      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:
     27   StreamWriteable() : is_cross_endian_(false) {}
     28   virtual ~StreamWriteable() {}
     29 
     30   virtual void WriteTo(std::ostream* out) const = 0;
     31 
     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.
     40   uint16_t MaybeSwap16(uint16_t value) const { return MaybeSwap(value); }
     41   uint32_t MaybeSwap32(uint32_t value) const { return MaybeSwap(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.
     48   bool is_cross_endian() const { return is_cross_endian_; }
     49 
     50  private:
     51   template <typename T>
     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 
     73   const struct perf_file_header& header() const { return header_; }
     74 
     75   u64 data_end_offset() const {
     76     return header_.data.offset + header_.data.size;
     77   }
     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:
     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;
    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) {}
    110   SelfT& WithConfig(u64 config) {
    111     config_ = config;
    112     return *this;
    113   }
    114   SelfT& WithAttrSize(u32 size) {
    115     attr_size_ = size;
    116     return *this;
    117   }
    118   SelfT& WithReadFormat(u64 format) {
    119     read_format_ = format;
    120     return *this;
    121   }
    122 
    123   SelfT& WithId(u64 id) {
    124     ids_.push_back(id);
    125     return *this;
    126   }
    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:
    144   explicit AttrIdsSection(size_t initial_offset) : offset_(initial_offset) {}
    145 
    146   perf_file_section AddId(u64 id) { return AddIds({id}); }
    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;
    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)}) {}
    174   SelfT& WithAttrSize(u32 size) {
    175     attr_size_ = size;
    176     return *this;
    177   }
    178   SelfT& WithConfig(u64 config) {
    179     config_ = config;
    180     return *this;
    181   }
    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:
    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:
    215   SampleInfo& Ip(u64 ip) { return AddField(ip); }
    216   SampleInfo& Tid(u32 pid, u32 tid) {
    217     return AddField(PunU32U64{.v32 = {pid, tid}}.v64);
    218   }
    219   SampleInfo& Tid(u32 pid) {
    220     return AddField(PunU32U64{.v32 = {pid, pid}}.v64);
    221   }
    222   SampleInfo& Time(u64 time) { return AddField(time); }
    223   SampleInfo& Id(u64 id) { return AddField(id); }
    224   SampleInfo& BranchStack_nr(u64 nr) { return AddField(nr); }
    225   SampleInfo& BranchStack_lbr(u64 from, u64 to, u64 flags) {
    226     AddField(from);
    227     AddField(to);
    228     AddField(flags);
    229     return *this;
    230   }
    231 
    232   const char* data() const {
    233     return reinterpret_cast<const char*>(fields_.data());
    234   }
    235   const size_t size() const {
    236     return fields_.size() * sizeof(decltype(fields_)::value_type);
    237   }
    238 
    239  private:
    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:
    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.
    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) {}
    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 
    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:
    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:
    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:
    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:
    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:
    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:
    394   MetadataIndexEntry(u64 offset, u64 size)
    395       : index_entry_{.offset = offset, .size = size} {}
    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.
    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 
    419   const MetadataIndexEntry& index_entry() { return index_entry_; }
    420   size_t size() const { return sizeof(u32) + data_.size(); }
    421 
    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|.
    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 
    459     explicit Data(ExampleTracingMetadata* parent) : parent_(parent) {}
    460 
    461     const string& value() const { return kTraceMetadata; }
    462 
    463     void WriteTo(std::ostream* out) const override;
    464 
    465    private:
    466     ExampleTracingMetadata* parent_;
    467   };
    468 
    469   explicit ExampleTracingMetadata(size_t offset)
    470       : data_(this), index_entry_(offset, data_.value().size()) {}
    471 
    472   const Data& data() { return data_; }
    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:
    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