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 PCHECK(trace_file_); |
| 56 trace_filename_ = filename; |
| 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) { |
71 tracing_ = false; | 122 const char* chars = static_cast<const char*>(data); |
72 base::trace_event::TraceLog::GetInstance()->SetDisabled(); | 123 trace_service_data_.append(chars, num_bytes); |
73 base::WaitableEvent flush_complete_event(false, false); | 124 } |
74 // TraceLog::Flush requires a message loop but we've already shut ours down. | 125 |
75 // Spin up a new thread to flush things out. | 126 void Tracer::OnDataComplete() { |
76 base::Thread flush_thread("mojo_shell_trace_event_flush"); | 127 if (!trace_service_data_.empty()) { |
77 flush_thread.Start(); | 128 WriteCommaIfNeeded(); |
78 flush_thread.message_loop()->PostTask( | 129 const char* const chars = trace_service_data_.data(); |
79 FROM_HERE, | 130 size_t num_bytes = trace_service_data_.length(); |
80 base::Bind(&Tracer::EndTraceAndFlush, base::Unretained(this), filename, | 131 PCHECK(fwrite(chars, 1, num_bytes, trace_file_) == num_bytes); |
81 base::Bind(&base::WaitableEvent::Signal, | 132 trace_service_data_ = std::string(); |
82 base::Unretained(&flush_complete_event)))); | 133 } |
83 flush_complete_event.Wait(); | 134 drainer_.reset(); |
84 LOG(INFO) << "Wrote trace data to " << filename; | 135 coordinator_.reset(); |
| 136 WriteFooterAndClose(); |
| 137 } |
| 138 |
| 139 void Tracer::WriteCommaIfNeeded() { |
| 140 if (first_chunk_written_) |
| 141 PCHECK(fwrite(",", 1, 1, trace_file_) == 1); |
| 142 first_chunk_written_ = true; |
85 } | 143 } |
86 | 144 |
87 } // namespace shell | 145 } // namespace shell |
OLD | NEW |