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