Index: chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc |
diff --git a/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc |
index b6c1a7fc8ca150e79acc084c8dec6d57efb1e388..41c7e02adaa7c8842baacc815cee4e5dca298172 100644 |
--- a/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc |
+++ b/chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc |
@@ -11,6 +11,8 @@ |
#include "components/page_load_metrics/common/page_load_timing.h" |
#include "net/base/registry_controlled_domains/registry_controlled_domain.h" |
+using page_load_metrics::UserAbortType; |
+ |
namespace internal { |
const char kHistogramFromGWSFirstPaint[] = |
@@ -30,8 +32,161 @@ const char kHistogramFromGWSParseDuration[] = |
const char kHistogramFromGWSLoad[] = |
"PageLoad.Clients.FromGWS2.Timing2.NavigationToLoadEventFired"; |
+const char kHistogramFromGWSAbortUnknownNavigationBeforeCommit[] = |
+ "PageLoad.Clients.FromGWS2.AbortTiming.UnknownNavigation.BeforeCommit"; |
+const char kHistogramFromGWSAbortNewNavigationBeforePaint[] = |
+ "PageLoad.Clients.FromGWS2.AbortTiming.NewNavigation.AfterCommit." |
+ "BeforePaint"; |
+const char kHistogramFromGWSAbortStopBeforeCommit[] = |
+ "PageLoad.Clients.FromGWS2.AbortTiming.Stop.BeforeCommit"; |
+const char kHistogramFromGWSAbortStopBeforePaint[] = |
+ "PageLoad.Clients.FromGWS2.AbortTiming.Stop.AfterCommit.BeforePaint"; |
+const char kHistogramFromGWSAbortCloseBeforeCommit[] = |
+ "PageLoad.Clients.FromGWS2.AbortTiming.Close.BeforeCommit"; |
+const char kHistogramFromGWSAbortCloseBeforePaint[] = |
+ "PageLoad.Clients.FromGWS2.AbortTiming.Close.AfterCommit.BeforePaint"; |
+ |
+const char kHistogramFromGWSAbortOtherBeforeCommit[] = |
+ "PageLoad.Clients.FromGWS2.AbortTiming.Other.BeforeCommit"; |
+const char kHistogramFromGWSAbortReloadBeforePaint[] = |
+ "PageLoad.Clients.FromGWS2.AbortTiming.Reload.AfterCommit.BeforePaint"; |
+const char kHistogramFromGWSAbortForwardBackBeforePaint[] = |
+ "PageLoad.Clients.FromGWS2.AbortTiming.ForwardBackNavigation." |
+ "AfterCommit.BeforePaint"; |
+ |
} // namespace internal |
+namespace { |
+ |
+void LogCommittedAbortsBeforePaint(UserAbortType abort_type, |
+ base::TimeDelta time_to_abort) { |
+ switch (abort_type) { |
+ case UserAbortType::ABORT_STOP: |
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSAbortStopBeforePaint, |
+ time_to_abort); |
+ break; |
+ case UserAbortType::ABORT_CLOSE: |
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSAbortCloseBeforePaint, |
+ time_to_abort); |
+ break; |
+ case UserAbortType::ABORT_NEW_NAVIGATION: |
+ PAGE_LOAD_HISTOGRAM( |
+ internal::kHistogramFromGWSAbortNewNavigationBeforePaint, |
+ time_to_abort); |
+ break; |
+ case UserAbortType::ABORT_RELOAD: |
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSAbortReloadBeforePaint, |
+ time_to_abort); |
+ break; |
+ case UserAbortType::ABORT_FORWARD_BACK: |
+ PAGE_LOAD_HISTOGRAM( |
+ internal::kHistogramFromGWSAbortForwardBackBeforePaint, |
+ time_to_abort); |
+ break; |
+ default: |
+ // These should only be logged for provisional aborts. |
+ DCHECK_NE(abort_type, UserAbortType::ABORT_OTHER); |
+ DCHECK_NE(abort_type, UserAbortType::ABORT_UNKNOWN_NAVIGATION); |
+ break; |
+ } |
+} |
+ |
+void LogProvisionalAborts(UserAbortType abort_type, |
+ base::TimeDelta time_to_abort) { |
+ switch (abort_type) { |
+ case UserAbortType::ABORT_STOP: |
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSAbortStopBeforeCommit, |
+ time_to_abort); |
+ break; |
+ case UserAbortType::ABORT_CLOSE: |
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSAbortCloseBeforeCommit, |
+ time_to_abort); |
+ break; |
+ case UserAbortType::ABORT_UNKNOWN_NAVIGATION: |
+ PAGE_LOAD_HISTOGRAM( |
+ internal::kHistogramFromGWSAbortUnknownNavigationBeforeCommit, |
+ time_to_abort); |
+ break; |
+ case UserAbortType::ABORT_OTHER: |
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSAbortOtherBeforeCommit, |
+ time_to_abort); |
+ break; |
+ default: |
+ // There are other abort types that could be logged, but they occur in |
+ // very small amounts that it isn't worth logging. |
+ // TODO(csharrison): Once transitions can be acquired before commit, log |
+ // the Reload/NewNavigation/ForwardBack variants here. |
+ break; |
+ } |
+} |
+ |
+void LogPerformanceMetrics( |
+ const page_load_metrics::PageLoadTiming& timing, |
+ const page_load_metrics::PageLoadExtraInfo& extra_info) { |
+ if (WasStartedInForegroundEventInForeground( |
+ timing.dom_content_loaded_event_start, extra_info)) { |
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSDomContentLoaded, |
+ timing.dom_content_loaded_event_start); |
+ } |
+ if (WasStartedInForegroundEventInForeground(timing.parse_stop, extra_info)) { |
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSParseDuration, |
+ timing.parse_stop - timing.parse_start); |
+ } |
+ if (WasStartedInForegroundEventInForeground(timing.load_event_start, |
+ extra_info)) { |
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSLoad, |
+ timing.load_event_start); |
+ } |
+ if (WasStartedInForegroundEventInForeground(timing.first_text_paint, |
+ extra_info)) { |
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSFirstTextPaint, |
+ timing.first_text_paint); |
+ } |
+ if (WasStartedInForegroundEventInForeground(timing.first_image_paint, |
+ extra_info)) { |
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSFirstImagePaint, |
+ timing.first_image_paint); |
+ } |
+ if (WasStartedInForegroundEventInForeground(timing.first_paint, extra_info)) { |
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSFirstPaint, |
+ timing.first_paint); |
+ } |
+ if (WasStartedInForegroundEventInForeground(timing.first_contentful_paint, |
+ extra_info)) { |
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSFirstContentfulPaint, |
+ timing.first_contentful_paint); |
+ |
+ // If we have a foreground paint, we should have a foreground parse start, |
+ // since paints can't happen until after parsing starts. |
+ DCHECK(WasStartedInForegroundEventInForeground(timing.parse_start, |
+ extra_info)); |
+ PAGE_LOAD_HISTOGRAM( |
+ internal::kHistogramFromGWSParseStartToFirstContentfulPaint, |
+ timing.first_contentful_paint - timing.parse_start); |
+ } |
+} |
+ |
+bool WasAbortedInForeground(UserAbortType abort_type, |
+ base::TimeDelta time_to_abort, |
+ const page_load_metrics::PageLoadExtraInfo& info) { |
+ if (time_to_abort.is_zero()) |
+ return false; |
+ if (abort_type == UserAbortType::ABORT_NONE) |
+ return false; |
+ if (WasStartedInForegroundEventInForeground(time_to_abort, info)) |
+ return true; |
+ DCHECK_GT(time_to_abort, info.first_background_time); |
+ base::TimeDelta bg_abort_delta = time_to_abort - info.first_background_time; |
+ // Consider this a foregrounded abort if it occurred within 100ms of a |
+ // background. This is needed for closing some tabs, where the signal for |
+ // background is often slightly ahead of the signal for close. |
+ if (bg_abort_delta.InMilliseconds() < 100) |
+ return true; |
+ return false; |
+} |
+ |
+} // namespace |
+ |
// See |
// https://docs.google.com/document/d/1jNPZ6Aeh0KV6umw1yZrrkfXRfxWNruwu7FELLx_cpOg/edit |
// for additional details. |
@@ -166,12 +321,24 @@ bool FromGWSPageLoadMetricsLogger::QueryContainsComponentHelper( |
return false; |
} |
+void FromGWSPageLoadMetricsLogger::SetPreviouslyCommittedUrl(const GURL& url) { |
+ previously_committed_url_is_search_results_ = IsGoogleSearchResultUrl(url); |
+ previously_committed_url_is_search_redirector_ = |
+ IsGoogleSearchRedirectorUrl(url); |
+} |
+ |
+void FromGWSPageLoadMetricsLogger::SetProvisionalUrl(const GURL& url) { |
+ provisional_url_is_search_results_or_google_redirector_ = |
+ IsGoogleSearchResultUrl(url) || IsGoogleRedirectorUrl(url); |
+} |
+ |
FromGWSPageLoadMetricsObserver::FromGWSPageLoadMetricsObserver() {} |
void FromGWSPageLoadMetricsObserver::OnStart( |
content::NavigationHandle* navigation_handle, |
const GURL& currently_committed_url) { |
- logger_.set_previously_committed_url(currently_committed_url); |
+ logger_.SetPreviouslyCommittedUrl(currently_committed_url); |
+ logger_.SetProvisionalUrl(navigation_handle->GetURL()); |
} |
void FromGWSPageLoadMetricsObserver::OnCommit( |
@@ -191,80 +358,60 @@ void FromGWSPageLoadMetricsObserver::OnComplete( |
void FromGWSPageLoadMetricsLogger::OnComplete( |
const page_load_metrics::PageLoadTiming& timing, |
const page_load_metrics::PageLoadExtraInfo& extra_info) { |
- if (ShouldLogMetrics(extra_info.committed_url)) { |
- LogMetrics(timing, extra_info); |
+ if (!ShouldLogMetrics(extra_info.committed_url)) |
+ return; |
+ |
+ // If we have a committed load but |timing.IsEmpty()|, then this load was not |
+ // tracked by the renderer. In this case, it is not possible to know whether |
+ // the abort signals came before the page painted. Additionally, for |
+ // consistency with PageLoad.Timing2 metrics, we ignore non-render-tracked |
+ // loads when tracking aborts after commit. |
+ UserAbortType abort_type = extra_info.abort_type; |
+ base::TimeDelta time_to_abort = extra_info.time_to_abort; |
+ bool aborted_in_foreground = |
+ WasAbortedInForeground(abort_type, time_to_abort, extra_info); |
+ |
+ if (!extra_info.committed_url.is_empty()) { |
+ LogPerformanceMetrics(timing, extra_info); |
+ bool aborted_before_paint = |
+ aborted_in_foreground && !timing.IsEmpty() && |
+ (timing.first_paint.is_zero() || timing.first_paint >= time_to_abort); |
+ if (aborted_before_paint) |
+ LogCommittedAbortsBeforePaint(abort_type, time_to_abort); |
+ } else { |
+ if (aborted_in_foreground) |
+ LogProvisionalAborts(abort_type, time_to_abort); |
} |
} |
-bool FromGWSPageLoadMetricsLogger::ShouldLogMetrics( |
- const GURL& committed_url) const { |
- // If we didn't navigate from another page, then this couldn't be a navigation |
- // from search, so don't log stats. |
- if (previously_committed_url_.is_empty()) |
- return false; |
- |
- // If this navigation didn't commit, or this page is a known google redirector |
- // URL or Google search results URL, then we should not log stats. |
- if (committed_url.is_empty() || IsGoogleRedirectorUrl(committed_url) || |
- IsGoogleSearchResultUrl(committed_url)) |
- return false; |
+bool FromGWSPageLoadMetricsLogger::ShouldLogMetrics(const GURL& committed_url) { |
+ // If this page is a known google redirector URL or Google search results URL, |
+ // then we should not log stats. Use the provisional url if the navigation |
+ // never commit. Note that this might throw away navigations to the Javascript |
+ // redirector url. |
+ if (committed_url.is_empty()) { |
+ if (provisional_url_is_search_results_or_google_redirector_) |
+ return false; |
+ } else { |
+ if (IsGoogleSearchResultUrl(committed_url) || |
+ IsGoogleRedirectorUrl(committed_url)) { |
+ return false; |
+ } |
+ } |
// We're only interested in tracking user gesture initiated navigations |
- // (e.g. clicks) initiated via links. |
- if (!navigation_initiated_via_link_) |
- return false; |
- |
- // We're only interested in navigations from the SRP or through the JS |
- // redirector. |
- if (!IsGoogleSearchResultUrl(previously_committed_url_) && |
- !IsGoogleSearchRedirectorUrl(previously_committed_url_)) |
- return false; |
- |
- return true; |
-} |
- |
-void FromGWSPageLoadMetricsLogger::LogMetrics( |
- const page_load_metrics::PageLoadTiming& timing, |
- const page_load_metrics::PageLoadExtraInfo& extra_info) { |
- if (WasStartedInForegroundEventInForeground( |
- timing.dom_content_loaded_event_start, extra_info)) { |
- PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSDomContentLoaded, |
- timing.dom_content_loaded_event_start); |
- } |
- if (WasStartedInForegroundEventInForeground(timing.parse_stop, extra_info)) { |
- PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSParseDuration, |
- timing.parse_stop - timing.parse_start); |
- } |
- if (WasStartedInForegroundEventInForeground(timing.load_event_start, |
- extra_info)) { |
- PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSLoad, |
- timing.load_event_start); |
- } |
- if (WasStartedInForegroundEventInForeground(timing.first_text_paint, |
- extra_info)) { |
- PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSFirstTextPaint, |
- timing.first_text_paint); |
- } |
- if (WasStartedInForegroundEventInForeground(timing.first_image_paint, |
- extra_info)) { |
- PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSFirstImagePaint, |
- timing.first_image_paint); |
- } |
- if (WasStartedInForegroundEventInForeground(timing.first_paint, extra_info)) { |
- PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSFirstPaint, |
- timing.first_paint); |
+ // (e.g. clicks) initiated via links. Note that the redirector will mask |
+ // these, so don't enforce this if the navigation came from a redirect url. |
+ // TODO(csharrison): Use this signal for provisional loads when the content |
+ // APIs allow for it. |
+ if (previously_committed_url_is_search_results_ && |
+ (committed_url.is_empty() || navigation_initiated_via_link_)) { |
+ return true; |
} |
- if (WasStartedInForegroundEventInForeground(timing.first_contentful_paint, |
- extra_info)) { |
- PAGE_LOAD_HISTOGRAM(internal::kHistogramFromGWSFirstContentfulPaint, |
- timing.first_contentful_paint); |
- // If we have a foreground paint, we should have a foreground parse start, |
- // since paints can't happen until after parsing starts. |
- DCHECK(WasStartedInForegroundEventInForeground(timing.parse_start, |
- extra_info)); |
- PAGE_LOAD_HISTOGRAM( |
- internal::kHistogramFromGWSParseStartToFirstContentfulPaint, |
- timing.first_contentful_paint - timing.parse_start); |
- } |
+ // If the navigation was via the search redirector, then the information about |
+ // whether the navigation was from a link would have been associated with the |
+ // navigation to the redirector, and not included in the redirected |
+ // navigation. Therefore, do not require link navigation this case. |
+ return previously_committed_url_is_search_redirector_; |
} |