| Index: trunk/src/base/debug/trace_event_impl.cc
|
| ===================================================================
|
| --- trunk/src/base/debug/trace_event_impl.cc (revision 237451)
|
| +++ trunk/src/base/debug/trace_event_impl.cc (working copy)
|
| @@ -99,6 +99,11 @@
|
| LazyInstance<ThreadLocalPointer<const char> >::Leaky
|
| g_current_thread_name = LAZY_INSTANCE_INITIALIZER;
|
|
|
| +const char kRecordUntilFull[] = "record-until-full";
|
| +const char kRecordContinuously[] = "record-continuously";
|
| +const char kEnableSampling[] = "enable-sampling";
|
| +const char kMonitorSampling[] = "monitor-sampling";
|
| +
|
| TimeTicks ThreadNow() {
|
| return TimeTicks::IsThreadNowSupported() ?
|
| TimeTicks::ThreadNow() : TimeTicks();
|
| @@ -939,10 +944,12 @@
|
| ThreadLocalEventBuffer(TraceLog* trace_log);
|
| virtual ~ThreadLocalEventBuffer();
|
|
|
| - TraceEvent* AddTraceEvent(TraceEventHandle* handle);
|
| + TraceEvent* AddTraceEvent(NotificationHelper* notifier,
|
| + TraceEventHandle* handle);
|
|
|
| void ReportOverhead(const TimeTicks& event_timestamp,
|
| - const TimeTicks& event_thread_timestamp);
|
| + const TimeTicks& event_thread_timestamp,
|
| + NotificationHelper* notifier);
|
|
|
| TraceEvent* GetEventByHandle(TraceEventHandle handle) {
|
| if (!chunk_ || handle.chunk_seq != chunk_->seq() ||
|
| @@ -999,10 +1006,12 @@
|
| // - the thread has no message loop;
|
| // - trace_event_overhead is disabled.
|
| if (event_count_) {
|
| - InitializeMetadataEvent(AddTraceEvent(NULL),
|
| + NotificationHelper notifier(trace_log_);
|
| + InitializeMetadataEvent(AddTraceEvent(¬ifier, NULL),
|
| static_cast<int>(base::PlatformThread::CurrentId()),
|
| "overhead", "average_overhead",
|
| overhead_.InMillisecondsF() / event_count_);
|
| + notifier.SendNotificationIfAny();
|
| }
|
|
|
| {
|
| @@ -1014,6 +1023,7 @@
|
| }
|
|
|
| TraceEvent* TraceLog::ThreadLocalEventBuffer::AddTraceEvent(
|
| + NotificationHelper* notifier,
|
| TraceEventHandle* handle) {
|
| CheckThisIsCurrentBuffer();
|
|
|
| @@ -1025,7 +1035,7 @@
|
| if (!chunk_) {
|
| AutoLock lock(trace_log_->lock_);
|
| chunk_ = trace_log_->logged_events_->GetChunk(&chunk_index_);
|
| - trace_log_->CheckIfBufferIsFullWhileLocked();
|
| + trace_log_->CheckIfBufferIsFullWhileLocked(notifier);
|
| }
|
| if (!chunk_)
|
| return NULL;
|
| @@ -1040,7 +1050,8 @@
|
|
|
| void TraceLog::ThreadLocalEventBuffer::ReportOverhead(
|
| const TimeTicks& event_timestamp,
|
| - const TimeTicks& event_thread_timestamp) {
|
| + const TimeTicks& event_thread_timestamp,
|
| + NotificationHelper* notifier) {
|
| if (!g_category_group_enabled[g_category_trace_event_overhead])
|
| return;
|
|
|
| @@ -1050,7 +1061,7 @@
|
| TimeTicks now = trace_log_->OffsetNow();
|
| TimeDelta overhead = now - event_timestamp;
|
| if (overhead.InMicroseconds() >= kOverheadReportThresholdInMicroseconds) {
|
| - TraceEvent* trace_event = AddTraceEvent(NULL);
|
| + TraceEvent* trace_event = AddTraceEvent(notifier, NULL);
|
| if (trace_event) {
|
| trace_event->Initialize(
|
| static_cast<int>(PlatformThread::CurrentId()),
|
| @@ -1081,14 +1092,66 @@
|
| // find the generation mismatch and delete this buffer soon.
|
| }
|
|
|
| +TraceLog::NotificationHelper::NotificationHelper(TraceLog* trace_log)
|
| + : trace_log_(trace_log),
|
| + notification_(0) {
|
| +}
|
| +
|
| +TraceLog::NotificationHelper::~NotificationHelper() {
|
| +}
|
| +
|
| +void TraceLog::NotificationHelper::AddNotificationWhileLocked(
|
| + int notification) {
|
| + trace_log_->lock_.AssertAcquired();
|
| + 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, LeakySingletonTraits<TraceLog> >::get();
|
| }
|
|
|
| +// static
|
| +// Note, if you add more options here you also need to update:
|
| +// content/browser/devtools/devtools_tracing_handler:TraceOptionsFromString
|
| +TraceLog::Options TraceLog::TraceOptionsFromString(const std::string& options) {
|
| + std::vector<std::string> split;
|
| + base::SplitString(options, ',', &split);
|
| + int ret = 0;
|
| + for (std::vector<std::string>::iterator iter = split.begin();
|
| + iter != split.end();
|
| + ++iter) {
|
| + if (*iter == kRecordUntilFull) {
|
| + ret |= RECORD_UNTIL_FULL;
|
| + } else if (*iter == kRecordContinuously) {
|
| + ret |= RECORD_CONTINUOUSLY;
|
| + } else if (*iter == kEnableSampling) {
|
| + ret |= ENABLE_SAMPLING;
|
| + } else if (*iter == kMonitorSampling) {
|
| + ret |= MONITOR_SAMPLING;
|
| + } else {
|
| + NOTREACHED(); // Unknown option provided.
|
| + }
|
| + }
|
| + if (!(ret & RECORD_UNTIL_FULL) && !(ret & RECORD_CONTINUOUSLY))
|
| + ret |= RECORD_UNTIL_FULL; // Default when no options are specified.
|
| +
|
| + return static_cast<Options>(ret);
|
| +}
|
| +
|
| TraceLog::TraceLog()
|
| : enabled_(false),
|
| num_traces_recorded_(0),
|
| + buffer_is_full_(0),
|
| event_callback_(0),
|
| dispatching_to_observer_list_(false),
|
| process_sort_index_(0),
|
| @@ -1265,6 +1328,7 @@
|
| subtle::NoBarrier_Store(&trace_options_, options);
|
| logged_events_.reset(CreateTraceBuffer());
|
| NextGeneration();
|
| + subtle::NoBarrier_Store(&buffer_is_full_, 0);
|
| }
|
|
|
| num_traces_recorded_++;
|
| @@ -1311,52 +1375,49 @@
|
| }
|
|
|
| void TraceLog::SetDisabled() {
|
| - AutoLock lock(lock_);
|
| - SetDisabledWhileLocked();
|
| -}
|
| + std::vector<EnabledStateObserver*> observer_list;
|
| + {
|
| + AutoLock lock(lock_);
|
| + if (!enabled_)
|
| + return;
|
|
|
| -void TraceLog::SetDisabledWhileLocked() {
|
| - lock_.AssertAcquired();
|
| + if (dispatching_to_observer_list_) {
|
| + DLOG(ERROR)
|
| + << "Cannot manipulate TraceLog::Enabled state from an observer.";
|
| + return;
|
| + }
|
|
|
| - if (!enabled_)
|
| - return;
|
| + enabled_ = false;
|
|
|
| - if (dispatching_to_observer_list_) {
|
| - DLOG(ERROR)
|
| - << "Cannot manipulate TraceLog::Enabled state from an observer.";
|
| - return;
|
| - }
|
| + if (sampling_thread_.get()) {
|
| + // Stop the sampling thread.
|
| + sampling_thread_->Stop();
|
| + lock_.Release();
|
| + PlatformThread::Join(sampling_thread_handle_);
|
| + lock_.Acquire();
|
| + sampling_thread_handle_ = PlatformThreadHandle();
|
| + sampling_thread_.reset();
|
| + }
|
|
|
| - enabled_ = false;
|
| + category_filter_.Clear();
|
| + subtle::NoBarrier_Store(&watch_category_, 0);
|
| + watch_event_name_ = "";
|
| + UpdateCategoryGroupEnabledFlags();
|
| + AddMetadataEventsWhileLocked();
|
|
|
| - if (sampling_thread_.get()) {
|
| - // Stop the sampling thread.
|
| - sampling_thread_->Stop();
|
| - lock_.Release();
|
| - PlatformThread::Join(sampling_thread_handle_);
|
| - lock_.Acquire();
|
| - sampling_thread_handle_ = PlatformThreadHandle();
|
| - sampling_thread_.reset();
|
| + dispatching_to_observer_list_ = true;
|
| + observer_list = enabled_state_observer_list_;
|
| }
|
|
|
| - category_filter_.Clear();
|
| - subtle::NoBarrier_Store(&watch_category_, 0);
|
| - watch_event_name_ = "";
|
| - UpdateCategoryGroupEnabledFlags();
|
| - AddMetadataEventsWhileLocked();
|
| + // Dispatch to observers outside the lock in case the observer triggers a
|
| + // trace event.
|
| + for (size_t i = 0; i < observer_list.size(); ++i)
|
| + observer_list[i]->OnTraceLogDisabled();
|
|
|
| - dispatching_to_observer_list_ = true;
|
| - std::vector<EnabledStateObserver*> observer_list =
|
| - enabled_state_observer_list_;
|
| -
|
| {
|
| - // Dispatch to observers outside the lock in case the observer triggers a
|
| - // trace event.
|
| - AutoUnlock unlock(lock_);
|
| - for (size_t i = 0; i < observer_list.size(); ++i)
|
| - observer_list[i]->OnTraceLogDisabled();
|
| + AutoLock lock(lock_);
|
| + dispatching_to_observer_list_ = false;
|
| }
|
| - dispatching_to_observer_list_ = false;
|
| }
|
|
|
| int TraceLog::GetNumTracesRecorded() {
|
| @@ -1388,14 +1449,14 @@
|
| }
|
|
|
| float TraceLog::GetBufferPercentFull() const {
|
| - AutoLock lock(lock_);
|
| return static_cast<float>(static_cast<double>(logged_events_->Size()) /
|
| logged_events_->Capacity());
|
| }
|
|
|
| -bool TraceLog::BufferIsFull() const {
|
| +void TraceLog::SetNotificationCallback(
|
| + const TraceLog::NotificationCallback& cb) {
|
| AutoLock lock(lock_);
|
| - return logged_events_->IsFull();
|
| + notification_callback_ = cb;
|
| }
|
|
|
| TraceBuffer* TraceLog::CreateTraceBuffer() {
|
| @@ -1410,7 +1471,7 @@
|
| }
|
|
|
| TraceEvent* TraceLog::AddEventToThreadSharedChunkWhileLocked(
|
| - TraceEventHandle* handle, bool check_buffer_is_full) {
|
| + NotificationHelper* notifier, TraceEventHandle* handle) {
|
| lock_.AssertAcquired();
|
|
|
| if (thread_shared_chunk_ && thread_shared_chunk_->IsFull()) {
|
| @@ -1421,8 +1482,8 @@
|
| if (!thread_shared_chunk_) {
|
| thread_shared_chunk_ = logged_events_->GetChunk(
|
| &thread_shared_chunk_index_);
|
| - if (check_buffer_is_full)
|
| - CheckIfBufferIsFullWhileLocked();
|
| + if (notifier)
|
| + CheckIfBufferIsFullWhileLocked(notifier);
|
| }
|
| if (!thread_shared_chunk_)
|
| return NULL;
|
| @@ -1436,10 +1497,13 @@
|
| return trace_event;
|
| }
|
|
|
| -void TraceLog::CheckIfBufferIsFullWhileLocked() {
|
| +void TraceLog::CheckIfBufferIsFullWhileLocked(NotificationHelper* notifier) {
|
| lock_.AssertAcquired();
|
| - if (logged_events_->IsFull())
|
| - SetDisabledWhileLocked();
|
| + if (!subtle::NoBarrier_Load(&buffer_is_full_) && logged_events_->IsFull()) {
|
| + subtle::NoBarrier_Store(&buffer_is_full_,
|
| + static_cast<subtle::AtomicWord>(1));
|
| + notifier->AddNotificationWhileLocked(TRACE_BUFFER_FULL);
|
| + }
|
| }
|
|
|
| void TraceLog::SetEventCallbackEnabled(const CategoryFilter& category_filter,
|
| @@ -1556,6 +1620,7 @@
|
| previous_logged_events.swap(logged_events_);
|
| logged_events_.reset(CreateTraceBuffer());
|
| NextGeneration();
|
| + subtle::NoBarrier_Store(&buffer_is_full_, 0);
|
| thread_message_loops_.clear();
|
|
|
| flush_message_loop_proxy_ = NULL;
|
| @@ -1675,6 +1740,8 @@
|
| TimeTicks now = OffsetTimestamp(timestamp);
|
| TimeTicks thread_now = ThreadNow();
|
|
|
| + NotificationHelper notifier(this);
|
| +
|
| ThreadLocalEventBuffer* thread_local_event_buffer = NULL;
|
| // A ThreadLocalEventBuffer needs the message loop
|
| // - to know when the thread exits;
|
| @@ -1731,13 +1798,15 @@
|
| }
|
|
|
| TraceEvent* trace_event = NULL;
|
| - if ((*category_group_enabled & ENABLED_FOR_RECORDING)) {
|
| + if ((*category_group_enabled & ENABLED_FOR_RECORDING) &&
|
| + !subtle::NoBarrier_Load(&buffer_is_full_)) {
|
| if (thread_local_event_buffer) {
|
| lock.EnsureReleased();
|
| - trace_event = thread_local_event_buffer->AddTraceEvent(&handle);
|
| + trace_event = thread_local_event_buffer->AddTraceEvent(¬ifier,
|
| + &handle);
|
| } else {
|
| lock.EnsureAcquired();
|
| - trace_event = AddEventToThreadSharedChunkWhileLocked(&handle, true);
|
| + trace_event = AddEventToThreadSharedChunkWhileLocked(¬ifier, &handle);
|
| }
|
|
|
| if (trace_event) {
|
| @@ -1750,24 +1819,20 @@
|
| trace_event->SendToATrace();
|
| #endif
|
| }
|
| + }
|
|
|
| - if (trace_options() & ECHO_TO_CONSOLE) {
|
| - lock.EnsureAcquired();
|
| - OutputEventToConsoleWhileLocked(
|
| - phase == TRACE_EVENT_PHASE_COMPLETE ? TRACE_EVENT_PHASE_BEGIN : phase,
|
| - timestamp, trace_event);
|
| - }
|
| + if (trace_options() & ECHO_TO_CONSOLE) {
|
| + lock.EnsureAcquired();
|
| + OutputEventToConsoleWhileLocked(
|
| + phase == TRACE_EVENT_PHASE_COMPLETE ? TRACE_EVENT_PHASE_BEGIN : phase,
|
| + timestamp, trace_event);
|
| }
|
|
|
| if (reinterpret_cast<const unsigned char*>(subtle::NoBarrier_Load(
|
| &watch_category_)) == category_group_enabled) {
|
| lock.EnsureAcquired();
|
| - if (watch_event_name_ == name) {
|
| - WatchEventCallback watch_event_callback_copy = watch_event_callback_;
|
| - lock.EnsureReleased();
|
| - if (!watch_event_callback_copy.is_null())
|
| - watch_event_callback_copy.Run();
|
| - }
|
| + if (watch_event_name_ == name)
|
| + notifier.AddNotificationWhileLocked(EVENT_WATCH_NOTIFICATION);
|
| }
|
|
|
| lock.EnsureReleased();
|
| @@ -1785,8 +1850,10 @@
|
| }
|
|
|
| if (thread_local_event_buffer)
|
| - thread_local_event_buffer->ReportOverhead(now, thread_now);
|
| + thread_local_event_buffer->ReportOverhead(now, thread_now, ¬ifier);
|
|
|
| + notifier.SendNotificationIfAny();
|
| +
|
| return handle;
|
| }
|
|
|
| @@ -1895,22 +1962,19 @@
|
| }
|
|
|
| void TraceLog::SetWatchEvent(const std::string& category_name,
|
| - const std::string& event_name,
|
| - const WatchEventCallback& callback) {
|
| + const std::string& event_name) {
|
| const unsigned char* category = GetCategoryGroupEnabled(
|
| category_name.c_str());
|
| AutoLock lock(lock_);
|
| subtle::NoBarrier_Store(&watch_category_,
|
| reinterpret_cast<subtle::AtomicWord>(category));
|
| watch_event_name_ = event_name;
|
| - watch_event_callback_ = callback;
|
| }
|
|
|
| void TraceLog::CancelWatchEvent() {
|
| AutoLock lock(lock_);
|
| subtle::NoBarrier_Store(&watch_category_, 0);
|
| watch_event_name_ = "";
|
| - watch_event_callback_.Reset();
|
| }
|
|
|
| void TraceLog::AddMetadataEventsWhileLocked() {
|
| @@ -1918,14 +1982,14 @@
|
|
|
| int current_thread_id = static_cast<int>(base::PlatformThread::CurrentId());
|
| if (process_sort_index_ != 0) {
|
| - InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
|
| + InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, NULL),
|
| current_thread_id,
|
| "process_sort_index", "sort_index",
|
| process_sort_index_);
|
| }
|
|
|
| if (process_name_.size()) {
|
| - InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
|
| + InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, NULL),
|
| current_thread_id,
|
| "process_name", "name",
|
| process_name_);
|
| @@ -1938,7 +2002,7 @@
|
| it++) {
|
| labels.push_back(it->second);
|
| }
|
| - InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
|
| + InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, NULL),
|
| current_thread_id,
|
| "process_labels", "labels",
|
| JoinString(labels, ','));
|
| @@ -1950,7 +2014,7 @@
|
| it++) {
|
| if (it->second == 0)
|
| continue;
|
| - InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
|
| + InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, NULL),
|
| it->first,
|
| "thread_sort_index", "sort_index",
|
| it->second);
|
| @@ -1962,7 +2026,7 @@
|
| it++) {
|
| if (it->second.empty())
|
| continue;
|
| - InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, false),
|
| + InitializeMetadataEvent(AddEventToThreadSharedChunkWhileLocked(NULL, NULL),
|
| it->first,
|
| "thread_name", "name",
|
| it->second);
|
|
|