Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(375)

Side by Side Diff: components/html_viewer/stats_collection_controller.cc

Issue 1278673002: Add stats collection for telemetry startup.warm.blank_page test. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Cache and reuse a single mojo:tracing connection in mojo:html_viewer. Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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 "components/html_viewer/stats_collection_controller.h"
6
7 #include "base/command_line.h"
8 #include "base/json/json_writer.h"
9 #include "base/metrics/histogram.h"
10 #include "base/metrics/statistics_recorder.h"
11 #include "base/run_loop.h"
12 #include "base/strings/string_util.h"
13 #include "base/values.h"
14 #include "components/html_viewer/html_document.h"
15 #include "components/startup_metric_utils/startup_metric_utils.h"
16 #include "gin/handle.h"
17 #include "gin/object_template_builder.h"
18 #include "mojo/application/public/cpp/application_impl.h"
19 #include "mojo/runner/switches.h"
20 #include "third_party/WebKit/public/web/WebKit.h"
21 #include "third_party/WebKit/public/web/WebLocalFrame.h"
22 #include "third_party/WebKit/public/web/WebView.h"
23
24 namespace html_viewer {
25
26 namespace {
27
28 // Initialize the histogram data using the given startup performance times.
29 // TODO(msw): Have mojo:tracing record the histograms and serve their JSON?
30 void GetStartupPerformanceTimesCallbackImpl(
31 const base::Closure& callback,
32 tracing::StartupPerformanceTimesPtr times) {
33 base::StatisticsRecorder::Initialize();
34
35 const base::Time shell_process_creation_time =
36 base::Time::FromInternalValue(times->shell_process_creation_time);
37 startup_metric_utils::RecordSavedMainEntryPointTime(
38 shell_process_creation_time);
39 // TODO(msw): Use |browser_message_loop_start_time|, instead of letting
40 // OnBrowserStartupComplete incorrectly call base::Time::Now()...
41 startup_metric_utils::OnBrowserStartupComplete(false);
42
43 // TODO(msw): Consolidate with chrome's Browser::OnWindowDidShow()...
44 const base::Time browser_window_display_time =
45 base::Time::FromInternalValue(times->browser_window_display_time);
46 base::TimeDelta browser_window_display_delta =
47 browser_window_display_time - shell_process_creation_time;
48 UMA_HISTOGRAM_LONG_TIMES("Startup.BrowserWindowDisplay",
49 browser_window_display_delta);
50
51 // TODO(msw): Consolidate with chrome's PreMainMessageLoopRunImpl()...
52 // TODO(msw): Need to measure the "browser_open_start" time for this delta...
53 const base::Time browser_open_tabs_time =
54 base::Time::FromInternalValue(times->browser_open_tabs_time);
55 base::TimeDelta browser_open_tabs_delta =
56 browser_open_tabs_time - shell_process_creation_time;
57 UMA_HISTOGRAM_LONG_TIMES_100("Startup.BrowserOpenTabs",
58 browser_open_tabs_delta);
59
60 // TODO(msw): Consolidate with chrome's first_web_contents_profiler.cc...
61 const base::Time first_web_contents_main_frame_load_time =
62 base::Time::FromInternalValue(
63 times->first_web_contents_main_frame_load_time);
64 base::TimeDelta first_web_contents_main_frame_load_delta =
65 first_web_contents_main_frame_load_time - shell_process_creation_time;
66 UMA_HISTOGRAM_LONG_TIMES_100("Startup.FirstWebContents.MainFrameLoad",
67 first_web_contents_main_frame_load_delta);
68
69 // TODO(msw): Consolidate with chrome's first_web_contents_profiler.cc...
70 const base::Time first_visually_non_empty_layout_time =
71 base::Time::FromInternalValue(
72 times->first_visually_non_empty_layout_time);
73 base::TimeDelta first_web_contents_non_empty_paint_delta =
74 first_visually_non_empty_layout_time - shell_process_creation_time;
75 UMA_HISTOGRAM_LONG_TIMES_100("Startup.FirstWebContents.NonEmptyPaint",
76 first_web_contents_non_empty_paint_delta);
77
78 callback.Run();
79 }
80
81 // Encodes a WebContentsLoadTime as JSON.
82 // Input:
83 // - |load_start_time| - time at which page load started.
84 // - |load_stop_time| - time at which page load stopped.
85 // - |result| - returned JSON.
86 // Example return value:
87 // {'load_start_ms': 1, 'load_duration_ms': 2.5}
88 // either value may be null if a web contents hasn't fully loaded.
89 // load_start_ms is represented as milliseconds since the unix epoch.
90 // TODO(msw): Consolidate with content/renderer/stats_collection_controller.cc.
91 void ConvertLoadTimeToJSON(const base::Time& load_start_time,
92 const base::Time& load_stop_time,
93 std::string* result) {
94 base::DictionaryValue item;
95
96 if (load_start_time.is_null()) {
97 item.Set("load_start_ms", base::Value::CreateNullValue());
98 } else {
99 item.SetDouble("load_start_ms", (load_start_time - base::Time::UnixEpoch())
100 .InMillisecondsF());
101 }
102 if (load_start_time.is_null() || load_stop_time.is_null()) {
103 item.Set("load_duration_ms", base::Value::CreateNullValue());
104 } else {
105 item.SetDouble("load_duration_ms",
106 (load_stop_time - load_start_time).InMillisecondsF());
107 }
108 base::JSONWriter::Write(item, result);
109 }
110
111 } // namespace
112
113 // static
114 gin::WrapperInfo StatsCollectionController::kWrapperInfo = {
115 gin::kEmbedderNativeGin};
116
117 // static
118 StatsCollectionController* StatsCollectionController::Install(
119 HTMLDocument* html_document,
120 mojo::ApplicationImpl* app) {
121 // Only make startup tracing available when running in the context of a test.
122 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
123 switches::kStatsCollectionController)) {
124 return nullptr;
125 }
126
127 blink::WebFrame* frame = html_document->web_view()->mainFrame();
128 v8::Isolate* isolate = blink::mainThreadIsolate();
129 v8::HandleScope handle_scope(isolate);
130 v8::Local<v8::Context> context = frame->mainWorldScriptContext();
131 if (context.IsEmpty())
132 return nullptr;
133
134 v8::Context::Scope context_scope(context);
135
136 StatsCollectionController* stats_collection_controller =
137 new StatsCollectionController(html_document, app);
138 gin::Handle<StatsCollectionController> controller =
139 gin::CreateHandle(isolate, stats_collection_controller);
140 if (controller.IsEmpty())
141 return nullptr;
142 v8::Local<v8::Object> global = context->Global();
143 global->Set(gin::StringToV8(isolate, "statsCollectionController"),
144 controller.ToV8());
145 return stats_collection_controller;
146 }
147
148 void StatsCollectionController::DidHandleOnloadEvents(const base::Time& time) {
149 startup_performance_controller_->SetFirstWebContentsMainFrameLoadTime(
150 time.ToInternalValue());
151 }
152
153 void StatsCollectionController::DidFirstVisuallyNonEmptyLayout(
154 const base::Time& time) {
155 startup_performance_controller_->SetFirstVisuallyNonEmptyLayoutTime(
156 time.ToInternalValue());
157 }
158
159 StatsCollectionController::StatsCollectionController(
160 HTMLDocument* html_document,
161 mojo::ApplicationImpl* app)
162 : observer_(html_document) {
163 mojo::URLRequestPtr request(mojo::URLRequest::New());
164 request->url = mojo::String::From("mojo:tracing");
165 app->ConnectToService(request.Pass(), &startup_performance_controller_);
166 }
167
168 StatsCollectionController::~StatsCollectionController() {}
169
170 gin::ObjectTemplateBuilder StatsCollectionController::GetObjectTemplateBuilder(
171 v8::Isolate* isolate) {
172 return gin::Wrappable<StatsCollectionController>::GetObjectTemplateBuilder(
173 isolate)
174 .SetMethod("getHistogram", &StatsCollectionController::GetHistogram)
175 .SetMethod("getBrowserHistogram",
176 &StatsCollectionController::GetBrowserHistogram)
177 .SetMethod("tabLoadTiming", &StatsCollectionController::GetTabLoadTiming);
178 }
179
180 std::string StatsCollectionController::GetHistogram(
181 const std::string& histogram_name) {
182 DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
183 switches::kStatsCollectionController));
184
185 // TODO(msw): Use a more robust check for startup histogram init.
186 if (!base::StatisticsRecorder::IsActive()) {
187 // Get the startup performance times from the tracing service.
188 // TODO(msw): Have mojo:tracing provide the histogram JSON?
189 base::RunLoop run_loop;
190 auto callback = base::Bind(&GetStartupPerformanceTimesCallbackImpl,
191 run_loop.QuitClosure());
192 startup_performance_controller_->GetStartupPerformanceTimes(callback);
193 run_loop.Run();
yzshen1 2015/08/13 15:59:12 Maybe consider using InterfacePtr<>::WaitForIncomi
msw 2015/08/14 23:20:34 Done.
194 DCHECK(base::StatisticsRecorder::IsActive());
195 }
196
197 std::string histogram_json = "{}";
198 base::HistogramBase* histogram =
199 base::StatisticsRecorder::FindHistogram(histogram_name);
200 if (histogram)
201 histogram->WriteJSON(&histogram_json);
202 // TODO(msw): Remove debug printing...
203 LOG(ERROR) << "MSW Histogram [" << histogram_name << "]: " << histogram_json;
204 return histogram_json;
205 }
206
207 std::string StatsCollectionController::GetBrowserHistogram(
208 const std::string& histogram_name) {
209 // TODO(msw): Should GetHistogram/GetBrowserHistogram return distinct values?
210 return GetHistogram(histogram_name);
211 }
212
213 std::string StatsCollectionController::GetTabLoadTiming() {
214 std::string tab_timing_json = "{}";
215 ConvertLoadTimeToJSON(observer_.load_start_time(), observer_.load_stop_time(),
216 &tab_timing_json);
217 return tab_timing_json;
218 }
219
220 } // namespace html_viewer
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698