// Copyright 2016 the V8 project 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 V8_LIBPLATFORM_V8_TRACING_H_ #define V8_LIBPLATFORM_V8_TRACING_H_ #include #include #include namespace v8 { namespace platform { namespace tracing { const int kTraceMaxNumArgs = 2; class TraceObject { public: union ArgValue { bool as_bool; uint64_t as_uint; int64_t as_int; double as_double; const void* as_pointer; const char* as_string; }; TraceObject() {} ~TraceObject(); void Initialize(char phase, const uint8_t* category_enabled_flag, const char* name, const char* scope, uint64_t id, uint64_t bind_id, int num_args, const char** arg_names, const uint8_t* arg_types, const uint64_t* arg_values, unsigned int flags); void UpdateDuration(); void InitializeForTesting(char phase, const uint8_t* category_enabled_flag, const char* name, const char* scope, uint64_t id, uint64_t bind_id, int num_args, const char** arg_names, const uint8_t* arg_types, const uint64_t* arg_values, unsigned int flags, int pid, int tid, int64_t ts, int64_t tts, uint64_t duration, uint64_t cpu_duration); int pid() const { return pid_; } int tid() const { return tid_; } char phase() const { return phase_; } const uint8_t* category_enabled_flag() const { return category_enabled_flag_; } const char* name() const { return name_; } const char* scope() const { return scope_; } uint64_t id() const { return id_; } uint64_t bind_id() const { return bind_id_; } int num_args() const { return num_args_; } const char** arg_names() { return arg_names_; } uint8_t* arg_types() { return arg_types_; } ArgValue* arg_values() { return arg_values_; } unsigned int flags() const { return flags_; } int64_t ts() { return ts_; } int64_t tts() { return tts_; } uint64_t duration() { return duration_; } uint64_t cpu_duration() { return cpu_duration_; } private: int pid_; int tid_; char phase_; const char* name_; const char* scope_; const uint8_t* category_enabled_flag_; uint64_t id_; uint64_t bind_id_; int num_args_; const char* arg_names_[kTraceMaxNumArgs]; uint8_t arg_types_[kTraceMaxNumArgs]; ArgValue arg_values_[kTraceMaxNumArgs]; char* parameter_copy_storage_ = nullptr; unsigned int flags_; int64_t ts_; int64_t tts_; uint64_t duration_; uint64_t cpu_duration_; // Disallow copy and assign TraceObject(const TraceObject&) = delete; void operator=(const TraceObject&) = delete; }; class TraceWriter { public: TraceWriter() {} virtual ~TraceWriter() {} virtual void AppendTraceEvent(TraceObject* trace_event) = 0; virtual void Flush() = 0; static TraceWriter* CreateJSONTraceWriter(std::ostream& stream); private: // Disallow copy and assign TraceWriter(const TraceWriter&) = delete; void operator=(const TraceWriter&) = delete; }; class TraceBufferChunk { public: explicit TraceBufferChunk(uint32_t seq); void Reset(uint32_t new_seq); bool IsFull() const { return next_free_ == kChunkSize; } TraceObject* AddTraceEvent(size_t* event_index); TraceObject* GetEventAt(size_t index) { return &chunk_[index]; } uint32_t seq() const { return seq_; } size_t size() const { return next_free_; } static const size_t kChunkSize = 64; private: size_t next_free_ = 0; TraceObject chunk_[kChunkSize]; uint32_t seq_; // Disallow copy and assign TraceBufferChunk(const TraceBufferChunk&) = delete; void operator=(const TraceBufferChunk&) = delete; }; class TraceBuffer { public: TraceBuffer() {} virtual ~TraceBuffer() {} virtual TraceObject* AddTraceEvent(uint64_t* handle) = 0; virtual TraceObject* GetEventByHandle(uint64_t handle) = 0; virtual bool Flush() = 0; static const size_t kRingBufferChunks = 1024; static TraceBuffer* CreateTraceBufferRingBuffer(size_t max_chunks, TraceWriter* trace_writer); private: // Disallow copy and assign TraceBuffer(const TraceBuffer&) = delete; void operator=(const TraceBuffer&) = delete; }; // Options determines how the trace buffer stores data. enum TraceRecordMode { // Record until the trace buffer is full. RECORD_UNTIL_FULL, // Record until the user ends the trace. The trace buffer is a fixed size // and we use it as a ring buffer during recording. RECORD_CONTINUOUSLY, // Record until the trace buffer is full, but with a huge buffer size. RECORD_AS_MUCH_AS_POSSIBLE, // Echo to console. Events are discarded. ECHO_TO_CONSOLE, }; class TraceConfig { public: typedef std::vector StringList; static TraceConfig* CreateDefaultTraceConfig(); TraceConfig() : enable_sampling_(false), enable_systrace_(false), enable_argument_filter_(false) {} TraceRecordMode GetTraceRecordMode() const { return record_mode_; } bool IsSamplingEnabled() const { return enable_sampling_; } bool IsSystraceEnabled() const { return enable_systrace_; } bool IsArgumentFilterEnabled() const { return enable_argument_filter_; } void SetTraceRecordMode(TraceRecordMode mode) { record_mode_ = mode; } void EnableSampling() { enable_sampling_ = true; } void EnableSystrace() { enable_systrace_ = true; } void EnableArgumentFilter() { enable_argument_filter_ = true; } void AddIncludedCategory(const char* included_category); void AddExcludedCategory(const char* excluded_category); bool IsCategoryGroupEnabled(const char* category_group) const; private: TraceRecordMode record_mode_; bool enable_sampling_ : 1; bool enable_systrace_ : 1; bool enable_argument_filter_ : 1; StringList included_categories_; StringList excluded_categories_; // Disallow copy and assign TraceConfig(const TraceConfig&) = delete; void operator=(const TraceConfig&) = delete; }; class TracingController { public: enum Mode { DISABLED = 0, RECORDING_MODE }; // The pointer returned from GetCategoryGroupEnabledInternal() points to a // value with zero or more of the following bits. Used in this class only. // The TRACE_EVENT macros should only use the value as a bool. // These values must be in sync with macro values in TraceEvent.h in Blink. enum CategoryGroupEnabledFlags { // Category group enabled for the recording mode. ENABLED_FOR_RECORDING = 1 << 0, // Category group enabled by SetEventCallbackEnabled(). ENABLED_FOR_EVENT_CALLBACK = 1 << 2, // Category group enabled to export events to ETW. ENABLED_FOR_ETW_EXPORT = 1 << 3 }; TracingController() {} void Initialize(TraceBuffer* trace_buffer); const uint8_t* GetCategoryGroupEnabled(const char* category_group); static const char* GetCategoryGroupName(const uint8_t* category_enabled_flag); uint64_t AddTraceEvent(char phase, const uint8_t* category_enabled_flag, const char* name, const char* scope, uint64_t id, uint64_t bind_id, int32_t num_args, const char** arg_names, const uint8_t* arg_types, const uint64_t* arg_values, unsigned int flags); void UpdateTraceEventDuration(const uint8_t* category_enabled_flag, const char* name, uint64_t handle); void StartTracing(TraceConfig* trace_config); void StopTracing(); private: const uint8_t* GetCategoryGroupEnabledInternal(const char* category_group); void UpdateCategoryGroupEnabledFlag(size_t category_index); void UpdateCategoryGroupEnabledFlags(); std::unique_ptr trace_buffer_; std::unique_ptr trace_config_; Mode mode_ = DISABLED; // Disallow copy and assign TracingController(const TracingController&) = delete; void operator=(const TracingController&) = delete; }; } // namespace tracing } // namespace platform } // namespace v8 #endif // V8_LIBPLATFORM_V8_TRACING_H_