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