• 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 #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.
WriteExtraBytes(size_t size,std::ostream * out)26 void WriteExtraBytes(size_t size, std::ostream* out) {
27   std::vector<char> padding(size);
28   out->write(padding.data(), size);
29 }
ReverseByte(u8 x)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 
SwapBitfieldOfBits(u8 * field,size_t len)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 
ExamplePerfDataFileHeader(const unsigned long features)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 
WithAttrIdsCount(size_t n)59 ExamplePerfDataFileHeader& ExamplePerfDataFileHeader::WithAttrIdsCount(
60     size_t n) {
61   attr_ids_count_ = n;
62   UpdateSectionOffsets();
63   return *this;
64 }
65 
WithAttrCount(size_t n)66 ExamplePerfDataFileHeader& ExamplePerfDataFileHeader::WithAttrCount(size_t n) {
67   header_.attrs.size = n * header_.attr_size;
68   UpdateSectionOffsets();
69   return *this;
70 }
71 
WithDataSize(size_t sz)72 ExamplePerfDataFileHeader& ExamplePerfDataFileHeader::WithDataSize(size_t sz) {
73   header_.data.size = sz;
74   UpdateSectionOffsets();
75   return *this;
76 }
77 
78 ExamplePerfDataFileHeader&
WithCustomPerfEventAttrSize(size_t sz)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 
UpdateSectionOffsets()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 
WriteTo(std::ostream * out) const97 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 
WriteTo(std::ostream * out) const124 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 
WriteTo(std::ostream * out) const133 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 
WriteTo(std::ostream * out) const163 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 
WriteTo(std::ostream * out) const168 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 
WriteTo(std::ostream * out) const205 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 
GetSize() const224 size_t ExampleMmapEvent::GetSize() const {
225   return offsetof(struct mmap_event, filename) +
226          GetUint64AlignedStringLength(filename_) +
227          sample_id_.size();  // sample_id_all
228 }
229 
WriteTo(std::ostream * out) const230 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 
WriteTo(std::ostream * out) const260 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 
WriteTo(std::ostream * out) const298 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 
WriteTo(std::ostream * out) const324 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 
GetSize() const333 size_t ExamplePerfSampleEvent::GetSize() const {
334   return sizeof(struct sample_event) + sample_info_.size();
335 }
336 
WriteTo(std::ostream * out) const337 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 
ExamplePerfSampleEvent_BranchStack()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 
WriteTo(std::ostream * out) const373 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 
WriteTo(std::ostream * out) const406 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 
WriteTo(std::ostream * out) const417 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 
WriteTo(std::ostream * out) const441 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 
GetSize() const449 size_t ExampleAuxtraceEvent::GetSize() const {
450   return sizeof(struct auxtrace_event);
451 }
452 
GetTraceSize() const453 size_t ExampleAuxtraceEvent::GetTraceSize() const { return trace_data_.size(); }
454 
WriteTo(std::ostream * out) const455 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