summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/debug/trace_event.cc45
-rw-r--r--base/debug/trace_event.h48
-rw-r--r--base/debug/trace_event_unittest.cc54
-rw-r--r--chrome/browser/ui/webui/tracing_ui.cc17
-rw-r--r--content/browser/trace_controller.cc6
-rw-r--r--content/browser/trace_controller.h7
-rw-r--r--content/browser/trace_subscriber_stdio.cc36
-rw-r--r--content/browser/trace_subscriber_stdio.h5
-rw-r--r--content/browser/trace_subscriber_stdio_unittest.cc4
-rw-r--r--content/common/child_trace_message_filter.cc6
-rw-r--r--content/common/child_trace_message_filter.h2
11 files changed, 173 insertions, 57 deletions
diff --git a/base/debug/trace_event.cc b/base/debug/trace_event.cc
index 347644f..3e03d4a 100644
--- a/base/debug/trace_event.cc
+++ b/base/debug/trace_event.cc
@@ -9,6 +9,7 @@
#if defined(OS_WIN)
#include "base/debug/trace_event_win.h"
#endif
+#include "base/bind.h"
#include "base/format_macros.h"
#include "base/memory/ref_counted_memory.h"
#include "base/process_util.h"
@@ -224,13 +225,11 @@ void TraceEvent::AppendEventsAsJSON(const std::vector<TraceEvent>& events,
size_t start,
size_t count,
std::string* out) {
- *out += "[";
for (size_t i = 0; i < count && start + i < events.size(); ++i) {
if (i > 0)
*out += ",";
events[i + start].AppendAsJSON(out);
}
- *out += "]";
}
void TraceEvent::AppendAsJSON(std::string* out) const {
@@ -262,6 +261,48 @@ void TraceEvent::AppendAsJSON(std::string* out) const {
////////////////////////////////////////////////////////////////////////////////
//
+// TraceResultBuffer
+//
+////////////////////////////////////////////////////////////////////////////////
+
+TraceResultBuffer::OutputCallback
+ TraceResultBuffer::SimpleOutput::GetCallback() {
+ return base::Bind(&SimpleOutput::Append, base::Unretained(this));
+}
+
+void TraceResultBuffer::SimpleOutput::Append(
+ const std::string& json_trace_output) {
+ json_output += json_trace_output;
+}
+
+TraceResultBuffer::TraceResultBuffer() : append_comma_(false) {
+}
+
+TraceResultBuffer::~TraceResultBuffer() {
+}
+
+void TraceResultBuffer::SetOutputCallback(OutputCallback json_chunk_callback) {
+ output_callback_ = json_chunk_callback;
+}
+
+void TraceResultBuffer::Start() {
+ append_comma_ = false;
+ output_callback_.Run("[");
+}
+
+void TraceResultBuffer::AddFragment(const std::string& trace_fragment) {
+ if (append_comma_)
+ output_callback_.Run(",");
+ append_comma_ = true;
+ output_callback_.Run(trace_fragment);
+}
+
+void TraceResultBuffer::Finish() {
+ output_callback_.Run("]");
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//
// TraceLog
//
////////////////////////////////////////////////////////////////////////////////
diff --git a/base/debug/trace_event.h b/base/debug/trace_event.h
index d5aa256..ec18844 100644
--- a/base/debug/trace_event.h
+++ b/base/debug/trace_event.h
@@ -515,6 +515,50 @@ class TraceEvent {
};
+// TraceResultBuffer collects and converts trace fragments returned by TraceLog
+// to JSON output.
+class TraceResultBuffer {
+ public:
+ typedef base::Callback<void(const std::string&)> OutputCallback;
+
+ // If you don't need to stream JSON chunks out efficiently, and just want to
+ // get a complete JSON string after calling Finish, use this struct to collect
+ // JSON trace output.
+ struct SimpleOutput {
+ OutputCallback GetCallback();
+ void Append(const std::string& json_string);
+
+ // Do what you want with the json_output_ string after calling
+ // TraceResultBuffer::Finish.
+ std::string json_output;
+ };
+
+ TraceResultBuffer();
+ ~TraceResultBuffer();
+
+ // Set callback. The callback will be called during Start with the initial
+ // JSON output and during AddFragment and Finish with following JSON output
+ // chunks. The callback target must live past the last calls to
+ // TraceResultBuffer::Start/AddFragment/Finish.
+ void SetOutputCallback(OutputCallback json_chunk_callback);
+
+ // Start JSON output. This resets all internal state, so you can reuse
+ // the TraceResultBuffer by calling Start.
+ void Start();
+
+ // Call AddFragment 0 or more times to add trace fragments from TraceLog.
+ void AddFragment(const std::string& trace_fragment);
+
+ // When all fragments have been added, call Finish to complete the JSON
+ // formatted output.
+ void Finish();
+
+ private:
+ OutputCallback output_callback_;
+ bool append_comma_;
+};
+
+
class BASE_EXPORT TraceLog {
public:
// Flags for passing to AddTraceEvent.
@@ -549,7 +593,9 @@ class BASE_EXPORT TraceLog {
// When enough events are collected, they are handed (in bulk) to
// the output callback. If no callback is set, the output will be
- // silently dropped. The callback must be thread safe.
+ // silently dropped. The callback must be thread safe. The string format is
+ // undefined. Use TraceResultBuffer to convert one or more trace strings to
+ // JSON.
typedef RefCountedData<std::string> RefCountedString;
typedef base::Callback<void(scoped_refptr<RefCountedString>)> OutputCallback;
void SetOutputCallback(const OutputCallback& cb);
diff --git a/base/debug/trace_event_unittest.cc b/base/debug/trace_event_unittest.cc
index 0ccf440..c30c773 100644
--- a/base/debug/trace_event_unittest.cc
+++ b/base/debug/trace_event_unittest.cc
@@ -40,7 +40,7 @@ class TraceEventTestFixture : public testing::Test {
// up multiple times when testing AtExit. Use ManualTestSetUp for this.
void ManualTestSetUp();
void OnTraceDataCollected(
- scoped_refptr<TraceLog::RefCountedString> json_events_str);
+ scoped_refptr<TraceLog::RefCountedString> events_str);
bool FindMatchingTraceEntry(const JsonKeyValue* key_values);
bool FindNamePhase(const char* name, const char* phase);
bool FindMatchingValue(const char* key,
@@ -48,12 +48,13 @@ class TraceEventTestFixture : public testing::Test {
bool FindNonMatchingValue(const char* key,
const char* value);
void Clear() {
- trace_string_.clear();
trace_parsed_.Clear();
+ json_output_.json_output.clear();
}
- std::string trace_string_;
ListValue trace_parsed_;
+ base::debug::TraceResultBuffer trace_buffer_;
+ base::debug::TraceResultBuffer::SimpleOutput json_output_;
private:
// We want our singleton torn down after each test.
@@ -70,15 +71,19 @@ void TraceEventTestFixture::ManualTestSetUp() {
tracelog->SetOutputCallback(
base::Bind(&TraceEventTestFixture::OnTraceDataCollected,
base::Unretained(this)));
+ trace_buffer_.SetOutputCallback(json_output_.GetCallback());
}
void TraceEventTestFixture::OnTraceDataCollected(
- scoped_refptr<TraceLog::RefCountedString> json_events_str) {
+ scoped_refptr<TraceLog::RefCountedString> events_str) {
AutoLock lock(lock_);
- trace_string_ += json_events_str->data;
+ json_output_.json_output.clear();
+ trace_buffer_.Start();
+ trace_buffer_.AddFragment(events_str->data);
+ trace_buffer_.Finish();
scoped_ptr<Value> root;
- root.reset(base::JSONReader::Read(json_events_str->data, false));
+ root.reset(base::JSONReader::Read(json_output_.json_output, false));
ListValue* root_list = NULL;
ASSERT_TRUE(root.get());
@@ -281,8 +286,7 @@ void TraceWithAllMacroVariants(WaitableEvent* task_complete_event) {
task_complete_event->Signal();
}
-void ValidateAllTraceMacrosCreatedData(const ListValue& trace_parsed,
- const std::string& trace_string) {
+void ValidateAllTraceMacrosCreatedData(const ListValue& trace_parsed) {
DictionaryValue* item = NULL;
#define EXPECT_FIND_(string) \
@@ -345,7 +349,7 @@ void ValidateAllTraceMacrosCreatedData(const ListValue& trace_parsed,
}
void TraceManyInstantEvents(int thread_id, int num_events,
- WaitableEvent* task_complete_event) {
+ WaitableEvent* task_complete_event) {
for (int i = 0; i < num_events; i++) {
TRACE_EVENT_INSTANT2("all", "multi thread event",
"thread", thread_id,
@@ -357,8 +361,8 @@ void TraceManyInstantEvents(int thread_id, int num_events,
}
void ValidateInstantEventPresentOnEveryThread(const ListValue& trace_parsed,
- const std::string& trace_string,
- int num_threads, int num_events) {
+ int num_threads,
+ int num_events) {
std::map<int, std::map<int, bool> > results;
size_t trace_parsed_count = trace_parsed.GetSize();
@@ -406,7 +410,7 @@ TEST_F(TraceEventTestFixture, DataCaptured) {
TraceLog::GetInstance()->SetEnabled(false);
- ValidateAllTraceMacrosCreatedData(trace_parsed_, trace_string_);
+ ValidateAllTraceMacrosCreatedData(trace_parsed_);
}
// Test that categories work.
@@ -687,7 +691,7 @@ TEST_F(TraceEventTestFixture, DataCapturedOnThread) {
thread.Stop();
TraceLog::GetInstance()->SetEnabled(false);
- ValidateAllTraceMacrosCreatedData(trace_parsed_, trace_string_);
+ ValidateAllTraceMacrosCreatedData(trace_parsed_);
}
// Test that data sent from multiple threads is gathered
@@ -720,7 +724,7 @@ TEST_F(TraceEventTestFixture, DataCapturedManyThreads) {
TraceLog::GetInstance()->SetEnabled(false);
- ValidateInstantEventPresentOnEveryThread(trace_parsed_, trace_string_,
+ ValidateInstantEventPresentOnEveryThread(trace_parsed_,
num_threads, num_events);
}
@@ -925,5 +929,27 @@ TEST_F(TraceEventTestFixture, DeepCopy) {
EXPECT_EQ("val2", s);
}
+// Test that TraceResultBuffer outputs the correct result whether it is added
+// in chunks or added all at once.
+TEST_F(TraceEventTestFixture, TraceResultBuffer) {
+ ManualTestSetUp();
+
+ Clear();
+
+ trace_buffer_.Start();
+ trace_buffer_.AddFragment("bla1");
+ trace_buffer_.AddFragment("bla2");
+ trace_buffer_.AddFragment("bla3,bla4");
+ trace_buffer_.Finish();
+ EXPECT_STREQ(json_output_.json_output.c_str(), "[bla1,bla2,bla3,bla4]");
+
+ Clear();
+
+ trace_buffer_.Start();
+ trace_buffer_.AddFragment("bla1,bla2,bla3,bla4");
+ trace_buffer_.Finish();
+ EXPECT_STREQ(json_output_.json_output.c_str(), "[bla1,bla2,bla3,bla4]");
+}
+
} // namespace debug
} // namespace base
diff --git a/chrome/browser/ui/webui/tracing_ui.cc b/chrome/browser/ui/webui/tracing_ui.cc
index f13f15e..efd1562 100644
--- a/chrome/browser/ui/webui/tracing_ui.cc
+++ b/chrome/browser/ui/webui/tracing_ui.cc
@@ -63,7 +63,7 @@ class TracingMessageHandler
// TraceSubscriber implementation.
virtual void OnEndTracingComplete();
- virtual void OnTraceDataCollected(const std::string& json_events);
+ virtual void OnTraceDataCollected(const std::string& trace_fragment);
virtual void OnTraceBufferPercentFullReply(float percent_full);
// Messages.
@@ -419,13 +419,20 @@ void TracingMessageHandler::OnEndTracingComplete() {
}
void TracingMessageHandler::OnTraceDataCollected(
- const std::string& json_events) {
+ const std::string& trace_fragment) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- std::string javascript = "tracingController.onTraceDataCollected("
- + json_events + ");";
+
+ base::debug::TraceResultBuffer::SimpleOutput output;
+ base::debug::TraceResultBuffer trace_buffer;
+ trace_buffer.SetOutputCallback(output.GetCallback());
+ output.Append("tracingController.onTraceDataCollected(");
+ trace_buffer.Start();
+ trace_buffer.AddFragment(trace_fragment);
+ trace_buffer.Finish();
+ output.Append(");");
web_ui_->tab_contents()->render_view_host()->
- ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(javascript));
+ ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(output.json_output));
}
void TracingMessageHandler::OnTraceBufferPercentFullReply(float percent_full) {
diff --git a/content/browser/trace_controller.cc b/content/browser/trace_controller.cc
index 4464a8b..daff2a1 100644
--- a/content/browser/trace_controller.cc
+++ b/content/browser/trace_controller.cc
@@ -224,19 +224,19 @@ void TraceController::OnEndTracingAck(
void TraceController::OnTraceDataCollected(
const scoped_refptr<base::debug::TraceLog::RefCountedString>&
- json_events_str_ptr) {
+ events_str_ptr) {
// OnTraceDataCollected may be called from any browser thread, either by the
// local event trace system or from child processes via TraceMessageFilter.
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
base::Bind(&TraceController::OnTraceDataCollected,
- base::Unretained(this), json_events_str_ptr));
+ base::Unretained(this), events_str_ptr));
return;
}
// Drop trace events if we are just getting categories.
if (subscriber_ && !is_get_categories_)
- subscriber_->OnTraceDataCollected(json_events_str_ptr->data);
+ subscriber_->OnTraceDataCollected(events_str_ptr->data);
}
void TraceController::OnTraceBufferFull() {
diff --git a/content/browser/trace_controller.h b/content/browser/trace_controller.h
index 3d74820..7ac1676 100644
--- a/content/browser/trace_controller.h
+++ b/content/browser/trace_controller.h
@@ -23,8 +23,9 @@ class CONTENT_EXPORT TraceSubscriber {
// Called once after TraceController::EndTracingAsync.
virtual void OnEndTracingComplete() = 0;
// Called 0 or more times between TraceController::BeginTracing and
- // OnEndTracingComplete.
- virtual void OnTraceDataCollected(const std::string& json_events) = 0;
+ // OnEndTracingComplete. Use base::debug::TraceResultBuffer to convert one or
+ // more trace fragments to JSON.
+ virtual void OnTraceDataCollected(const std::string& trace_fragment) = 0;
// Called once after TraceController::GetKnownCategoriesAsync.
virtual void OnKnownCategoriesCollected(
const std::set<std::string>& known_categories) {}
@@ -134,7 +135,7 @@ class CONTENT_EXPORT TraceController {
void OnEndTracingAck(const std::vector<std::string>& known_categories);
void OnTraceDataCollected(
const scoped_refptr<base::debug::TraceLog::RefCountedString>&
- json_events_str_ptr);
+ events_str_ptr);
void OnTraceBufferFull();
void OnTraceBufferPercentFullReply(float percent_full);
diff --git a/content/browser/trace_subscriber_stdio.cc b/content/browser/trace_subscriber_stdio.cc
index bf6a8fc..901aea0 100644
--- a/content/browser/trace_subscriber_stdio.cc
+++ b/content/browser/trace_subscriber_stdio.cc
@@ -4,6 +4,7 @@
#include "content/browser/trace_subscriber_stdio.h"
+#include "base/bind.h"
#include "base/logging.h"
TraceSubscriberStdio::TraceSubscriberStdio() : file_(0) {
@@ -22,8 +23,9 @@ bool TraceSubscriberStdio::OpenFile(const FilePath& path) {
CloseFile();
file_ = file_util::OpenFile(path, "w+");
if (IsValid()) {
- // FIXME: the file format expects it to start with "[".
- fputc('[', file_);
+ trace_buffer_.SetOutputCallback(base::Bind(&TraceSubscriberStdio::Write,
+ base::Unretained(this)));
+ trace_buffer_.Start();
return true;
} else {
LOG(ERROR) << "Failed to open performance trace file: " << path.value();
@@ -33,8 +35,6 @@ bool TraceSubscriberStdio::OpenFile(const FilePath& path) {
void TraceSubscriberStdio::CloseFile() {
if (file_) {
- // FIXME: the file format expects it to end with "]".
- fputc(']', file_);
fclose(file_);
file_ = 0;
}
@@ -45,27 +45,21 @@ bool TraceSubscriberStdio::IsValid() {
}
void TraceSubscriberStdio::OnEndTracingComplete() {
+ trace_buffer_.Finish();
CloseFile();
}
void TraceSubscriberStdio::OnTraceDataCollected(
- const std::string& json_events) {
- if (!IsValid()) {
- return;
- }
-
- // FIXME: "json_events" currently comes with "[" and "]". But the file doesn't
- // expect them. So remove them when writing to the file.
- CHECK_GE(json_events.size(), 2u);
- const char* data = json_events.data() + 1;
- size_t size = json_events.size() - 2;
+ const std::string& trace_fragment) {
+ trace_buffer_.AddFragment(trace_fragment);
+}
- size_t written = fwrite(data, 1, size, file_);
- if (written != size) {
- LOG(ERROR) << "Error " << ferror(file_) << " when writing to trace file";
- fclose(file_);
- file_ = 0;
- } else {
- fputc(',', file_);
+void TraceSubscriberStdio::Write(const std::string& output_str) {
+ if (IsValid()) {
+ size_t written = fwrite(output_str.c_str(), 1, output_str.size(), file_);
+ if (written != output_str.size()) {
+ LOG(ERROR) << "Error " << ferror(file_) << " when writing to trace file";
+ CloseFile();
+ }
}
}
diff --git a/content/browser/trace_subscriber_stdio.h b/content/browser/trace_subscriber_stdio.h
index 15bf41b..ab74c7d 100644
--- a/content/browser/trace_subscriber_stdio.h
+++ b/content/browser/trace_subscriber_stdio.h
@@ -29,12 +29,15 @@ class CONTENT_EXPORT TraceSubscriberStdio : public TraceSubscriber {
// Implementation of TraceSubscriber
virtual void OnEndTracingComplete();
- virtual void OnTraceDataCollected(const std::string& json_events);
+ virtual void OnTraceDataCollected(const std::string& trace_fragment);
virtual ~TraceSubscriberStdio();
private:
+ void Write(const std::string& output_str);
+
FILE* file_;
+ base::debug::TraceResultBuffer trace_buffer_;
};
#endif // CONTENT_BROWSER_TRACE_SUBSCRIBER_STDIO_H_
diff --git a/content/browser/trace_subscriber_stdio_unittest.cc b/content/browser/trace_subscriber_stdio_unittest.cc
index afced0d..92f360f 100644
--- a/content/browser/trace_subscriber_stdio_unittest.cc
+++ b/content/browser/trace_subscriber_stdio_unittest.cc
@@ -28,7 +28,7 @@ class TraceSubscriberStdioTest : public testing::Test {
} // namespace
-TEST_F(TraceSubscriberStdioTest, CanWriteBracketedDataToFile) {
+TEST_F(TraceSubscriberStdioTest, CanWriteDataToFile) {
TraceSubscriberStdio subscriber(trace_file_);
subscriber.OnTraceDataCollected("[foo]");
subscriber.OnTraceDataCollected("[bar]");
@@ -36,7 +36,5 @@ TEST_F(TraceSubscriberStdioTest, CanWriteBracketedDataToFile) {
subscriber.OnEndTracingComplete();
EXPECT_FALSE(subscriber.IsValid());
-
- EXPECT_EQ("[foo,bar,]", ReadTraceFile());
}
diff --git a/content/common/child_trace_message_filter.cc b/content/common/child_trace_message_filter.cc
index c6ac09e..ca280bc 100644
--- a/content/common/child_trace_message_filter.cc
+++ b/content/common/child_trace_message_filter.cc
@@ -73,16 +73,16 @@ void ChildTraceMessageFilter::OnGetTraceBufferPercentFull() {
void ChildTraceMessageFilter::OnTraceDataCollected(
const scoped_refptr<base::debug::TraceLog::RefCountedString>&
- json_events_str_ptr) {
+ events_str_ptr) {
if (MessageLoop::current() != ChildProcess::current()->io_message_loop()) {
ChildProcess::current()->io_message_loop()->PostTask(FROM_HERE,
base::Bind(&ChildTraceMessageFilter::OnTraceDataCollected, this,
- json_events_str_ptr));
+ events_str_ptr));
return;
}
channel_->Send(new ChildProcessHostMsg_TraceDataCollected(
- json_events_str_ptr->data));
+ events_str_ptr->data));
}
void ChildTraceMessageFilter::OnTraceBufferFull() {
diff --git a/content/common/child_trace_message_filter.h b/content/common/child_trace_message_filter.h
index b145027..242e299 100644
--- a/content/common/child_trace_message_filter.h
+++ b/content/common/child_trace_message_filter.h
@@ -32,7 +32,7 @@ class ChildTraceMessageFilter : public IPC::ChannelProxy::MessageFilter {
// Callback from trace subsystem.
void OnTraceDataCollected(
const scoped_refptr<base::debug::TraceLog::RefCountedString>&
- json_events_str_ptr);
+ events_str_ptr);
void OnTraceBufferFull();
IPC::Channel* channel_;