| // Copyright 2020 The Fuchsia 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 SRC_TESTING_LOADBENCH_TRACING_H_ | |
| #define SRC_TESTING_LOADBENCH_TRACING_H_ | |
| #include <lib/zircon-internal/ktrace.h> | |
| #include <array> | |
| #include <map> | |
| #include <string> | |
| #include <vector> | |
| #include "utility.h" | |
| typedef enum { kTag16B, kTag32B, kTagNAME } TagType; | |
| typedef struct { | |
| uint32_t num; | |
| uint32_t group; | |
| TagType type; | |
| const char* name; | |
| } TagDefinition; | |
| static TagDefinition kTags[] = { | |
| #define KTRACE_DEF(num, type, name, group) [num] = {num, KTRACE_GRP_##group, kTag##type, #name}, | |
| #include <lib/zircon-internal/ktrace-def.h> | |
| }; | |
| class KTraceRecord { | |
| public: | |
| static std::optional<KTraceRecord> ParseRecord(uint8_t* data_buf, size_t buf_len); | |
| bool Get16BRecord(ktrace_header_t** record) const; | |
| bool Get32BRecord(ktrace_rec_32b_t** record) const; | |
| bool GetNameRecord(ktrace_rec_name_t** record) const; | |
| std::optional<std::array<uint32_t, 2>> Get64BitPayload() const; | |
| std::optional<std::array<uint64_t, 2>> Get128BitPayload() const; | |
| std::optional<const uint64_t> GetFlowID() const; | |
| std::optional<const uint64_t> GetAssociatedThread() const; | |
| uint32_t GetEvent() const { return event_; } | |
| TagDefinition* GetInfo() const { return info_; } | |
| bool IsNamed() const { return is_named_; } | |
| bool IsProbeGroup() const { return is_probe_group_; } | |
| bool IsFlow() const { return is_flow_; } | |
| bool IsBegin() const { return is_begin_; } | |
| bool IsEnd() const { return is_end_; } | |
| bool IsDuration() const { return is_duration_; } | |
| bool HasUnexpectedEvent() const { return has_unexpected_event_; } | |
| private: | |
| size_t data_buf_len_; | |
| ktrace_header_t* rec_16b_ = nullptr; | |
| uint32_t event_; | |
| TagDefinition* info_; | |
| bool is_named_ = false; | |
| bool is_probe_group_ = false; | |
| bool is_flow_ = false; | |
| bool is_begin_ = false; | |
| bool is_end_ = false; | |
| bool is_duration_ = false; | |
| bool has_unexpected_event_ = false; | |
| }; | |
| class Tracing { | |
| public: | |
| Tracing() = default; | |
| Tracing(const Tracing&) = delete; | |
| Tracing& operator=(const Tracing&) = delete; | |
| Tracing(Tracing&&) = delete; | |
| Tracing& operator=(Tracing&&) = delete; | |
| virtual ~Tracing() { Stop(); } | |
| struct DurationStats { | |
| uint64_t begin_ts_ns = 0; | |
| uint64_t end_ts_ns = 0; | |
| uint64_t wall_duration_ns = 0; | |
| std::optional<std::array<uint64_t, 2>> payload = std::nullopt; | |
| DurationStats(uint64_t begin) { begin_ts_ns = begin; } | |
| }; | |
| struct QueuingStats { | |
| uint64_t begin_ts_ns = 0; | |
| uint64_t end_ts_ns = 0; | |
| uint64_t queuing_time_ns = 0; | |
| uint64_t associated_thread = 0; | |
| QueuingStats(uint64_t begin, uint64_t thread) { | |
| begin_ts_ns = begin; | |
| associated_thread = thread; | |
| } | |
| }; | |
| // Rewinds kernel trace buffer. | |
| void Rewind(); | |
| // Starts kernel tracing. | |
| void Start(uint32_t group_mask); | |
| // Stops kernel tracing. | |
| void Stop(); | |
| // Fetches record from kernel buffer if available. Returns false if errors were encountered. | |
| // Returns two booleans, first signals whether read was successful, second signals whether entire | |
| // kernel trace buffer has been read. | |
| virtual std::tuple<bool, bool> FetchRecord(zx_handle_t handle, uint8_t* data_buf, | |
| uint32_t* offset, size_t* bytes_read, size_t buf_len); | |
| // Reads trace buffer and converts output into human-readable format. Stores in location defined | |
| // by <filepath>. Will overwrite any existing files with same name. | |
| bool WriteHumanReadable(std::ostream& filepath); | |
| // Picks out traces pertaining to name in string_ref and runs stats on them. Returns false if name | |
| // not found. | |
| bool PopulateDurationStats(std::string string_ref, std::vector<DurationStats>* duration_stats, | |
| std::map<uint64_t, QueuingStats>* queuing_stats); | |
| bool running() const { return running_; } | |
| private: | |
| enum EventState { | |
| kBegin, | |
| kEnd, | |
| kNone, | |
| }; | |
| // Performs same action as zx_ktrace_read and does necessary checks. | |
| virtual void ReadKernelBuffer(zx_handle_t handle, void* data_buf, uint32_t offset, size_t len, | |
| size_t* bytes_read); | |
| // Returns a string with human-readable translations of tag name, event, and any possible flags. | |
| std::string InterpretTag(const uint32_t tag, const TagDefinition& info); | |
| // Writes human-readable translation for 16 byte records into file specified by <file>. | |
| void Write16B(const KTraceRecord record, std::ostream* file); | |
| // Writes human-readable translation for 32 byte records into file specified by <file>. | |
| void Write32B(const KTraceRecord record, std::ostream* file); | |
| // Writes human-readable translation name type records into file specified by <file>. | |
| void WriteName(const KTraceRecord record, std::ostream* file); | |
| // Writes human-readable translation for probe records into file specified by <file>. | |
| void WriteProbeRecord(const KTraceRecord record, std::ostream* file); | |
| // Writes human-readable translation for probe records into file specified by <file>. | |
| void WriteDurationRecord(const KTraceRecord record, const EventState event_state, | |
| std::ostream* file); | |
| // Writes human-readable translation for flow records into file specified by <file>. | |
| void WriteFlowRecord(const KTraceRecord record, const EventState event_state, std::ostream* file); | |
| zx_handle_t root_resource_ = GetRootResource()->get(); | |
| bool running_ = false; | |
| }; | |
| #endif // SRC_TESTING_LOADBENCH_TRACING_H_ |