erg | b921058 | 2015-05-09 03:52:16 +0900 | [diff] [blame] | 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 |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "mojo/services/tracing/tracing_app.h" |
| 6 | |
| 7 | #include "base/bind.h" |
erg | e5f066b | 2015-10-22 03:24:05 +0900 | [diff] [blame] | 8 | #include "base/logging.h" |
erg | b921058 | 2015-05-09 03:52:16 +0900 | [diff] [blame] | 9 | #include "base/message_loop/message_loop.h" |
jam | 8bb27ff | 2015-05-15 07:56:10 +0900 | [diff] [blame] | 10 | #include "mojo/application/public/cpp/application_connection.h" |
erg | b921058 | 2015-05-09 03:52:16 +0900 | [diff] [blame] | 11 | |
| 12 | namespace tracing { |
| 13 | |
erg | e5f066b | 2015-10-22 03:24:05 +0900 | [diff] [blame] | 14 | TracingApp::TracingApp() : collector_binding_(this), tracing_active_(false) { |
| 15 | } |
erg | b921058 | 2015-05-09 03:52:16 +0900 | [diff] [blame] | 16 | |
erg | e5f066b | 2015-10-22 03:24:05 +0900 | [diff] [blame] | 17 | TracingApp::~TracingApp() { |
| 18 | } |
erg | b921058 | 2015-05-09 03:52:16 +0900 | [diff] [blame] | 19 | |
| 20 | bool TracingApp::ConfigureIncomingConnection( |
| 21 | mojo::ApplicationConnection* connection) { |
erg | e5f066b | 2015-10-22 03:24:05 +0900 | [diff] [blame] | 22 | connection->AddService<TraceCollector>(this); |
msw | 339a3c4 | 2015-08-19 03:55:31 +0900 | [diff] [blame] | 23 | connection->AddService<StartupPerformanceDataCollector>(this); |
erg | b921058 | 2015-05-09 03:52:16 +0900 | [diff] [blame] | 24 | |
erg | e5f066b | 2015-10-22 03:24:05 +0900 | [diff] [blame] | 25 | // If someone connects to us they may want to use the TraceCollector |
erg | b921058 | 2015-05-09 03:52:16 +0900 | [diff] [blame] | 26 | // interface and/or they may want to expose themselves to be traced. Attempt |
erg | e5f066b | 2015-10-22 03:24:05 +0900 | [diff] [blame] | 27 | // to connect to the TraceProvider interface to see if the application |
erg | b921058 | 2015-05-09 03:52:16 +0900 | [diff] [blame] | 28 | // connecting to us wants to be traced. They can refuse the connection or |
| 29 | // close the pipe if not. |
erg | e5f066b | 2015-10-22 03:24:05 +0900 | [diff] [blame] | 30 | TraceProviderPtr provider_ptr; |
| 31 | connection->ConnectToService(&provider_ptr); |
| 32 | if (tracing_active_) { |
| 33 | TraceRecorderPtr recorder_ptr; |
| 34 | recorder_impls_.push_back( |
| 35 | new TraceRecorderImpl(GetProxy(&recorder_ptr), sink_.get())); |
| 36 | provider_ptr->StartTracing(tracing_categories_, recorder_ptr.Pass()); |
| 37 | } |
| 38 | provider_ptrs_.AddInterfacePtr(provider_ptr.Pass()); |
erg | b921058 | 2015-05-09 03:52:16 +0900 | [diff] [blame] | 39 | return true; |
| 40 | } |
| 41 | |
erg | e5f066b | 2015-10-22 03:24:05 +0900 | [diff] [blame] | 42 | void TracingApp::Create(mojo::ApplicationConnection* connection, |
| 43 | mojo::InterfaceRequest<TraceCollector> request) { |
| 44 | collector_binding_.Bind(request.Pass()); |
erg | b921058 | 2015-05-09 03:52:16 +0900 | [diff] [blame] | 45 | } |
| 46 | |
msw | 339a3c4 | 2015-08-19 03:55:31 +0900 | [diff] [blame] | 47 | void TracingApp::Create( |
| 48 | mojo::ApplicationConnection* connection, |
| 49 | mojo::InterfaceRequest<StartupPerformanceDataCollector> request) { |
| 50 | startup_performance_data_collector_bindings_.AddBinding(this, request.Pass()); |
| 51 | } |
| 52 | |
erg | b921058 | 2015-05-09 03:52:16 +0900 | [diff] [blame] | 53 | void TracingApp::Start(mojo::ScopedDataPipeProducerHandle stream, |
| 54 | const mojo::String& categories) { |
erg | e5f066b | 2015-10-22 03:24:05 +0900 | [diff] [blame] | 55 | tracing_categories_ = categories; |
erg | b921058 | 2015-05-09 03:52:16 +0900 | [diff] [blame] | 56 | sink_.reset(new TraceDataSink(stream.Pass())); |
erg | e5f066b | 2015-10-22 03:24:05 +0900 | [diff] [blame] | 57 | provider_ptrs_.ForAllPtrs([categories, this](TraceProvider* controller) { |
| 58 | TraceRecorderPtr ptr; |
| 59 | recorder_impls_.push_back( |
| 60 | new TraceRecorderImpl(GetProxy(&ptr), sink_.get())); |
| 61 | controller->StartTracing(categories, ptr.Pass()); |
| 62 | }); |
| 63 | tracing_active_ = true; |
erg | b921058 | 2015-05-09 03:52:16 +0900 | [diff] [blame] | 64 | } |
| 65 | |
| 66 | void TracingApp::StopAndFlush() { |
erg | e5f066b | 2015-10-22 03:24:05 +0900 | [diff] [blame] | 67 | // Remove any collectors that closed their message pipes before we called |
| 68 | // StopTracing(). |
| 69 | for (int i = static_cast<int>(recorder_impls_.size()) - 1; i >= 0; --i) { |
| 70 | if (!recorder_impls_[i]->TraceRecorderHandle().is_valid()) { |
| 71 | recorder_impls_.erase(recorder_impls_.begin() + i); |
| 72 | } |
| 73 | } |
erg | b921058 | 2015-05-09 03:52:16 +0900 | [diff] [blame] | 74 | |
erg | e5f066b | 2015-10-22 03:24:05 +0900 | [diff] [blame] | 75 | tracing_active_ = false; |
| 76 | provider_ptrs_.ForAllPtrs( |
| 77 | [](TraceProvider* controller) { controller->StopTracing(); }); |
| 78 | |
| 79 | // Sending the StopTracing message to registered controllers will request that |
| 80 | // they send trace data back via the collector interface and, when they are |
| 81 | // done, close the collector pipe. We don't know how long they will take. We |
| 82 | // want to read all data that any collector might send until all collectors or |
| 83 | // closed or an (arbitrary) deadline has passed. Since the bindings don't |
| 84 | // support this directly we do our own MojoWaitMany over the handles and read |
| 85 | // individual messages until all are closed or our absolute deadline has |
| 86 | // elapsed. |
| 87 | static const MojoDeadline kTimeToWaitMicros = 1000 * 1000; |
| 88 | MojoTimeTicks end = MojoGetTimeTicksNow() + kTimeToWaitMicros; |
| 89 | |
| 90 | while (!recorder_impls_.empty()) { |
| 91 | MojoTimeTicks now = MojoGetTimeTicksNow(); |
| 92 | if (now >= end) // Timed out? |
| 93 | break; |
| 94 | |
| 95 | MojoDeadline mojo_deadline = end - now; |
| 96 | std::vector<mojo::Handle> handles; |
| 97 | std::vector<MojoHandleSignals> signals; |
| 98 | for (const auto& it : recorder_impls_) { |
| 99 | handles.push_back(it->TraceRecorderHandle()); |
| 100 | signals.push_back(MOJO_HANDLE_SIGNAL_READABLE | |
| 101 | MOJO_HANDLE_SIGNAL_PEER_CLOSED); |
| 102 | } |
| 103 | std::vector<MojoHandleSignalsState> signals_states(signals.size()); |
| 104 | const mojo::WaitManyResult wait_many_result = |
| 105 | mojo::WaitMany(handles, signals, mojo_deadline, &signals_states); |
| 106 | if (wait_many_result.result == MOJO_RESULT_DEADLINE_EXCEEDED) { |
| 107 | // Timed out waiting, nothing more to read. |
| 108 | LOG(WARNING) << "Timed out waiting for trace flush"; |
| 109 | break; |
| 110 | } |
| 111 | if (wait_many_result.IsIndexValid()) { |
| 112 | // Iterate backwards so we can remove closed pipes from |recorder_impls_| |
| 113 | // without invalidating subsequent offsets. |
| 114 | for (size_t i = signals_states.size(); i != 0; --i) { |
| 115 | size_t index = i - 1; |
| 116 | MojoHandleSignals satisfied = signals_states[index].satisfied_signals; |
| 117 | // To avoid dropping data, don't close unless there's no |
| 118 | // readable signal. |
| 119 | if (satisfied & MOJO_HANDLE_SIGNAL_READABLE) |
| 120 | recorder_impls_[index]->TryRead(); |
| 121 | else if (satisfied & MOJO_HANDLE_SIGNAL_PEER_CLOSED) |
| 122 | recorder_impls_.erase(recorder_impls_.begin() + index); |
| 123 | } |
| 124 | } |
| 125 | } |
| 126 | AllDataCollected(); |
erg | b921058 | 2015-05-09 03:52:16 +0900 | [diff] [blame] | 127 | } |
| 128 | |
msw | 339a3c4 | 2015-08-19 03:55:31 +0900 | [diff] [blame] | 129 | void TracingApp::SetShellProcessCreationTime(int64 time) { |
| 130 | if (startup_performance_times_.shell_process_creation_time == 0) |
| 131 | startup_performance_times_.shell_process_creation_time = time; |
| 132 | } |
| 133 | |
msw | de4a511 | 2015-08-26 12:28:35 +0900 | [diff] [blame] | 134 | void TracingApp::SetShellMainEntryPointTime(int64 time) { |
| 135 | if (startup_performance_times_.shell_main_entry_point_time == 0) |
| 136 | startup_performance_times_.shell_main_entry_point_time = time; |
| 137 | } |
| 138 | |
gab | df51c13 | 2015-11-12 08:37:19 +0900 | [diff] [blame] | 139 | void TracingApp::SetBrowserMessageLoopStartTicks(int64 ticks) { |
| 140 | if (startup_performance_times_.browser_message_loop_start_ticks == 0) |
| 141 | startup_performance_times_.browser_message_loop_start_ticks = ticks; |
msw | 339a3c4 | 2015-08-19 03:55:31 +0900 | [diff] [blame] | 142 | } |
| 143 | |
gab | df51c13 | 2015-11-12 08:37:19 +0900 | [diff] [blame] | 144 | void TracingApp::SetBrowserWindowDisplayTicks(int64 ticks) { |
| 145 | if (startup_performance_times_.browser_window_display_ticks == 0) |
| 146 | startup_performance_times_.browser_window_display_ticks = ticks; |
msw | 339a3c4 | 2015-08-19 03:55:31 +0900 | [diff] [blame] | 147 | } |
| 148 | |
msw | 565fba8 | 2015-08-28 08:06:12 +0900 | [diff] [blame] | 149 | void TracingApp::SetBrowserOpenTabsTimeDelta(int64 delta) { |
| 150 | if (startup_performance_times_.browser_open_tabs_time_delta == 0) |
| 151 | startup_performance_times_.browser_open_tabs_time_delta = delta; |
msw | 339a3c4 | 2015-08-19 03:55:31 +0900 | [diff] [blame] | 152 | } |
| 153 | |
gab | df51c13 | 2015-11-12 08:37:19 +0900 | [diff] [blame] | 154 | void TracingApp::SetFirstWebContentsMainFrameLoadTicks(int64 ticks) { |
| 155 | if (startup_performance_times_.first_web_contents_main_frame_load_ticks == 0) |
| 156 | startup_performance_times_.first_web_contents_main_frame_load_ticks = ticks; |
msw | 339a3c4 | 2015-08-19 03:55:31 +0900 | [diff] [blame] | 157 | } |
| 158 | |
gab | df51c13 | 2015-11-12 08:37:19 +0900 | [diff] [blame] | 159 | void TracingApp::SetFirstVisuallyNonEmptyLayoutTicks(int64 ticks) { |
| 160 | if (startup_performance_times_.first_visually_non_empty_layout_ticks == 0) |
| 161 | startup_performance_times_.first_visually_non_empty_layout_ticks = ticks; |
msw | 339a3c4 | 2015-08-19 03:55:31 +0900 | [diff] [blame] | 162 | } |
| 163 | |
| 164 | void TracingApp::GetStartupPerformanceTimes( |
| 165 | const GetStartupPerformanceTimesCallback& callback) { |
| 166 | callback.Run(startup_performance_times_.Clone()); |
| 167 | } |
| 168 | |
erg | b921058 | 2015-05-09 03:52:16 +0900 | [diff] [blame] | 169 | void TracingApp::AllDataCollected() { |
erg | e5f066b | 2015-10-22 03:24:05 +0900 | [diff] [blame] | 170 | recorder_impls_.clear(); |
| 171 | sink_.reset(); |
erg | b921058 | 2015-05-09 03:52:16 +0900 | [diff] [blame] | 172 | } |
| 173 | |
| 174 | } // namespace tracing |