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 #include "test_perf_data.h"
      6 
      7 #include <stddef.h>
      8 
      9 #include <algorithm>
     10 #include <ostream>
     11 #include <vector>
     12 
     13 #include "base/logging.h"
     14 
     15 #include "binary_data_utils.h"
     16 #include "compat/string.h"
     17 #include "kernel/perf_internals.h"
     18 #include "perf_data_utils.h"
     19 
     20 namespace quipper {
     21 namespace testing {
     22 
     23 namespace {
     24 
     25 // Write extra bytes to an output stream.
     26 void WriteExtraBytes(size_t size, std::ostream* out) {
     27   std::vector<char> padding(size);
     28   out->write(padding.data(), size);
     29 }
     30 u8 ReverseByte(u8 x) {
     31   x = (x & 0xf0) >> 4 | (x & 0x0f) << 4;  // exchange nibbles
     32   x = (x & 0xcc) >> 2 | (x & 0x33) << 2;  // exchange pairs
     33   x = (x & 0xaa) >> 1 | (x & 0x55) << 1;  // exchange neighbors
     34   return x;
     35 }
     36 
     37 void SwapBitfieldOfBits(u8* field, size_t len) {
     38   for (size_t i = 0; i < len; i++) {
     39     field[i] = ReverseByte(field[i]);
     40   }
     41 }
     42 
     43 }  // namespace
     44 
     45 ExamplePerfDataFileHeader::ExamplePerfDataFileHeader(
     46     const unsigned long features) {
     47   CHECK_EQ(112U, sizeof(perf_file_attr)) << "perf_file_attr has changed size";
     48   header_ = {
     49       .magic = kPerfMagic,
     50       .size = 104,
     51       .attr_size = sizeof(struct perf_file_attr),
     52       .attrs = {.offset = 104, .size = 0},
     53       .data = {.offset = 104, .size = 0},
     54       .event_types = {0},
     55       .adds_features = {features, 0, 0, 0},
     56   };
     57 }
     58 
     59 ExamplePerfDataFileHeader& ExamplePerfDataFileHeader::WithAttrIdsCount(
     60     size_t n) {
     61   attr_ids_count_ = n;
     62   UpdateSectionOffsets();
     63   return *this;
     64 }
     65 
     66 ExamplePerfDataFileHeader& ExamplePerfDataFileHeader::WithAttrCount(size_t n) {
     67   header_.attrs.size = n * header_.attr_size;
     68   UpdateSectionOffsets();
     69   return *this;
     70 }
     71 
     72 ExamplePerfDataFileHeader& ExamplePerfDataFileHeader::WithDataSize(size_t sz) {
     73   header_.data.size = sz;
     74   UpdateSectionOffsets();
     75   return *this;
     76 }
     77 
     78 ExamplePerfDataFileHeader&
     79 ExamplePerfDataFileHeader::WithCustomPerfEventAttrSize(size_t sz) {
     80   size_t n_attrs = header_.attrs.size / header_.attr_size;
     81   // Calculate sizeof(perf_file_attr) given the custom sizeof(perf_event_attr)
     82   header_.attr_size = sz + sizeof(perf_file_section);
     83   // Re-calculate the attrs section size and update offsets.
     84   return WithAttrCount(n_attrs);
     85 }
     86 
     87 void ExamplePerfDataFileHeader::UpdateSectionOffsets() {
     88   u64 offset = header_.size;
     89   offset += attr_ids_count_ * sizeof(u64);
     90   header_.attrs.offset = offset;
     91   offset += header_.attrs.size;
     92   header_.data.offset = offset;
     93   offset += header_.data.size;
     94   CHECK_EQ(data_end_offset(), offset);  // aka, the metadata offset.
     95 }
     96 
     97 void ExamplePerfDataFileHeader::WriteTo(std::ostream* out) const {
     98   struct perf_file_header local_header = {
     99       .magic = MaybeSwap64(header_.magic),
    100       .size = MaybeSwap64(header_.size),
    101       .attr_size = MaybeSwap64(header_.attr_size),
    102       .attrs = {.offset = MaybeSwap64(header_.attrs.offset),
    103                 .size = MaybeSwap64(header_.attrs.size)},
    104       .data = {.offset = MaybeSwap64(header_.data.offset),
    105                .size = MaybeSwap64(header_.data.size)},
    106       .event_types = {.offset = MaybeSwap64(header_.event_types.offset),
    107                       .size = MaybeSwap64(header_.event_types.size)},
    108       .adds_features = {0},
    109   };
    110   // Copy over the features bits manually since the byte swapping is more
    111   // complicated.
    112   for (size_t i = 0; i < sizeof(header_.adds_features) / sizeof(uint64_t);
    113        ++i) {
    114     reinterpret_cast<uint64_t*>(local_header.adds_features)[i] = MaybeSwap64(
    115         reinterpret_cast<const uint64_t*>(header_.adds_features)[i]);
    116   }
    117 
    118   out->write(reinterpret_cast<const char*>(&local_header),
    119              sizeof(local_header));
    120   // Use original header values that weren't endian-swapped.
    121   CHECK_EQ(static_cast<u64>(out->tellp()), header_.size);
    122 }
    123 
    124 void ExamplePipedPerfDataFileHeader::WriteTo(std::ostream* out) const {
    125   const perf_pipe_file_header header = {
    126       .magic = kPerfMagic,
    127       .size = 16,
    128   };
    129   out->write(reinterpret_cast<const char*>(&header), sizeof(header));
    130   CHECK_EQ(static_cast<u64>(out->tellp()), header.size);
    131 }
    132 
    133 void ExamplePerfEventAttrEvent_Hardware::WriteTo(std::ostream* out) const {
    134   // Due to the unnamed union fields (eg, sample_period), this structure can't
    135   // be initialized with designated initializers.
    136   perf_event_attr attr = {};
    137   attr.type = PERF_TYPE_HARDWARE;
    138   attr.size = attr_size_;
    139   attr.config = config_;
    140   attr.sample_period = 100001;
    141   attr.sample_type = sample_type_;
    142   attr.read_format = read_format_;
    143   attr.sample_id_all = sample_id_all_;
    144 
    145   const size_t event_size = sizeof(perf_event_header) + attr.size +
    146                             ids_.size() * sizeof(decltype(ids_)::value_type);
    147 
    148   const perf_event_header header = {
    149       .type = PERF_RECORD_HEADER_ATTR,
    150       .misc = 0,
    151       .size = static_cast<u16>(event_size),
    152   };
    153 
    154   out->write(reinterpret_cast<const char*>(&header), sizeof(header));
    155   out->write(reinterpret_cast<const char*>(&attr),
    156              std::min(sizeof(attr), static_cast<size_t>(attr_size_)));
    157   if (sizeof(attr) < attr_size_)
    158     WriteExtraBytes(attr_size_ - sizeof(attr), out);
    159   out->write(reinterpret_cast<const char*>(ids_.data()),
    160              ids_.size() * sizeof(decltype(ids_)::value_type));
    161 }
    162 
    163 void AttrIdsSection::WriteTo(std::ostream* out) const {
    164   out->write(reinterpret_cast<const char*>(ids_.data()),
    165              ids_.size() * sizeof(decltype(ids_)::value_type));
    166 }
    167 
    168 void ExamplePerfFileAttr_Hardware::WriteTo(std::ostream* out) const {
    169   // Due to the unnamed union fields (eg, sample_period), this structure can't
    170   // be initialized with designated initializers.
    171   perf_event_attr attr = {0};
    172   attr.type = MaybeSwap32(PERF_TYPE_HARDWARE);
    173   attr.size = MaybeSwap32(attr_size_);
    174   attr.config = MaybeSwap64(config_);
    175   attr.sample_period = MaybeSwap64(1);
    176   attr.sample_type = MaybeSwap64(sample_type_);
    177   // Bit fields.
    178   attr.sample_id_all = sample_id_all_;
    179   attr.precise_ip = 2;  // For testing a bit field that is more than one bit.
    180 
    181   if (is_cross_endian()) {
    182     // The order of operations here is for native-to-cross-endian conversion.
    183     // Contrast with similar code in PerfReader for cross-endian-to-native
    184     // conversion, which performs these swap operations in reverse order.
    185     const auto tmp = attr.precise_ip;
    186     attr.precise_ip = (tmp & 0x2) >> 1 | (tmp & 0x1) << 1;
    187 
    188     auto* const bitfield_start = &attr.read_format + 1;
    189     SwapBitfieldOfBits(reinterpret_cast<u8*>(bitfield_start), sizeof(u64));
    190   }
    191 
    192   // perf_event_attr can be of a size other than the static struct size. Thus we
    193   // cannot simply statically create a perf_file_attr (which contains a
    194   // perf_event_attr and a perf_file_section). Instead, create and write each
    195   // component separately.
    196   out->write(reinterpret_cast<const char*>(&attr),
    197              std::min(sizeof(attr), static_cast<size_t>(attr_size_)));
    198   if (sizeof(attr) < attr_size_)
    199     WriteExtraBytes(attr_size_ - sizeof(attr), out);
    200 
    201   out->write(reinterpret_cast<const char*>(&ids_section_),
    202              sizeof(ids_section_));
    203 }
    204 
    205 void ExamplePerfFileAttr_Tracepoint::WriteTo(std::ostream* out) const {
    206   // Due to the unnamed union fields (eg, sample_period), this structure can't
    207   // be initialized with designated initializers.
    208   perf_event_attr attr = {};
    209   // See kernel src: tools/perf/util/evsel.c perf_evsel__newtp()
    210   attr.type = PERF_TYPE_TRACEPOINT;
    211   attr.size = sizeof(perf_event_attr);
    212   attr.config = tracepoint_event_id_;
    213   attr.sample_period = 1;
    214   attr.sample_type = (PERF_SAMPLE_IP | PERF_SAMPLE_TID | PERF_SAMPLE_TIME |
    215                       PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD | PERF_SAMPLE_RAW);
    216 
    217   const perf_file_attr file_attr = {
    218       .attr = attr,
    219       .ids = {.offset = 104, .size = 0},
    220   };
    221   out->write(reinterpret_cast<const char*>(&file_attr), sizeof(file_attr));
    222 }
    223 
    224 size_t ExampleMmapEvent::GetSize() const {
    225   return offsetof(struct mmap_event, filename) +
    226          GetUint64AlignedStringLength(filename_) +
    227          sample_id_.size();  // sample_id_all
    228 }
    229 
    230 void ExampleMmapEvent::WriteTo(std::ostream* out) const {
    231   const size_t event_size = GetSize();
    232 
    233   struct mmap_event event = {
    234       .header =
    235           {
    236               .type = MaybeSwap32(PERF_RECORD_MMAP),
    237               .misc = 0,
    238               .size = MaybeSwap16(static_cast<u16>(event_size)),
    239           },
    240       .pid = MaybeSwap32(pid_),
    241       .tid = MaybeSwap32(pid_),
    242       .start = MaybeSwap64(start_),
    243       .len = MaybeSwap64(len_),
    244       .pgoff = MaybeSwap64(pgoff_),
    245       // .filename = ..., // written separately
    246   };
    247 
    248   const size_t pre_mmap_offset = out->tellp();
    249   out->write(reinterpret_cast<const char*>(&event),
    250              offsetof(struct mmap_event, filename));
    251   const size_t filename_aligned_length =
    252       GetUint64AlignedStringLength(filename_);
    253   *out << filename_ << string(filename_aligned_length - filename_.size(), '\0');
    254   out->write(sample_id_.data(), sample_id_.size());
    255   const size_t written_event_size =
    256       static_cast<size_t>(out->tellp()) - pre_mmap_offset;
    257   CHECK_EQ(event_size, static_cast<u64>(written_event_size));
    258 }
    259 
    260 void ExampleMmap2Event::WriteTo(std::ostream* out) const {
    261   const size_t filename_aligned_length =
    262       GetUint64AlignedStringLength(filename_);
    263   const size_t event_size = offsetof(struct mmap2_event, filename) +
    264                             filename_aligned_length +
    265                             sample_id_.size();  // sample_id_all
    266 
    267   struct mmap2_event event = {
    268       .header =
    269           {
    270               .type = PERF_RECORD_MMAP2,
    271               .misc = 0,
    272               .size = static_cast<u16>(event_size),
    273           },
    274       .pid = pid_,
    275       .tid = tid_,
    276       .start = start_,
    277       .len = len_,
    278       .pgoff = pgoff_,
    279       .maj = maj_,
    280       .min = min_,
    281       .ino = ino_,
    282       .ino_generation = 9,
    283       .prot = 1 | 2,  // == PROT_READ | PROT_WRITE
    284       .flags = 2,     // == MAP_PRIVATE
    285                       // .filename = ..., // written separately
    286   };
    287 
    288   const size_t pre_mmap_offset = out->tellp();
    289   out->write(reinterpret_cast<const char*>(&event),
    290              offsetof(struct mmap2_event, filename));
    291   *out << filename_ << string(filename_aligned_length - filename_.size(), '\0');
    292   out->write(sample_id_.data(), sample_id_.size());
    293   const size_t written_event_size =
    294       static_cast<size_t>(out->tellp()) - pre_mmap_offset;
    295   CHECK_EQ(event.header.size, static_cast<u64>(written_event_size));
    296 }
    297 
    298 void ExampleForkExitEvent::WriteTo(std::ostream* out) const {
    299   const size_t event_size = sizeof(struct fork_event) + sample_id_.size();
    300 
    301   struct fork_event event = {
    302       .header =
    303           {
    304               .type = MaybeSwap32(type_),
    305               .misc = 0,
    306               .size = MaybeSwap16(static_cast<u16>(event_size)),
    307           },
    308       .pid = MaybeSwap32(pid_),
    309       .ppid = MaybeSwap32(ppid_),
    310       .tid = MaybeSwap32(tid_),
    311       .ptid = MaybeSwap32(ptid_),
    312       .time = MaybeSwap64(time_),
    313   };
    314 
    315   const size_t pre_event_offset = out->tellp();
    316   out->write(reinterpret_cast<const char*>(&event), sizeof(event));
    317   out->write(sample_id_.data(), sample_id_.size());
    318   const size_t written_event_size =
    319       static_cast<size_t>(out->tellp()) - pre_event_offset;
    320   CHECK_EQ(MaybeSwap16(event.header.size),
    321            static_cast<u64>(written_event_size));
    322 }
    323 
    324 void FinishedRoundEvent::WriteTo(std::ostream* out) const {
    325   const perf_event_header event = {
    326       .type = PERF_RECORD_FINISHED_ROUND,
    327       .misc = 0,
    328       .size = sizeof(struct perf_event_header),
    329   };
    330   out->write(reinterpret_cast<const char*>(&event), sizeof(event));
    331 }
    332 
    333 size_t ExamplePerfSampleEvent::GetSize() const {
    334   return sizeof(struct sample_event) + sample_info_.size();
    335 }
    336 
    337 void ExamplePerfSampleEvent::WriteTo(std::ostream* out) const {
    338   const sample_event event = {
    339       .header = {
    340           .type = MaybeSwap32(PERF_RECORD_SAMPLE),
    341           .misc = MaybeSwap16(PERF_RECORD_MISC_USER),
    342           .size = MaybeSwap16(static_cast<u16>(GetSize())),
    343       }};
    344   out->write(reinterpret_cast<const char*>(&event), sizeof(event));
    345   out->write(sample_info_.data(), sample_info_.size());
    346 }
    347 
    348 ExamplePerfSampleEvent_BranchStack::ExamplePerfSampleEvent_BranchStack()
    349     : ExamplePerfSampleEvent(
    350           SampleInfo()
    351               .BranchStack_nr(16)
    352               .BranchStack_lbr(0x00007f4a313bb8cc, 0x00007f4a313bdb40, 0x02)
    353               .BranchStack_lbr(0x00007f4a30ce4de2, 0x00007f4a313bb8b3, 0x02)
    354               .BranchStack_lbr(0x00007f4a313bb8b0, 0x00007f4a30ce4de0, 0x01)
    355               .BranchStack_lbr(0x00007f4a30ff45c1, 0x00007f4a313bb8a0, 0x02)
    356               .BranchStack_lbr(0x00007f4a30ff49f2, 0x00007f4a30ff45bb, 0x02)
    357               .BranchStack_lbr(0x00007f4a30ff4a98, 0x00007f4a30ff49ed, 0x02)
    358               .BranchStack_lbr(0x00007f4a30ff4a7c, 0x00007f4a30ff4a91, 0x02)
    359               .BranchStack_lbr(0x00007f4a30ff4a34, 0x00007f4a30ff4a46, 0x02)
    360               .BranchStack_lbr(0x00007f4a30ff4c22, 0x00007f4a30ff4a0e, 0x02)
    361               .BranchStack_lbr(0x00007f4a30ff4bb3, 0x00007f4a30ff4c1b, 0x01)
    362               .BranchStack_lbr(0x00007f4a30ff4a09, 0x00007f4a30ff4b60, 0x02)
    363               .BranchStack_lbr(0x00007f4a30ff49e8, 0x00007f4a30ff4a00, 0x02)
    364               .BranchStack_lbr(0x00007f4a30ff42db, 0x00007f4a30ff49e0, 0x02)
    365               .BranchStack_lbr(0x00007f4a30ff42bb, 0x00007f4a30ff42d4, 0x02)
    366               .BranchStack_lbr(0x00007f4a333bf88b, 0x00007f4a30ff42ac, 0x02)
    367               .BranchStack_lbr(0x00007f4a333bf853, 0x00007f4a333bf885, 0x02)) {}
    368 
    369 // Event size matching the event produced above
    370 const size_t ExamplePerfSampleEvent_BranchStack::kEventSize =
    371     (1 /*perf_event_header*/ + 1 /*nr*/ + 16 * 3 /*lbr*/) * sizeof(u64);
    372 
    373 void ExamplePerfSampleEvent_Tracepoint::WriteTo(std::ostream* out) const {
    374   const sample_event event = {.header = {
    375                                   .type = PERF_RECORD_SAMPLE,
    376                                   .misc = PERF_RECORD_MISC_USER,
    377                                   .size = 0x0078,
    378                               }};
    379   const u64 sample_event_array[] = {
    380       0x00007f999c38d15a,  // IP
    381       0x0000068d0000068d,  // TID (u32 pid, tid)
    382       0x0001e0211cbab7b9,  // TIME
    383       0x0000000000000000,  // CPU
    384       0x0000000000000001,  // PERIOD
    385       0x0000004900000044,  // RAW (u32 size = 0x44 = 68 = 4 + 8*sizeof(u64))
    386       0x000000090000068d,  //  .
    387       0x0000000000000000,  //  .
    388       0x0000100000000000,  //  .
    389       0x0000000300000000,  //  .
    390       0x0000002200000000,  //  .
    391       0xffffffff00000000,  //  .
    392       0x0000000000000000,  //  .
    393       0x0000000000000000,  //  .
    394   };
    395   CHECK_EQ(event.header.size,
    396            sizeof(event.header) + sizeof(sample_event_array));
    397   out->write(reinterpret_cast<const char*>(&event), sizeof(event));
    398   out->write(reinterpret_cast<const char*>(sample_event_array),
    399              sizeof(sample_event_array));
    400 }
    401 
    402 // Event size matching the event produced above
    403 const size_t ExamplePerfSampleEvent_Tracepoint::kEventSize =
    404     (1 /*perf_event_header*/ + 14 /*sample array*/) * sizeof(u64);
    405 
    406 void ExampleStringMetadata::WriteTo(std::ostream* out) const {
    407   const perf_file_section& index_entry = index_entry_.index_entry_;
    408   CHECK_EQ(static_cast<u64>(out->tellp()), index_entry.offset);
    409   const u32 data_size_value = MaybeSwap32(data_.size());
    410   out->write(reinterpret_cast<const char*>(&data_size_value),
    411              sizeof(data_size_value));
    412   out->write(data_.data(), data_.size());
    413 
    414   CHECK_EQ(static_cast<u64>(out->tellp()), index_entry.offset + size());
    415 }
    416 
    417 void ExampleStringMetadataEvent::WriteTo(std::ostream* out) const {
    418   const size_t initial_position = out->tellp();
    419 
    420   const u32 data_size = data_.size();
    421   const perf_event_header header = {
    422       .type = type_,
    423       .misc = 0,
    424       .size =
    425           static_cast<u16>(sizeof(header) + sizeof(data_size) + data_.size()),
    426   };
    427   out->write(reinterpret_cast<const char*>(&header), sizeof(header));
    428 
    429   out->write(reinterpret_cast<const char*>(&data_size), sizeof(data_size));
    430   out->write(reinterpret_cast<const char*>(data_.data()), data_.size());
    431 
    432   CHECK_EQ(static_cast<u64>(out->tellp()), initial_position + header.size);
    433 }
    434 
    435 static const char kTraceMetadataValue[] =
    436     "\x17\x08\x44tracing0.5BLAHBLAHBLAH....";
    437 
    438 const string ExampleTracingMetadata::Data::kTraceMetadata(
    439     kTraceMetadataValue, sizeof(kTraceMetadataValue) - 1);
    440 
    441 void ExampleTracingMetadata::Data::WriteTo(std::ostream* out) const {
    442   const perf_file_section& index_entry = parent_->index_entry_.index_entry_;
    443   CHECK_EQ(static_cast<u64>(out->tellp()), index_entry.offset);
    444   out->write(kTraceMetadata.data(), kTraceMetadata.size());
    445   CHECK_EQ(static_cast<u64>(out->tellp()),
    446            index_entry.offset + index_entry.size);
    447 }
    448 
    449 size_t ExampleAuxtraceEvent::GetSize() const {
    450   return sizeof(struct auxtrace_event);
    451 }
    452 
    453 size_t ExampleAuxtraceEvent::GetTraceSize() const { return trace_data_.size(); }
    454 
    455 void ExampleAuxtraceEvent::WriteTo(std::ostream* out) const {
    456   const size_t event_size = GetSize();
    457 
    458   struct auxtrace_event event = {
    459       .header =
    460           {
    461               .type = MaybeSwap32(PERF_RECORD_AUXTRACE),
    462               .misc = 0,
    463               .size = MaybeSwap16(static_cast<u16>(event_size)),
    464           },
    465       .size = MaybeSwap64(size_),
    466       .offset = MaybeSwap64(offset_),
    467       .reference = MaybeSwap64(reference_),
    468       .idx = MaybeSwap32(idx_),
    469       .tid = MaybeSwap32(tid_),
    470       .cpu = MaybeSwap32(cpu_),
    471       .reserved__ = MaybeSwap32(reserved_),
    472   };
    473 
    474   out->write(reinterpret_cast<const char*>(&event), event_size);
    475   out->write(trace_data_.data(), trace_data_.size());
    476 }
    477 
    478 }  // namespace testing
    479 }  // namespace quipper
    480