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/page_load_metrics/browser/observers/core/uma_page_load_metrics_observer.h"
6
7 #include <stddef.h>
8 #include <stdint.h>
9 #include <memory>
10 #include <utility>
11
12 #include "base/feature_list.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "components/page_load_metrics/browser/observers/core/largest_contentful_paint_handler.h"
15 #include "components/page_load_metrics/browser/page_load_metrics_util.h"
16 #include "content/public/common/process_type.h"
17 #include "net/http/http_response_headers.h"
18 #include "third_party/blink/public/common/input/web_gesture_event.h"
19 #include "third_party/blink/public/common/input/web_mouse_event.h"
20 #include "ui/base/page_transition_types.h"
21 #include "ui/events/blink/blink_features.h"
22
23 namespace {
24
25 // Used to generate a unique id when emitting the "Long Navigation to First
26 // Contentful Paint" trace event.
27 int g_num_trace_events_in_process = 0;
28
29 // The threshold to emit a trace event is the 99th percentile
30 // of the histogram on Windows Stable as of Feb 26th, 2020.
31 constexpr base::TimeDelta kFirstContentfulPaintTraceThreshold =
32 base::TimeDelta::FromMilliseconds(12388);
33
34 // TODO(bmcquade): If other observers want to log histograms based on load type,
35 // promote this enum to page_load_metrics_observer.h.
36 enum PageLoadType {
37 LOAD_TYPE_NONE = 0,
38 LOAD_TYPE_RELOAD,
39 LOAD_TYPE_FORWARD_BACK,
40 LOAD_TYPE_NEW_NAVIGATION
41 };
42
GetPageLoadType(ui::PageTransition transition)43 PageLoadType GetPageLoadType(ui::PageTransition transition) {
44 if (transition & ui::PAGE_TRANSITION_FORWARD_BACK) {
45 return LOAD_TYPE_FORWARD_BACK;
46 }
47 if (ui::PageTransitionCoreTypeIs(transition, ui::PAGE_TRANSITION_RELOAD)) {
48 return LOAD_TYPE_RELOAD;
49 }
50 if (ui::PageTransitionIsNewNavigation(transition)) {
51 return LOAD_TYPE_NEW_NAVIGATION;
52 }
53 NOTREACHED() << "Received PageTransition with no matching PageLoadType.";
54 return LOAD_TYPE_NONE;
55 }
56
RecordFirstMeaningfulPaintStatus(internal::FirstMeaningfulPaintStatus status)57 void RecordFirstMeaningfulPaintStatus(
58 internal::FirstMeaningfulPaintStatus status) {
59 UMA_HISTOGRAM_ENUMERATION(internal::kHistogramFirstMeaningfulPaintStatus,
60 status,
61 internal::FIRST_MEANINGFUL_PAINT_LAST_ENTRY);
62 }
63
FirstInputDelayTraceData(const page_load_metrics::mojom::PageLoadTiming & timing)64 std::unique_ptr<base::trace_event::TracedValue> FirstInputDelayTraceData(
65 const page_load_metrics::mojom::PageLoadTiming& timing) {
66 std::unique_ptr<base::trace_event::TracedValue> data =
67 std::make_unique<base::trace_event::TracedValue>();
68 data->SetDouble(
69 "firstInputDelayInMilliseconds",
70 timing.interactive_timing->first_input_delay->InMillisecondsF());
71 data->SetDouble(
72 "navStartToFirstInputTimestampInMilliseconds",
73 timing.interactive_timing->first_input_timestamp->InMillisecondsF());
74 return data;
75 }
76
77 // TODO(crbug/1097328): Remove collecting visits to support.google.com after
78 // language settings update fully launches.
79 #if defined(OS_CHROMEOS)
RecordVisitToLanguageSettingsSupportPage(const GURL & url)80 void RecordVisitToLanguageSettingsSupportPage(const GURL& url) {
81 if (url.is_empty() || !url.DomainIs("support.google.com"))
82 return;
83
84 // Keep these pages in order with SettingsLanguagesSupportPage in enums.xml
85 std::vector<std::string> kSupportPages = {
86 "chrome/answer/173424?co=GENIE.Platform%3DDesktop",
87 "chromebook/answer/1059490",
88 "chromebook/answer/1059492",
89 };
90 const size_t num_pages = 3;
91 for (size_t i = 0; i < num_pages; ++i) {
92 if (url.spec().find(kSupportPages[i]) != std::string::npos) {
93 UMA_HISTOGRAM_ENUMERATION("ChromeOS.Settings.Languages.SupportPageVisits",
94 i, num_pages);
95 return;
96 }
97 }
98 }
99 #endif // defined(OS_CHROMEOS)
100
101 } // namespace
102
103 namespace internal {
104
105 const char kHistogramDomContentLoaded[] =
106 "PageLoad.DocumentTiming.NavigationToDOMContentLoadedEventFired";
107 const char kBackgroundHistogramDomContentLoaded[] =
108 "PageLoad.DocumentTiming.NavigationToDOMContentLoadedEventFired.Background";
109 const char kHistogramLoad[] =
110 "PageLoad.DocumentTiming.NavigationToLoadEventFired";
111 const char kBackgroundHistogramLoad[] =
112 "PageLoad.DocumentTiming.NavigationToLoadEventFired.Background";
113 const char kHistogramFirstPaint[] =
114 "PageLoad.PaintTiming.NavigationToFirstPaint";
115 const char kBackgroundHistogramFirstPaint[] =
116 "PageLoad.PaintTiming.NavigationToFirstPaint.Background";
117 const char kHistogramFirstImagePaint[] =
118 "PageLoad.PaintTiming.NavigationToFirstImagePaint";
119 const char kBackgroundHistogramFirstImagePaint[] =
120 "PageLoad.PaintTiming.NavigationToFirstImagePaint.Background";
121 const char kHistogramFirstContentfulPaint[] =
122 "PageLoad.PaintTiming.NavigationToFirstContentfulPaint";
123 const char kBackgroundHistogramFirstContentfulPaint[] =
124 "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.Background";
125 const char kHistogramFirstContentfulPaintInitiatingProcess[] =
126 "PageLoad.Internal.PaintTiming.NavigationToFirstContentfulPaint."
127 "InitiatingProcess";
128 const char kHistogramFirstMeaningfulPaint[] =
129 "PageLoad.Experimental.PaintTiming.NavigationToFirstMeaningfulPaint";
130 const char kHistogramLargestContentfulPaint[] =
131 "PageLoad.PaintTiming.NavigationToLargestContentfulPaint2";
132 const char kHistogramLargestContentfulPaintContentType[] =
133 "PageLoad.Internal.PaintTiming.LargestContentfulPaint.ContentType";
134 const char kHistogramLargestContentfulPaintMainFrame[] =
135 "PageLoad.PaintTiming.NavigationToLargestContentfulPaint2.MainFrame";
136 const char kHistogramLargestContentfulPaintMainFrameContentType[] =
137 "PageLoad.Internal.PaintTiming.LargestContentfulPaint.MainFrame."
138 "ContentType";
139 // TODO(crbug.com/1045640): Stop reporting these obsolete versions after some
140 // time.
141 const char kDeprecatedHistogramLargestContentfulPaint[] =
142 "PageLoad.PaintTiming.NavigationToLargestContentfulPaint";
143 const char kHistogramExperimentalLargestContentfulPaintContentType[] =
144 "PageLoad.Internal.PaintTiming.ExperimentalLargestContentfulPaint."
145 "ContentType";
146 const char kDeprecatedHistogramLargestContentfulPaintMainFrame[] =
147 "PageLoad.PaintTiming.NavigationToLargestContentfulPaint."
148 "MainFrame";
149 const char kHistogramExperimentalLargestContentfulPaintMainFrameContentType[] =
150 "PageLoad.Internal.PaintTiming.ExperimentalLargestContentfulPaint."
151 "MainFrame."
152 "ContentType";
153 const char kHistogramFirstInputDelay[] =
154 "PageLoad.InteractiveTiming.FirstInputDelay4";
155 const char kHistogramFirstInputTimestamp[] =
156 "PageLoad.InteractiveTiming.FirstInputTimestamp4";
157 const char kHistogramLongestInputDelay[] =
158 "PageLoad.InteractiveTiming.LongestInputDelay4";
159 const char kHistogramLongestInputTimestamp[] =
160 "PageLoad.InteractiveTiming.LongestInputTimestamp4";
161 const char kHistogramParseStartToFirstMeaningfulPaint[] =
162 "PageLoad.Experimental.PaintTiming.ParseStartToFirstMeaningfulPaint";
163 const char kHistogramParseStartToFirstContentfulPaint[] =
164 "PageLoad.PaintTiming.ParseStartToFirstContentfulPaint";
165 const char kBackgroundHistogramParseStartToFirstContentfulPaint[] =
166 "PageLoad.PaintTiming.ParseStartToFirstContentfulPaint.Background";
167 const char kHistogramParseStart[] =
168 "PageLoad.ParseTiming.NavigationToParseStart";
169 const char kBackgroundHistogramParseStart[] =
170 "PageLoad.ParseTiming.NavigationToParseStart.Background";
171 const char kHistogramParseDuration[] = "PageLoad.ParseTiming.ParseDuration";
172 const char kBackgroundHistogramParseDuration[] =
173 "PageLoad.ParseTiming.ParseDuration.Background";
174 const char kHistogramParseBlockedOnScriptLoad[] =
175 "PageLoad.ParseTiming.ParseBlockedOnScriptLoad";
176 const char kBackgroundHistogramParseBlockedOnScriptLoad[] =
177 "PageLoad.ParseTiming.ParseBlockedOnScriptLoad.Background";
178 const char kHistogramParseBlockedOnScriptLoadDocumentWrite[] =
179 "PageLoad.ParseTiming.ParseBlockedOnScriptLoadFromDocumentWrite";
180 const char kBackgroundHistogramParseBlockedOnScriptLoadDocumentWrite[] =
181 "PageLoad.ParseTiming.ParseBlockedOnScriptLoadFromDocumentWrite."
182 "Background";
183 const char kHistogramParseBlockedOnScriptExecution[] =
184 "PageLoad.ParseTiming.ParseBlockedOnScriptExecution";
185 const char kHistogramParseBlockedOnScriptExecutionDocumentWrite[] =
186 "PageLoad.ParseTiming.ParseBlockedOnScriptExecutionFromDocumentWrite";
187
188 const char kHistogramFirstContentfulPaintNoStore[] =
189 "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.NoStore";
190
191 const char kHistogramFirstContentfulPaintHiddenWhileFlushing[] =
192 "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.HiddenWhileFlushing";
193
194 const char kHistogramLoadTypeFirstContentfulPaintReload[] =
195 "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.LoadType."
196 "Reload";
197 const char kHistogramLoadTypeFirstContentfulPaintReloadByGesture[] =
198 "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.LoadType."
199 "Reload.UserGesture";
200 const char kHistogramLoadTypeFirstContentfulPaintForwardBack[] =
201 "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.LoadType."
202 "ForwardBackNavigation";
203 const char kHistogramLoadTypeFirstContentfulPaintForwardBackNoStore[] =
204 "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.LoadType."
205 "ForwardBackNavigation.NoStore";
206 const char kHistogramLoadTypeFirstContentfulPaintNewNavigation[] =
207 "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.LoadType."
208 "NewNavigation";
209
210 const char kHistogramPageTimingForegroundDuration[] =
211 "PageLoad.PageTiming.ForegroundDuration";
212 const char kHistogramPageTimingForegroundDurationAfterPaint[] =
213 "PageLoad.PageTiming.ForegroundDuration.AfterPaint";
214 const char kHistogramPageTimingForegroundDurationNoCommit[] =
215 "PageLoad.PageTiming.ForegroundDuration.NoCommit";
216 const char kHistogramPageTimingForegroundDurationWithPaint[] =
217 "PageLoad.PageTiming.ForegroundDuration.WithPaint";
218 const char kHistogramPageTimingForegroundDurationWithoutPaint[] =
219 "PageLoad.PageTiming.ForegroundDuration.WithoutPaint";
220
221 const char kHistogramLoadTypeParseStartReload[] =
222 "PageLoad.ParseTiming.NavigationToParseStart.LoadType.Reload";
223 const char kHistogramLoadTypeParseStartForwardBack[] =
224 "PageLoad.ParseTiming.NavigationToParseStart.LoadType."
225 "ForwardBackNavigation";
226 const char kHistogramLoadTypeParseStartForwardBackNoStore[] =
227 "PageLoad.ParseTiming.NavigationToParseStart.LoadType."
228 "ForwardBackNavigation.NoStore";
229 const char kHistogramLoadTypeParseStartNewNavigation[] =
230 "PageLoad.ParseTiming.NavigationToParseStart.LoadType.NewNavigation";
231
232 const char kHistogramFirstForeground[] =
233 "PageLoad.PageTiming.NavigationToFirstForeground";
234
235 const char kHistogramFailedProvisionalLoad[] =
236 "PageLoad.PageTiming.NavigationToFailedProvisionalLoad";
237
238 const char kHistogramUserGestureNavigationToForwardBack[] =
239 "PageLoad.PageTiming.ForegroundDuration.PageEndReason."
240 "ForwardBackNavigation.UserGesture";
241
242 const char kHistogramForegroundToFirstPaint[] =
243 "PageLoad.PaintTiming.ForegroundToFirstPaint";
244 const char kHistogramForegroundToFirstContentfulPaint[] =
245 "PageLoad.PaintTiming.ForegroundToFirstContentfulPaint";
246
247 const char kHistogramFirstContentfulPaintUserInitiated[] =
248 "PageLoad.PaintTiming.NavigationToFirstContentfulPaint.UserInitiated";
249
250 const char kHistogramFirstMeaningfulPaintStatus[] =
251 "PageLoad.Experimental.PaintTiming.FirstMeaningfulPaintStatus";
252
253 const char kHistogramFirstNonScrollInputAfterFirstPaint[] =
254 "PageLoad.InputTiming.NavigationToFirstNonScroll.AfterPaint";
255 const char kHistogramFirstScrollInputAfterFirstPaint[] =
256 "PageLoad.InputTiming.NavigationToFirstScroll.AfterPaint";
257
258 const char kHistogramPageLoadTotalBytes[] =
259 "PageLoad.Experimental.Bytes.Total2";
260 const char kHistogramPageLoadNetworkBytes[] =
261 "PageLoad.Experimental.Bytes.Network";
262 const char kHistogramPageLoadCacheBytes[] =
263 "PageLoad.Experimental.Bytes.Cache2";
264 const char kHistogramPageLoadNetworkBytesIncludingHeaders[] =
265 "PageLoad.Experimental.Bytes.NetworkIncludingHeaders";
266 const char kHistogramPageLoadUnfinishedBytes[] =
267 "PageLoad.Experimental.Bytes.Unfinished";
268
269 const char kHistogramPageLoadCpuTotalUsage[] = "PageLoad.Cpu.TotalUsage";
270 const char kHistogramPageLoadCpuTotalUsageForegrounded[] =
271 "PageLoad.Cpu.TotalUsageForegrounded";
272
273 const char kHistogramLoadTypeTotalBytesForwardBack[] =
274 "PageLoad.Experimental.Bytes.Total2.LoadType.ForwardBackNavigation";
275 const char kHistogramLoadTypeNetworkBytesForwardBack[] =
276 "PageLoad.Experimental.Bytes.Network.LoadType.ForwardBackNavigation";
277 const char kHistogramLoadTypeCacheBytesForwardBack[] =
278 "PageLoad.Experimental.Bytes.Cache2.LoadType.ForwardBackNavigation";
279
280 const char kHistogramLoadTypeTotalBytesReload[] =
281 "PageLoad.Experimental.Bytes.Total2.LoadType.Reload";
282 const char kHistogramLoadTypeNetworkBytesReload[] =
283 "PageLoad.Experimental.Bytes.Network.LoadType.Reload";
284 const char kHistogramLoadTypeCacheBytesReload[] =
285 "PageLoad.Experimental.Bytes.Cache2.LoadType.Reload";
286
287 const char kHistogramLoadTypeTotalBytesNewNavigation[] =
288 "PageLoad.Experimental.Bytes.Total2.LoadType.NewNavigation";
289 const char kHistogramLoadTypeNetworkBytesNewNavigation[] =
290 "PageLoad.Experimental.Bytes.Network.LoadType.NewNavigation";
291 const char kHistogramLoadTypeCacheBytesNewNavigation[] =
292 "PageLoad.Experimental.Bytes.Cache2.LoadType.NewNavigation";
293
294 const char kHistogramTotalCompletedResources[] =
295 "PageLoad.Experimental.CompletedResources.Total2";
296 const char kHistogramNetworkCompletedResources[] =
297 "PageLoad.Experimental.CompletedResources.Network";
298 const char kHistogramCacheCompletedResources[] =
299 "PageLoad.Experimental.CompletedResources.Cache2";
300
301 const char kHistogramInputToNavigation[] =
302 "PageLoad.Experimental.InputTiming.InputToNavigationStart";
303 const char kBackgroundHistogramInputToNavigation[] =
304 "PageLoad.Experimental.InputTiming.InputToNavigationStart.Background";
305 const char kHistogramInputToNavigationLinkClick[] =
306 "PageLoad.Experimental.InputTiming.InputToNavigationStart.FromLinkClick";
307 const char kHistogramInputToNavigationOmnibox[] =
308 "PageLoad.Experimental.InputTiming.InputToNavigationStart.FromOmnibox";
309 const char kHistogramInputToFirstPaint[] =
310 "PageLoad.Experimental.PaintTiming.InputToFirstPaint";
311 const char kBackgroundHistogramInputToFirstPaint[] =
312 "PageLoad.Experimental.PaintTiming.InputToFirstPaint.Background";
313 const char kHistogramInputToFirstContentfulPaint[] =
314 "PageLoad.Experimental.PaintTiming.InputToFirstContentfulPaint";
315 const char kBackgroundHistogramInputToFirstContentfulPaint[] =
316 "PageLoad.Experimental.PaintTiming.InputToFirstContentfulPaint.Background";
317
318 const char kHistogramBackForwardCacheEvent[] =
319 "PageLoad.BackForwardCache.Event";
320
321 // Navigation metrics from the navigation start.
322 const char kHistogramNavigationTimingNavigationStartToFirstRequestStart[] =
323 "PageLoad.Experimental.NavigationTiming.NavigationStartToFirstRequestStart";
324 const char kHistogramNavigationTimingNavigationStartToFirstResponseStart[] =
325 "PageLoad.Experimental.NavigationTiming."
326 "NavigationStartToFirstResponseStart";
327 const char kHistogramNavigationTimingNavigationStartToFirstLoaderCallback[] =
328 "PageLoad.Experimental.NavigationTiming."
329 "NavigationStartToFirstLoaderCallback";
330 const char kHistogramNavigationTimingNavigationStartToFinalRequestStart[] =
331 "PageLoad.Experimental.NavigationTiming.NavigationStartToFinalRequestStart";
332 const char kHistogramNavigationTimingNavigationStartToFinalResponseStart[] =
333 "PageLoad.Experimental.NavigationTiming."
334 "NavigationStartToFinalResponseStart";
335 const char kHistogramNavigationTimingNavigationStartToFinalLoaderCallback[] =
336 "PageLoad.Experimental.NavigationTiming."
337 "NavigationStartToFinalLoaderCallback";
338 const char kHistogramNavigationTimingNavigationStartToNavigationCommitSent[] =
339 "PageLoad.Experimental.NavigationTiming."
340 "NavigationStartToNavigationCommitSent";
341
342 // Navigation metrics between milestones.
343 const char kHistogramNavigationTimingFirstRequestStartToFirstResponseStart[] =
344 "PageLoad.Experimental.NavigationTiming."
345 "FirstRequestStartToFirstResponseStart";
346 const char kHistogramNavigationTimingFirstResponseStartToFirstLoaderCallback[] =
347 "PageLoad.Experimental.NavigationTiming."
348 "FirstResponseStartToFirstLoaderCallback";
349 const char kHistogramNavigationTimingFinalRequestStartToFinalResponseStart[] =
350 "PageLoad.Experimental.NavigationTiming."
351 "FinalRequestStartToFinalResponseStart";
352 const char kHistogramNavigationTimingFinalResponseStartToFinalLoaderCallback[] =
353 "PageLoad.Experimental.NavigationTiming."
354 "FinalResponseStartToFinalLoaderCallback";
355 const char
356 kHistogramNavigationTimingFinalLoaderCallbackToNavigationCommitSent[] =
357 "PageLoad.Experimental.NavigationTiming."
358 "FinalLoaderCallbackToNavigationCommitSent";
359
360 // 103 Early Hints metrics for experiment (https://crbug.com/1093693).
361 const char kHistogramEarlyHintsFirstRequestStartToEarlyHints[] =
362 "PageLoad.Experimental.EarlyHints.FirstRequestStartToEarlyHints";
363 const char kHistogramEarlyHintsFinalRequestStartToEarlyHints[] =
364 "PageLoad.Experimental.EarlyHints.FinalRequestStartToEarlyHints";
365 const char kHistogramEarlyHintsEarlyHintsToFinalResponseStart[] =
366 "PageLoad.Experimental.EarlyHints.EarlyHintsToFinalResponseStart";
367
368 } // namespace internal
369
UmaPageLoadMetricsObserver()370 UmaPageLoadMetricsObserver::UmaPageLoadMetricsObserver()
371 : transition_(ui::PAGE_TRANSITION_LINK),
372 was_no_store_main_resource_(false),
373 num_cache_resources_(0),
374 num_network_resources_(0),
375 cache_bytes_(0),
376 network_bytes_(0),
377 network_bytes_including_headers_(0),
378 redirect_chain_size_(0) {}
379
~UmaPageLoadMetricsObserver()380 UmaPageLoadMetricsObserver::~UmaPageLoadMetricsObserver() {}
381
382 page_load_metrics::PageLoadMetricsObserver::ObservePolicy
OnRedirect(content::NavigationHandle * navigation_handle)383 UmaPageLoadMetricsObserver::OnRedirect(
384 content::NavigationHandle* navigation_handle) {
385 redirect_chain_size_++;
386 return CONTINUE_OBSERVING;
387 }
388
389 page_load_metrics::PageLoadMetricsObserver::ObservePolicy
OnCommit(content::NavigationHandle * navigation_handle,ukm::SourceId source_id)390 UmaPageLoadMetricsObserver::OnCommit(
391 content::NavigationHandle* navigation_handle,
392 ukm::SourceId source_id) {
393 transition_ = navigation_handle->GetPageTransition();
394 const net::HttpResponseHeaders* headers =
395 navigation_handle->GetResponseHeaders();
396 if (headers) {
397 was_no_store_main_resource_ =
398 headers->HasHeaderValue("cache-control", "no-store");
399 }
400 UMA_HISTOGRAM_COUNTS_100("PageLoad.Navigation.RedirectChainLength",
401 redirect_chain_size_);
402 navigation_handle_timing_ = navigation_handle->GetNavigationHandleTiming();
403
404 // TODO(crbug/1097328): Remove collecting visits to support.google.com after
405 // language settings update fully launches.
406 #if defined(OS_CHROMEOS)
407 RecordVisitToLanguageSettingsSupportPage(navigation_handle->GetURL());
408 #endif // defined(OS_CHROMEOS)
409 return CONTINUE_OBSERVING;
410 }
411
OnDomContentLoadedEventStart(const page_load_metrics::mojom::PageLoadTiming & timing)412 void UmaPageLoadMetricsObserver::OnDomContentLoadedEventStart(
413 const page_load_metrics::mojom::PageLoadTiming& timing) {
414 if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
415 timing.document_timing->dom_content_loaded_event_start,
416 GetDelegate())) {
417 PAGE_LOAD_HISTOGRAM(
418 internal::kHistogramDomContentLoaded,
419 timing.document_timing->dom_content_loaded_event_start.value());
420 } else {
421 PAGE_LOAD_HISTOGRAM(
422 internal::kBackgroundHistogramDomContentLoaded,
423 timing.document_timing->dom_content_loaded_event_start.value());
424 }
425 }
426
OnLoadEventStart(const page_load_metrics::mojom::PageLoadTiming & timing)427 void UmaPageLoadMetricsObserver::OnLoadEventStart(
428 const page_load_metrics::mojom::PageLoadTiming& timing) {
429 if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
430 timing.document_timing->load_event_start, GetDelegate())) {
431 PAGE_LOAD_HISTOGRAM(internal::kHistogramLoad,
432 timing.document_timing->load_event_start.value());
433 } else {
434 PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramLoad,
435 timing.document_timing->load_event_start.value());
436 }
437 }
438
OnFirstPaintInPage(const page_load_metrics::mojom::PageLoadTiming & timing)439 void UmaPageLoadMetricsObserver::OnFirstPaintInPage(
440 const page_load_metrics::mojom::PageLoadTiming& timing) {
441 first_paint_ = GetDelegate().GetNavigationStart() +
442 timing.paint_timing->first_paint.value();
443 if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
444 timing.paint_timing->first_paint, GetDelegate())) {
445 PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstPaint,
446 timing.paint_timing->first_paint.value());
447
448 if (timing.input_to_navigation_start) {
449 PAGE_LOAD_HISTOGRAM(internal::kHistogramInputToFirstPaint,
450 timing.input_to_navigation_start.value() +
451 timing.paint_timing->first_paint.value());
452 }
453 } else {
454 PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramFirstPaint,
455 timing.paint_timing->first_paint.value());
456 if (timing.input_to_navigation_start) {
457 PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramInputToFirstPaint,
458 timing.input_to_navigation_start.value() +
459 timing.paint_timing->first_paint.value());
460 }
461 }
462
463 if (page_load_metrics::WasStartedInBackgroundOptionalEventInForeground(
464 timing.paint_timing->first_paint, GetDelegate())) {
465 PAGE_LOAD_HISTOGRAM(internal::kHistogramForegroundToFirstPaint,
466 timing.paint_timing->first_paint.value() -
467 GetDelegate().GetFirstForegroundTime().value());
468 }
469 }
470
OnFirstImagePaintInPage(const page_load_metrics::mojom::PageLoadTiming & timing)471 void UmaPageLoadMetricsObserver::OnFirstImagePaintInPage(
472 const page_load_metrics::mojom::PageLoadTiming& timing) {
473 if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
474 timing.paint_timing->first_image_paint, GetDelegate())) {
475 PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstImagePaint,
476 timing.paint_timing->first_image_paint.value());
477 } else {
478 PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramFirstImagePaint,
479 timing.paint_timing->first_image_paint.value());
480 }
481 }
482
OnFirstContentfulPaintInPage(const page_load_metrics::mojom::PageLoadTiming & timing)483 void UmaPageLoadMetricsObserver::OnFirstContentfulPaintInPage(
484 const page_load_metrics::mojom::PageLoadTiming& timing) {
485 if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
486 timing.paint_timing->first_contentful_paint, GetDelegate())) {
487 PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstContentfulPaint,
488 timing.paint_timing->first_contentful_paint.value());
489 PAGE_LOAD_HISTOGRAM(internal::kHistogramParseStartToFirstContentfulPaint,
490 timing.paint_timing->first_contentful_paint.value() -
491 timing.parse_timing->parse_start.value());
492
493 // Emit a trace event to highlight a long navigation to first contentful
494 // paint.
495 if (timing.paint_timing->first_contentful_paint >
496 kFirstContentfulPaintTraceThreshold) {
497 base::TimeTicks navigation_start = GetDelegate().GetNavigationStart();
498 TRACE_EVENT_NESTABLE_ASYNC_BEGIN_WITH_TIMESTAMP0(
499 "latency", "Long Navigation to First Contentful Paint",
500 TRACE_ID_LOCAL(g_num_trace_events_in_process), navigation_start);
501 TRACE_EVENT_NESTABLE_ASYNC_END_WITH_TIMESTAMP0(
502 "latency", "Long Navigation to First Contentful Paint",
503 TRACE_ID_LOCAL(g_num_trace_events_in_process),
504 navigation_start +
505 timing.paint_timing->first_contentful_paint.value());
506 g_num_trace_events_in_process++;
507 }
508
509 UMA_HISTOGRAM_ENUMERATION(
510 internal::kHistogramFirstContentfulPaintInitiatingProcess,
511 GetDelegate().GetUserInitiatedInfo().browser_initiated
512 ? content::PROCESS_TYPE_BROWSER
513 : content::PROCESS_TYPE_RENDERER,
514 content::PROCESS_TYPE_CONTENT_END);
515
516 if (was_no_store_main_resource_) {
517 PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstContentfulPaintNoStore,
518 timing.paint_timing->first_contentful_paint.value());
519 }
520
521 // TODO(bmcquade): consider adding a histogram that uses
522 // UserInputInfo.user_input_event.
523 if (GetDelegate().GetUserInitiatedInfo().browser_initiated ||
524 GetDelegate().GetUserInitiatedInfo().user_gesture) {
525 PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstContentfulPaintUserInitiated,
526 timing.paint_timing->first_contentful_paint.value());
527 }
528
529 if (timing.input_to_navigation_start) {
530 PAGE_LOAD_HISTOGRAM(internal::kHistogramInputToNavigation,
531 timing.input_to_navigation_start.value());
532 PAGE_LOAD_HISTOGRAM(
533 internal::kHistogramInputToFirstContentfulPaint,
534 timing.input_to_navigation_start.value() +
535 timing.paint_timing->first_contentful_paint.value());
536
537 if (ui::PageTransitionCoreTypeIs(transition_, ui::PAGE_TRANSITION_LINK)) {
538 PAGE_LOAD_HISTOGRAM(internal::kHistogramInputToNavigationLinkClick,
539 timing.input_to_navigation_start.value());
540 } else if (ui::PageTransitionCoreTypeIs(transition_,
541 ui::PAGE_TRANSITION_GENERATED) ||
542 ui::PageTransitionCoreTypeIs(transition_,
543 ui::PAGE_TRANSITION_TYPED)) {
544 PAGE_LOAD_HISTOGRAM(internal::kHistogramInputToNavigationOmnibox,
545 timing.input_to_navigation_start.value());
546 }
547 }
548
549 if (GetDelegate().GetFirstBackgroundTime()) {
550 // We were started in the foreground, and got FCP while in foreground, but
551 // became hidden while propagating the FCP value from Blink into the PLM
552 // observer. In this case, we will have missed the FCP UKM value, since it
553 // is logged in UkmPageLoadMetricsObserver::OnHidden.
554 PAGE_LOAD_HISTOGRAM(
555 internal::kHistogramFirstContentfulPaintHiddenWhileFlushing,
556 timing.paint_timing->first_contentful_paint.value());
557 }
558
559 switch (GetPageLoadType(transition_)) {
560 case LOAD_TYPE_RELOAD:
561 PAGE_LOAD_HISTOGRAM(
562 internal::kHistogramLoadTypeFirstContentfulPaintReload,
563 timing.paint_timing->first_contentful_paint.value());
564 // TODO(bmcquade): consider adding a histogram that uses
565 // UserInputInfo.user_input_event.
566 if (GetDelegate().GetUserInitiatedInfo().browser_initiated ||
567 GetDelegate().GetUserInitiatedInfo().user_gesture) {
568 PAGE_LOAD_HISTOGRAM(
569 internal::kHistogramLoadTypeFirstContentfulPaintReloadByGesture,
570 timing.paint_timing->first_contentful_paint.value());
571 }
572 break;
573 case LOAD_TYPE_FORWARD_BACK:
574 PAGE_LOAD_HISTOGRAM(
575 internal::kHistogramLoadTypeFirstContentfulPaintForwardBack,
576 timing.paint_timing->first_contentful_paint.value());
577 if (was_no_store_main_resource_) {
578 PAGE_LOAD_HISTOGRAM(
579 internal::
580 kHistogramLoadTypeFirstContentfulPaintForwardBackNoStore,
581 timing.paint_timing->first_contentful_paint.value());
582 }
583 break;
584 case LOAD_TYPE_NEW_NAVIGATION:
585 PAGE_LOAD_HISTOGRAM(
586 internal::kHistogramLoadTypeFirstContentfulPaintNewNavigation,
587 timing.paint_timing->first_contentful_paint.value());
588 break;
589 case LOAD_TYPE_NONE:
590 NOTREACHED();
591 break;
592 }
593 } else {
594 PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramFirstContentfulPaint,
595 timing.paint_timing->first_contentful_paint.value());
596 PAGE_LOAD_HISTOGRAM(
597 internal::kBackgroundHistogramParseStartToFirstContentfulPaint,
598 timing.paint_timing->first_contentful_paint.value() -
599 timing.parse_timing->parse_start.value());
600 if (timing.input_to_navigation_start) {
601 PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramInputToNavigation,
602 timing.input_to_navigation_start.value());
603 PAGE_LOAD_HISTOGRAM(
604 internal::kBackgroundHistogramInputToFirstContentfulPaint,
605 timing.input_to_navigation_start.value() +
606 timing.paint_timing->first_contentful_paint.value());
607 }
608 }
609
610 if (page_load_metrics::WasStartedInBackgroundOptionalEventInForeground(
611 timing.paint_timing->first_contentful_paint, GetDelegate())) {
612 PAGE_LOAD_HISTOGRAM(internal::kHistogramForegroundToFirstContentfulPaint,
613 timing.paint_timing->first_contentful_paint.value() -
614 GetDelegate().GetFirstForegroundTime().value());
615 }
616 }
617
OnFirstMeaningfulPaintInMainFrameDocument(const page_load_metrics::mojom::PageLoadTiming & timing)618 void UmaPageLoadMetricsObserver::OnFirstMeaningfulPaintInMainFrameDocument(
619 const page_load_metrics::mojom::PageLoadTiming& timing) {
620 if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
621 timing.paint_timing->first_meaningful_paint, GetDelegate())) {
622 PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstMeaningfulPaint,
623 timing.paint_timing->first_meaningful_paint.value());
624 PAGE_LOAD_HISTOGRAM(internal::kHistogramParseStartToFirstMeaningfulPaint,
625 timing.paint_timing->first_meaningful_paint.value() -
626 timing.parse_timing->parse_start.value());
627 RecordFirstMeaningfulPaintStatus(internal::FIRST_MEANINGFUL_PAINT_RECORDED);
628 } else {
629 RecordFirstMeaningfulPaintStatus(
630 internal::FIRST_MEANINGFUL_PAINT_BACKGROUNDED);
631 }
632 }
633
OnFirstInputInPage(const page_load_metrics::mojom::PageLoadTiming & timing)634 void UmaPageLoadMetricsObserver::OnFirstInputInPage(
635 const page_load_metrics::mojom::PageLoadTiming& timing) {
636 if (!page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
637 timing.interactive_timing->first_input_timestamp, GetDelegate())) {
638 return;
639 }
640 UMA_HISTOGRAM_CUSTOM_TIMES(
641 internal::kHistogramFirstInputDelay,
642 timing.interactive_timing->first_input_delay.value(),
643 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromSeconds(60),
644 50);
645 PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstInputTimestamp,
646 timing.interactive_timing->first_input_timestamp.value());
647 TRACE_EVENT_MARK_WITH_TIMESTAMP1(
648 "loading", "FirstInputDelay::AllFrames::UMA",
649 GetDelegate().GetNavigationStart() +
650 timing.interactive_timing->first_input_timestamp.value(),
651 "data", FirstInputDelayTraceData(timing));
652 }
653
OnParseStart(const page_load_metrics::mojom::PageLoadTiming & timing)654 void UmaPageLoadMetricsObserver::OnParseStart(
655 const page_load_metrics::mojom::PageLoadTiming& timing) {
656 if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
657 timing.parse_timing->parse_start, GetDelegate())) {
658 PAGE_LOAD_HISTOGRAM(internal::kHistogramParseStart,
659 timing.parse_timing->parse_start.value());
660
661 switch (GetPageLoadType(transition_)) {
662 case LOAD_TYPE_RELOAD:
663 PAGE_LOAD_HISTOGRAM(internal::kHistogramLoadTypeParseStartReload,
664 timing.parse_timing->parse_start.value());
665 break;
666 case LOAD_TYPE_FORWARD_BACK:
667 PAGE_LOAD_HISTOGRAM(internal::kHistogramLoadTypeParseStartForwardBack,
668 timing.parse_timing->parse_start.value());
669 if (was_no_store_main_resource_) {
670 PAGE_LOAD_HISTOGRAM(
671 internal::kHistogramLoadTypeParseStartForwardBackNoStore,
672 timing.parse_timing->parse_start.value());
673 }
674 break;
675 case LOAD_TYPE_NEW_NAVIGATION:
676 PAGE_LOAD_HISTOGRAM(internal::kHistogramLoadTypeParseStartNewNavigation,
677 timing.parse_timing->parse_start.value());
678 break;
679 case LOAD_TYPE_NONE:
680 NOTREACHED();
681 break;
682 }
683 } else {
684 PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramParseStart,
685 timing.parse_timing->parse_start.value());
686 }
687 }
688
OnParseStop(const page_load_metrics::mojom::PageLoadTiming & timing)689 void UmaPageLoadMetricsObserver::OnParseStop(
690 const page_load_metrics::mojom::PageLoadTiming& timing) {
691 base::TimeDelta parse_duration = timing.parse_timing->parse_stop.value() -
692 timing.parse_timing->parse_start.value();
693 if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
694 timing.parse_timing->parse_stop, GetDelegate())) {
695 PAGE_LOAD_HISTOGRAM(internal::kHistogramParseDuration, parse_duration);
696 PAGE_LOAD_HISTOGRAM(
697 internal::kHistogramParseBlockedOnScriptLoad,
698 timing.parse_timing->parse_blocked_on_script_load_duration.value());
699 PAGE_LOAD_HISTOGRAM(
700 internal::kHistogramParseBlockedOnScriptLoadDocumentWrite,
701 timing.parse_timing
702 ->parse_blocked_on_script_load_from_document_write_duration
703 .value());
704 PAGE_LOAD_HISTOGRAM(
705 internal::kHistogramParseBlockedOnScriptExecution,
706 timing.parse_timing->parse_blocked_on_script_execution_duration
707 .value());
708 PAGE_LOAD_HISTOGRAM(
709 internal::kHistogramParseBlockedOnScriptExecutionDocumentWrite,
710 timing.parse_timing
711 ->parse_blocked_on_script_execution_from_document_write_duration
712 .value());
713 } else {
714 PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramParseDuration,
715 parse_duration);
716 PAGE_LOAD_HISTOGRAM(
717 internal::kBackgroundHistogramParseBlockedOnScriptLoad,
718 timing.parse_timing->parse_blocked_on_script_load_duration.value());
719 PAGE_LOAD_HISTOGRAM(
720 internal::kBackgroundHistogramParseBlockedOnScriptLoadDocumentWrite,
721 timing.parse_timing
722 ->parse_blocked_on_script_load_from_document_write_duration
723 .value());
724 }
725 }
726
OnComplete(const page_load_metrics::mojom::PageLoadTiming & timing)727 void UmaPageLoadMetricsObserver::OnComplete(
728 const page_load_metrics::mojom::PageLoadTiming& timing) {
729 RecordNavigationTimingHistograms();
730 RecordTimingHistograms(timing);
731 RecordByteAndResourceHistograms(timing);
732 RecordCpuUsageHistograms();
733 RecordForegroundDurationHistograms(timing, base::TimeTicks());
734 }
735
736 page_load_metrics::PageLoadMetricsObserver::ObservePolicy
FlushMetricsOnAppEnterBackground(const page_load_metrics::mojom::PageLoadTiming & timing)737 UmaPageLoadMetricsObserver::FlushMetricsOnAppEnterBackground(
738 const page_load_metrics::mojom::PageLoadTiming& timing) {
739 // FlushMetricsOnAppEnterBackground is invoked on Android in cases where the
740 // app is about to be backgrounded, as part of the Activity.onPause()
741 // flow. After this method is invoked, Chrome may be killed without further
742 // notification, so we record final metrics collected up to this point.
743 if (GetDelegate().DidCommit()) {
744 RecordNavigationTimingHistograms();
745 RecordTimingHistograms(timing);
746 RecordByteAndResourceHistograms(timing);
747 RecordCpuUsageHistograms();
748 }
749 RecordForegroundDurationHistograms(timing, base::TimeTicks::Now());
750 return STOP_OBSERVING;
751 }
752
OnFailedProvisionalLoad(const page_load_metrics::FailedProvisionalLoadInfo & failed_load_info)753 void UmaPageLoadMetricsObserver::OnFailedProvisionalLoad(
754 const page_load_metrics::FailedProvisionalLoadInfo& failed_load_info) {
755 // Only handle actual failures; provisional loads that failed due to another
756 // committed load or due to user action are recorded in
757 // AbortsPageLoadMetricsObserver.
758 if (failed_load_info.error != net::OK &&
759 failed_load_info.error != net::ERR_ABORTED) {
760 if (page_load_metrics::WasStartedInForegroundOptionalEventInForeground(
761 failed_load_info.time_to_failed_provisional_load, GetDelegate())) {
762 PAGE_LOAD_HISTOGRAM(internal::kHistogramFailedProvisionalLoad,
763 failed_load_info.time_to_failed_provisional_load);
764 }
765 }
766 // Provide an empty PageLoadTiming, since we don't have any timing metrics
767 // for failed provisional loads.
768 RecordForegroundDurationHistograms(page_load_metrics::mojom::PageLoadTiming(),
769 base::TimeTicks());
770 }
771
OnUserInput(const blink::WebInputEvent & event,const page_load_metrics::mojom::PageLoadTiming & timing)772 void UmaPageLoadMetricsObserver::OnUserInput(
773 const blink::WebInputEvent& event,
774 const page_load_metrics::mojom::PageLoadTiming& timing) {
775 base::TimeTicks now;
776
777 if (first_paint_.is_null())
778 return;
779
780 // Track clicks after first paint for possible click burst.
781 click_tracker_.OnUserInput(event);
782
783 if (!received_non_scroll_input_after_first_paint_) {
784 if (event.GetType() == blink::WebInputEvent::Type::kGestureTap ||
785 event.GetType() == blink::WebInputEvent::Type::kMouseUp) {
786 received_non_scroll_input_after_first_paint_ = true;
787 if (now.is_null())
788 now = base::TimeTicks::Now();
789 PAGE_LOAD_HISTOGRAM(
790 internal::kHistogramFirstNonScrollInputAfterFirstPaint,
791 now - first_paint_);
792 }
793 }
794 if (!received_scroll_input_after_first_paint_ &&
795 event.GetType() == blink::WebInputEvent::Type::kGestureScrollBegin) {
796 received_scroll_input_after_first_paint_ = true;
797 if (now.is_null())
798 now = base::TimeTicks::Now();
799 PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstScrollInputAfterFirstPaint,
800 now - first_paint_);
801 }
802 }
803
OnResourceDataUseObserved(content::RenderFrameHost * rfh,const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr> & resources)804 void UmaPageLoadMetricsObserver::OnResourceDataUseObserved(
805 content::RenderFrameHost* rfh,
806 const std::vector<page_load_metrics::mojom::ResourceDataUpdatePtr>&
807 resources) {
808 for (auto const& resource : resources) {
809 if (resource->is_complete) {
810 if (resource->cache_type ==
811 page_load_metrics::mojom::CacheType::kNotCached) {
812 network_bytes_ += resource->encoded_body_length;
813 num_network_resources_++;
814 } else {
815 cache_bytes_ += resource->encoded_body_length;
816 num_cache_resources_++;
817 }
818 }
819 network_bytes_including_headers_ += resource->delta_bytes;
820 }
821 }
822
RecordNavigationTimingHistograms()823 void UmaPageLoadMetricsObserver::RecordNavigationTimingHistograms() {
824 const base::TimeTicks navigation_start_time =
825 GetDelegate().GetNavigationStart();
826 const content::NavigationHandleTiming& timing = navigation_handle_timing_;
827
828 // Record metrics for navigation only when all relevant milestones are
829 // recorded and in the expected order. It is allowed that they have the same
830 // value for some cases (e.g., internal redirection for HSTS).
831 if (navigation_start_time.is_null() ||
832 timing.first_request_start_time.is_null() ||
833 timing.first_response_start_time.is_null() ||
834 timing.first_loader_callback_time.is_null() ||
835 timing.final_request_start_time.is_null() ||
836 timing.final_response_start_time.is_null() ||
837 timing.final_loader_callback_time.is_null() ||
838 timing.navigation_commit_sent_time.is_null()) {
839 return;
840 }
841 // TODO(https://crbug.com/1076710): Change these early-returns to DCHECKs
842 // after the issue 1076710 is fixed.
843 if (navigation_start_time > timing.first_request_start_time ||
844 timing.first_request_start_time > timing.first_response_start_time ||
845 timing.first_response_start_time > timing.first_loader_callback_time ||
846 timing.first_loader_callback_time > timing.navigation_commit_sent_time) {
847 return;
848 }
849 if (navigation_start_time > timing.final_request_start_time ||
850 timing.final_request_start_time > timing.final_response_start_time ||
851 timing.final_response_start_time > timing.final_loader_callback_time ||
852 timing.final_loader_callback_time > timing.navigation_commit_sent_time) {
853 return;
854 }
855 DCHECK_LE(timing.first_request_start_time, timing.final_request_start_time);
856 DCHECK_LE(timing.first_response_start_time, timing.final_response_start_time);
857 DCHECK_LE(timing.first_loader_callback_time,
858 timing.final_loader_callback_time);
859
860 // Record the elapsed time from the navigation start milestone.
861 PAGE_LOAD_HISTOGRAM(
862 internal::kHistogramNavigationTimingNavigationStartToFirstRequestStart,
863 timing.first_request_start_time - navigation_start_time);
864 PAGE_LOAD_HISTOGRAM(
865 internal::kHistogramNavigationTimingNavigationStartToFirstResponseStart,
866 timing.first_response_start_time - navigation_start_time);
867 PAGE_LOAD_HISTOGRAM(
868 internal::kHistogramNavigationTimingNavigationStartToFirstLoaderCallback,
869 timing.first_loader_callback_time - navigation_start_time);
870
871 PAGE_LOAD_HISTOGRAM(
872 internal::kHistogramNavigationTimingNavigationStartToFinalRequestStart,
873 timing.final_request_start_time - navigation_start_time);
874 PAGE_LOAD_HISTOGRAM(
875 internal::kHistogramNavigationTimingNavigationStartToFinalResponseStart,
876 timing.final_response_start_time - navigation_start_time);
877 PAGE_LOAD_HISTOGRAM(
878 internal::kHistogramNavigationTimingNavigationStartToFinalLoaderCallback,
879 timing.final_loader_callback_time - navigation_start_time);
880
881 PAGE_LOAD_HISTOGRAM(
882 internal::kHistogramNavigationTimingNavigationStartToNavigationCommitSent,
883 timing.navigation_commit_sent_time - navigation_start_time);
884
885 // Record the intervals between milestones.
886 PAGE_LOAD_HISTOGRAM(
887 internal::kHistogramNavigationTimingFirstRequestStartToFirstResponseStart,
888 timing.first_response_start_time - timing.first_request_start_time);
889 PAGE_LOAD_HISTOGRAM(
890 internal::
891 kHistogramNavigationTimingFirstResponseStartToFirstLoaderCallback,
892 timing.first_loader_callback_time - timing.first_response_start_time);
893
894 PAGE_LOAD_HISTOGRAM(
895 internal::kHistogramNavigationTimingFinalRequestStartToFinalResponseStart,
896 timing.final_response_start_time - timing.final_request_start_time);
897 PAGE_LOAD_HISTOGRAM(
898 internal::
899 kHistogramNavigationTimingFinalResponseStartToFinalLoaderCallback,
900 timing.final_loader_callback_time - timing.final_response_start_time);
901
902 PAGE_LOAD_HISTOGRAM(
903 internal::
904 kHistogramNavigationTimingFinalLoaderCallbackToNavigationCommitSent,
905 timing.navigation_commit_sent_time - timing.final_loader_callback_time);
906
907 // Record the following intervals for the 103 Early Hints experiment
908 // (https://crbug.com/1093693).
909 // - The first request start to the 103 response,
910 // - The final request start to the 103 response, and the 103 response to the
911 // final response,
912 // Note that multiple 103 responses can be served per request. These metrics
913 // use the first 103 response as the timing.
914 if (!timing.early_hints_for_first_request_time.is_null()) {
915 PAGE_LOAD_HISTOGRAM(
916 internal::kHistogramEarlyHintsFirstRequestStartToEarlyHints,
917 timing.first_request_start_time -
918 timing.early_hints_for_first_request_time);
919 }
920 if (!timing.early_hints_for_final_request_time.is_null()) {
921 PAGE_LOAD_HISTOGRAM(
922 internal::kHistogramEarlyHintsFinalRequestStartToEarlyHints,
923 timing.final_request_start_time -
924 timing.early_hints_for_final_request_time);
925 PAGE_LOAD_HISTOGRAM(
926 internal::kHistogramEarlyHintsEarlyHintsToFinalResponseStart,
927 timing.early_hints_for_final_request_time -
928 timing.final_response_start_time);
929 }
930 }
931
932 // This method records values for metrics that were not recorded during any
933 // other event, or records failure status for metrics that have not been
934 // collected yet. This is meant to be called at the end of a page lifetime, for
935 // example, when the user is navigating away from the page.
RecordTimingHistograms(const page_load_metrics::mojom::PageLoadTiming & main_frame_timing)936 void UmaPageLoadMetricsObserver::RecordTimingHistograms(
937 const page_load_metrics::mojom::PageLoadTiming& main_frame_timing) {
938 // Log time to first foreground / time to first background. Log counts that we
939 // started a relevant page load in the foreground / background.
940 if (!GetDelegate().StartedInForeground() &&
941 GetDelegate().GetFirstForegroundTime()) {
942 PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstForeground,
943 GetDelegate().GetFirstForegroundTime().value());
944 }
945
946 const page_load_metrics::ContentfulPaintTimingInfo&
947 main_frame_largest_contentful_paint =
948 GetDelegate()
949 .GetLargestContentfulPaintHandler()
950 .MainFrameLargestContentfulPaint();
951 if (main_frame_largest_contentful_paint.ContainsValidTime() &&
952 WasStartedInForegroundOptionalEventInForeground(
953 main_frame_largest_contentful_paint.Time(), GetDelegate())) {
954 PAGE_LOAD_HISTOGRAM(internal::kHistogramLargestContentfulPaintMainFrame,
955 main_frame_largest_contentful_paint.Time().value());
956 UMA_HISTOGRAM_ENUMERATION(
957 internal::kHistogramLargestContentfulPaintMainFrameContentType,
958 main_frame_largest_contentful_paint.Type());
959 }
960
961 const page_load_metrics::ContentfulPaintTimingInfo&
962 all_frames_largest_contentful_paint =
963 GetDelegate()
964 .GetLargestContentfulPaintHandler()
965 .MergeMainFrameAndSubframes();
966 if (all_frames_largest_contentful_paint.ContainsValidTime() &&
967 WasStartedInForegroundOptionalEventInForeground(
968 all_frames_largest_contentful_paint.Time(), GetDelegate())) {
969 PAGE_LOAD_HISTOGRAM(internal::kHistogramLargestContentfulPaint,
970 all_frames_largest_contentful_paint.Time().value());
971 UMA_HISTOGRAM_ENUMERATION(
972 internal::kHistogramLargestContentfulPaintContentType,
973 all_frames_largest_contentful_paint.Type());
974 TRACE_EVENT_MARK_WITH_TIMESTAMP1(
975 "loading", "NavStartToLargestContentfulPaint::AllFrames::UMA",
976 GetDelegate().GetNavigationStart() +
977 all_frames_largest_contentful_paint.Time().value(),
978 "data", all_frames_largest_contentful_paint.DataAsTraceValue());
979 }
980
981 const page_load_metrics::ContentfulPaintTimingInfo&
982 main_frame_experimental_largest_contentful_paint =
983 GetDelegate()
984 .GetExperimentalLargestContentfulPaintHandler()
985 .MainFrameLargestContentfulPaint();
986 if (main_frame_experimental_largest_contentful_paint.ContainsValidTime() &&
987 WasStartedInForegroundOptionalEventInForeground(
988 main_frame_experimental_largest_contentful_paint.Time(),
989 GetDelegate())) {
990 PAGE_LOAD_HISTOGRAM(
991 internal::kDeprecatedHistogramLargestContentfulPaintMainFrame,
992 main_frame_experimental_largest_contentful_paint.Time().value());
993 UMA_HISTOGRAM_ENUMERATION(
994 internal::
995 kHistogramExperimentalLargestContentfulPaintMainFrameContentType,
996 main_frame_experimental_largest_contentful_paint.Type());
997 }
998
999 const page_load_metrics::ContentfulPaintTimingInfo&
1000 all_frames_experimental_largest_contentful_paint =
1001 GetDelegate()
1002 .GetExperimentalLargestContentfulPaintHandler()
1003 .MergeMainFrameAndSubframes();
1004 if (all_frames_experimental_largest_contentful_paint.ContainsValidTime() &&
1005 WasStartedInForegroundOptionalEventInForeground(
1006 all_frames_experimental_largest_contentful_paint.Time(),
1007 GetDelegate())) {
1008 PAGE_LOAD_HISTOGRAM(
1009 internal::kDeprecatedHistogramLargestContentfulPaint,
1010 all_frames_experimental_largest_contentful_paint.Time().value());
1011 UMA_HISTOGRAM_ENUMERATION(
1012 internal::kHistogramExperimentalLargestContentfulPaintContentType,
1013 all_frames_experimental_largest_contentful_paint.Type());
1014 TRACE_EVENT_MARK_WITH_TIMESTAMP1(
1015 "loading",
1016 "NavStartToExperimentalLargestContentfulPaint::AllFrames::UMA",
1017 GetDelegate().GetNavigationStart() +
1018 all_frames_experimental_largest_contentful_paint.Time().value(),
1019 "data",
1020 all_frames_experimental_largest_contentful_paint.DataAsTraceValue());
1021 }
1022
1023 if (main_frame_timing.paint_timing->first_paint &&
1024 !main_frame_timing.paint_timing->first_meaningful_paint) {
1025 RecordFirstMeaningfulPaintStatus(
1026 main_frame_timing.paint_timing->first_contentful_paint
1027 ? internal::FIRST_MEANINGFUL_PAINT_DID_NOT_REACH_NETWORK_STABLE
1028 : internal::
1029 FIRST_MEANINGFUL_PAINT_DID_NOT_REACH_FIRST_CONTENTFUL_PAINT);
1030 }
1031
1032 if (main_frame_timing.interactive_timing->longest_input_timestamp) {
1033 DCHECK(main_frame_timing.interactive_timing->longest_input_delay);
1034 UMA_HISTOGRAM_CUSTOM_TIMES(
1035 internal::kHistogramLongestInputDelay,
1036 main_frame_timing.interactive_timing->longest_input_delay.value(),
1037 base::TimeDelta::FromMilliseconds(1), base::TimeDelta::FromSeconds(60),
1038 50);
1039 PAGE_LOAD_HISTOGRAM(
1040 internal::kHistogramLongestInputTimestamp,
1041 main_frame_timing.interactive_timing->longest_input_timestamp.value());
1042 }
1043 }
1044
RecordForegroundDurationHistograms(const page_load_metrics::mojom::PageLoadTiming & timing,base::TimeTicks app_background_time)1045 void UmaPageLoadMetricsObserver::RecordForegroundDurationHistograms(
1046 const page_load_metrics::mojom::PageLoadTiming& timing,
1047 base::TimeTicks app_background_time) {
1048 base::Optional<base::TimeDelta> foreground_duration =
1049 page_load_metrics::GetInitialForegroundDuration(GetDelegate(),
1050 app_background_time);
1051 if (!foreground_duration)
1052 return;
1053
1054 if (GetDelegate().DidCommit()) {
1055 PAGE_LOAD_LONG_HISTOGRAM(internal::kHistogramPageTimingForegroundDuration,
1056 foreground_duration.value());
1057 if (timing.paint_timing->first_paint &&
1058 timing.paint_timing->first_paint < foreground_duration) {
1059 PAGE_LOAD_LONG_HISTOGRAM(
1060 internal::kHistogramPageTimingForegroundDurationAfterPaint,
1061 foreground_duration.value() -
1062 timing.paint_timing->first_paint.value());
1063 PAGE_LOAD_LONG_HISTOGRAM(
1064 internal::kHistogramPageTimingForegroundDurationWithPaint,
1065 foreground_duration.value());
1066 } else {
1067 PAGE_LOAD_LONG_HISTOGRAM(
1068 internal::kHistogramPageTimingForegroundDurationWithoutPaint,
1069 foreground_duration.value());
1070 }
1071 } else {
1072 PAGE_LOAD_LONG_HISTOGRAM(
1073 internal::kHistogramPageTimingForegroundDurationNoCommit,
1074 foreground_duration.value());
1075 }
1076
1077 if (GetDelegate().GetPageEndReason() == page_load_metrics::END_FORWARD_BACK &&
1078 GetDelegate().GetUserInitiatedInfo().user_gesture &&
1079 !GetDelegate().GetUserInitiatedInfo().browser_initiated &&
1080 GetDelegate().GetPageEndTime() <= foreground_duration) {
1081 PAGE_LOAD_HISTOGRAM(internal::kHistogramUserGestureNavigationToForwardBack,
1082 GetDelegate().GetPageEndTime().value());
1083 }
1084 }
1085
OnCpuTimingUpdate(content::RenderFrameHost * subframe_rfh,const page_load_metrics::mojom::CpuTiming & timing)1086 void UmaPageLoadMetricsObserver::OnCpuTimingUpdate(
1087 content::RenderFrameHost* subframe_rfh,
1088 const page_load_metrics::mojom::CpuTiming& timing) {
1089 total_cpu_usage_ += timing.task_time;
1090
1091 if (GetDelegate().GetVisibilityTracker().currently_in_foreground()) {
1092 foreground_cpu_usage_ += timing.task_time;
1093 }
1094 }
1095
RecordByteAndResourceHistograms(const page_load_metrics::mojom::PageLoadTiming & timing)1096 void UmaPageLoadMetricsObserver::RecordByteAndResourceHistograms(
1097 const page_load_metrics::mojom::PageLoadTiming& timing) {
1098 DCHECK_GE(network_bytes_, 0);
1099 DCHECK_GE(cache_bytes_, 0);
1100 int64_t total_bytes = network_bytes_ + cache_bytes_;
1101
1102 PAGE_BYTES_HISTOGRAM(internal::kHistogramPageLoadNetworkBytes,
1103 network_bytes_);
1104 PAGE_BYTES_HISTOGRAM(internal::kHistogramPageLoadCacheBytes, cache_bytes_);
1105 PAGE_BYTES_HISTOGRAM(internal::kHistogramPageLoadTotalBytes, total_bytes);
1106 PAGE_BYTES_HISTOGRAM(internal::kHistogramPageLoadNetworkBytesIncludingHeaders,
1107 network_bytes_including_headers_);
1108
1109 size_t unfinished_bytes = 0;
1110 for (auto const& kv :
1111 GetDelegate().GetResourceTracker().unfinished_resources())
1112 unfinished_bytes += kv.second->received_data_length;
1113 PAGE_BYTES_HISTOGRAM(internal::kHistogramPageLoadUnfinishedBytes,
1114 unfinished_bytes);
1115
1116 switch (GetPageLoadType(transition_)) {
1117 case LOAD_TYPE_RELOAD:
1118 PAGE_BYTES_HISTOGRAM(internal::kHistogramLoadTypeNetworkBytesReload,
1119 network_bytes_);
1120 PAGE_BYTES_HISTOGRAM(internal::kHistogramLoadTypeCacheBytesReload,
1121 cache_bytes_);
1122 PAGE_BYTES_HISTOGRAM(internal::kHistogramLoadTypeTotalBytesReload,
1123 total_bytes);
1124 break;
1125 case LOAD_TYPE_FORWARD_BACK:
1126 PAGE_BYTES_HISTOGRAM(internal::kHistogramLoadTypeNetworkBytesForwardBack,
1127 network_bytes_);
1128 PAGE_BYTES_HISTOGRAM(internal::kHistogramLoadTypeCacheBytesForwardBack,
1129 cache_bytes_);
1130 PAGE_BYTES_HISTOGRAM(internal::kHistogramLoadTypeTotalBytesForwardBack,
1131 total_bytes);
1132 break;
1133 case LOAD_TYPE_NEW_NAVIGATION:
1134 PAGE_BYTES_HISTOGRAM(
1135 internal::kHistogramLoadTypeNetworkBytesNewNavigation,
1136 network_bytes_);
1137 PAGE_BYTES_HISTOGRAM(internal::kHistogramLoadTypeCacheBytesNewNavigation,
1138 cache_bytes_);
1139 PAGE_BYTES_HISTOGRAM(internal::kHistogramLoadTypeTotalBytesNewNavigation,
1140 total_bytes);
1141 break;
1142 case LOAD_TYPE_NONE:
1143 NOTREACHED();
1144 break;
1145 }
1146
1147 PAGE_RESOURCE_COUNT_HISTOGRAM(internal::kHistogramNetworkCompletedResources,
1148 num_network_resources_);
1149 PAGE_RESOURCE_COUNT_HISTOGRAM(internal::kHistogramCacheCompletedResources,
1150 num_cache_resources_);
1151 PAGE_RESOURCE_COUNT_HISTOGRAM(internal::kHistogramTotalCompletedResources,
1152 num_cache_resources_ + num_network_resources_);
1153
1154 click_tracker_.RecordClickBurst(GetDelegate().GetPageUkmSourceId());
1155 }
1156
RecordCpuUsageHistograms()1157 void UmaPageLoadMetricsObserver::RecordCpuUsageHistograms() {
1158 PAGE_LOAD_HISTOGRAM(internal::kHistogramPageLoadCpuTotalUsage,
1159 total_cpu_usage_);
1160 PAGE_LOAD_HISTOGRAM(internal::kHistogramPageLoadCpuTotalUsageForegrounded,
1161 foreground_cpu_usage_);
1162 }
1163
1164 page_load_metrics::PageLoadMetricsObserver::ObservePolicy
OnEnterBackForwardCache(const page_load_metrics::mojom::PageLoadTiming & timing)1165 UmaPageLoadMetricsObserver::OnEnterBackForwardCache(
1166 const page_load_metrics::mojom::PageLoadTiming& timing) {
1167 UMA_HISTOGRAM_ENUMERATION(
1168 internal::kHistogramBackForwardCacheEvent,
1169 internal::PageLoadBackForwardCacheEvent::kEnterBackForwardCache);
1170 return PageLoadMetricsObserver::OnEnterBackForwardCache(timing);
1171 }
1172
OnRestoreFromBackForwardCache(const page_load_metrics::mojom::PageLoadTiming & timing,content::NavigationHandle * navigation_handle)1173 void UmaPageLoadMetricsObserver::OnRestoreFromBackForwardCache(
1174 const page_load_metrics::mojom::PageLoadTiming& timing,
1175 content::NavigationHandle* navigation_handle) {
1176 // This never reaches yet because OnEnterBackForwardCache returns
1177 // STOP_OBSERVING.
1178 // TODO(hajimehoshi): After changing OnEnterBackForwardCache to continue
1179 // observation, remove the above comment.
1180 UMA_HISTOGRAM_ENUMERATION(
1181 internal::kHistogramBackForwardCacheEvent,
1182 internal::PageLoadBackForwardCacheEvent::kRestoreFromBackForwardCache);
1183 }
1184