| // Copyright (c) 2014 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROMIUMOS_WIDE_PROFILING_TEST_PERF_DATA_H_ |
| #define CHROMIUMOS_WIDE_PROFILING_TEST_PERF_DATA_H_ |
| |
| #include <memory> |
| #include <ostream> // NOLINT |
| #include <vector> |
| |
| #include "chromiumos-wide-profiling/compat/string.h" |
| #include "chromiumos-wide-profiling/kernel/perf_internals.h" |
| #include "chromiumos-wide-profiling/utils.h" |
| |
| namespace quipper { |
| namespace testing { |
| |
| // Union for punning 32-bit words into a 64-bit word. |
| union PunU32U64 { |
| u32 v32[2]; |
| u64 v64; |
| }; |
| |
| class StreamWriteable { |
| public: |
| StreamWriteable() : is_cross_endian_(false) {} |
| virtual ~StreamWriteable() {} |
| |
| virtual void WriteTo(std::ostream* out) const = 0; |
| |
| virtual StreamWriteable& WithCrossEndianness(bool value) { |
| is_cross_endian_ = value; |
| return *this; |
| } |
| |
| // Do not call MaybeSwap() directly. The syntax of test data structure |
| // initialization makes data sizes ambiguous, so these force the caller to |
| // explicitly specify value sizes. |
| uint16_t MaybeSwap16(uint16_t value) const { |
| return MaybeSwap(value); |
| } |
| uint32_t MaybeSwap32(uint32_t value) const { |
| return MaybeSwap(value); |
| } |
| uint64_t MaybeSwap64(uint64_t value) const { |
| return MaybeSwap(value); |
| } |
| |
| protected: |
| // Derived classes can call this to determine the cross-endianness. However, |
| // the actual implementation of cross-endianness is up to the derived class, |
| // if it supports it at all. |
| bool is_cross_endian() const { |
| return is_cross_endian_; |
| } |
| |
| private: |
| template <typename T> |
| T MaybeSwap(T value) const { |
| if (is_cross_endian()) |
| ByteSwap(&value); |
| return value; |
| } |
| |
| bool is_cross_endian_; |
| }; |
| |
| // Normal mode header |
| class ExamplePerfDataFileHeader : public StreamWriteable { |
| public: |
| typedef ExamplePerfDataFileHeader SelfT; |
| explicit ExamplePerfDataFileHeader(const unsigned long features); // NOLINT |
| |
| SelfT& WithAttrIdsCount(size_t n); |
| SelfT& WithAttrCount(size_t n); |
| SelfT& WithDataSize(size_t sz); |
| |
| // Used for testing compatibility w.r.t. sizeof(perf_event_attr) |
| SelfT& WithCustomPerfEventAttrSize(size_t sz); |
| |
| const struct perf_file_header& header() const { |
| return header_; |
| } |
| |
| u64 data_end_offset() const { |
| return header_.data.offset + header_.data.size; |
| } |
| ssize_t data_end() const { |
| return static_cast<ssize_t>(data_end_offset()); |
| } |
| |
| void WriteTo(std::ostream* out) const override; |
| |
| protected: |
| struct perf_file_header header_; |
| size_t attr_ids_count_ = 0; |
| |
| private: |
| void UpdateSectionOffsets(); |
| }; |
| |
| // Produces the pipe-mode file header. |
| class ExamplePipedPerfDataFileHeader : public StreamWriteable { |
| public: |
| ExamplePipedPerfDataFileHeader() {} |
| void WriteTo(std::ostream* out) const override; |
| }; |
| |
| // Produces a PERF_RECORD_HEADER_ATTR event with struct perf_event_attr |
| // describing a hardware event. The sample_type mask and the sample_id_all |
| // bit are paramatized. |
| class ExamplePerfEventAttrEvent_Hardware : public StreamWriteable { |
| public: |
| typedef ExamplePerfEventAttrEvent_Hardware SelfT; |
| explicit ExamplePerfEventAttrEvent_Hardware(u64 sample_type, |
| bool sample_id_all) |
| : attr_size_(sizeof(perf_event_attr)), |
| sample_type_(sample_type), |
| sample_id_all_(sample_id_all), |
| config_(0) { |
| } |
| SelfT& WithConfig(u64 config) { config_ = config; return *this; } |
| SelfT& WithAttrSize(u32 size) { attr_size_ = size; return *this; } |
| SelfT& WithId(u64 id) { ids_.push_back(id); return *this; } |
| SelfT& WithIds(std::initializer_list<u64> ids) { |
| ids_.insert(ids_.end(), ids.begin(), ids.end()); |
| return *this; |
| } |
| void WriteTo(std::ostream* out) const override; |
| private: |
| u32 attr_size_; |
| const u64 sample_type_; |
| const bool sample_id_all_; |
| u64 config_; |
| std::vector<u64> ids_; |
| }; |
| |
| class AttrIdsSection : public StreamWriteable { |
| public: |
| explicit AttrIdsSection(size_t initial_offset) : offset_(initial_offset) {} |
| |
| perf_file_section AddId(u64 id) { return AddIds({id}); } |
| perf_file_section AddIds(std::initializer_list<u64> ids) { |
| ids_.insert(ids_.end(), ids.begin(), ids.end()); |
| perf_file_section s = { |
| .offset = offset_, |
| .size = ids.size() * sizeof(decltype(ids)::value_type), |
| }; |
| offset_ += s.size; |
| return s; |
| } |
| void WriteTo(std::ostream* out) const override; |
| private: |
| u64 offset_; |
| std::vector<u64> ids_; |
| }; |
| |
| // Produces a struct perf_file_attr with a perf_event_attr describing a |
| // hardware event. |
| class ExamplePerfFileAttr_Hardware : public StreamWriteable { |
| public: |
| typedef ExamplePerfFileAttr_Hardware SelfT; |
| explicit ExamplePerfFileAttr_Hardware(u64 sample_type, bool sample_id_all) |
| : attr_size_(sizeof(perf_event_attr)), |
| sample_type_(sample_type), |
| sample_id_all_(sample_id_all), |
| config_(0), |
| ids_section_({.offset = MaybeSwap64(104), .size = MaybeSwap64(0)}) { |
| } |
| SelfT& WithAttrSize(u32 size) { attr_size_ = size; return *this; } |
| SelfT& WithConfig(u64 config) { config_ = config; return *this; } |
| SelfT& WithIds(const perf_file_section& section) { |
| ids_section_ = section; |
| return *this; |
| } |
| void WriteTo(std::ostream* out) const override; |
| private: |
| u32 attr_size_; |
| const u64 sample_type_; |
| const bool sample_id_all_; |
| u64 config_; |
| perf_file_section ids_section_; |
| }; |
| |
| // Produces a struct perf_file_attr with a perf_event_attr describing a |
| // tracepoint event. |
| class ExamplePerfFileAttr_Tracepoint : public StreamWriteable { |
| public: |
| explicit ExamplePerfFileAttr_Tracepoint(const u64 tracepoint_event_id) |
| : tracepoint_event_id_(tracepoint_event_id) {} |
| void WriteTo(std::ostream* out) const override; |
| private: |
| const u64 tracepoint_event_id_; |
| }; |
| |
| // Produces a sample field array that can be used with either SAMPLE events |
| // or as the sample_id of another event. |
| // NB: This class simply places the fields in the order called. It does not |
| // enforce that they are in the correct order, or match the sample type. |
| // See enum perf_event_type in perf_event.h. |
| class SampleInfo { |
| public: |
| SampleInfo& Ip(u64 ip) { return AddField(ip); } |
| SampleInfo& Tid(u32 pid, u32 tid) { |
| return AddField(PunU32U64{.v32 = {pid, tid}}.v64); |
| } |
| SampleInfo& Tid(u32 pid) { |
| return AddField(PunU32U64{.v32 = {pid, pid}}.v64); |
| } |
| SampleInfo& Time(u64 time) { return AddField(time); } |
| SampleInfo& Id(u64 id) { return AddField(id); } |
| SampleInfo& BranchStack_nr(u64 nr) { return AddField(nr); } |
| SampleInfo& BranchStack_lbr(u64 from, u64 to, u64 flags) { |
| AddField(from); |
| AddField(to); |
| AddField(flags); |
| return *this; |
| } |
| |
| const char* data() const { |
| return reinterpret_cast<const char *>(fields_.data()); |
| } |
| const size_t size() const { |
| return fields_.size() * sizeof(decltype(fields_)::value_type); |
| } |
| |
| private: |
| SampleInfo& AddField(u64 value) { |
| fields_.push_back(value); |
| return *this; |
| } |
| |
| std::vector<u64> fields_; |
| }; |
| |
| // Produces a PERF_RECORD_MMAP event with the given file and mapping. |
| class ExampleMmapEvent : public StreamWriteable { |
| public: |
| ExampleMmapEvent(u32 pid, u64 start, u64 len, u64 pgoff, string filename, |
| const SampleInfo& sample_id) |
| : pid_(pid), |
| start_(start), |
| len_(len), |
| pgoff_(pgoff), |
| filename_(filename), |
| sample_id_(sample_id) { |
| } |
| size_t GetSize() const; |
| void WriteTo(std::ostream* out) const override; |
| private: |
| const u32 pid_; |
| const u64 start_; |
| const u64 len_; |
| const u64 pgoff_; |
| const string filename_; |
| const SampleInfo sample_id_; |
| }; |
| |
| // Produces a PERF_RECORD_MMAP2 event with the given file and mapping. |
| class ExampleMmap2Event : public StreamWriteable { |
| public: |
| typedef ExampleMmap2Event SelfT; |
| // pid is used as both pid and tid. |
| ExampleMmap2Event(u32 pid, u64 start, u64 len, u64 pgoff, |
| string filename, const SampleInfo& sample_id) |
| : 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) |
| : pid_(pid), |
| tid_(tid), |
| start_(start), |
| len_(len), |
| pgoff_(pgoff), |
| maj_(6), |
| min_(7), |
| ino_(8), |
| filename_(filename), |
| sample_id_(sample_id) { |
| } |
| |
| SelfT& WithDeviceInfo(u32 maj, u32 min, u64 ino) { |
| maj_ = maj; |
| min_ = min; |
| ino_ = ino; |
| return *this; |
| } |
| |
| void WriteTo(std::ostream* out) const override; |
| private: |
| const u32 pid_; |
| const u32 tid_; |
| const u64 start_; |
| const u64 len_; |
| const u64 pgoff_; |
| u32 maj_; |
| u32 min_; |
| u64 ino_; |
| const string filename_; |
| const SampleInfo sample_id_; |
| }; |
| |
| // Produces a PERF_RECORD_FORK or PERF_RECORD_EXIT event. |
| // Cannot be instantiated directly; use a derived class. |
| class ExampleForkExitEvent : public StreamWriteable { |
| public: |
| void WriteTo(std::ostream* out) const override; |
| protected: |
| ExampleForkExitEvent(u32 type, u32 pid, u32 ppid, u32 tid, u32 ptid, u64 time, |
| const SampleInfo& sample_id) |
| : type_(type), |
| pid_(pid), ppid_(ppid), |
| tid_(tid), ptid_(ptid), |
| time_(time), |
| sample_id_(sample_id) {} |
| const u32 type_; // Either PERF_RECORD_FORK or PERF_RECORD_EXIT. |
| private: |
| const u32 pid_; |
| const u32 ppid_; |
| const u32 tid_; |
| const u32 ptid_; |
| const u64 time_; |
| const SampleInfo sample_id_; |
| }; |
| |
| // Produces a PERF_RECORD_FORK event. |
| class ExampleForkEvent : public ExampleForkExitEvent { |
| public: |
| ExampleForkEvent(u32 pid, u32 ppid, u32 tid, u32 ptid, u64 time, |
| const SampleInfo& sample_id) |
| : ExampleForkExitEvent(PERF_RECORD_FORK, pid, ppid, tid, ptid, time, |
| sample_id) {} |
| }; |
| |
| // Produces a PERF_RECORD_EXIT event. |
| class ExampleExitEvent : public ExampleForkExitEvent { |
| public: |
| ExampleExitEvent(u32 pid, u32 ppid, u32 tid, u32 ptid, u64 time, |
| const SampleInfo& sample_id) |
| : ExampleForkExitEvent(PERF_RECORD_EXIT, pid, ppid, tid, ptid, time, |
| sample_id) {} |
| }; |
| |
| // Produces the PERF_RECORD_FINISHED_ROUND event. This event is just a header. |
| class FinishedRoundEvent : public StreamWriteable { |
| public: |
| void WriteTo(std::ostream* out) const override; |
| }; |
| |
| // Produces a simple PERF_RECORD_SAMPLE event with the given sample info. |
| // NB: The sample_info must match the sample_type of the relevant attr. |
| class ExamplePerfSampleEvent : public StreamWriteable { |
| public: |
| explicit ExamplePerfSampleEvent(const SampleInfo& sample_info) |
| : sample_info_(sample_info) { |
| } |
| size_t GetSize() const; |
| void WriteTo(std::ostream* out) const override; |
| private: |
| const SampleInfo sample_info_; |
| }; |
| |
| class ExamplePerfSampleEvent_BranchStack : public ExamplePerfSampleEvent { |
| public: |
| ExamplePerfSampleEvent_BranchStack(); |
| static const size_t kEventSize; |
| }; |
| |
| // Produces a struct sample_event matching ExamplePerfFileAttr_Tracepoint. |
| class ExamplePerfSampleEvent_Tracepoint : public StreamWriteable { |
| public: |
| ExamplePerfSampleEvent_Tracepoint() {} |
| void WriteTo(std::ostream* out) const override; |
| static const size_t kEventSize; |
| }; |
| |
| // Produces a struct perf_file_section suitable for use in the metadata index. |
| class MetadataIndexEntry : public StreamWriteable { |
| public: |
| MetadataIndexEntry(u64 offset, u64 size) |
| : index_entry_{.offset = offset, .size = size} {} |
| void WriteTo(std::ostream* out) const override { |
| struct perf_file_section entry = { |
| .offset = MaybeSwap64(index_entry_.offset), |
| .size = MaybeSwap64(index_entry_.size), |
| }; |
| out->write(reinterpret_cast<const char*>(&entry), sizeof(entry)); |
| } |
| public: |
| const perf_file_section index_entry_; |
| }; |
| |
| // Produces sample string metadata, and corresponding metadata index entry. |
| class ExampleStringMetadata : public StreamWriteable { |
| public: |
| // The input string gets zero-padded/truncated to |kStringAlignSize| bytes if |
| // it is shorter/longer, respectively. |
| explicit ExampleStringMetadata(const string& data, size_t offset) |
| : data_(data), |
| index_entry_(offset, sizeof(u32) + kStringAlignSize) { |
| data_.resize(kStringAlignSize); |
| } |
| void WriteTo(std::ostream* out) const override; |
| |
| const MetadataIndexEntry& index_entry() { return index_entry_; } |
| size_t size() const { |
| return sizeof(u32) + data_.size(); |
| } |
| |
| StreamWriteable& WithCrossEndianness(bool value) override { |
| // Set index_entry_'s endianness since it is owned by this class. |
| index_entry_.WithCrossEndianness(value); |
| return StreamWriteable::WithCrossEndianness(value); |
| } |
| |
| private: |
| string data_; |
| MetadataIndexEntry index_entry_; |
| |
| static const int kStringAlignSize = 64; |
| }; |
| |
| // Produces sample string metadata event for piped mode. |
| class ExampleStringMetadataEvent : public StreamWriteable { |
| public: |
| // The input string gets aligned to |kStringAlignSize|. |
| explicit ExampleStringMetadataEvent(u32 type, const string& data) |
| : type_(type), data_(data) { |
| data_.resize(kStringAlignSize); |
| } |
| void WriteTo(std::ostream* out) const override; |
| |
| private: |
| u32 type_; |
| string data_; |
| |
| static const int kStringAlignSize = 64; |
| }; |
| |
| // Produces sample tracing metadata, and corresponding metadata index entry. |
| class ExampleTracingMetadata { |
| public: |
| class Data : public StreamWriteable { |
| public: |
| static const string kTraceMetadata; |
| |
| explicit Data(ExampleTracingMetadata* parent) : parent_(parent) {} |
| |
| const string& value() const { return kTraceMetadata; } |
| |
| void WriteTo(std::ostream* out) const override; |
| |
| private: |
| ExampleTracingMetadata* parent_; |
| }; |
| |
| explicit ExampleTracingMetadata(size_t offset) |
| : data_(this), index_entry_(offset, data_.value().size()) {} |
| |
| const Data &data() { return data_; } |
| const MetadataIndexEntry &index_entry() { return index_entry_; } |
| |
| private: |
| friend class Data; |
| Data data_; |
| MetadataIndexEntry index_entry_; |
| }; |
| |
| } // namespace testing |
| } // namespace quipper |
| |
| #endif // CHROMIUMOS_WIDE_PROFILING_TEST_PERF_DATA_H_ |