summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorharaken@chromium.org <haraken@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-08 01:01:25 +0000
committerharaken@chromium.org <haraken@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-08 01:01:25 +0000
commit7ad4e2d50a8ae5cc1502a29166721fa447eb1ee5 (patch)
treea7dcc30be12c22a4d4900a92d58b26a086aabc3b
parent7cc7ebd4924ef763abfbdf334824e075330b0c14 (diff)
downloadchromium_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.cc136
-rw-r--r--base/debug/trace_event_impl.h13
-rw-r--r--base/debug/trace_event_unittest.cc64
-rw-r--r--components/tracing/child_trace_message_filter.cc47
-rw-r--r--components/tracing/child_trace_message_filter.h12
-rw-r--r--components/tracing/tracing_messages.h24
-rw-r--r--content/browser/tracing/trace_message_filter.cc48
-rw-r--r--content/browser/tracing/trace_message_filter.h8
-rw-r--r--content/browser/tracing/tracing_controller_browsertest.cc93
-rw-r--r--content/browser/tracing/tracing_controller_impl.cc201
-rw-r--r--content/browser/tracing/tracing_controller_impl.h39
-rw-r--r--content/public/browser/trace_subscriber.h2
-rw-r--r--content/public/browser/tracing_controller.h12
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: