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