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.
5 #include "components/html_viewer/stats_collection_controller.h"
7 #include "base/command_line.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/metrics/histogram.h"
10 #include "base/metrics/statistics_recorder.h"
11 #include "base/time/time.h"
12 #include "components/startup_metric_utils/startup_metric_utils.h"
13 #include "gin/handle.h"
14 #include "gin/object_template_builder.h"
15 #include "mojo/application/public/cpp/application_impl.h"
16 #include "mojo/services/tracing/public/cpp/switches.h"
17 #include "third_party/WebKit/public/web/WebKit.h"
18 #include "third_party/WebKit/public/web/WebLocalFrame.h"
20 namespace html_viewer
{
24 // Initialize the histogram data using the given startup performance times.
25 // TODO(msw): Use TimeTicks to avoid system clock changes: crbug.com/521164
26 void GetStartupPerformanceTimesCallbackImpl(
27 tracing::StartupPerformanceTimesPtr times
) {
28 base::StatisticsRecorder::Initialize();
30 startup_metric_utils::RecordStartupProcessCreationTime(
31 base::Time::FromInternalValue(times
->shell_process_creation_time
));
33 // TODO(msw): Record the MojoMain() entry point time of mojo:browser instead?
34 startup_metric_utils::RecordMainEntryPointTime(
35 base::Time::FromInternalValue(times
->shell_main_entry_point_time
));
37 // TODO(msw): Determine if this is the first run.
38 startup_metric_utils::RecordBrowserMainMessageLoopStart(
39 base::Time::FromInternalValue(times
->browser_message_loop_start_time
),
42 startup_metric_utils::RecordBrowserWindowDisplay(
43 base::Time::FromInternalValue(times
->browser_window_display_time
));
45 startup_metric_utils::RecordBrowserOpenTabsDelta(
46 base::TimeDelta::FromInternalValue(times
->browser_open_tabs_time_delta
));
48 startup_metric_utils::RecordFirstWebContentsMainFrameLoad(
49 base::Time::FromInternalValue(
50 times
->first_web_contents_main_frame_load_time
));
52 startup_metric_utils::RecordFirstWebContentsNonEmptyPaint(
53 base::Time::FromInternalValue(
54 times
->first_visually_non_empty_layout_time
));
60 gin::WrapperInfo
StatsCollectionController::kWrapperInfo
= {
61 gin::kEmbedderNativeGin
};
64 tracing::StartupPerformanceDataCollectorPtr
StatsCollectionController::Install(
65 blink::WebFrame
* frame
,
66 mojo::ApplicationImpl
* app
) {
67 // Only make startup tracing available when running in the context of a test.
69 !base::CommandLine::ForCurrentProcess()->HasSwitch(
70 tracing::kEnableStatsCollectionBindings
)) {
74 v8::Isolate
* isolate
= blink::mainThreadIsolate();
75 v8::HandleScope
handle_scope(isolate
);
76 v8::Local
<v8::Context
> context
= frame
->mainWorldScriptContext();
77 if (context
.IsEmpty())
80 v8::Context::Scope
context_scope(context
);
82 mojo::URLRequestPtr
request(mojo::URLRequest::New());
83 request
->url
= mojo::String::From("mojo:tracing");
84 scoped_ptr
<mojo::ApplicationConnection
> connection
=
85 app
->ConnectToApplication(request
.Pass());
88 tracing::StartupPerformanceDataCollectorPtr collector_for_controller
;
89 tracing::StartupPerformanceDataCollectorPtr collector_for_caller
;
90 connection
->ConnectToService(&collector_for_controller
);
91 connection
->ConnectToService(&collector_for_caller
);
93 gin::Handle
<StatsCollectionController
> controller
= gin::CreateHandle(
94 isolate
, new StatsCollectionController(collector_for_controller
.Pass()));
95 DCHECK(!controller
.IsEmpty());
96 v8::Local
<v8::Object
> global
= context
->Global();
97 global
->Set(gin::StringToV8(isolate
, "statsCollectionController"),
99 return collector_for_caller
.Pass();
103 tracing::StartupPerformanceDataCollectorPtr
104 StatsCollectionController::ConnectToDataCollector(mojo::ApplicationImpl
* app
) {
105 // Only make startup tracing available when running in the context of a test.
107 !base::CommandLine::ForCurrentProcess()->HasSwitch(
108 tracing::kEnableStatsCollectionBindings
)) {
112 mojo::URLRequestPtr
request(mojo::URLRequest::New());
113 request
->url
= mojo::String::From("mojo:tracing");
114 tracing::StartupPerformanceDataCollectorPtr collector
;
115 app
->ConnectToService(request
.Pass(), &collector
);
116 return collector
.Pass();
119 StatsCollectionController::StatsCollectionController(
120 tracing::StartupPerformanceDataCollectorPtr collector
)
121 : startup_performance_data_collector_(collector
.Pass()) {}
123 StatsCollectionController::~StatsCollectionController() {}
125 gin::ObjectTemplateBuilder
StatsCollectionController::GetObjectTemplateBuilder(
126 v8::Isolate
* isolate
) {
127 return gin::Wrappable
<StatsCollectionController
>::GetObjectTemplateBuilder(
129 .SetMethod("getHistogram", &StatsCollectionController::GetHistogram
)
130 .SetMethod("getBrowserHistogram",
131 &StatsCollectionController::GetBrowserHistogram
);
134 std::string
StatsCollectionController::GetHistogram(
135 const std::string
& histogram_name
) {
136 DCHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
137 tracing::kEnableStatsCollectionBindings
));
139 static bool startup_histogram_initialized
= false;
140 if (!startup_histogram_initialized
) {
141 // Get the startup performance times from the tracing service.
142 auto callback
= base::Bind(&GetStartupPerformanceTimesCallbackImpl
);
143 startup_performance_data_collector_
->GetStartupPerformanceTimes(callback
);
144 startup_performance_data_collector_
.WaitForIncomingResponse();
145 DCHECK(base::StatisticsRecorder::IsActive());
146 startup_histogram_initialized
= true;
149 std::string histogram_json
= "{}";
150 base::HistogramBase
* histogram
=
151 base::StatisticsRecorder::FindHistogram(histogram_name
);
153 histogram
->WriteJSON(&histogram_json
);
154 return histogram_json
;
157 std::string
StatsCollectionController::GetBrowserHistogram(
158 const std::string
& histogram_name
) {
159 return GetHistogram(histogram_name
);
162 } // namespace html_viewer