diff options
author | haraken@chromium.org <haraken@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-08 01:01:25 +0000 |
---|---|---|
committer | haraken@chromium.org <haraken@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-08 01:01:25 +0000 |
commit | 7ad4e2d50a8ae5cc1502a29166721fa447eb1ee5 (patch) | |
tree | a7dcc30be12c22a4d4900a92d58b26a086aabc3b | |
parent | 7cc7ebd4924ef763abfbdf334824e075330b0c14 (diff) | |
download | chromium_src-7ad4e2d50a8ae5cc1502a29166721fa447eb1ee5.zip chromium_src-7ad4e2d50a8ae5cc1502a29166721fa447eb1ee5.tar.gz chromium_src-7ad4e2d50a8ae5cc1502a29166721fa447eb1ee5.tar.bz2 |
Revert 227354 "Revert "Implement TracingController::{Enable,Disa..."
The original CL was reverted because it increased the binary size of
nacl-helper/data by 0.45%, but the increase was just 128 bytes.
So I'll reland this CL, supressing the size failure.
> Revert "Implement TracingController::{Enable,Disable,Capture}Monitoring"
> Revert "Fix failures in chrome os after r227262"
> Revert "Fix the content_browser breakage after r227269"
>
> Caused sizes regression on linux for nacl-helper-data.
>
> TBR=haraken
> BUG=304789
>
> > Implement TracingController::{Enable,Disable,Capture}Monitoring
> >
> > This CL implements TracingController::EnableMonitoring,
> > TracingController::DisableMonitoring and
> > TracingController::CaptureMonitoringSnapshot.
> >
> > BUG=241743
> > TEST=base_unittests::TraceEventTestFixture.TraceContinuousSampling,
> > content_browsertests::TracingControllerTest.EnableCaptureAndDisableMonitoring
> >
> > Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=226701
> >
> > R=dsinclair@chromium.org, joi@chromium.org, nduca@chromium.org, tsepez@chromium.org
> >
> > Review URL: https://codereview.chromium.org/23531042
>
> Review URL: https://codereview.chromium.org/26294003
TBR=justinlin@chromium.org
Review URL: https://codereview.chromium.org/26272005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@227413 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | base/debug/trace_event_impl.cc | 136 | ||||
-rw-r--r-- | base/debug/trace_event_impl.h | 13 | ||||
-rw-r--r-- | base/debug/trace_event_unittest.cc | 64 | ||||
-rw-r--r-- | components/tracing/child_trace_message_filter.cc | 47 | ||||
-rw-r--r-- | components/tracing/child_trace_message_filter.h | 12 | ||||
-rw-r--r-- | components/tracing/tracing_messages.h | 24 | ||||
-rw-r--r-- | content/browser/tracing/trace_message_filter.cc | 48 | ||||
-rw-r--r-- | content/browser/tracing/trace_message_filter.h | 8 | ||||
-rw-r--r-- | content/browser/tracing/tracing_controller_browsertest.cc | 93 | ||||
-rw-r--r-- | content/browser/tracing/tracing_controller_impl.cc | 201 | ||||
-rw-r--r-- | content/browser/tracing/tracing_controller_impl.h | 39 | ||||
-rw-r--r-- | content/public/browser/trace_subscriber.h | 2 | ||||
-rw-r--r-- | content/public/browser/tracing_controller.h | 12 |
13 files changed, 594 insertions, 105 deletions
diff --git a/base/debug/trace_event_impl.cc b/base/debug/trace_event_impl.cc index 42c6d84..9ee9fc8 100644 --- a/base/debug/trace_event_impl.cc +++ b/base/debug/trace_event_impl.cc @@ -61,6 +61,8 @@ const size_t kTraceEventRingBufferSize = kTraceEventVectorBufferSize / 4; const size_t kTraceEventThreadLocalBufferSize = 64; const size_t kTraceEventBatchSize = 1000; const size_t kTraceEventInitialBufferSize = 1024; +// Can store results for 30 seconds with 1 ms sampling interval. +const size_t kMonitorTraceEventBufferSize = 30000; const int kThreadFlushTimeoutMs = 1000; @@ -97,6 +99,7 @@ LazyInstance<ThreadLocalPointer<const char> >::Leaky 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() ? @@ -105,10 +108,11 @@ TimeTicks ThreadNow() { class TraceBufferRingBuffer : public TraceBuffer { public: - TraceBufferRingBuffer() + TraceBufferRingBuffer(size_t buffer_size) : unused_event_index_(0), - oldest_event_index_(0) { - logged_events_.reserve(kTraceEventInitialBufferSize); + oldest_event_index_(0), + buffer_size_(buffer_size) { + logged_events_.reserve(buffer_size_); } virtual ~TraceBufferRingBuffer() {} @@ -119,9 +123,10 @@ class TraceBufferRingBuffer : public TraceBuffer { else logged_events_.push_back(event); - unused_event_index_ = NextIndex(unused_event_index_); + unused_event_index_ = NextIndex(unused_event_index_, buffer_size_); if (unused_event_index_ == oldest_event_index_) { - oldest_event_index_ = NextIndex(oldest_event_index_); + oldest_event_index_ = NextIndex( + oldest_event_index_, buffer_size_); } } @@ -133,7 +138,7 @@ class TraceBufferRingBuffer : public TraceBuffer { DCHECK(HasMoreEvents()); size_t next = oldest_event_index_; - oldest_event_index_ = NextIndex(oldest_event_index_); + oldest_event_index_ = NextIndex(oldest_event_index_, buffer_size_); return GetEventAt(next); } @@ -152,7 +157,7 @@ class TraceBufferRingBuffer : public TraceBuffer { strcmp(event_name.c_str(), event.name()) == 0) { ++notify_count; } - index = NextIndex(index); + index = NextIndex(index, buffer_size_); } return notify_count; } @@ -170,16 +175,29 @@ class TraceBufferRingBuffer : public TraceBuffer { return kTraceEventRingBufferSize; } + virtual TraceBuffer* Clone() const OVERRIDE { + TraceBufferRingBuffer* clonedBuffer = + new TraceBufferRingBuffer(buffer_size_); + size_t index = oldest_event_index_; + while (index != unused_event_index_) { + const TraceEvent& event = GetEventAt(index); + clonedBuffer->AddEvent(event); + index = NextIndex(index, buffer_size_); + } + return clonedBuffer; + } + private: - static size_t NextIndex(size_t index) { + static size_t NextIndex(size_t index, size_t buffer_size) { index++; - if (index >= kTraceEventRingBufferSize) + if (index >= buffer_size) index = 0; return index; } size_t unused_event_index_; size_t oldest_event_index_; + size_t buffer_size_; std::vector<TraceEvent> logged_events_; DISALLOW_COPY_AND_ASSIGN(TraceBufferRingBuffer); @@ -246,6 +264,11 @@ class TraceBufferVector : public TraceBuffer { return kTraceEventVectorBufferSize; } + virtual TraceBuffer* Clone() const OVERRIDE { + NOTIMPLEMENTED(); + return NULL; + } + private: size_t current_iteration_index_; std::vector<TraceEvent> logged_events_; @@ -282,6 +305,11 @@ class TraceBufferDiscardsEvents : public TraceBuffer { NOTREACHED(); return *static_cast<TraceEvent*>(NULL); } + + virtual TraceBuffer* Clone() const OVERRIDE { + NOTIMPLEMENTED(); + return NULL; + } }; } // namespace @@ -669,7 +697,7 @@ class TraceSamplingThread : public PlatformThread::Delegate { // Implementation of PlatformThread::Delegate: virtual void ThreadMain() OVERRIDE; - static void DefaultSampleCallback(TraceBucketData* bucekt_data); + static void DefaultSamplingCallback(TraceBucketData* bucekt_data); void Stop(); void InstallWaitableEventForSamplingTesting(WaitableEvent* waitable_event); @@ -716,7 +744,8 @@ void TraceSamplingThread::ThreadMain() { } // static -void TraceSamplingThread::DefaultSampleCallback(TraceBucketData* bucket_data) { +void TraceSamplingThread::DefaultSamplingCallback( + TraceBucketData* bucket_data) { TRACE_EVENT_API_ATOMIC_WORD category_and_name = TRACE_EVENT_API_ATOMIC_LOAD(*bucket_data->bucket); if (!category_and_name) @@ -763,7 +792,6 @@ void TraceSamplingThread::InstallWaitableEventForSamplingTesting( waitable_event_for_testing_.reset(waitable_event); } - TraceBucketData::TraceBucketData(base::subtle::AtomicWord* bucket, const char* name, TraceSampleCallback callback) @@ -957,6 +985,8 @@ TraceLog::Options TraceLog::TraceOptionsFromString(const std::string& options) { ret |= RECORD_CONTINUOUSLY; } else if (*iter == kEnableSampling) { ret |= ENABLE_SAMPLING; + } else if (*iter == kMonitorSampling) { + ret |= MONITOR_SAMPLING; } else { NOTREACHED(); // Unknown option provided. } @@ -1160,20 +1190,20 @@ void TraceLog::SetEnabled(const CategoryFilter& category_filter, category_filter_ = CategoryFilter(category_filter); UpdateCategoryGroupEnabledFlags(); - if (options & ENABLE_SAMPLING) { + if ((options & ENABLE_SAMPLING) || (options & MONITOR_SAMPLING)) { sampling_thread_.reset(new TraceSamplingThread); sampling_thread_->RegisterSampleBucket( &g_trace_state[0], "bucket0", - Bind(&TraceSamplingThread::DefaultSampleCallback)); + Bind(&TraceSamplingThread::DefaultSamplingCallback)); sampling_thread_->RegisterSampleBucket( &g_trace_state[1], "bucket1", - Bind(&TraceSamplingThread::DefaultSampleCallback)); + Bind(&TraceSamplingThread::DefaultSamplingCallback)); sampling_thread_->RegisterSampleBucket( &g_trace_state[2], "bucket2", - Bind(&TraceSamplingThread::DefaultSampleCallback)); + Bind(&TraceSamplingThread::DefaultSamplingCallback)); if (!PlatformThread::Create( 0, sampling_thread_.get(), &sampling_thread_handle_)) { DCHECK(false) << "failed to create thread"; @@ -1287,7 +1317,9 @@ void TraceLog::SetNotificationCallback( TraceBuffer* TraceLog::GetTraceBuffer() { Options options = trace_options(); if (options & RECORD_CONTINUOUSLY) - return new TraceBufferRingBuffer(); + return new TraceBufferRingBuffer(kTraceEventRingBufferSize); + else if (options & MONITOR_SAMPLING) + return new TraceBufferRingBuffer(kMonitorTraceEventBufferSize); else if (options & ECHO_TO_CONSOLE) return new TraceBufferDiscardsEvents(); return new TraceBufferVector(); @@ -1366,27 +1398,13 @@ void TraceLog::Flush(const TraceLog::OutputCallback& cb) { FinishFlush(flush_count); } -void TraceLog::FinishFlush(int flush_count) { - scoped_ptr<TraceBuffer> previous_logged_events; - OutputCallback flush_output_callback; - - { - AutoLock lock(lock_); - if (flush_count != flush_count_) - return; - - previous_logged_events.swap(logged_events_); - logged_events_.reset(GetTraceBuffer()); - subtle::NoBarrier_Store(&buffer_is_full_, 0); - flush_message_loop_proxy_ = NULL; - flush_output_callback = flush_output_callback_; - flush_output_callback_.Reset(); - } - +void TraceLog::ConvertTraceEventsToTraceFormat( + scoped_ptr<TraceBuffer> logged_events, + const TraceLog::OutputCallback& flush_output_callback) { if (flush_output_callback.is_null()) return; - bool has_more_events = previous_logged_events->HasMoreEvents(); + bool has_more_events = logged_events->HasMoreEvents(); // The callback need to be called at least once even if there is no events // to let the caller know the completion of flush. do { @@ -1397,16 +1415,37 @@ void TraceLog::FinishFlush(int flush_count) { if (i > 0) *(&(json_events_str_ptr->data())) += ","; - previous_logged_events->NextEvent().AppendAsJSON( + logged_events->NextEvent().AppendAsJSON( &(json_events_str_ptr->data())); - has_more_events = previous_logged_events->HasMoreEvents(); + has_more_events = logged_events->HasMoreEvents(); } flush_output_callback.Run(json_events_str_ptr, has_more_events); } while (has_more_events); } +void TraceLog::FinishFlush(int flush_count) { + scoped_ptr<TraceBuffer> previous_logged_events; + OutputCallback flush_output_callback; + + { + AutoLock lock(lock_); + if (flush_count != flush_count_) + return; + + previous_logged_events.swap(logged_events_); + logged_events_.reset(GetTraceBuffer()); + subtle::NoBarrier_Store(&buffer_is_full_, 0); + flush_message_loop_proxy_ = NULL; + flush_output_callback = flush_output_callback_; + flush_output_callback_.Reset(); + } + + ConvertTraceEventsToTraceFormat(previous_logged_events.Pass(), + flush_output_callback); +} + // Run in each thread holding a local event buffer. void TraceLog::FlushCurrentThread(int flush_count) { { @@ -1445,6 +1484,22 @@ void TraceLog::OnFlushTimeout(int flush_count) { FinishFlush(flush_count); } +void TraceLog::FlushButLeaveBufferIntact( + const TraceLog::OutputCallback& flush_output_callback) { + if (!sampling_thread_) + return; + + scoped_ptr<TraceBuffer> previous_logged_events; + { + AutoLock lock(lock_); + AddMetadataEvents(); + previous_logged_events.reset(logged_events_->Clone()); + } // release lock + + ConvertTraceEventsToTraceFormat(previous_logged_events.Pass(), + flush_output_callback); +} + void TraceLog::AddTraceEvent( char phase, const unsigned char* category_group_enabled, @@ -1743,6 +1798,7 @@ void TraceLog::AddMetadataEvents() { it++) { if (it->second.empty()) continue; + AddMetadataEventToBuffer(logged_events_.get(), it->first, "thread_name", "name", @@ -1752,6 +1808,8 @@ void TraceLog::AddMetadataEvents() { void TraceLog::InstallWaitableEventForSamplingTesting( WaitableEvent* waitable_event) { + if (!sampling_thread_) + return; sampling_thread_->InstallWaitableEventForSamplingTesting(waitable_event); } @@ -1791,7 +1849,7 @@ void TraceLog::UpdateProcessLabel( void TraceLog::RemoveProcessLabel(int label_id) { AutoLock lock(lock_); base::hash_map<int, std::string>::iterator it = process_labels_.find( - label_id); + label_id); if (it == process_labels_.end()) return; @@ -1987,7 +2045,7 @@ ScopedTrace::ScopedTrace( name_ = name; TRACE_EVENT_API_ADD_TRACE_EVENT( TRACE_EVENT_PHASE_BEGIN, // phase - category_group_enabled_, // category enabled + category_group_enabled_, // category enabled name, // name 0, // id 0, // num_args diff --git a/base/debug/trace_event_impl.h b/base/debug/trace_event_impl.h index 4967c10..ba35cde 100644 --- a/base/debug/trace_event_impl.h +++ b/base/debug/trace_event_impl.h @@ -171,6 +171,7 @@ class BASE_EXPORT TraceBuffer { virtual size_t Size() const = 0; virtual size_t Capacity() const = 0; virtual const TraceEvent& GetEventAt(size_t index) const = 0; + virtual TraceBuffer* Clone() const = 0; }; // TraceResultBuffer collects and converts trace fragments returned by TraceLog @@ -308,11 +309,14 @@ class BASE_EXPORT TraceLog { // and we use it as a ring buffer during recording. RECORD_CONTINUOUSLY = 1 << 1, - // Enable the sampling profiler. + // Enable the sampling profiler in the recording mode. ENABLE_SAMPLING = 1 << 2, + // Enable the sampling profiler in the monitoring mode. + MONITOR_SAMPLING = 1 << 3, + // Echo to console. Events are discarded. - ECHO_TO_CONSOLE = 1 << 3, + ECHO_TO_CONSOLE = 1 << 4, }; static TraceLog* GetInstance(); @@ -336,7 +340,7 @@ class BASE_EXPORT TraceLog { // on how to control what categories will be traced. void SetEnabled(const CategoryFilter& category_filter, Options options); - // Disable tracing for all categories. + // Disables tracing for all categories. void SetDisabled(); bool IsEnabled() { return !!enable_count_; } @@ -407,6 +411,7 @@ class BASE_EXPORT TraceLog { typedef base::Callback<void(const scoped_refptr<base::RefCountedString>&, bool has_more_events)> OutputCallback; void Flush(const OutputCallback& cb); + void FlushButLeaveBufferIntact(const OutputCallback& flush_output_callback); // Called by TRACE_EVENT* macros, don't call this directly. // The name parameter is a category group for example: @@ -580,6 +585,8 @@ class BASE_EXPORT TraceLog { // |flush_count| is used in the following callbacks to check if the callback // is called for the current flush. void FlushCurrentThread(int flush_count); + void ConvertTraceEventsToTraceFormat(scoped_ptr<TraceBuffer> logged_events, + const TraceLog::OutputCallback& flush_output_callback); void FinishFlush(int flush_count); void OnFlushTimeout(int flush_count); diff --git a/base/debug/trace_event_unittest.cc b/base/debug/trace_event_unittest.cc index e7883d0..c81b4f8 100644 --- a/base/debug/trace_event_unittest.cc +++ b/base/debug/trace_event_unittest.cc @@ -99,6 +99,19 @@ class TraceEventTestFixture : public testing::Test { base::Unretained(flush_complete_event))); } + void FlushMonitoring() { + WaitableEvent flush_complete_event(false, false); + FlushMonitoring(&flush_complete_event); + flush_complete_event.Wait(); + } + + void FlushMonitoring(WaitableEvent* flush_complete_event) { + TraceLog::GetInstance()->FlushButLeaveBufferIntact( + base::Bind(&TraceEventTestFixture::OnTraceDataCollected, + base::Unretained(static_cast<TraceEventTestFixture*>(this)), + base::Unretained(flush_complete_event))); + } + virtual void SetUp() OVERRIDE { const char* name = PlatformThread::GetName(); old_thread_name_ = name ? strdup(name) : NULL; @@ -1765,6 +1778,57 @@ TEST_F(TraceEventTestFixture, TraceSamplingScope) { EndTraceAndFlush(); } +TEST_F(TraceEventTestFixture, TraceContinuousSampling) { + event_watch_notification_ = 0; + TraceLog::GetInstance()->SetEnabled( + CategoryFilter("*"), + TraceLog::Options(TraceLog::MONITOR_SAMPLING)); + + WaitableEvent* sampled = new WaitableEvent(false, false); + TraceLog::GetInstance()->InstallWaitableEventForSamplingTesting( + sampled); + + TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "category", "AAA"); + sampled->Wait(); + TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "category", "BBB"); + sampled->Wait(); + + FlushMonitoring(); + + // Make sure we can get the profiled data. + EXPECT_TRUE(FindNamePhase("AAA", "P")); + EXPECT_TRUE(FindNamePhase("BBB", "P")); + + Clear(); + sampled->Wait(); + + TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "category", "CCC"); + sampled->Wait(); + TRACE_EVENT_SET_SAMPLING_STATE_FOR_BUCKET(1, "category", "DDD"); + sampled->Wait(); + + FlushMonitoring(); + + // Make sure the profiled data is accumulated. + EXPECT_TRUE(FindNamePhase("AAA", "P")); + EXPECT_TRUE(FindNamePhase("BBB", "P")); + EXPECT_TRUE(FindNamePhase("CCC", "P")); + EXPECT_TRUE(FindNamePhase("DDD", "P")); + + Clear(); + + TraceLog::GetInstance()->SetDisabled(); + + // Make sure disabling the continuous sampling thread clears + // the profiled data. + EXPECT_FALSE(FindNamePhase("AAA", "P")); + EXPECT_FALSE(FindNamePhase("BBB", "P")); + EXPECT_FALSE(FindNamePhase("CCC", "P")); + EXPECT_FALSE(FindNamePhase("DDD", "P")); + + Clear(); +} + class MyData : public base::debug::ConvertableToTraceFormat { public: MyData() {} diff --git a/components/tracing/child_trace_message_filter.cc b/components/tracing/child_trace_message_filter.cc index 8310ec5..9925f3f 100644 --- a/components/tracing/child_trace_message_filter.cc +++ b/components/tracing/child_trace_message_filter.cc @@ -34,6 +34,10 @@ bool ChildTraceMessageFilter::OnMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(ChildTraceMessageFilter, message) IPC_MESSAGE_HANDLER(TracingMsg_BeginTracing, OnBeginTracing) IPC_MESSAGE_HANDLER(TracingMsg_EndTracing, OnEndTracing) + IPC_MESSAGE_HANDLER(TracingMsg_EnableMonitoring, OnEnableMonitoring) + IPC_MESSAGE_HANDLER(TracingMsg_DisableMonitoring, OnDisableMonitoring) + IPC_MESSAGE_HANDLER(TracingMsg_CaptureMonitoringSnapshot, + OnCaptureMonitoringSnapshot) IPC_MESSAGE_HANDLER(TracingMsg_GetTraceBufferPercentFull, OnGetTraceBufferPercentFull) IPC_MESSAGE_HANDLER(TracingMsg_SetWatchEvent, OnSetWatchEvent) @@ -73,6 +77,33 @@ void ChildTraceMessageFilter::OnEndTracing() { base::Bind(&ChildTraceMessageFilter::OnTraceDataCollected, this)); } +void ChildTraceMessageFilter::OnEnableMonitoring( + const std::string& category_filter_str, + base::TimeTicks browser_time, + int options) { + TraceLog::GetInstance()->SetEnabled( + base::debug::CategoryFilter(category_filter_str), + static_cast<base::debug::TraceLog::Options>(options)); +} + +void ChildTraceMessageFilter::OnDisableMonitoring() { + TraceLog::GetInstance()->SetDisabled(); +} + +void ChildTraceMessageFilter::OnCaptureMonitoringSnapshot() { + // Flush will generate one or more callbacks to + // OnMonitoringTraceDataCollected. It's important that the last + // OnMonitoringTraceDataCollected gets called before + // CaptureMonitoringSnapshotAck below. We are already on the IO thread, + // so the OnMonitoringTraceDataCollected calls will not be deferred. + TraceLog::GetInstance()->FlushButLeaveBufferIntact( + base::Bind(&ChildTraceMessageFilter:: + OnMonitoringTraceDataCollected, + this)); + + channel_->Send(new TracingHostMsg_CaptureMonitoringSnapshotAck()); +} + void ChildTraceMessageFilter::OnGetTraceBufferPercentFull() { float bpf = TraceLog::GetInstance()->GetBufferPercentFull(); @@ -109,6 +140,22 @@ void ChildTraceMessageFilter::OnTraceDataCollected( } } +void ChildTraceMessageFilter::OnMonitoringTraceDataCollected( + const scoped_refptr<base::RefCountedString>& events_str_ptr, + bool has_more_events) { + if (!ipc_message_loop_->BelongsToCurrentThread()) { + ipc_message_loop_->PostTask(FROM_HERE, + base::Bind(&ChildTraceMessageFilter:: + OnMonitoringTraceDataCollected, + this, + events_str_ptr, + has_more_events)); + return; + } + channel_->Send(new TracingHostMsg_MonitoringTraceDataCollected( + events_str_ptr->data())); +} + void ChildTraceMessageFilter::OnTraceNotification(int notification) { if (!ipc_message_loop_->BelongsToCurrentThread()) { ipc_message_loop_->PostTask(FROM_HERE, diff --git a/components/tracing/child_trace_message_filter.h b/components/tracing/child_trace_message_filter.h index 9f10b4a..cbd300f 100644 --- a/components/tracing/child_trace_message_filter.h +++ b/components/tracing/child_trace_message_filter.h @@ -32,8 +32,13 @@ class ChildTraceMessageFilter : public IPC::ChannelProxy::MessageFilter { // Message handlers. void OnBeginTracing(const std::string& category_filter_str, base::TimeTicks browser_time, - int mode); + int options); void OnEndTracing(); + void OnEnableMonitoring(const std::string& category_filter_str, + base::TimeTicks browser_time, + int options); + void OnDisableMonitoring(); + void OnCaptureMonitoringSnapshot(); void OnGetTraceBufferPercentFull(); void OnSetWatchEvent(const std::string& category_name, const std::string& event_name); @@ -43,6 +48,11 @@ class ChildTraceMessageFilter : public IPC::ChannelProxy::MessageFilter { void OnTraceDataCollected( const scoped_refptr<base::RefCountedString>& events_str_ptr, bool has_more_events); + + void OnMonitoringTraceDataCollected( + const scoped_refptr<base::RefCountedString>& events_str_ptr, + bool has_more_events); + void OnTraceNotification(int notification); IPC::Channel* channel_; diff --git a/components/tracing/tracing_messages.h b/components/tracing/tracing_messages.h index 9beb7e1..25b45bd 100644 --- a/components/tracing/tracing_messages.h +++ b/components/tracing/tracing_messages.h @@ -24,6 +24,18 @@ IPC_MESSAGE_CONTROL3(TracingMsg_BeginTracing, // Sent to all child processes to disable trace event recording. IPC_MESSAGE_CONTROL0(TracingMsg_EndTracing) +// Sent to all child processes to start monitoring. +IPC_MESSAGE_CONTROL3(TracingMsg_EnableMonitoring, + std::string /* category_filter_str */, + base::TimeTicks /* browser_time */, + int /* base::debug::TraceLog::Options */) + +// Sent to all child processes to stop monitoring.. +IPC_MESSAGE_CONTROL0(TracingMsg_DisableMonitoring) + +// Sent to all child processes to capture the current monitorint snapshot. +IPC_MESSAGE_CONTROL0(TracingMsg_CaptureMonitoringSnapshot) + // Sent to all child processes to get trace buffer fullness. IPC_MESSAGE_CONTROL0(TracingMsg_GetTraceBufferPercentFull) @@ -38,18 +50,26 @@ IPC_MESSAGE_CONTROL0(TracingMsg_CancelWatchEvent) // Notify the browser that this child process supports tracing. IPC_MESSAGE_CONTROL0(TracingHostMsg_ChildSupportsTracing) -// Reply from child processes acking ChildProcessMsg_TraceChangeStatus(false). +// Reply from child processes acking TracingMsg_EndTracing. IPC_MESSAGE_CONTROL1(TracingHostMsg_EndTracingAck, std::vector<std::string> /* known_categories */) +// Reply from child processes acking TracingMsg_CaptureMonitoringSnapshot. +IPC_MESSAGE_CONTROL0(TracingHostMsg_CaptureMonitoringSnapshotAck) + // Sent if the trace buffer becomes full. IPC_MESSAGE_CONTROL1(TracingHostMsg_TraceNotification, int /* base::debug::TraceLog::Notification */) -// Child processes send trace data back in JSON chunks. +// Child processes send back trace data in JSON chunks. IPC_MESSAGE_CONTROL1(TracingHostMsg_TraceDataCollected, std::string /*json trace data*/) +// Child processes send back trace data of the current monitoring +// in JSON chunks. +IPC_MESSAGE_CONTROL1(TracingHostMsg_MonitoringTraceDataCollected, + std::string /*json trace data*/) + // Reply to TracingMsg_GetTraceBufferPercentFull. IPC_MESSAGE_CONTROL1(TracingHostMsg_TraceBufferPercentFullReply, float /*trace buffer percent full*/) diff --git a/content/browser/tracing/trace_message_filter.cc b/content/browser/tracing/trace_message_filter.cc index b77c908..628a92f 100644 --- a/content/browser/tracing/trace_message_filter.cc +++ b/content/browser/tracing/trace_message_filter.cc @@ -6,12 +6,14 @@ #include "components/tracing/tracing_messages.h" #include "content/browser/tracing/trace_controller_impl.h" +#include "content/browser/tracing/tracing_controller_impl.h" namespace content { TraceMessageFilter::TraceMessageFilter() : has_child_(false), is_awaiting_end_ack_(false), + is_awaiting_capture_monitoring_snapshot_ack_(false), is_awaiting_buffer_percent_full_ack_(false) { } @@ -20,6 +22,9 @@ void TraceMessageFilter::OnChannelClosing() { if (is_awaiting_end_ack_) OnEndTracingAck(std::vector<std::string>()); + if (is_awaiting_capture_monitoring_snapshot_ack_) + OnCaptureMonitoringSnapshotAcked(); + if (is_awaiting_buffer_percent_full_ack_) OnTraceBufferPercentFullReply(0.0f); @@ -35,8 +40,12 @@ bool TraceMessageFilter::OnMessageReceived(const IPC::Message& message, IPC_MESSAGE_HANDLER(TracingHostMsg_ChildSupportsTracing, OnChildSupportsTracing) IPC_MESSAGE_HANDLER(TracingHostMsg_EndTracingAck, OnEndTracingAck) + IPC_MESSAGE_HANDLER(TracingHostMsg_CaptureMonitoringSnapshotAck, + OnCaptureMonitoringSnapshotAcked) IPC_MESSAGE_HANDLER(TracingHostMsg_TraceDataCollected, OnTraceDataCollected) + IPC_MESSAGE_HANDLER(TracingHostMsg_MonitoringTraceDataCollected, + OnMonitoringTraceDataCollected) IPC_MESSAGE_HANDLER(TracingHostMsg_TraceNotification, OnTraceNotification) IPC_MESSAGE_HANDLER(TracingHostMsg_TraceBufferPercentFullReply, @@ -62,6 +71,27 @@ void TraceMessageFilter::SendEndTracing() { Send(new TracingMsg_EndTracing); } +void TraceMessageFilter::SendEnableMonitoring( + const std::string& category_filter_str, + base::debug::TraceLog::Options options) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + Send(new TracingMsg_EnableMonitoring(category_filter_str, + base::TimeTicks::NowFromSystemTraceTime(), + options)); +} + +void TraceMessageFilter::SendDisableMonitoring() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + Send(new TracingMsg_DisableMonitoring); +} + +void TraceMessageFilter::SendCaptureMonitoringSnapshot() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(!is_awaiting_capture_monitoring_snapshot_ack_); + is_awaiting_capture_monitoring_snapshot_ack_ = true; + Send(new TracingMsg_CaptureMonitoringSnapshot); +} + void TraceMessageFilter::SendGetTraceBufferPercentFull() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(!is_awaiting_buffer_percent_full_ack_); @@ -97,12 +127,30 @@ void TraceMessageFilter::OnEndTracingAck( } } +void TraceMessageFilter::OnCaptureMonitoringSnapshotAcked() { + // is_awaiting_capture_monitoring_snapshot_ack_ should always be true here, + // but check in case the child process is compromised. + if (is_awaiting_capture_monitoring_snapshot_ack_) { + is_awaiting_capture_monitoring_snapshot_ack_ = false; + TracingControllerImpl::GetInstance()->OnCaptureMonitoringSnapshotAcked(); + } else { + NOTREACHED(); + } +} + void TraceMessageFilter::OnTraceDataCollected(const std::string& data) { scoped_refptr<base::RefCountedString> data_ptr(new base::RefCountedString()); data_ptr->data() = data; TraceControllerImpl::GetInstance()->OnTraceDataCollected(data_ptr); } +void TraceMessageFilter::OnMonitoringTraceDataCollected( + const std::string& data) { + scoped_refptr<base::RefCountedString> data_ptr(new base::RefCountedString()); + data_ptr->data() = data; + TracingControllerImpl::GetInstance()->OnTraceDataCollected(data_ptr); +} + void TraceMessageFilter::OnTraceNotification(int notification) { TraceControllerImpl::GetInstance()->OnTraceNotification(notification); } diff --git a/content/browser/tracing/trace_message_filter.h b/content/browser/tracing/trace_message_filter.h index 9f97184..c8290d9 100644 --- a/content/browser/tracing/trace_message_filter.h +++ b/content/browser/tracing/trace_message_filter.h @@ -28,6 +28,10 @@ class TraceMessageFilter : public BrowserMessageFilter { void SendBeginTracing(const std::string& category_filter_str, base::debug::TraceLog::Options options); void SendEndTracing(); + void SendEnableMonitoring(const std::string& category_filter_str, + base::debug::TraceLog::Options options); + void SendDisableMonitoring(); + void SendCaptureMonitoringSnapshot(); void SendGetTraceBufferPercentFull(); void SendSetWatchEvent(const std::string& category_name, const std::string& event_name); @@ -40,15 +44,19 @@ class TraceMessageFilter : public BrowserMessageFilter { // Message handlers. void OnChildSupportsTracing(); void OnEndTracingAck(const std::vector<std::string>& known_categories); + void OnCaptureMonitoringSnapshotAcked(); void OnTraceNotification(int notification); void OnTraceBufferPercentFullReply(float percent_full); void OnTraceDataCollected(const std::string& data); + void OnMonitoringTraceDataCollected(const std::string& data); // ChildTraceMessageFilter exists: bool has_child_; // Awaiting ack for previously sent SendEndTracing bool is_awaiting_end_ack_; + // Awaiting ack for previously sent SendCaptureMonitoringSnapshot + bool is_awaiting_capture_monitoring_snapshot_ack_; // Awaiting ack for previously sent SendGetTraceBufferPercentFull bool is_awaiting_buffer_percent_full_ack_; diff --git a/content/browser/tracing/tracing_controller_browsertest.cc b/content/browser/tracing/tracing_controller_browsertest.cc index c88932e..a3a589f 100644 --- a/content/browser/tracing/tracing_controller_browsertest.cc +++ b/content/browser/tracing/tracing_controller_browsertest.cc @@ -20,6 +20,9 @@ class TracingControllerTest : public ContentBrowserTest { get_categories_done_callback_count_ = 0; enable_recording_done_callback_count_ = 0; disable_recording_done_callback_count_ = 0; + enable_monitoring_done_callback_count_ = 0; + disable_monitoring_done_callback_count_ = 0; + capture_monitoring_snapshot_done_callback_count_ = 0; ContentBrowserTest::SetUp(); } @@ -47,6 +50,29 @@ class TracingControllerTest : public ContentBrowserTest { scoped_ptr<base::FilePath> file_path) { disable_recording_done_callback_count_++; EXPECT_TRUE(PathExists(*file_path)); + int64 file_size; + file_util::GetFileSize(*file_path, &file_size); + EXPECT_TRUE(file_size > 0); + quit_callback.Run(); + } + + void EnableMonitoringDoneCallbackTest(base::Closure quit_callback) { + enable_monitoring_done_callback_count_++; + quit_callback.Run(); + } + + void DisableMonitoringDoneCallbackTest(base::Closure quit_callback) { + disable_monitoring_done_callback_count_++; + quit_callback.Run(); + } + + void CaptureMonitoringSnapshotDoneCallbackTest( + base::Closure quit_callback, scoped_ptr<base::FilePath> file_path) { + capture_monitoring_snapshot_done_callback_count_++; + EXPECT_TRUE(PathExists(*file_path)); + int64 file_size; + file_util::GetFileSize(*file_path, &file_size); + EXPECT_TRUE(file_size > 0); quit_callback.Run(); } @@ -62,10 +88,25 @@ class TracingControllerTest : public ContentBrowserTest { return disable_recording_done_callback_count_; } + int enable_monitoring_done_callback_count() const { + return enable_monitoring_done_callback_count_; + } + + int disable_monitoring_done_callback_count() const { + return disable_monitoring_done_callback_count_; + } + + int capture_monitoring_snapshot_done_callback_count() const { + return capture_monitoring_snapshot_done_callback_count_; + } + private: int get_categories_done_callback_count_; int enable_recording_done_callback_count_; int disable_recording_done_callback_count_; + int enable_monitoring_done_callback_count_; + int disable_monitoring_done_callback_count_; + int capture_monitoring_snapshot_done_callback_count_; }; IN_PROC_BROWSER_TEST_F(TracingControllerTest, GetCategories) { @@ -94,8 +135,9 @@ IN_PROC_BROWSER_TEST_F(TracingControllerTest, EnableAndDisableRecording) { base::Bind(&TracingControllerTest::EnableRecordingDoneCallbackTest, base::Unretained(this), run_loop.QuitClosure()); - controller->EnableRecording(base::debug::CategoryFilter("*"), - TracingController::Options(), callback); + bool result = controller->EnableRecording(base::debug::CategoryFilter("*"), + TracingController::Options(), callback); + EXPECT_TRUE(result); run_loop.Run(); EXPECT_EQ(enable_recording_done_callback_count(), 1); } @@ -106,10 +148,55 @@ IN_PROC_BROWSER_TEST_F(TracingControllerTest, EnableAndDisableRecording) { base::Bind(&TracingControllerTest::DisableRecordingDoneCallbackTest, base::Unretained(this), run_loop.QuitClosure()); - controller->DisableRecording(callback); + bool result = controller->DisableRecording(callback); + EXPECT_TRUE(result); run_loop.Run(); EXPECT_EQ(disable_recording_done_callback_count(), 1); } } +IN_PROC_BROWSER_TEST_F(TracingControllerTest, + EnableCaptureAndDisableMonitoring) { + Navigate(shell()); + + TracingController* controller = TracingController::GetInstance(); + + { + base::RunLoop run_loop; + TracingController::EnableMonitoringDoneCallback callback = + base::Bind(&TracingControllerTest::EnableMonitoringDoneCallbackTest, + base::Unretained(this), + run_loop.QuitClosure()); + bool result = controller->EnableMonitoring(base::debug::CategoryFilter("*"), + TracingController::ENABLE_SAMPLING, callback); + EXPECT_TRUE(result); + run_loop.Run(); + EXPECT_EQ(enable_monitoring_done_callback_count(), 1); + } + + { + base::RunLoop run_loop; + TracingController::TracingFileResultCallback callback = + base::Bind(&TracingControllerTest:: + CaptureMonitoringSnapshotDoneCallbackTest, + base::Unretained(this), + run_loop.QuitClosure()); + controller->CaptureMonitoringSnapshot(callback); + run_loop.Run(); + EXPECT_EQ(capture_monitoring_snapshot_done_callback_count(), 1); + } + + { + base::RunLoop run_loop; + TracingController::DisableMonitoringDoneCallback callback = + base::Bind(&TracingControllerTest::DisableMonitoringDoneCallbackTest, + base::Unretained(this), + run_loop.QuitClosure()); + bool result = controller->DisableMonitoring(callback); + EXPECT_TRUE(result); + run_loop.Run(); + EXPECT_EQ(disable_monitoring_done_callback_count(), 1); + } +} + } // namespace content diff --git a/content/browser/tracing/tracing_controller_impl.cc b/content/browser/tracing/tracing_controller_impl.cc index 1c1c43a..dd10071 100644 --- a/content/browser/tracing/tracing_controller_impl.cc +++ b/content/browser/tracing/tracing_controller_impl.cc @@ -29,10 +29,14 @@ TracingController* TracingController::GetInstance() { } TracingControllerImpl::TracingControllerImpl() : - pending_end_ack_count_(0), + pending_disable_recording_ack_count_(0), + pending_capture_monitoring_snapshot_ack_count_(0), is_recording_(false), + is_monitoring_(false), category_filter_( - base::debug::CategoryFilter::kDefaultCategoryFilterString) { + base::debug::CategoryFilter::kDefaultCategoryFilterString), + result_file_(0), + result_file_has_at_least_one_result_(false) { } TracingControllerImpl::~TracingControllerImpl() { @@ -58,14 +62,14 @@ void TracingControllerImpl::GetCategories( DisableRecording(TracingFileResultCallback()); } -void TracingControllerImpl::EnableRecording( +bool TracingControllerImpl::EnableRecording( const base::debug::CategoryFilter& filter, TracingController::Options options, const EnableRecordingDoneCallback& callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); if (!can_enable_recording()) - return; + return false; trace_options_ = TraceLog::GetInstance()->trace_options(); TraceLog::GetInstance()->SetEnabled(filter, trace_options_); @@ -80,14 +84,15 @@ void TracingControllerImpl::EnableRecording( if (!callback.is_null()) callback.Run(); + return true; } -void TracingControllerImpl::DisableRecording( +bool TracingControllerImpl::DisableRecording( const TracingFileResultCallback& callback) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (!can_end_recording()) - return; + if (!can_disable_recording()) + return false; pending_disable_recording_done_callback_ = callback; @@ -99,18 +104,24 @@ void TracingControllerImpl::DisableRecording( if (pending_get_categories_done_callback_.is_null()) { base::FilePath temporary_file; file_util::CreateTemporaryFile(&temporary_file); - recording_result_file_.reset(new base::FilePath(temporary_file)); + result_file_path_.reset(new base::FilePath(temporary_file)); + result_file_ = file_util::OpenFile(*result_file_path_, "w"); + result_file_has_at_least_one_result_ = false; + const char* preamble = "{\"traceEvents\": ["; + size_t written = fwrite(preamble, strlen(preamble), 1, result_file_); + DCHECK(written == 1); } // There could be a case where there are no child processes and filters_ // is empty. In that case we can immediately tell the subscriber that tracing // has ended. To avoid recursive calls back to the subscriber, we will just // use the existing asynchronous OnDisableRecordingAcked code. - // Count myself (local trace) in pending_end_ack_count_, acked below. - pending_end_ack_count_ = filters_.size() + 1; + // Count myself (local trace) in pending_disable_recording_ack_count_, + // acked below. + pending_disable_recording_ack_count_ = filters_.size() + 1; // Handle special case of zero child processes. - if (pending_end_ack_count_ == 1) { + if (pending_disable_recording_ack_count_ == 1) { // Ack asynchronously now, because we don't have any children to wait for. std::vector<std::string> category_groups; TraceLog::GetInstance()->GetKnownCategoryGroups(&category_groups); @@ -123,18 +134,50 @@ void TracingControllerImpl::DisableRecording( for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) { it->get()->SendEndTracing(); } + return true; } -void TracingControllerImpl::EnableMonitoring( +bool TracingControllerImpl::EnableMonitoring( const base::debug::CategoryFilter& filter, TracingController::Options options, const EnableMonitoringDoneCallback& callback) { - NOTIMPLEMENTED(); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + if (!can_enable_monitoring()) + return false; + is_monitoring_ = true; + + int monitoring_tracing_options = 0; + if (options & ENABLE_SAMPLING) + monitoring_tracing_options |= base::debug::TraceLog::MONITOR_SAMPLING; + + // Notify all child processes. + for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) { + it->get()->SendEnableMonitoring(filter.ToString(), + base::debug::TraceLog::Options(monitoring_tracing_options)); + } + + if (!callback.is_null()) + callback.Run(); + return true; } -void TracingControllerImpl::DisableMonitoring( +bool TracingControllerImpl::DisableMonitoring( const DisableMonitoringDoneCallback& callback) { - NOTIMPLEMENTED(); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + if (!can_disable_monitoring()) + return false; + is_monitoring_ = false; + + // Notify all child processes. + for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) { + it->get()->SendDisableMonitoring(); + } + + if (!callback.is_null()) + callback.Run(); + return true; } void TracingControllerImpl::GetMonitoringStatus( @@ -144,9 +187,44 @@ void TracingControllerImpl::GetMonitoringStatus( NOTIMPLEMENTED(); } -void TracingControllerImpl::CaptureCurrentMonitoringSnapshot( +void TracingControllerImpl::CaptureMonitoringSnapshot( const TracingFileResultCallback& callback) { - NOTIMPLEMENTED(); + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + if (!can_disable_monitoring()) + return; + + pending_capture_monitoring_snapshot_done_callback_ = callback; + + base::FilePath temporary_file; + file_util::CreateTemporaryFile(&temporary_file); + result_file_path_.reset(new base::FilePath(temporary_file)); + result_file_ = file_util::OpenFile(*result_file_path_, "w"); + result_file_has_at_least_one_result_ = false; + const char* preamble = "{\"traceEvents\": ["; + size_t written = fwrite(preamble, strlen(preamble), 1, result_file_); + DCHECK(written == 1); + + // There could be a case where there are no child processes and filters_ + // is empty. In that case we can immediately tell the subscriber that tracing + // has ended. To avoid recursive calls back to the subscriber, we will just + // use the existing asynchronous OnCaptureMonitoringSnapshotAcked code. + // Count myself in pending_capture_monitoring_snapshot_ack_count_, + // acked below. + pending_capture_monitoring_snapshot_ack_count_ = filters_.size() + 1; + + // Handle special case of zero child processes. + if (pending_capture_monitoring_snapshot_ack_count_ == 1) { + // Ack asynchronously now, because we don't have any children to wait for. + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked, + base::Unretained(this))); + } + + // Notify all child processes. + for (FilterMap::iterator it = filters_.begin(); it != filters_.end(); ++it) { + it->get()->SendCaptureMonitoringSnapshot(); + } } void TracingControllerImpl::AddFilter(TraceMessageFilter* filter) { @@ -158,7 +236,7 @@ void TracingControllerImpl::AddFilter(TraceMessageFilter* filter) { } filters_.insert(filter); - if (is_recording_enabled()) { + if (can_disable_recording()) { std::string cf_str = category_filter_.ToString(); filter->SendBeginTracing(cf_str, trace_options_); } @@ -188,10 +266,10 @@ void TracingControllerImpl::OnDisableRecordingAcked( known_category_groups_.insert(known_category_groups.begin(), known_category_groups.end()); - if (pending_end_ack_count_ == 0) + if (pending_disable_recording_ack_count_ == 0) return; - if (--pending_end_ack_count_ == 1) { + if (--pending_disable_recording_ack_count_ == 1) { // All acks from subprocesses have been received. Now flush the local trace. // During or after this call, our OnLocalTraceDataCollected will be // called with the last of the local trace data. @@ -200,7 +278,7 @@ void TracingControllerImpl::OnDisableRecordingAcked( base::Unretained(this))); } - if (pending_end_ack_count_ != 0) + if (pending_disable_recording_ack_count_ != 0) return; // All acks (including from the subprocesses and the local trace) have been @@ -211,17 +289,50 @@ void TracingControllerImpl::OnDisableRecordingAcked( if (!pending_get_categories_done_callback_.is_null()) { pending_get_categories_done_callback_.Run(known_category_groups_); pending_get_categories_done_callback_.Reset(); - } else { - OnEndTracingComplete(); + } else if (!pending_disable_recording_done_callback_.is_null()) { + const char* trailout = "]}"; + size_t written = fwrite(trailout, strlen(trailout), 1, result_file_); + DCHECK(written == 1); + file_util::CloseFile(result_file_); + result_file_ = 0; + pending_disable_recording_done_callback_.Run(result_file_path_.Pass()); + pending_disable_recording_done_callback_.Reset(); } } -void TracingControllerImpl::OnEndTracingComplete() { - if (pending_disable_recording_done_callback_.is_null()) +void TracingControllerImpl::OnCaptureMonitoringSnapshotAcked() { + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(&TracingControllerImpl::OnCaptureMonitoringSnapshotAcked, + base::Unretained(this))); + return; + } + + if (pending_capture_monitoring_snapshot_ack_count_ == 0) return; - pending_disable_recording_done_callback_.Run(recording_result_file_.Pass()); - pending_disable_recording_done_callback_.Reset(); + if (--pending_capture_monitoring_snapshot_ack_count_ == 1) { + // All acks from subprocesses have been received. Now flush the local trace. + // During or after this call, our OnLocalMonitoringTraceDataCollected + // will be called with the last of the local trace data. + TraceLog::GetInstance()->FlushButLeaveBufferIntact( + base::Bind(&TracingControllerImpl::OnLocalMonitoringTraceDataCollected, + base::Unretained(this))); + } + + if (pending_capture_monitoring_snapshot_ack_count_ != 0) + return; + + if (!pending_capture_monitoring_snapshot_done_callback_.is_null()) { + const char* trailout = "]}"; + size_t written = fwrite(trailout, strlen(trailout), 1, result_file_); + DCHECK(written == 1); + file_util::CloseFile(result_file_); + result_file_ = 0; + pending_capture_monitoring_snapshot_done_callback_.Run( + result_file_path_.Pass()); + pending_capture_monitoring_snapshot_done_callback_.Reset(); + } } void TracingControllerImpl::OnTraceDataCollected( @@ -239,17 +350,18 @@ void TracingControllerImpl::OnTraceDataCollected( if (!pending_get_categories_done_callback_.is_null()) return; - std::string javascript; - javascript.reserve(events_str_ptr->size() * 2); - base::JsonDoubleQuote(events_str_ptr->data(), false, &javascript); - - // Intentionally append a , to the traceData. This technically causes all - // traceData that we pass back to JS to end with a comma, but that is - // actually something the JS side strips away anyway - javascript.append(","); - - file_util::WriteFile(*recording_result_file_, - javascript.c_str(), javascript.length()); + // If there is already a result in the file, then put a commma + // before the next batch of results. + if (result_file_has_at_least_one_result_) { + size_t written = fwrite(",", 1, 1, result_file_); + DCHECK(written == 1); + } else { + result_file_has_at_least_one_result_ = true; + } + size_t written = fwrite(events_str_ptr->data().c_str(), + events_str_ptr->data().size(), 1, + result_file_); + DCHECK(written == 1); } void TracingControllerImpl::OnLocalTraceDataCollected( @@ -267,4 +379,17 @@ void TracingControllerImpl::OnLocalTraceDataCollected( OnDisableRecordingAcked(category_groups); } +void TracingControllerImpl::OnLocalMonitoringTraceDataCollected( + const scoped_refptr<base::RefCountedString>& events_str_ptr, + bool has_more_events) { + if (events_str_ptr->data().size()) + OnTraceDataCollected(events_str_ptr); + + if (has_more_events) + return; + + // Simulate an CaptureMonitoringSnapshotAcked for the local trace. + OnCaptureMonitoringSnapshotAcked(); +} + } // namespace content diff --git a/content/browser/tracing/tracing_controller_impl.h b/content/browser/tracing/tracing_controller_impl.h index 2219225..175365e 100644 --- a/content/browser/tracing/tracing_controller_impl.h +++ b/content/browser/tracing/tracing_controller_impl.h @@ -25,22 +25,22 @@ class TracingControllerImpl : // TracingController implementation. virtual void GetCategories( const GetCategoriesDoneCallback& callback) OVERRIDE; - virtual void EnableRecording( + virtual bool EnableRecording( const base::debug::CategoryFilter& filter, TracingController::Options options, const EnableRecordingDoneCallback& callback) OVERRIDE; - virtual void DisableRecording( + virtual bool DisableRecording( const TracingFileResultCallback& callback) OVERRIDE; - virtual void EnableMonitoring(const base::debug::CategoryFilter& filter, + virtual bool EnableMonitoring(const base::debug::CategoryFilter& filter, TracingController::Options options, const EnableMonitoringDoneCallback& callback) OVERRIDE; - virtual void DisableMonitoring( + virtual bool DisableMonitoring( const DisableMonitoringDoneCallback& callback) OVERRIDE; virtual void GetMonitoringStatus( bool* out_enabled, base::debug::CategoryFilter* out_filter, TracingController::Options* out_options) OVERRIDE; - virtual void CaptureCurrentMonitoringSnapshot( + virtual void CaptureMonitoringSnapshot( const TracingFileResultCallback& callback) OVERRIDE; private: @@ -53,7 +53,6 @@ class TracingControllerImpl : virtual ~TracingControllerImpl(); // TraceSubscriber implementation. - virtual void OnEndTracingComplete() OVERRIDE; virtual void OnTraceDataCollected( const scoped_refptr<base::RefCountedString>& events_str_ptr) OVERRIDE; @@ -61,12 +60,17 @@ class TracingControllerImpl : return !is_recording_; } - bool can_end_recording() const { - return is_recording_ && pending_end_ack_count_ == 0; + bool can_disable_recording() const { + return is_recording_ && pending_disable_recording_ack_count_ == 0; } - bool is_recording_enabled() const { - return can_end_recording(); + bool can_enable_monitoring() const { + return !is_monitoring_; + } + + bool can_disable_monitoring() const { + return is_monitoring_ && + pending_capture_monitoring_snapshot_ack_count_ == 0; } // Methods for use by TraceMessageFilter. @@ -77,20 +81,31 @@ class TracingControllerImpl : void OnLocalTraceDataCollected( const scoped_refptr<base::RefCountedString>& events_str_ptr, bool has_more_events); + // Callback of TraceLog::FlushMonitoring() for the local trace. + void OnLocalMonitoringTraceDataCollected( + const scoped_refptr<base::RefCountedString>& events_str_ptr, + bool has_more_events); void OnDisableRecordingAcked( const std::vector<std::string>& known_category_groups); + void OnCaptureMonitoringSnapshotAcked(); FilterMap filters_; // Pending acks for DisableRecording. - int pending_end_ack_count_; + int pending_disable_recording_ack_count_; + // Pending acks for CaptureMonitoringSnapshot. + int pending_capture_monitoring_snapshot_ack_count_; bool is_recording_; + bool is_monitoring_; GetCategoriesDoneCallback pending_get_categories_done_callback_; TracingFileResultCallback pending_disable_recording_done_callback_; + TracingFileResultCallback pending_capture_monitoring_snapshot_done_callback_; std::set<std::string> known_category_groups_; base::debug::TraceLog::Options trace_options_; base::debug::CategoryFilter category_filter_; - scoped_ptr<base::FilePath> recording_result_file_; + FILE* result_file_; + scoped_ptr<base::FilePath> result_file_path_; + bool result_file_has_at_least_one_result_; DISALLOW_COPY_AND_ASSIGN(TracingControllerImpl); }; diff --git a/content/public/browser/trace_subscriber.h b/content/public/browser/trace_subscriber.h index 02e9f1c..8b63d35 100644 --- a/content/public/browser/trace_subscriber.h +++ b/content/public/browser/trace_subscriber.h @@ -18,7 +18,7 @@ namespace content { class TraceSubscriber { public: // Called once after TraceController::EndTracingAsync. - virtual void OnEndTracingComplete() = 0; + virtual void OnEndTracingComplete() {} // Called 0 or more times between TraceController::BeginTracing and // OnEndTracingComplete. Use base::debug::TraceResultBuffer to convert one or diff --git a/content/public/browser/tracing_controller.h b/content/public/browser/tracing_controller.h index 18d4355..d3bc7bd 100644 --- a/content/public/browser/tracing_controller.h +++ b/content/public/browser/tracing_controller.h @@ -59,7 +59,7 @@ class TracingController { // // |options| controls what kind of tracing is enabled. typedef base::Callback<void()> EnableRecordingDoneCallback; - virtual void EnableRecording( + virtual bool EnableRecording( const base::debug::CategoryFilter& filter, TracingController::Options options, const EnableRecordingDoneCallback& callback) = 0; @@ -77,7 +77,7 @@ class TracingController { // the traced data. typedef base::Callback<void(scoped_ptr<base::FilePath>)> TracingFileResultCallback; - virtual void DisableRecording(const TracingFileResultCallback& callback) = 0; + virtual bool DisableRecording(const TracingFileResultCallback& callback) = 0; // Start monitoring on all processes. // @@ -91,7 +91,7 @@ class TracingController { // // |options| controls what kind of tracing is enabled. typedef base::Callback<void()> EnableMonitoringDoneCallback; - virtual void EnableMonitoring(const base::debug::CategoryFilter& filter, + virtual bool EnableMonitoring(const base::debug::CategoryFilter& filter, TracingController::Options options, const EnableMonitoringDoneCallback& callback) = 0; @@ -100,7 +100,7 @@ class TracingController { // Once all child processes have acked to the DisableMonitoring request, // DisableMonitoringDoneCallback is called back. typedef base::Callback<void()> DisableMonitoringDoneCallback; - virtual void DisableMonitoring( + virtual bool DisableMonitoring( const DisableMonitoringDoneCallback& callback) = 0; // Get the current monitoring configuration. @@ -116,10 +116,10 @@ class TracingController { // to avoid much runtime overhead of tracing. So, to end tracing, we must // asynchronously ask all child processes to flush any pending trace data. // - // Once all child processes have acked to the CaptureCurrentMonitoringSnapshot + // Once all child processes have acked to the CaptureMonitoringSnapshot // request, TracingFileResultCallback will be called back with a file that // contains the traced data. - virtual void CaptureCurrentMonitoringSnapshot( + virtual void CaptureMonitoringSnapshot( const TracingFileResultCallback& callback) = 0; protected: |