// Copyright 2015 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_TRACE_EVENT_TRACE_LOG_H_
#define BASE_TRACE_EVENT_TRACE_LOG_H_
#include <stddef.h>
#include <stdint.h>
#include <string>
#include <vector>
#include "base/atomicops.h"
#include "base/containers/hash_tables.h"
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/trace_event/memory_dump_provider.h"
#include "base/trace_event/trace_config.h"
#include "base/trace_event/trace_event_impl.h"
#include "build/build_config.h"
namespace base {
template <typename Type>
struct DefaultSingletonTraits;
class RefCountedString;
namespace trace_event {
class TraceBuffer;
class TraceBufferChunk;
class TraceEvent;
class TraceEventMemoryOverhead;
class TraceSamplingThread;
struct BASE_EXPORT TraceLogStatus {
TraceLogStatus();
~TraceLogStatus();
size_t event_capacity;
size_t event_count;
};
class BASE_EXPORT TraceLog : public MemoryDumpProvider {
public:
enum Mode {
DISABLED = 0,
RECORDING_MODE,
MONITORING_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 for the monitoring mode.
ENABLED_FOR_MONITORING = 1 << 1,
// 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
};
static TraceLog* GetInstance();
// Get set of known category groups. This can change as new code paths are
// reached. The known category groups are inserted into |category_groups|.
void GetKnownCategoryGroups(std::vector<std::string>* category_groups);
// Retrieves a copy (for thread-safety) of the current TraceConfig.
TraceConfig GetCurrentTraceConfig() const;
// Initializes the thread-local event buffer, if not already initialized and
// if the current thread supports that (has a message loop).
void InitializeThreadLocalEventBufferIfSupported();
// Enables normal tracing (recording trace events in the trace buffer).
// See TraceConfig comments for details on how to control what categories
// will be traced. If tracing has already been enabled, |category_filter| will
// be merged into the current category filter.
void SetEnabled(const TraceConfig& trace_config, Mode mode);
// Disables normal tracing for all categories.
void SetDisabled();
bool IsEnabled() { return mode_ != DISABLED; }
// The number of times we have begun recording traces. If tracing is off,
// returns -1. If tracing is on, then it returns the number of times we have
// recorded a trace. By watching for this number to increment, you can
// passively discover when a new trace has begun. This is then used to
// implement the TRACE_EVENT_IS_NEW_TRACE() primitive.
int GetNumTracesRecorded();
#if defined(OS_ANDROID)
void StartATrace();
void StopATrace();
void AddClockSyncMetadataEvent();
#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 BASE_EXPORT EnabledStateObserver {
public:
virtual ~EnabledStateObserver() = default;
// Called just after the tracing system becomes enabled, outside of the
// |lock_|. TraceLog::IsEnabled() is true at this point.
virtual void OnTraceLogEnabled() = 0;
// Called just after the tracing system disables, outside of the |lock_|.
// TraceLog::IsEnabled() is false at this point.
virtual void OnTraceLogDisabled() = 0;
};
void AddEnabledStateObserver(EnabledStateObserver* listener);
void RemoveEnabledStateObserver(EnabledStateObserver* listener);
bool HasEnabledStateObserver(EnabledStateObserver* listener) const;
TraceLogStatus GetStatus() const;
bool BufferIsFull() const;
// Computes an estimate of the size of the TraceLog including all the retained
// objects.
void EstimateTraceMemoryOverhead(TraceEventMemoryOverhead* overhead);
// Not using base::Callback because of its limited by 7 parameters.
// Also, using primitive type allows directly passing callback from WebCore.
// WARNING: It is possible for the previously set callback to be called
// after a call to SetEventCallbackEnabled() that replaces or a call to
// SetEventCallbackDisabled() that disables the callback.
// This callback may be invoked on any thread.
// For TRACE_EVENT_PHASE_COMPLETE events, the client will still receive pairs
// of TRACE_EVENT_PHASE_BEGIN and TRACE_EVENT_PHASE_END events to keep the
// interface simple.
typedef void (*EventCallback)(TimeTicks timestamp,
char phase,
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
int num_args,
const char* const arg_names[],
const unsigned char arg_types[],
const unsigned long long arg_values[],
unsigned int flags);
// Enable tracing for EventCallback.
void SetEventCallbackEnabled(const TraceConfig& trace_config,
EventCallback cb);
void SetEventCallbackDisabled();
void SetArgumentFilterPredicate(
const ArgumentFilterPredicate& argument_filter_predicate);
// Flush all collected events to the given output callback. The callback will
// be called one or more times either synchronously or asynchronously from
// the current thread with IPC-bite-size chunks. The string format is
// undefined. Use TraceResultBuffer to convert one or more trace strings to
// JSON. The callback can be null if the caller doesn't want any data.
// Due to the implementation of thread-local buffers, flush can't be
// done when tracing is enabled. If called when tracing is enabled, the
// callback will be called directly with (empty_string, false) to indicate
// the end of this unsuccessful flush. Flush does the serialization
// on the same thread if the caller doesn't set use_worker_thread explicitly.
typedef base::Callback<void(const scoped_refptr<base::RefCountedString>&,
bool has_more_events)> OutputCallback;
void Flush(const OutputCallback& cb, bool use_worker_thread = false);
void FlushButLeaveBufferIntact(const OutputCallback& flush_output_callback);
// Cancels tracing and discards collected data.
void CancelTracing(const OutputCallback& cb);
// Called by TRACE_EVENT* macros, don't call this directly.
// The name parameter is a category group for example:
// TRACE_EVENT0("renderer,webkit", "WebViewImpl::HandleInputEvent")
static const unsigned char* GetCategoryGroupEnabled(const char* name);
static const char* GetCategoryGroupName(
const unsigned char* category_group_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.
TraceEventHandle AddTraceEvent(
char phase,
const unsigned char* category_group_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,
const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
unsigned int flags);
TraceEventHandle AddTraceEventWithBindId(
char phase,
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
unsigned long long bind_id,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
unsigned int flags);
TraceEventHandle AddTraceEventWithProcessId(
char phase,
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
int process_id,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
unsigned int flags);
TraceEventHandle AddTraceEventWithThreadIdAndTimestamp(
char phase,
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
int thread_id,
const TimeTicks& timestamp,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
unsigned int flags);
TraceEventHandle AddTraceEventWithThreadIdAndTimestamp(
char phase,
const unsigned char* category_group_enabled,
const char* name,
unsigned long long id,
unsigned long long bind_id,
int thread_id,
const TimeTicks& timestamp,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
unsigned int flags);
// Adds a metadata event that will be written when the trace log is flushed.
void AddMetadataEvent(
const char* name,
int num_args,
const char** arg_names,
const unsigned char* arg_types,
const unsigned long long* arg_values,
const scoped_refptr<ConvertableToTraceFormat>* convertable_values,
unsigned int flags);
void UpdateTraceEventDuration(const unsigned char* category_group_enabled,
const char* name,
TraceEventHandle handle);
// For every matching event, the callback will be called.
typedef base::Callback<void()> WatchEventCallback;
void SetWatchEvent(const std::string& category_name,
const std::string& event_name,
const WatchEventCallback& callback);
// 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_; }
uint64_t MangleEventId(uint64_t id);
// Exposed for unittesting:
void WaitSamplingEventForTesting();
// Allows deleting our singleton instance.
static void DeleteForTesting();
// Allow tests to inspect TraceEvents.
TraceEvent* GetEventByHandle(TraceEventHandle handle);
void SetProcessID(int process_id);
// Process sort indices, if set, override the order of a process will appear
// relative to other processes in the trace viewer. Processes are sorted first
// on their sort index, ascending, then by their name, and then tid.
void SetProcessSortIndex(int sort_index);
// Sets the name of the process.
void SetProcessName(const std::string& process_name);
// Processes can have labels in addition to their names. Use labels, for
// instance, to list out the web page titles that a process is handling.
void UpdateProcessLabel(int label_id, const std::string& current_label);
void RemoveProcessLabel(int label_id);
// Thread sort indices, if set, override the order of a thread will appear
// within its process in the trace viewer. Threads are sorted first on their
// sort index, ascending, then by their name, and then tid.
void SetThreadSortIndex(PlatformThreadId thread_id, int sort_index);
// Allow setting an offset between the current TimeTicks time and the time
// that should be reported.
void SetTimeOffset(TimeDelta offset);
size_t GetObserverCountForTest() const;
// Call this method if the current thread may block the message loop to
// prevent the thread from using the thread-local buffer because the thread
// may not handle the flush request in time causing lost of unflushed events.
void SetCurrentThreadBlocksMessageLoop();
#if defined(OS_WIN)
// This function is called by the ETW exporting module whenever the ETW
// keyword (flags) changes. This keyword indicates which categories should be
// exported, so whenever it changes, we adjust accordingly.
void UpdateETWCategoryGroupEnabledFlags();
#endif
private:
typedef unsigned int InternalTraceOptions;
FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
TraceBufferRingBufferGetReturnChunk);
FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
TraceBufferRingBufferHalfIteration);
FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
TraceBufferRingBufferFullIteration);
FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture, TraceBufferVectorReportFull);
FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
ConvertTraceConfigToInternalOptions);
FRIEND_TEST_ALL_PREFIXES(TraceEventTestFixture,
TraceRecordAsMuchAsPossibleMode);
// This allows constructor and destructor to be private and usable only
// by the Singleton class.
friend struct DefaultSingletonTraits<TraceLog>;
// MemoryDumpProvider implementation.
bool OnMemoryDump(const MemoryDumpArgs& args,
ProcessMemoryDump* pmd) override;
// Enable/disable each category group based on the current mode_,
// category_filter_, event_callback_ and event_callback_category_filter_.
// Enable the category group in the enabled mode if category_filter_ matches
// the category group, or event_callback_ is not null and
// event_callback_category_filter_ matches the category group.
void UpdateCategoryGroupEnabledFlags();
void UpdateCategoryGroupEnabledFlag(size_t category_index);
// Configure synthetic delays based on the values set in the current
// trace config.
void UpdateSyntheticDelaysFromTraceConfig();
InternalTraceOptions GetInternalOptionsFromTraceConfig(
const TraceConfig& config);
class ThreadLocalEventBuffer;
class OptionalAutoLock;
TraceLog();
~TraceLog() override;
const unsigned char* GetCategoryGroupEnabledInternal(const char* name);
void AddMetadataEventsWhileLocked();
InternalTraceOptions trace_options() const {
return static_cast<InternalTraceOptions>(
subtle::NoBarrier_Load(&trace_options_));
}
TraceBuffer* trace_buffer() const { return logged_events_.get(); }
TraceBuffer* CreateTraceBuffer();
std::string EventToConsoleMessage(unsigned char phase,
const TimeTicks& timestamp,
TraceEvent* trace_event);
TraceEvent* AddEventToThreadSharedChunkWhileLocked(TraceEventHandle* handle,
bool check_buffer_is_full);
void CheckIfBufferIsFullWhileLocked();
void SetDisabledWhileLocked();
TraceEvent* GetEventByHandleInternal(TraceEventHandle handle,
OptionalAutoLock* lock);
void FlushInternal(const OutputCallback& cb,
bool use_worker_thread,
bool discard_events);
// |generation| is used in the following callbacks to check if the callback
// is called for the flush of the current |logged_events_|.
void FlushCurrentThread(int generation, bool discard_events);
// Usually it runs on a different thread.
static void ConvertTraceEventsToTraceFormat(
scoped_ptr<TraceBuffer> logged_events,
const TraceLog::OutputCallback& flush_output_callback,
const ArgumentFilterPredicate& argument_filter_predicate);
void FinishFlush(int generation, bool discard_events);
void OnFlushTimeout(int generation, bool discard_events);
int generation() const {
return static_cast<int>(subtle::NoBarrier_Load(&generation_));
}
bool CheckGeneration(int generation) const {
return generation == this->generation();
}
void UseNextTraceBuffer();
TimeTicks OffsetNow() const { return OffsetTimestamp(TimeTicks::Now()); }
TimeTicks OffsetTimestamp(const TimeTicks& timestamp) const {
return timestamp - time_offset_;
}
// Internal representation of trace options since we store the currently used
// trace option as an AtomicWord.
static const InternalTraceOptions kInternalNone;
static const InternalTraceOptions kInternalRecordUntilFull;
static const InternalTraceOptions kInternalRecordContinuously;
static const InternalTraceOptions kInternalEchoToConsole;
static const InternalTraceOptions kInternalEnableSampling;
static const InternalTraceOptions kInternalRecordAsMuchAsPossible;
static const InternalTraceOptions kInternalEnableArgumentFilter;
// This lock protects TraceLog member accesses (except for members protected
// by thread_info_lock_) from arbitrary threads.
mutable Lock lock_;
// This lock protects accesses to thread_names_, thread_event_start_times_
// and thread_colors_.
Lock thread_info_lock_;
Mode mode_;
int num_traces_recorded_;
scoped_ptr<TraceBuffer> logged_events_;
std::vector<scoped_ptr<TraceEvent>> metadata_events_;
subtle::AtomicWord /* EventCallback */ event_callback_;
bool dispatching_to_observer_list_;
std::vector<EnabledStateObserver*> enabled_state_observer_list_;
std::string process_name_;
base::hash_map<int, std::string> process_labels_;
int process_sort_index_;
base::hash_map<int, int> thread_sort_indices_;
base::hash_map<int, std::string> thread_names_;
// The following two maps are used only when ECHO_TO_CONSOLE.
base::hash_map<int, std::stack<TimeTicks>> thread_event_start_times_;
base::hash_map<std::string, int> thread_colors_;
TimeTicks buffer_limit_reached_timestamp_;
// 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.
WatchEventCallback watch_event_callback_;
subtle::AtomicWord /* const unsigned char* */ watch_category_;
std::string watch_event_name_;
subtle::AtomicWord /* Options */ trace_options_;
// Sampling thread handles.
scoped_ptr<TraceSamplingThread> sampling_thread_;
PlatformThreadHandle sampling_thread_handle_;
TraceConfig trace_config_;
TraceConfig event_callback_trace_config_;
ThreadLocalPointer<ThreadLocalEventBuffer> thread_local_event_buffer_;
ThreadLocalBoolean thread_blocks_message_loop_;
ThreadLocalBoolean thread_is_in_trace_event_;
// Contains the message loops of threads that have had at least one event
// added into the local event buffer. Not using SingleThreadTaskRunner
// because we need to know the life time of the message loops.
hash_set<MessageLoop*> thread_message_loops_;
// For events which can't be added into the thread local buffer, e.g. events
// from threads without a message loop.
scoped_ptr<TraceBufferChunk> thread_shared_chunk_;
size_t thread_shared_chunk_index_;
// Set when asynchronous Flush is in progress.
OutputCallback flush_output_callback_;
scoped_refptr<SingleThreadTaskRunner> flush_task_runner_;
ArgumentFilterPredicate argument_filter_predicate_;
subtle::AtomicWord generation_;
bool use_worker_thread_;
DISALLOW_COPY_AND_ASSIGN(TraceLog);
};
} // namespace trace_event
} // namespace base
#endif // BASE_TRACE_EVENT_TRACE_LOG_H_