| Index: base/debug/trace_event_impl.cc
|
| diff --git a/base/debug/trace_event_impl.cc b/base/debug/trace_event_impl.cc
|
| index 9cf33417e8e1654e47b50e5a390ee94ef637bca0..13b6a97440f87c56a777b29b6ac1ae2ff817082f 100644
|
| --- a/base/debug/trace_event_impl.cc
|
| +++ b/base/debug/trace_event_impl.cc
|
| @@ -7,21 +7,23 @@
|
| #include <algorithm>
|
|
|
| #include "base/bind.h"
|
| +#include "base/debug/leak_annotations.h"
|
| #include "base/debug/trace_event.h"
|
| #include "base/file_util.h"
|
| #include "base/format_macros.h"
|
| #include "base/lazy_instance.h"
|
| #include "base/memory/singleton.h"
|
| #include "base/process_util.h"
|
| +#include "base/stl_util.h"
|
| #include "base/stringprintf.h"
|
| #include "base/string_tokenizer.h"
|
| -#include "base/threading/platform_thread.h"
|
| -#include "base/threading/thread_local.h"
|
| -#include "base/utf_string_conversions.h"
|
| -#include "base/stl_util.h"
|
| +#include "base/string_util.h"
|
| #include "base/sys_info.h"
|
| #include "base/third_party/dynamic_annotations/dynamic_annotations.h"
|
| +#include "base/threading/platform_thread.h"
|
| +#include "base/threading/thread_local.h"
|
| #include "base/time.h"
|
| +#include "base/utf_string_conversions.h"
|
|
|
| #if defined(OS_WIN)
|
| #include "base/debug/trace_event_win.h"
|
| @@ -316,14 +318,37 @@ void TraceResultBuffer::Finish() {
|
| //
|
| ////////////////////////////////////////////////////////////////////////////////
|
|
|
| +TraceLog::NotificationHelper::NotificationHelper(TraceLog* trace_log)
|
| + : trace_log_(trace_log),
|
| + notification_(0) {
|
| +}
|
| +
|
| +TraceLog::NotificationHelper::~NotificationHelper() {
|
| +}
|
| +
|
| +void TraceLog::NotificationHelper::AddNotificationWhileLocked(
|
| + int notification) {
|
| + if (trace_log_->notification_callback_.is_null())
|
| + return;
|
| + if (notification_ == 0)
|
| + callback_copy_ = trace_log_->notification_callback_;
|
| + notification_ |= notification;
|
| +}
|
| +
|
| +void TraceLog::NotificationHelper::SendNotificationIfAny() {
|
| + if (notification_)
|
| + callback_copy_.Run(notification_);
|
| +}
|
| +
|
| // static
|
| TraceLog* TraceLog::GetInstance() {
|
| return Singleton<TraceLog, StaticMemorySingletonTraits<TraceLog> >::get();
|
| }
|
|
|
| TraceLog::TraceLog()
|
| - : enabled_(false)
|
| - , dispatching_to_observer_list_(false) {
|
| + : enabled_(false),
|
| + dispatching_to_observer_list_(false),
|
| + watch_category_(NULL) {
|
| // Trace is enabled or disabled on one thread while other threads are
|
| // accessing the enabled flag. We don't care whether edge-case events are
|
| // traced or not, so we allow races on the enabled flag to keep the trace
|
| @@ -406,7 +431,11 @@ const unsigned char* TraceLog::GetCategoryEnabledInternal(const char* name) {
|
| "must increase TRACE_EVENT_MAX_CATEGORIES";
|
| if (g_category_index < TRACE_EVENT_MAX_CATEGORIES) {
|
| int new_index = g_category_index++;
|
| - g_categories[new_index] = name;
|
| + // Don't hold on to the name pointer, so that we can create categories with
|
| + // strings not known at compile time (this is required by SetWatchEvent).
|
| + const char* new_name = base::strdup(name);
|
| + ANNOTATE_LEAKING_OBJECT_PTR(new_name);
|
| + g_categories[new_index] = new_name;
|
| DCHECK(!g_category_enabled[new_index]);
|
| if (enabled_) {
|
| // Note that if both included and excluded_categories are empty, the else
|
| @@ -491,31 +520,30 @@ void TraceLog::GetEnabledTraceCategories(
|
| }
|
|
|
| void TraceLog::SetDisabled() {
|
| - {
|
| - AutoLock lock(lock_);
|
| - if (!enabled_)
|
| - return;
|
| + AutoLock lock(lock_);
|
| + if (!enabled_)
|
| + return;
|
|
|
| - if (dispatching_to_observer_list_) {
|
| - DLOG(ERROR)
|
| - << "Cannot manipulate TraceLog::Enabled state from an observer.";
|
| - return;
|
| - }
|
| + if (dispatching_to_observer_list_) {
|
| + DLOG(ERROR)
|
| + << "Cannot manipulate TraceLog::Enabled state from an observer.";
|
| + return;
|
| + }
|
|
|
| - dispatching_to_observer_list_ = true;
|
| - FOR_EACH_OBSERVER(EnabledStateChangedObserver, enabled_state_observer_list_,
|
| - OnTraceLogWillDisable());
|
| - dispatching_to_observer_list_ = false;
|
| -
|
| - enabled_ = false;
|
| - included_categories_.clear();
|
| - excluded_categories_.clear();
|
| - for (int i = 0; i < g_category_index; i++)
|
| - g_category_enabled[i] = 0;
|
| - AddThreadNameMetadataEvents();
|
| - AddClockSyncMetadataEvents();
|
| - } // release lock
|
| - Flush();
|
| + dispatching_to_observer_list_ = true;
|
| + FOR_EACH_OBSERVER(EnabledStateChangedObserver, enabled_state_observer_list_,
|
| + OnTraceLogWillDisable());
|
| + dispatching_to_observer_list_ = false;
|
| +
|
| + enabled_ = false;
|
| + included_categories_.clear();
|
| + excluded_categories_.clear();
|
| + watch_category_ = NULL;
|
| + watch_event_name_ = "";
|
| + for (int i = 0; i < g_category_index; i++)
|
| + g_category_enabled[i] = 0;
|
| + AddThreadNameMetadataEvents();
|
| + AddClockSyncMetadataEvents();
|
| }
|
|
|
| void TraceLog::SetEnabled(bool enabled) {
|
| @@ -538,28 +566,19 @@ float TraceLog::GetBufferPercentFull() const {
|
| return (float)((double)logged_events_.size()/(double)kTraceEventBufferSize);
|
| }
|
|
|
| -void TraceLog::SetOutputCallback(const TraceLog::OutputCallback& cb) {
|
| +void TraceLog::SetNotificationCallback(
|
| + const TraceLog::NotificationCallback& cb) {
|
| AutoLock lock(lock_);
|
| - output_callback_ = cb;
|
| + notification_callback_ = cb;
|
| }
|
|
|
| -void TraceLog::SetBufferFullCallback(const TraceLog::BufferFullCallback& cb) {
|
| - AutoLock lock(lock_);
|
| - buffer_full_callback_ = cb;
|
| -}
|
| -
|
| -void TraceLog::Flush() {
|
| +void TraceLog::Flush(const TraceLog::OutputCallback& cb) {
|
| std::vector<TraceEvent> previous_logged_events;
|
| - OutputCallback output_callback_copy;
|
| {
|
| AutoLock lock(lock_);
|
| previous_logged_events.swap(logged_events_);
|
| - output_callback_copy = output_callback_;
|
| } // release lock
|
|
|
| - if (output_callback_copy.is_null())
|
| - return;
|
| -
|
| for (size_t i = 0;
|
| i < previous_logged_events.size();
|
| i += kTraceEventBatchSize) {
|
| @@ -569,7 +588,7 @@ void TraceLog::Flush() {
|
| i,
|
| kTraceEventBatchSize,
|
| &(json_events_str_ptr->data()));
|
| - output_callback_copy.Run(json_events_str_ptr);
|
| + cb.Run(json_events_str_ptr);
|
| }
|
| }
|
|
|
| @@ -586,7 +605,7 @@ int TraceLog::AddTraceEvent(char phase,
|
| unsigned char flags) {
|
| DCHECK(name);
|
| TimeTicks now = TimeTicks::NowFromSystemTraceTime();
|
| - BufferFullCallback buffer_full_callback_copy;
|
| + NotificationHelper notifier(this);
|
| int ret_begin_id = -1;
|
| {
|
| AutoLock lock(lock_);
|
| @@ -652,13 +671,14 @@ int TraceLog::AddTraceEvent(char phase,
|
| num_args, arg_names, arg_types, arg_values,
|
| flags));
|
|
|
| - if (logged_events_.size() == kTraceEventBufferSize) {
|
| - buffer_full_callback_copy = buffer_full_callback_;
|
| - }
|
| + if (logged_events_.size() == kTraceEventBufferSize)
|
| + notifier.AddNotificationWhileLocked(TRACE_BUFFER_FULL);
|
| +
|
| + if (watch_category_ == category_enabled && watch_event_name_ == name)
|
| + notifier.AddNotificationWhileLocked(EVENT_WATCH_NOTIFICATION);
|
| } // release lock
|
|
|
| - if (!buffer_full_callback_copy.is_null())
|
| - buffer_full_callback_copy.Run();
|
| + notifier.SendNotificationIfAny();
|
|
|
| return ret_begin_id;
|
| }
|
| @@ -686,6 +706,41 @@ void TraceLog::AddTraceEventEtw(char phase,
|
| TRACE_EVENT_FLAG_COPY, "id", id, "extra", extra);
|
| }
|
|
|
| +void TraceLog::SetWatchEvent(const std::string& category_name,
|
| + const std::string& event_name) {
|
| + const unsigned char* category = GetCategoryEnabled(category_name.c_str());
|
| + int notify_count = 0;
|
| + {
|
| + AutoLock lock(lock_);
|
| + watch_category_ = category;
|
| + watch_event_name_ = event_name;
|
| +
|
| + // First, search existing events for watch event because we want to catch it
|
| + // even if it has already occurred.
|
| + for (size_t i = 0u; i < logged_events_.size(); ++i) {
|
| + if (category == logged_events_[i].category_enabled() &&
|
| + strcmp(event_name.c_str(), logged_events_[i].name()) == 0) {
|
| + ++notify_count;
|
| + }
|
| + }
|
| + } // release lock
|
| +
|
| + // Send notification for each event found.
|
| + for (int i = 0; i < notify_count; ++i) {
|
| + NotificationHelper notifier(this);
|
| + lock_.Acquire();
|
| + notifier.AddNotificationWhileLocked(EVENT_WATCH_NOTIFICATION);
|
| + lock_.Release();
|
| + notifier.SendNotificationIfAny();
|
| + }
|
| +}
|
| +
|
| +void TraceLog::CancelWatchEvent() {
|
| + AutoLock lock(lock_);
|
| + watch_category_ = NULL;
|
| + watch_event_name_ = "";
|
| +}
|
| +
|
| void TraceLog::AddClockSyncMetadataEvents() {
|
| #if defined(OS_ANDROID)
|
| // Since Android does not support sched_setaffinity, we cannot establish clock
|
|
|