| // Copyright (c) 2012 The Chromium 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 BASE_DEBUG_TRACE_EVENT_IMPL_H_ |
| #define BASE_DEBUG_TRACE_EVENT_IMPL_H_ |
| |
| #include "build/build_config.h" |
| |
| #include <string> |
| #include <vector> |
| |
| #include "base/callback.h" |
| #include "base/hash_tables.h" |
| #include "base/memory/ref_counted_memory.h" |
| #include "base/observer_list.h" |
| #include "base/string_util.h" |
| #include "base/synchronization/condition_variable.h" |
| #include "base/synchronization/lock.h" |
| #include "base/timer.h" |
| |
| // Older style trace macros with explicit id and extra data |
| // Only these macros result in publishing data to ETW as currently implemented. |
| #define TRACE_EVENT_BEGIN_ETW(name, id, extra) \ |
| base::debug::TraceLog::AddTraceEventEtw( \ |
| TRACE_EVENT_PHASE_BEGIN, \ |
| name, reinterpret_cast<const void*>(id), extra) |
| |
| #define TRACE_EVENT_END_ETW(name, id, extra) \ |
| base::debug::TraceLog::AddTraceEventEtw( \ |
| TRACE_EVENT_PHASE_END, \ |
| name, reinterpret_cast<const void*>(id), extra) |
| |
| #define TRACE_EVENT_INSTANT_ETW(name, id, extra) \ |
| base::debug::TraceLog::AddTraceEventEtw( \ |
| TRACE_EVENT_PHASE_INSTANT, \ |
| name, reinterpret_cast<const void*>(id), extra) |
| |
| template <typename Type> |
| struct StaticMemorySingletonTraits; |
| |
| namespace base { |
| |
| namespace debug { |
| |
| const int kTraceMaxNumArgs = 2; |
| |
| // Output records are "Events" and can be obtained via the |
| // OutputCallback whenever the tracing system decides to flush. This |
| // can happen at any time, on any thread, or you can programatically |
| // force it to happen. |
| class BASE_EXPORT TraceEvent { |
| public: |
| union TraceValue { |
| bool as_bool; |
| unsigned long long as_uint; |
| long long as_int; |
| double as_double; |
| const void* as_pointer; |
| const char* as_string; |
| }; |
| |
| TraceEvent(); |
| TraceEvent(int thread_id, |
| TimeTicks timestamp, |
| TimeTicks thread_timestamp, |
| char phase, |
| const unsigned char* category_enabled, |
| const char* name, |
| unsigned long long id, |
| int num_args, |
| const char** arg_names, |
| const unsigned char* arg_types, |
| const unsigned long long* arg_values, |
| unsigned char flags); |
| ~TraceEvent(); |
| |
| // Serialize event data to JSON |
| static void AppendEventsAsJSON(const std::vector<TraceEvent>& events, |
| size_t start, |
| size_t count, |
| std::string* out); |
| void AppendAsJSON(std::string* out) const; |
| |
| static void AppendValueAsJSON(unsigned char type, |
| TraceValue value, |
| std::string* out); |
| |
| TimeTicks timestamp() const { return timestamp_; } |
| TimeTicks thread_timestamp() const { return thread_timestamp_; } |
| |
| // Exposed for unittesting: |
| |
| const base::RefCountedString* parameter_copy_storage() const { |
| return parameter_copy_storage_.get(); |
| } |
| |
| const unsigned char* category_enabled() const { return category_enabled_; } |
| const char* name() const { return name_; } |
| |
| #if defined(COBALT) |
| unsigned long long id() const { return id_; } |
| const TraceValue* arg_values() const { return arg_values_; } |
| int thread_id() const { return thread_id_; } |
| char phase() const { return phase_; } |
| #endif |
| |
| private: |
| // Note: these are ordered by size (largest first) for optimal packing. |
| TimeTicks timestamp_; |
| TimeTicks thread_timestamp_; |
| // id_ can be used to store phase-specific data. |
| unsigned long long id_; |
| TraceValue arg_values_[kTraceMaxNumArgs]; |
| const char* arg_names_[kTraceMaxNumArgs]; |
| const unsigned char* category_enabled_; |
| const char* name_; |
| scoped_refptr<base::RefCountedString> parameter_copy_storage_; |
| int thread_id_; |
| char phase_; |
| unsigned char flags_; |
| unsigned char arg_types_[kTraceMaxNumArgs]; |
| }; |
| |
| |
| // TraceResultBuffer collects and converts trace fragments returned by TraceLog |
| // to JSON output. |
| class BASE_EXPORT TraceResultBuffer { |
| public: |
| typedef base::Callback<void(const std::string&)> OutputCallback; |
| |
| // If you don't need to stream JSON chunks out efficiently, and just want to |
| // get a complete JSON string after calling Finish, use this struct to collect |
| // JSON trace output. |
| struct BASE_EXPORT SimpleOutput { |
| OutputCallback GetCallback(); |
| void Append(const std::string& json_string); |
| |
| // Do what you want with the json_output_ string after calling |
| // TraceResultBuffer::Finish. |
| std::string json_output; |
| }; |
| |
| TraceResultBuffer(); |
| ~TraceResultBuffer(); |
| |
| // Set callback. The callback will be called during Start with the initial |
| // JSON output and during AddFragment and Finish with following JSON output |
| // chunks. The callback target must live past the last calls to |
| // TraceResultBuffer::Start/AddFragment/Finish. |
| void SetOutputCallback(const OutputCallback& json_chunk_callback); |
| |
| // Start JSON output. This resets all internal state, so you can reuse |
| // the TraceResultBuffer by calling Start. |
| void Start(); |
| |
| // Call AddFragment 0 or more times to add trace fragments from TraceLog. |
| void AddFragment(const std::string& trace_fragment); |
| |
| // When all fragments have been added, call Finish to complete the JSON |
| // formatted output. |
| void Finish(); |
| |
| private: |
| OutputCallback output_callback_; |
| bool append_comma_; |
| }; |
| |
| |
| class BASE_EXPORT TraceLog { |
| public: |
| // Notification is a mask of one or more of the following events. |
| enum Notification { |
| // The trace buffer does not flush dynamically, so when it fills up, |
| // subsequent trace events will be dropped. This callback is generated when |
| // the trace buffer is full. The callback must be thread safe. |
| TRACE_BUFFER_FULL = 1 << 0, |
| // A subscribed trace-event occurred. |
| EVENT_WATCH_NOTIFICATION = 1 << 1 |
| }; |
| |
| static TraceLog* GetInstance(); |
| |
| // Get set of known categories. This can change as new code paths are reached. |
| // The known categories are inserted into |categories|. |
| void GetKnownCategories(std::vector<std::string>* categories); |
| |
| // Enable tracing for provided list of categories. If tracing is already |
| // enabled, this method does nothing -- changing categories during trace is |
| // not supported. |
| // If both included_categories and excluded_categories are empty, |
| // all categories are traced. |
| // Else if included_categories is non-empty, only those are traced. |
| // Else if excluded_categories is non-empty, everything but those are traced. |
| // Wildcards * and ? are supported (see MatchPattern in string_util.h). |
| void SetEnabled(const std::vector<std::string>& included_categories, |
| const std::vector<std::string>& excluded_categories); |
| |
| // |categories| is a comma-delimited list of category wildcards. |
| // A category can have an optional '-' prefix to make it an excluded category. |
| // All the same rules apply above, so for example, having both included and |
| // excluded categories in the same list would not be supported. |
| // |
| // Example: SetEnabled("test_MyTest*"); |
| // Example: SetEnabled("test_MyTest*,test_OtherStuff"); |
| // Example: SetEnabled("-excluded_category1,-excluded_category2"); |
| void SetEnabled(const std::string& categories); |
| |
| // Retieves the categories set via a prior call to SetEnabled(). Only |
| // meaningful if |IsEnabled()| is true. |
| void GetEnabledTraceCategories(std::vector<std::string>* included_out, |
| std::vector<std::string>* excluded_out); |
| |
| // Disable tracing for all categories. |
| void SetDisabled(); |
| // Helper method to enable/disable tracing for all categories. |
| void SetEnabled(bool enabled); |
| bool IsEnabled() { return enabled_; } |
| |
| #if defined(OS_ANDROID) || defined(__LB_ANDROID__) |
| static void InitATrace(); |
| #endif |
| |
| // Enabled state listeners give a callback when tracing is enabled or |
| // disabled. This can be used to tie into other library's tracing systems |
| // on-demand. |
| class EnabledStateChangedObserver { |
| public: |
| // Called just before the tracing system becomes |
| // enabled. TraceLog::IsEnabled will return false at this point and trace |
| // macros and methods called within the observer will deadlock. |
| virtual void OnTraceLogWillEnable() { } |
| |
| // Called just before the tracing system disables. TraceLog::IsEnabled is |
| // still false at this point TRACE macros will still be capturing |
| // data. However, trace macros and methods called within the observer will |
| // deadlock. |
| virtual void OnTraceLogWillDisable() { } |
| }; |
| void AddEnabledStateObserver(EnabledStateChangedObserver* listener); |
| void RemoveEnabledStateObserver(EnabledStateChangedObserver* listener); |
| |
| float GetBufferPercentFull() const; |
| |
| // Set the thread-safe notification callback. The callback can occur at any |
| // time and from any thread. WARNING: It is possible for the previously set |
| // callback to be called during OR AFTER a call to SetNotificationCallback. |
| // Therefore, the target of the callback must either be a global function, |
| // ref-counted object or a LazyInstance with Leaky traits (or equivalent). |
| typedef base::Callback<void(int)> NotificationCallback; |
| void SetNotificationCallback(const NotificationCallback& cb); |
| |
| // Flush all collected events to the given output callback. The callback will |
| // be called one or more times with IPC-bite-size chunks. The string format is |
| // undefined. Use TraceResultBuffer to convert one or more trace strings to |
| // JSON. |
| typedef base::Callback<void(const scoped_refptr<base::RefCountedString>&)> |
| OutputCallback; |
| void Flush(const OutputCallback& cb); |
| |
| #if defined(COBALT) |
| // Flush out events as raw TraceEvent structures. Optinally also flush out |
| // JSON output as well. |
| typedef base::Callback<void(const TraceEvent&)> RawEventOutputCallback; |
| void FlushWithRawEvents(const RawEventOutputCallback& raw_event_callback, |
| const OutputCallback& json_output_callback); |
| #endif |
| |
| // Called by TRACE_EVENT* macros, don't call this directly. |
| static const unsigned char* GetCategoryEnabled(const char* name); |
| static const char* GetCategoryName(const unsigned char* category_enabled); |
| |
| // Called by TRACE_EVENT* macros, don't call this directly. |
| // If |copy| is set, |name|, |arg_name1| and |arg_name2| will be deep copied |
| // into the event; see "Memory scoping note" and TRACE_EVENT_COPY_XXX above. |
| void AddTraceEvent(char phase, |
| const unsigned char* category_enabled, |
| const char* name, |
| unsigned long long id, |
| int num_args, |
| const char** arg_names, |
| const unsigned char* arg_types, |
| const unsigned long long* arg_values, |
| unsigned char flags); |
| static void AddTraceEventEtw(char phase, |
| const char* name, |
| const void* id, |
| const char* extra); |
| static void AddTraceEventEtw(char phase, |
| const char* name, |
| const void* id, |
| const std::string& extra); |
| |
| // For every matching event, a notification will be fired. NOTE: the |
| // notification will fire for each matching event that has already occurred |
| // since tracing was started (including before tracing if the process was |
| // started with tracing turned on). |
| void SetWatchEvent(const std::string& category_name, |
| const std::string& event_name); |
| // Cancel the watch event. If tracing is enabled, this may race with the |
| // watch event notification firing. |
| void CancelWatchEvent(); |
| |
| int process_id() const { return process_id_; } |
| |
| // Exposed for unittesting: |
| |
| // Allows deleting our singleton instance. |
| static void DeleteForTesting(); |
| |
| // Allows resurrecting our singleton instance post-AtExit processing. |
| static void Resurrect(); |
| |
| // Allow tests to inspect TraceEvents. |
| size_t GetEventsSize() const { return logged_events_.size(); } |
| const TraceEvent& GetEventAt(size_t index) const { |
| DCHECK(index < logged_events_.size()); |
| return logged_events_[index]; |
| } |
| |
| void SetProcessID(int process_id); |
| |
| // Allow setting an offset between the current TimeTicks time and the time |
| // that should be reported. |
| void SetTimeOffset(TimeDelta offset); |
| |
| private: |
| // This allows constructor and destructor to be private and usable only |
| // by the Singleton class. |
| friend struct StaticMemorySingletonTraits<TraceLog>; |
| |
| // The pointer returned from GetCategoryEnabledInternal() 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. |
| enum CategoryEnabledFlags { |
| // Normal enabled flag for categories enabled with Enable(). |
| CATEGORY_ENABLED = 1 << 0, |
| // On Android if ATrace is enabled, all categories will have this bit. |
| // Not used on other platforms. |
| ATRACE_ENABLED = 1 << 1 |
| }; |
| |
| // Helper class for managing notification_thread_count_ and running |
| // notification callbacks. This is very similar to a reader-writer lock, but |
| // shares the lock with TraceLog and manages the notification flags. |
| class NotificationHelper { |
| public: |
| inline explicit NotificationHelper(TraceLog* trace_log); |
| inline ~NotificationHelper(); |
| |
| // Called only while TraceLog::lock_ is held. This ORs the given |
| // notification with any existing notifcations. |
| inline void AddNotificationWhileLocked(int notification); |
| |
| // Called only while TraceLog::lock_ is NOT held. If there are any pending |
| // notifications from previous calls to AddNotificationWhileLocked, this |
| // will call the NotificationCallback. |
| inline void SendNotificationIfAny(); |
| |
| private: |
| TraceLog* trace_log_; |
| NotificationCallback callback_copy_; |
| int notification_; |
| }; |
| |
| TraceLog(); |
| ~TraceLog(); |
| const unsigned char* GetCategoryEnabledInternal(const char* name); |
| void AddThreadNameMetadataEvents(); |
| |
| #if defined(OS_ANDROID) || defined(__LB_ANDROID__) |
| void SendToATrace(char phase, |
| const char* category, |
| const char* name, |
| int num_args, |
| const char** arg_names, |
| const unsigned char* arg_types, |
| const unsigned long long* arg_values); |
| void AddClockSyncMetadataEvents(); |
| static void ApplyATraceEnabledFlag(unsigned char* category_enabled); |
| #endif |
| |
| // TODO(nduca): switch to per-thread trace buffers to reduce thread |
| // synchronization. |
| // This lock protects TraceLog member accesses from arbitrary threads. |
| Lock lock_; |
| bool enabled_; |
| NotificationCallback notification_callback_; |
| std::vector<TraceEvent> logged_events_; |
| std::vector<std::string> included_categories_; |
| std::vector<std::string> excluded_categories_; |
| bool dispatching_to_observer_list_; |
| ObserverList<EnabledStateChangedObserver> enabled_state_observer_list_; |
| |
| base::hash_map<int, std::string> thread_names_; |
| |
| // XORed with TraceID to make it unlikely to collide with other processes. |
| unsigned long long process_id_hash_; |
| |
| int process_id_; |
| |
| TimeDelta time_offset_; |
| |
| // Allow tests to wake up when certain events occur. |
| const unsigned char* watch_category_; |
| std::string watch_event_name_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TraceLog); |
| }; |
| |
| } // namespace debug |
| } // namespace base |
| |
| #endif // BASE_DEBUG_TRACE_EVENT_IMPL_H_ |