diff options
-rw-r--r-- | base/debug/trace_event.cc | 45 | ||||
-rw-r--r-- | base/debug/trace_event.h | 48 | ||||
-rw-r--r-- | base/debug/trace_event_unittest.cc | 54 | ||||
-rw-r--r-- | chrome/browser/ui/webui/tracing_ui.cc | 17 | ||||
-rw-r--r-- | content/browser/trace_controller.cc | 6 | ||||
-rw-r--r-- | content/browser/trace_controller.h | 7 | ||||
-rw-r--r-- | content/browser/trace_subscriber_stdio.cc | 36 | ||||
-rw-r--r-- | content/browser/trace_subscriber_stdio.h | 5 | ||||
-rw-r--r-- | content/browser/trace_subscriber_stdio_unittest.cc | 4 | ||||
-rw-r--r-- | content/common/child_trace_message_filter.cc | 6 | ||||
-rw-r--r-- | content/common/child_trace_message_filter.h | 2 |
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_; |