OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "shell/tracer.h" | 5 #include "shell/tracer.h" |
6 | 6 |
7 #include <stdio.h> | 7 #include <stdio.h> |
8 #include <string.h> | 8 #include <string.h> |
9 | 9 |
10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
(...skipping 11 matching lines...) Expand all Loading... | |
22 } | 22 } |
23 | 23 |
24 void Tracer::Start(const std::string& categories) { | 24 void Tracer::Start(const std::string& categories) { |
25 tracing_ = true; | 25 tracing_ = true; |
26 base::trace_event::CategoryFilter category_filter(categories); | 26 base::trace_event::CategoryFilter category_filter(categories); |
27 base::trace_event::TraceLog::GetInstance()->SetEnabled( | 27 base::trace_event::TraceLog::GetInstance()->SetEnabled( |
28 category_filter, base::trace_event::TraceLog::RECORDING_MODE, | 28 category_filter, base::trace_event::TraceLog::RECORDING_MODE, |
29 base::trace_event::TraceOptions(base::trace_event::RECORD_UNTIL_FULL)); | 29 base::trace_event::TraceOptions(base::trace_event::RECORD_UNTIL_FULL)); |
30 } | 30 } |
31 | 31 |
32 void Tracer::StartCollectingFromTracingService( | |
33 tracing::TraceCoordinatorPtr coordinator) { | |
34 coordinator_ = coordinator.Pass(); | |
35 mojo::DataPipe data_pipe; | |
36 coordinator_->Start(data_pipe.producer_handle.Pass(), "*"); | |
37 drainer_.reset(new mojo::common::DataPipeDrainer( | |
38 this, data_pipe.consumer_handle.Pass())); | |
39 } | |
40 | |
32 void Tracer::StopAndFlushToFile(const std::string& filename) { | 41 void Tracer::StopAndFlushToFile(const std::string& filename) { |
33 if (tracing_) | 42 if (tracing_) |
34 StopTracingAndFlushToDisk(filename); | 43 StopTracingAndFlushToDisk(filename); |
35 } | 44 } |
36 | 45 |
46 void Tracer::ConnectToController( | |
47 mojo::InterfaceRequest<tracing::TraceController> request) { | |
48 auto impl = new mojo::TraceControllerImpl(request.Pass()); | |
49 impl->set_tracing_already_started(tracing_); | |
50 } | |
51 | |
52 void Tracer::StopTracingAndFlushToDisk(const std::string& filename) { | |
53 tracing_ = false; | |
54 trace_file_ = fopen(filename.c_str(), "w+"); | |
55 trace_filename_ = filename; | |
56 PCHECK(trace_file_); | |
viettrungluu
2015/04/28 00:42:17
nit: move this to be immediately after the fopen()
| |
57 static const char kStart[] = "{\"traceEvents\":["; | |
58 PCHECK(fwrite(kStart, 1, strlen(kStart), trace_file_) == strlen(kStart)); | |
59 | |
60 // At this point we might be connected to the tracing service, in which case | |
61 // we want to tell it to stop tracing and we will send the data we've | |
62 // collected in process to it. | |
63 if (coordinator_) { | |
64 coordinator_->StopAndFlush(); | |
65 } else { | |
66 // Or we might not be connected. If we aren't connected to the tracing | |
67 // service we want to collect the tracing data gathered ourselves and flush | |
68 // it to disk. We do this in a blocking fashion (for this thread) so we can | |
69 // gather as much data as possible on shutdown. | |
70 base::trace_event::TraceLog::GetInstance()->SetDisabled(); | |
71 { | |
72 base::WaitableEvent flush_complete_event(false, false); | |
73 // TraceLog::Flush requires a message loop but we've already shut ours | |
74 // down. | |
75 // Spin up a new thread to flush things out. | |
76 base::Thread flush_thread("mojo_shell_trace_event_flush"); | |
77 flush_thread.Start(); | |
78 flush_thread.message_loop()->PostTask( | |
79 FROM_HERE, | |
80 base::Bind(&Tracer::EndTraceAndFlush, base::Unretained(this), | |
81 filename, | |
82 base::Bind(&base::WaitableEvent::Signal, | |
83 base::Unretained(&flush_complete_event)))); | |
84 base::trace_event::TraceLog::GetInstance() | |
85 ->SetCurrentThreadBlocksMessageLoop(); | |
86 flush_complete_event.Wait(); | |
87 } | |
88 } | |
89 } | |
90 | |
91 void Tracer::WriteFooterAndClose() { | |
92 static const char kEnd[] = "]}"; | |
93 PCHECK(fwrite(kEnd, 1, strlen(kEnd), trace_file_) == strlen(kEnd)); | |
94 PCHECK(fclose(trace_file_) == 0); | |
95 trace_file_ = nullptr; | |
96 LOG(INFO) << "Wrote trace data to " << trace_filename_; | |
97 } | |
98 | |
37 void Tracer::EndTraceAndFlush(const std::string& filename, | 99 void Tracer::EndTraceAndFlush(const std::string& filename, |
38 const base::Closure& done_callback) { | 100 const base::Closure& done_callback) { |
39 trace_file_ = fopen(filename.c_str(), "w+"); | |
40 PCHECK(trace_file_); | |
41 static const char kStart[] = "{\"traceEvents\":["; | |
42 fwrite(kStart, 1, strlen(kStart), trace_file_); | |
43 base::trace_event::TraceLog::GetInstance()->SetDisabled(); | 101 base::trace_event::TraceLog::GetInstance()->SetDisabled(); |
44 base::trace_event::TraceLog::GetInstance()->Flush(base::Bind( | 102 base::trace_event::TraceLog::GetInstance()->Flush(base::Bind( |
45 &Tracer::WriteTraceDataCollected, base::Unretained(this), done_callback)); | 103 &Tracer::WriteTraceDataCollected, base::Unretained(this), done_callback)); |
46 } | 104 } |
47 | 105 |
48 void Tracer::WriteTraceDataCollected( | 106 void Tracer::WriteTraceDataCollected( |
49 const base::Closure& done_callback, | 107 const base::Closure& done_callback, |
50 const scoped_refptr<base::RefCountedString>& events_str, | 108 const scoped_refptr<base::RefCountedString>& events_str, |
51 bool has_more_events) { | 109 bool has_more_events) { |
52 if (events_str->size()) { | 110 if (events_str->size()) { |
53 if (first_chunk_written_) | 111 WriteCommaIfNeeded(); |
54 fwrite(",", 1, 1, trace_file_); | |
55 | 112 |
56 first_chunk_written_ = true; | 113 PCHECK(fwrite(events_str->data().c_str(), 1, events_str->data().length(), |
57 fwrite(events_str->data().c_str(), 1, events_str->data().length(), | 114 trace_file_) == events_str->data().length()); |
58 trace_file_); | |
59 } | 115 } |
60 | 116 |
61 if (!has_more_events) { | 117 if (!has_more_events && !done_callback.is_null()) |
62 static const char kEnd[] = "]}"; | |
63 fwrite(kEnd, 1, strlen(kEnd), trace_file_); | |
64 PCHECK(fclose(trace_file_) == 0); | |
65 trace_file_ = nullptr; | |
66 done_callback.Run(); | 118 done_callback.Run(); |
67 } | |
68 } | 119 } |
69 | 120 |
70 void Tracer::StopTracingAndFlushToDisk(const std::string& filename) { | 121 void Tracer::OnDataAvailable(const void* data, size_t num_bytes) { |
viettrungluu
2015/04/28 00:42:17
Hmmm, this seems sketchy to me -- you may not get
| |
71 tracing_ = false; | 122 const char* chars = static_cast<const char*>(data); |
72 base::trace_event::TraceLog::GetInstance()->SetDisabled(); | 123 if (num_bytes == 1u && *chars == ',') |
73 base::WaitableEvent flush_complete_event(false, false); | 124 return; |
74 // TraceLog::Flush requires a message loop but we've already shut ours down. | 125 WriteCommaIfNeeded(); |
75 // Spin up a new thread to flush things out. | 126 PCHECK(fwrite(chars, 1, num_bytes, trace_file_) == num_bytes); |
76 base::Thread flush_thread("mojo_shell_trace_event_flush"); | 127 } |
77 flush_thread.Start(); | 128 |
78 flush_thread.message_loop()->PostTask( | 129 void Tracer::OnDataComplete() { |
79 FROM_HERE, | 130 drainer_.reset(); |
80 base::Bind(&Tracer::EndTraceAndFlush, base::Unretained(this), filename, | 131 coordinator_.reset(); |
81 base::Bind(&base::WaitableEvent::Signal, | 132 WriteFooterAndClose(); |
82 base::Unretained(&flush_complete_event)))); | 133 } |
83 flush_complete_event.Wait(); | 134 |
84 LOG(INFO) << "Wrote trace data to " << filename; | 135 void Tracer::WriteCommaIfNeeded() { |
136 if (first_chunk_written_) | |
137 PCHECK(fwrite(",", 1, 1, trace_file_) == 1); | |
138 first_chunk_written_ = true; | |
85 } | 139 } |
86 | 140 |
87 } // namespace shell | 141 } // namespace shell |
OLD | NEW |