summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbmcquade <bmcquade@chromium.org>2016-01-05 08:15:27 -0800
committerCommit bot <commit-bot@chromium.org>2016-01-05 16:16:34 +0000
commit7f749795cf6d86e2c4ccb6ea7eae0801694c561a (patch)
tree0d7ab536317552990b0cb6e918b931af318b73fd
parent9c89670185e91c2679b2119007e55f3b23c657f0 (diff)
downloadchromium_src-7f749795cf6d86e2c4ccb6ea7eae0801694c561a.zip
chromium_src-7f749795cf6d86e2c4ccb6ea7eae0801694c561a.tar.gz
chromium_src-7f749795cf6d86e2c4ccb6ea7eae0801694c561a.tar.bz2
Factor core page load timing histograms into separate observer.
This change moves PageLoad.Timing2 and rappor metrics into a separate observer class. This moves the responsibility of metric tracking out of MetricsWCO, and allows that class to focus on page load lifecycle state management and observer notifications. This has the additional benefit of breaking the dependency on RapporService in the embedder interface (thanks csharrison for suggesting this!). This change does not migrate provisional events from the MetricsWCO to the new observer. That should be done in a follow up change, as it requires changes to PLMObserver interface. BUG=571509, 570092 Review URL: https://codereview.chromium.org/1549453002 Cr-Commit-Position: refs/heads/master@{#367542}
-rw-r--r--chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc244
-rw-r--r--chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h68
-rw-r--r--chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc334
-rw-r--r--chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc2
-rw-r--r--chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h4
-rw-r--r--chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc28
-rw-r--r--chrome/browser/page_load_metrics/page_load_metrics_initialize.cc17
-rw-r--r--chrome/browser/page_load_metrics/page_load_metrics_initialize.h5
-rw-r--r--chrome/chrome_browser.gypi2
-rw-r--r--chrome/chrome_tests_unit.gypi1
-rw-r--r--chrome/test/base/testing_browser_process.cc8
-rw-r--r--chrome/test/base/testing_browser_process.h2
-rw-r--r--components/page_load_metrics/browser/metrics_web_contents_observer.cc222
-rw-r--r--components/page_load_metrics/browser/metrics_web_contents_observer.h84
-rw-r--r--components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc413
-rw-r--r--components/page_load_metrics/browser/page_load_metrics_observer.cc5
-rw-r--r--components/page_load_metrics/browser/page_load_metrics_observer.h6
17 files changed, 786 insertions, 659 deletions
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
new file mode 100644
index 0000000..d9ef53c
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.cc
@@ -0,0 +1,244 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h"
+
+#include <stddef.h>
+#include <stdint.h>
+#include <utility>
+
+#include "chrome/browser/browser_process.h"
+#include "components/page_load_metrics/browser/page_load_metrics_util.h"
+#include "components/rappor/rappor_service.h"
+#include "components/rappor/rappor_utils.h"
+
+namespace {
+
+// The number of buckets in the bitfield histogram. These buckets are described
+// in rappor.xml in PageLoad.CoarseTiming.NavigationToFirstContentfulPaint.
+// The bucket flag is defined by 1 << bucket_index, and is the bitfield
+// representing which timing bucket the page load falls into, i.e. 000010
+// would be the bucket flag showing that the page took between 2 and 4 seconds
+// to load.
+const size_t kNumRapporHistogramBuckets = 6;
+
+uint64_t RapporHistogramBucketIndex(const base::TimeDelta& time) {
+ int64_t seconds = time.InSeconds();
+ if (seconds < 2)
+ return 0;
+ if (seconds < 4)
+ return 1;
+ if (seconds < 8)
+ return 2;
+ if (seconds < 16)
+ return 3;
+ if (seconds < 32)
+ return 4;
+ return 5;
+}
+
+} // namespace
+
+namespace internal {
+
+const char kHistogramCommit[] = "PageLoad.Timing2.NavigationToCommit";
+const char kHistogramFirstLayout[] = "PageLoad.Timing2.NavigationToFirstLayout";
+const char kHistogramFirstTextPaint[] =
+ "PageLoad.Timing2.NavigationToFirstTextPaint";
+const char kHistogramDomContentLoaded[] =
+ "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired";
+const char kHistogramLoad[] = "PageLoad.Timing2.NavigationToLoadEventFired";
+const char kHistogramFirstPaint[] = "PageLoad.Timing2.NavigationToFirstPaint";
+const char kHistogramFirstImagePaint[] =
+ "PageLoad.Timing2.NavigationToFirstImagePaint";
+const char kHistogramFirstContentfulPaint[] =
+ "PageLoad.Timing2.NavigationToFirstContentfulPaint";
+const char kBackgroundHistogramCommit[] =
+ "PageLoad.Timing2.NavigationToCommit.Background";
+const char kBackgroundHistogramFirstLayout[] =
+ "PageLoad.Timing2.NavigationToFirstLayout.Background";
+const char kBackgroundHistogramFirstTextPaint[] =
+ "PageLoad.Timing2.NavigationToFirstTextPaint.Background";
+const char kBackgroundHistogramDomContentLoaded[] =
+ "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired.Background";
+const char kBackgroundHistogramLoad[] =
+ "PageLoad.Timing2.NavigationToLoadEventFired.Background";
+const char kBackgroundHistogramFirstPaint[] =
+ "PageLoad.Timing2.NavigationToFirstPaint.Background";
+const char kBackgroundHistogramFirstImagePaint[] =
+ "PageLoad.Timing2.NavigationToFirstImagePaint.Background.";
+const char kBackgroundHistogramFirstContentfulPaint[] =
+ "PageLoad.Timing2.NavigationToFirstContentfulPaint.Background";
+
+const char kHistogramFirstContentfulPaintHigh[] =
+ "PageLoad.Timing2.NavigationToFirstContentfulPaint.HighResolutionClock";
+const char kHistogramFirstContentfulPaintLow[] =
+ "PageLoad.Timing2.NavigationToFirstContentfulPaint.LowResolutionClock";
+
+const char kHistogramFirstBackground[] =
+ "PageLoad.Timing2.NavigationToFirstBackground";
+const char kHistogramFirstForeground[] =
+ "PageLoad.Timing2.NavigationToFirstForeground";
+
+const char kHistogramBackgroundBeforePaint[] =
+ "PageLoad.Timing2.NavigationToFirstBackground.AfterCommit.BeforePaint";
+const char kHistogramBackgroundBeforeCommit[] =
+ "PageLoad.Timing2.NavigationToFirstBackground.BeforeCommit";
+
+const char kRapporMetricsNameCoarseTiming[] =
+ "PageLoad.CoarseTiming.NavigationToFirstContentfulPaint";
+
+} // namespace internal
+
+CorePageLoadMetricsObserver::CorePageLoadMetricsObserver() {}
+
+CorePageLoadMetricsObserver::~CorePageLoadMetricsObserver() {}
+
+void CorePageLoadMetricsObserver::OnComplete(
+ const page_load_metrics::PageLoadTiming& timing,
+ const page_load_metrics::PageLoadExtraInfo& info) {
+ RecordTimingHistograms(timing, info);
+ RecordRappor(timing, info);
+}
+
+void CorePageLoadMetricsObserver::RecordTimingHistograms(
+ const page_load_metrics::PageLoadTiming& timing,
+ const page_load_metrics::PageLoadExtraInfo& info) {
+ if (!info.first_background_time.is_zero() &&
+ !EventOccurredInForeground(timing.first_paint, info)) {
+ if (!info.time_to_commit.is_zero()) {
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramBackgroundBeforePaint,
+ info.first_background_time);
+ } else {
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramBackgroundBeforeCommit,
+ info.first_background_time);
+ }
+ }
+
+ // The rest of the histograms require the load to have commit and be relevant.
+ // If |timing.IsEmpty()|, then this load was not tracked by the renderer.
+ if (info.time_to_commit.is_zero() || timing.IsEmpty())
+ return;
+
+ if (EventOccurredInForeground(info.time_to_commit, info)) {
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramCommit, info.time_to_commit);
+ } else {
+ PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramCommit,
+ info.time_to_commit);
+ }
+ if (!timing.dom_content_loaded_event_start.is_zero()) {
+ if (EventOccurredInForeground(timing.dom_content_loaded_event_start,
+ info)) {
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramDomContentLoaded,
+ timing.dom_content_loaded_event_start);
+ } else {
+ PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramDomContentLoaded,
+ timing.dom_content_loaded_event_start);
+ }
+ }
+ if (!timing.load_event_start.is_zero()) {
+ if (EventOccurredInForeground(timing.load_event_start, info)) {
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramLoad, timing.load_event_start);
+ } else {
+ PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramLoad,
+ timing.load_event_start);
+ }
+ }
+ if (!timing.first_layout.is_zero()) {
+ if (EventOccurredInForeground(timing.first_layout, info)) {
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstLayout, timing.first_layout);
+ } else {
+ PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramFirstLayout,
+ timing.first_layout);
+ }
+ }
+ if (!timing.first_paint.is_zero()) {
+ if (EventOccurredInForeground(timing.first_paint, info)) {
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstPaint, timing.first_paint);
+ } else {
+ PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramFirstPaint,
+ timing.first_paint);
+ }
+ }
+ if (!timing.first_text_paint.is_zero()) {
+ if (EventOccurredInForeground(timing.first_text_paint, info)) {
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstTextPaint,
+ timing.first_text_paint);
+ } else {
+ PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramFirstTextPaint,
+ timing.first_text_paint);
+ }
+ }
+ if (!timing.first_image_paint.is_zero()) {
+ if (EventOccurredInForeground(timing.first_image_paint, info)) {
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstImagePaint,
+ timing.first_image_paint);
+ } else {
+ PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramFirstImagePaint,
+ timing.first_image_paint);
+ }
+ }
+ base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing);
+ if (!first_contentful_paint.is_zero()) {
+ if (EventOccurredInForeground(first_contentful_paint, info)) {
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstContentfulPaint,
+ first_contentful_paint);
+ // Bucket these histograms into high/low resolution clock systems. This
+ // might point us to directions that will de-noise some UMA.
+ if (base::TimeTicks::IsHighResolution()) {
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstContentfulPaintHigh,
+ first_contentful_paint);
+ } else {
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstContentfulPaintLow,
+ first_contentful_paint);
+ }
+ } else {
+ PAGE_LOAD_HISTOGRAM(internal::kBackgroundHistogramFirstContentfulPaint,
+ first_contentful_paint);
+ }
+ }
+
+ // Log time to first foreground / time to first background. Log counts that we
+ // started a relevant page load in the foreground / background.
+ if (!info.first_background_time.is_zero())
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstBackground,
+ info.first_background_time);
+ else if (!info.first_foreground_time.is_zero())
+ PAGE_LOAD_HISTOGRAM(internal::kHistogramFirstForeground,
+ info.first_foreground_time);
+}
+
+void CorePageLoadMetricsObserver::RecordRappor(
+ const page_load_metrics::PageLoadTiming& timing,
+ const page_load_metrics::PageLoadExtraInfo& info) {
+ // During the browser process shutdown path, calling
+ // BrowserProcess::rappor_service() can reinitialize multiple destroyed
+ // objects. This alters shutdown ordering, so we avoid it by testing
+ // IsShuttingDown() first.
+ if (g_browser_process->IsShuttingDown())
+ return;
+ rappor::RapporService* rappor_service = g_browser_process->rappor_service();
+ if (!rappor_service)
+ return;
+ if (info.time_to_commit.is_zero())
+ return;
+ DCHECK(!info.committed_url.is_empty());
+ base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing);
+ // Log the eTLD+1 of sites that show poor loading performance.
+ if (!EventOccurredInForeground(first_contentful_paint, info)) {
+ return;
+ }
+ scoped_ptr<rappor::Sample> sample =
+ rappor_service->CreateSample(rappor::UMA_RAPPOR_TYPE);
+ sample->SetStringField(
+ "Domain", rappor::GetDomainAndRegistrySampleFromGURL(info.committed_url));
+ uint64_t bucket_index = RapporHistogramBucketIndex(first_contentful_paint);
+ sample->SetFlagsField("Bucket", uint64_t(1) << bucket_index,
+ kNumRapporHistogramBuckets);
+ // The IsSlow flag is just a one bit boolean if the first contentful paint
+ // was > 10s.
+ sample->SetFlagsField("IsSlow", first_contentful_paint.InSecondsF() >= 10, 1);
+ rappor_service->RecordSampleObj(internal::kRapporMetricsNameCoarseTiming,
+ std::move(sample));
+}
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h
new file mode 100644
index 0000000..cc7329a
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h
@@ -0,0 +1,68 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_CORE_PAGE_LOAD_METRICS_OBSERVER_H_
+#define CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_CORE_PAGE_LOAD_METRICS_OBSERVER_H_
+
+#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
+
+namespace internal {
+
+// NOTE: Some of these histograms are separated into a separate histogram
+// specified by the ".Background" suffix. For these events, we put them into the
+// background histogram if the web contents was ever in the background from
+// navigation start to the event in question.
+extern const char kHistogramCommit[];
+extern const char kHistogramFirstLayout[];
+extern const char kHistogramFirstTextPaint[];
+extern const char kHistogramDomContentLoaded[];
+extern const char kHistogramLoad[];
+extern const char kHistogramFirstPaint[];
+extern const char kHistogramFirstImagePaint[];
+extern const char kHistogramFirstContentfulPaint[];
+extern const char kBackgroundHistogramCommit[];
+extern const char kBackgroundHistogramFirstLayout[];
+extern const char kBackgroundHistogramFirstTextPaint[];
+extern const char kBackgroundHistogramDomContentLoaded[];
+extern const char kBackgroundHistogramLoad[];
+extern const char kBackgroundHistogramFirstPaint[];
+extern const char kBackgroundHistogramFirstImagePaint[];
+extern const char kBackgroundHistogramFirstContentfulPaint[];
+
+extern const char kHistogramFirstContentfulPaintHigh[];
+extern const char kHistogramFirstContentfulPaintLow[];
+
+extern const char kHistogramFirstBackground[];
+extern const char kHistogramFirstForeground[];
+
+extern const char kHistogramBackgroundBeforePaint[];
+extern const char kHistogramBackgroundBeforeCommit[];
+
+extern const char kRapporMetricsNameCoarseTiming[];
+
+} // namespace internal
+
+// Observer responsible for recording 'core' page load metrics. Core metrics are
+// maintained by loading-dev team, typically the metrics under
+// PageLoad.Timing2.*.
+class CorePageLoadMetricsObserver
+ : public page_load_metrics::PageLoadMetricsObserver {
+ public:
+ CorePageLoadMetricsObserver();
+ ~CorePageLoadMetricsObserver() override;
+
+ // page_load_metrics::PageLoadMetricsObserver:
+ void OnComplete(const page_load_metrics::PageLoadTiming& timing,
+ const page_load_metrics::PageLoadExtraInfo& info) override;
+
+ private:
+ void RecordTimingHistograms(const page_load_metrics::PageLoadTiming& timing,
+ const page_load_metrics::PageLoadExtraInfo& info);
+ void RecordRappor(const page_load_metrics::PageLoadTiming& timing,
+ const page_load_metrics::PageLoadExtraInfo& info);
+
+ DISALLOW_COPY_AND_ASSIGN(CorePageLoadMetricsObserver);
+};
+
+#endif // CHROME_BROWSER_PAGE_LOAD_METRICS_OBSERVERS_CORE_PAGE_LOAD_METRICS_OBSERVER_H_
diff --git a/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
new file mode 100644
index 0000000..757e0bf
--- /dev/null
+++ b/chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc
@@ -0,0 +1,334 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h"
+#include "chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h"
+#include "chrome/test/base/testing_browser_process.h"
+#include "components/rappor/rappor_utils.h"
+#include "components/rappor/test_rappor_service.h"
+
+namespace {
+
+const char kDefaultTestUrl[] = "https://google.com";
+const char kDefaultTestUrlAnchor[] = "https://google.com#samepage";
+const char kDefaultTestUrl2[] = "https://whatever.com";
+
+} // namespace
+
+class CorePageLoadMetricsObserverTest
+ : public page_load_metrics::PageLoadMetricsObserverTestHarness {
+ protected:
+ void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override {
+ tracker->AddObserver(make_scoped_ptr(new CorePageLoadMetricsObserver()));
+ }
+
+ void AssertNoHistogramsLogged() {
+ histogram_tester().ExpectTotalCount(internal::kHistogramDomContentLoaded,
+ 0);
+ histogram_tester().ExpectTotalCount(internal::kHistogramLoad, 0);
+ histogram_tester().ExpectTotalCount(internal::kHistogramFirstLayout, 0);
+ histogram_tester().ExpectTotalCount(internal::kHistogramFirstTextPaint, 0);
+ }
+
+ void SetUp() override {
+ page_load_metrics::PageLoadMetricsObserverTestHarness::SetUp();
+ TestingBrowserProcess::GetGlobal()->SetRapporService(&rappor_tester_);
+ }
+
+ rappor::TestRapporService rappor_tester_;
+};
+
+TEST_F(CorePageLoadMetricsObserverTest, NoMetrics) {
+ AssertNoHistogramsLogged();
+}
+
+TEST_F(CorePageLoadMetricsObserverTest, SamePageNoTriggerUntilTrueNavCommit) {
+ base::TimeDelta first_layout = base::TimeDelta::FromMilliseconds(1);
+
+ page_load_metrics::PageLoadTiming timing;
+ timing.navigation_start = base::Time::FromDoubleT(1);
+ timing.first_layout = first_layout;
+
+ NavigateAndCommit(GURL(kDefaultTestUrl));
+ SimulateTimingUpdate(timing);
+
+ NavigateAndCommit(GURL(kDefaultTestUrlAnchor));
+ // A same page navigation shouldn't trigger logging UMA for the original.
+ AssertNoHistogramsLogged();
+
+ // But we should keep the timing info and log it when we get another
+ // navigation.
+ NavigateAndCommit(GURL(kDefaultTestUrl2));
+ histogram_tester().ExpectTotalCount(internal::kHistogramCommit, 1);
+ histogram_tester().ExpectTotalCount(internal::kHistogramDomContentLoaded, 0);
+ histogram_tester().ExpectTotalCount(internal::kHistogramLoad, 0);
+ histogram_tester().ExpectTotalCount(internal::kHistogramFirstLayout, 1);
+ histogram_tester().ExpectBucketCount(internal::kHistogramFirstLayout,
+ first_layout.InMilliseconds(), 1);
+ histogram_tester().ExpectTotalCount(internal::kHistogramFirstTextPaint, 0);
+}
+
+TEST_F(CorePageLoadMetricsObserverTest, SingleMetricAfterCommit) {
+ base::TimeDelta first_layout = base::TimeDelta::FromMilliseconds(1);
+
+ page_load_metrics::PageLoadTiming timing;
+ timing.navigation_start = base::Time::FromDoubleT(1);
+ timing.first_layout = first_layout;
+
+ NavigateAndCommit(GURL(kDefaultTestUrl));
+ SimulateTimingUpdate(timing);
+
+ AssertNoHistogramsLogged();
+
+ // Navigate again to force histogram recording.
+ NavigateAndCommit(GURL(kDefaultTestUrl2));
+
+ histogram_tester().ExpectTotalCount(internal::kHistogramCommit, 1);
+ histogram_tester().ExpectTotalCount(internal::kHistogramDomContentLoaded, 0);
+ histogram_tester().ExpectTotalCount(internal::kHistogramLoad, 0);
+ histogram_tester().ExpectTotalCount(internal::kHistogramFirstLayout, 1);
+ histogram_tester().ExpectBucketCount(internal::kHistogramFirstLayout,
+ first_layout.InMilliseconds(), 1);
+ histogram_tester().ExpectTotalCount(internal::kHistogramFirstTextPaint, 0);
+}
+
+TEST_F(CorePageLoadMetricsObserverTest, MultipleMetricsAfterCommits) {
+ base::TimeDelta first_layout_1 = base::TimeDelta::FromMilliseconds(1);
+ base::TimeDelta first_layout_2 = base::TimeDelta::FromMilliseconds(20);
+ base::TimeDelta response = base::TimeDelta::FromMilliseconds(10);
+ base::TimeDelta first_text_paint = base::TimeDelta::FromMilliseconds(30);
+ base::TimeDelta dom_content = base::TimeDelta::FromMilliseconds(40);
+ base::TimeDelta load = base::TimeDelta::FromMilliseconds(100);
+
+ page_load_metrics::PageLoadTiming timing;
+ timing.navigation_start = base::Time::FromDoubleT(1);
+ timing.first_layout = first_layout_1;
+ timing.response_start = response;
+ timing.first_text_paint = first_text_paint;
+ timing.dom_content_loaded_event_start = dom_content;
+ timing.load_event_start = load;
+
+ NavigateAndCommit(GURL(kDefaultTestUrl));
+ SimulateTimingUpdate(timing);
+
+ NavigateAndCommit(GURL(kDefaultTestUrl2));
+
+ page_load_metrics::PageLoadTiming timing2;
+ timing2.navigation_start = base::Time::FromDoubleT(200);
+ timing2.first_layout = first_layout_2;
+
+ SimulateTimingUpdate(timing2);
+
+ NavigateAndCommit(GURL(kDefaultTestUrl));
+
+ histogram_tester().ExpectTotalCount(internal::kHistogramCommit, 2);
+ histogram_tester().ExpectBucketCount(internal::kHistogramFirstLayout,
+ first_layout_1.InMilliseconds(), 1);
+ histogram_tester().ExpectTotalCount(internal::kHistogramFirstLayout, 2);
+ histogram_tester().ExpectBucketCount(internal::kHistogramFirstLayout,
+ first_layout_1.InMilliseconds(), 1);
+ histogram_tester().ExpectBucketCount(internal::kHistogramFirstLayout,
+ first_layout_2.InMilliseconds(), 1);
+
+ histogram_tester().ExpectTotalCount(internal::kHistogramFirstTextPaint, 1);
+ histogram_tester().ExpectBucketCount(internal::kHistogramFirstTextPaint,
+ first_text_paint.InMilliseconds(), 1);
+
+ histogram_tester().ExpectTotalCount(internal::kHistogramDomContentLoaded, 1);
+ histogram_tester().ExpectBucketCount(internal::kHistogramDomContentLoaded,
+ dom_content.InMilliseconds(), 1);
+
+ histogram_tester().ExpectTotalCount(internal::kHistogramLoad, 1);
+ histogram_tester().ExpectBucketCount(internal::kHistogramLoad,
+ load.InMilliseconds(), 1);
+}
+
+TEST_F(CorePageLoadMetricsObserverTest, BackgroundDifferentHistogram) {
+ base::TimeDelta first_layout = base::TimeDelta::FromSeconds(2);
+
+ page_load_metrics::PageLoadTiming timing;
+ timing.navigation_start = base::Time::FromDoubleT(1);
+ timing.first_layout = first_layout;
+
+ // Simulate "Open link in new tab."
+ web_contents()->WasHidden();
+ NavigateAndCommit(GURL(kDefaultTestUrl));
+ SimulateTimingUpdate(timing);
+
+ // Simulate switching to the tab and making another navigation.
+ web_contents()->WasShown();
+ AssertNoHistogramsLogged();
+
+ // Navigate again to force histogram recording.
+ NavigateAndCommit(GURL(kDefaultTestUrl2));
+
+ histogram_tester().ExpectTotalCount(internal::kBackgroundHistogramCommit, 1);
+ histogram_tester().ExpectTotalCount(
+ internal::kBackgroundHistogramDomContentLoaded, 0);
+ histogram_tester().ExpectTotalCount(internal::kBackgroundHistogramLoad, 0);
+ histogram_tester().ExpectTotalCount(internal::kBackgroundHistogramFirstLayout,
+ 1);
+ histogram_tester().ExpectBucketCount(
+ internal::kBackgroundHistogramFirstLayout, first_layout.InMilliseconds(),
+ 1);
+ histogram_tester().ExpectTotalCount(
+ internal::kBackgroundHistogramFirstTextPaint, 0);
+
+ histogram_tester().ExpectTotalCount(internal::kHistogramCommit, 0);
+ histogram_tester().ExpectTotalCount(internal::kHistogramDomContentLoaded, 0);
+ histogram_tester().ExpectTotalCount(internal::kHistogramLoad, 0);
+ histogram_tester().ExpectTotalCount(internal::kHistogramFirstLayout, 0);
+ histogram_tester().ExpectTotalCount(internal::kHistogramFirstTextPaint, 0);
+}
+
+TEST_F(CorePageLoadMetricsObserverTest, OnlyBackgroundLaterEvents) {
+ page_load_metrics::PageLoadTiming timing;
+ timing.navigation_start = base::Time::FromDoubleT(1);
+ // Set these events at 1 microsecond so they are definitely occur before we
+ // background the tab later in the test.
+ timing.response_start = base::TimeDelta::FromMicroseconds(1);
+ timing.dom_content_loaded_event_start = base::TimeDelta::FromMicroseconds(1);
+
+ NavigateAndCommit(GURL(kDefaultTestUrl));
+ SimulateTimingUpdate(timing);
+
+ // Background the tab, then forground it.
+ web_contents()->WasHidden();
+ web_contents()->WasShown();
+ timing.first_layout = base::TimeDelta::FromSeconds(3);
+ timing.first_text_paint = base::TimeDelta::FromSeconds(4);
+ SimulateTimingUpdate(timing);
+
+ // Navigate again to force histogram recording.
+ NavigateAndCommit(GURL(kDefaultTestUrl2));
+
+ histogram_tester().ExpectTotalCount(internal::kBackgroundHistogramCommit, 0);
+ histogram_tester().ExpectTotalCount(
+ internal::kBackgroundHistogramDomContentLoaded, 0);
+ histogram_tester().ExpectTotalCount(internal::kBackgroundHistogramLoad, 0);
+ histogram_tester().ExpectTotalCount(internal::kBackgroundHistogramFirstLayout,
+ 1);
+ histogram_tester().ExpectBucketCount(
+ internal::kBackgroundHistogramFirstLayout,
+ timing.first_layout.InMilliseconds(), 1);
+ histogram_tester().ExpectTotalCount(
+ internal::kBackgroundHistogramFirstTextPaint, 1);
+ histogram_tester().ExpectBucketCount(
+ internal::kBackgroundHistogramFirstTextPaint,
+ timing.first_text_paint.InMilliseconds(), 1);
+
+ histogram_tester().ExpectTotalCount(internal::kHistogramCommit, 1);
+ histogram_tester().ExpectTotalCount(internal::kHistogramDomContentLoaded, 1);
+ histogram_tester().ExpectBucketCount(
+ internal::kHistogramDomContentLoaded,
+ timing.dom_content_loaded_event_start.InMilliseconds(), 1);
+ histogram_tester().ExpectTotalCount(internal::kHistogramLoad, 0);
+ histogram_tester().ExpectTotalCount(internal::kHistogramFirstLayout, 0);
+ histogram_tester().ExpectTotalCount(internal::kHistogramFirstTextPaint, 0);
+}
+
+TEST_F(CorePageLoadMetricsObserverTest, DontBackgroundQuickerLoad) {
+ // Set this event at 1 microsecond so it occurs before we foreground later in
+ // the test.
+ base::TimeDelta first_layout = base::TimeDelta::FromMicroseconds(1);
+
+ page_load_metrics::PageLoadTiming timing;
+ timing.navigation_start = base::Time::FromDoubleT(1);
+ timing.first_layout = first_layout;
+
+ web_contents()->WasHidden();
+
+ // Open in new tab
+ StartNavigation(GURL(kDefaultTestUrl));
+
+ // Switch to the tab
+ web_contents()->WasShown();
+
+ // Start another provisional load
+ StartNavigation(GURL(kDefaultTestUrl2));
+ content::RenderFrameHostTester* rfh_tester =
+ content::RenderFrameHostTester::For(main_rfh());
+ rfh_tester->SimulateNavigationCommit(GURL(kDefaultTestUrl2));
+ SimulateTimingUpdate(timing);
+ rfh_tester->SimulateNavigationStop();
+
+ // Navigate again to see if the timing updated for the foregrounded load.
+ NavigateAndCommit(GURL(kDefaultTestUrl));
+
+ histogram_tester().ExpectTotalCount(internal::kHistogramCommit, 1);
+ histogram_tester().ExpectTotalCount(internal::kHistogramDomContentLoaded, 0);
+ histogram_tester().ExpectTotalCount(internal::kHistogramLoad, 0);
+ histogram_tester().ExpectTotalCount(internal::kHistogramFirstLayout, 1);
+ histogram_tester().ExpectBucketCount(internal::kHistogramFirstLayout,
+ first_layout.InMilliseconds(), 1);
+ histogram_tester().ExpectTotalCount(internal::kHistogramFirstTextPaint, 0);
+}
+
+TEST_F(CorePageLoadMetricsObserverTest, BackgroundBeforePaint) {
+ page_load_metrics::PageLoadTiming timing;
+ timing.navigation_start = base::Time::FromDoubleT(1);
+ timing.first_paint = base::TimeDelta::FromSeconds(10);
+ NavigateAndCommit(GURL(kDefaultTestUrl));
+ // Background the tab and go for a coffee or something.
+ web_contents()->WasHidden();
+ SimulateTimingUpdate(timing);
+ // Come back and start browsing again.
+ web_contents()->WasShown();
+ // Simulate the user performaning another navigation.
+ NavigateAndCommit(GURL("https://www.example.com"));
+ histogram_tester().ExpectTotalCount(internal::kHistogramBackgroundBeforePaint,
+ 1);
+}
+
+TEST_F(CorePageLoadMetricsObserverTest, NoRappor) {
+ rappor::TestSample::Shadow* sample_obj =
+ rappor_tester_.GetRecordedSampleForMetric(
+ internal::kRapporMetricsNameCoarseTiming);
+ EXPECT_EQ(sample_obj, nullptr);
+}
+
+TEST_F(CorePageLoadMetricsObserverTest, RapporLongPageLoad) {
+ page_load_metrics::PageLoadTiming timing;
+ timing.navigation_start = base::Time::FromDoubleT(1);
+ timing.first_image_paint = base::TimeDelta::FromSeconds(40);
+ NavigateAndCommit(GURL(kDefaultTestUrl));
+ SimulateTimingUpdate(timing);
+
+ // Navigate again to force logging RAPPOR.
+ NavigateAndCommit(GURL(kDefaultTestUrl2));
+ rappor::TestSample::Shadow* sample_obj =
+ rappor_tester_.GetRecordedSampleForMetric(
+ internal::kRapporMetricsNameCoarseTiming);
+ const auto& string_it = sample_obj->string_fields.find("Domain");
+ EXPECT_NE(string_it, sample_obj->string_fields.end());
+ EXPECT_EQ(rappor::GetDomainAndRegistrySampleFromGURL(GURL(kDefaultTestUrl)),
+ string_it->second);
+
+ const auto& flag_it = sample_obj->flag_fields.find("IsSlow");
+ EXPECT_NE(flag_it, sample_obj->flag_fields.end());
+ EXPECT_EQ(1u, flag_it->second);
+}
+
+TEST_F(CorePageLoadMetricsObserverTest, RapporQuickPageLoad) {
+ page_load_metrics::PageLoadTiming timing;
+ timing.navigation_start = base::Time::FromDoubleT(1);
+ timing.first_text_paint = base::TimeDelta::FromSeconds(1);
+
+ NavigateAndCommit(GURL(kDefaultTestUrl));
+ SimulateTimingUpdate(timing);
+
+ // Navigate again to force logging RAPPOR.
+ NavigateAndCommit(GURL(kDefaultTestUrl2));
+ rappor::TestSample::Shadow* sample_obj =
+ rappor_tester_.GetRecordedSampleForMetric(
+ internal::kRapporMetricsNameCoarseTiming);
+ const auto& string_it = sample_obj->string_fields.find("Domain");
+ EXPECT_NE(string_it, sample_obj->string_fields.end());
+ EXPECT_EQ(rappor::GetDomainAndRegistrySampleFromGURL(GURL(kDefaultTestUrl)),
+ string_it->second);
+
+ const auto& flag_it = sample_obj->flag_fields.find("IsSlow");
+ EXPECT_NE(flag_it, sample_obj->flag_fields.end());
+ EXPECT_EQ(0u, flag_it->second);
+}
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
index 24b5589..44ff512 100644
--- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
+++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc
@@ -19,8 +19,6 @@ class TestPageLoadMetricsEmbedderInterface
PageLoadMetricsObserverTestHarness* test)
: test_(test) {}
- rappor::RapporService* GetRapporService() override { return nullptr; }
-
bool IsPrerendering(content::WebContents* web_contents) override {
return false;
}
diff --git a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h
index c2abae4..56e0832 100644
--- a/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h
+++ b/chrome/browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h
@@ -11,10 +11,6 @@
#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
#include "content/public/test/web_contents_tester.h"
-namespace rappor {
-class RapporService;
-} // namespace rappor
-
namespace page_load_metrics {
// This class can be used to drive tests of PageLoadMetricsObservers. To hook up
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
index 74d9f81..1d6d56c 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -4,17 +4,15 @@
#include "base/macros.h"
#include "base/test/histogram_tester.h"
+#include "chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
-#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
-namespace page_load_metrics {
-
class MetricsWebContentsObserverBrowserTest : public InProcessBrowserTest {
public:
- MetricsWebContentsObserverBrowserTest(){};
- ~MetricsWebContentsObserverBrowserTest() override{};
+ MetricsWebContentsObserverBrowserTest() {}
+ ~MetricsWebContentsObserverBrowserTest() override {}
protected:
base::HistogramTester histogram_tester_;
@@ -25,9 +23,9 @@ class MetricsWebContentsObserverBrowserTest : public InProcessBrowserTest {
IN_PROC_BROWSER_TEST_F(MetricsWebContentsObserverBrowserTest, NoNavigation) {
ASSERT_TRUE(embedded_test_server()->Start());
- histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0);
- histogram_tester_.ExpectTotalCount(kHistogramLoad, 0);
- histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 0);
+ histogram_tester_.ExpectTotalCount(internal::kHistogramDomContentLoaded, 0);
+ histogram_tester_.ExpectTotalCount(internal::kHistogramLoad, 0);
+ histogram_tester_.ExpectTotalCount(internal::kHistogramFirstLayout, 0);
}
IN_PROC_BROWSER_TEST_F(MetricsWebContentsObserverBrowserTest, NewPage) {
@@ -38,9 +36,9 @@ IN_PROC_BROWSER_TEST_F(MetricsWebContentsObserverBrowserTest, NewPage) {
ui_test_utils::NavigateToURL(browser(),
embedded_test_server()->GetURL("/title2.html"));
- histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 1);
- histogram_tester_.ExpectTotalCount(kHistogramLoad, 1);
- histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 1);
+ histogram_tester_.ExpectTotalCount(internal::kHistogramDomContentLoaded, 1);
+ histogram_tester_.ExpectTotalCount(internal::kHistogramLoad, 1);
+ histogram_tester_.ExpectTotalCount(internal::kHistogramFirstLayout, 1);
}
IN_PROC_BROWSER_TEST_F(MetricsWebContentsObserverBrowserTest, AnchorLink) {
@@ -53,9 +51,7 @@ IN_PROC_BROWSER_TEST_F(MetricsWebContentsObserverBrowserTest, AnchorLink) {
ui_test_utils::NavigateToURL(browser(),
embedded_test_server()->GetURL("/title2.html"));
- histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 1);
- histogram_tester_.ExpectTotalCount(kHistogramLoad, 1);
- histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 1);
+ histogram_tester_.ExpectTotalCount(internal::kHistogramDomContentLoaded, 1);
+ histogram_tester_.ExpectTotalCount(internal::kHistogramLoad, 1);
+ histogram_tester_.ExpectTotalCount(internal::kHistogramFirstLayout, 1);
}
-
-} // namespace page_load_metrics
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
index a66737d..d922118 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.cc
@@ -4,8 +4,8 @@
#include "chrome/browser/page_load_metrics/page_load_metrics_initialize.h"
-#include "chrome/browser/browser_process.h"
#include "chrome/browser/page_load_metrics/observers/aborts_page_load_metrics_observer.h"
+#include "chrome/browser/page_load_metrics/observers/core_page_load_metrics_observer.h"
#include "chrome/browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h"
#include "chrome/browser/page_load_metrics/observers/google_captcha_observer.h"
#include "chrome/browser/page_load_metrics/observers/stale_while_revalidate_metrics_observer.h"
@@ -19,8 +19,7 @@ namespace chrome {
void InitializePageLoadMetricsForWebContents(
content::WebContents* web_contents) {
page_load_metrics::MetricsWebContentsObserver::CreateForWebContents(
- web_contents,
- make_scoped_ptr(new PageLoadMetricsEmbedder()));
+ web_contents, make_scoped_ptr(new PageLoadMetricsEmbedder()));
}
PageLoadMetricsEmbedder::~PageLoadMetricsEmbedder() {}
@@ -28,22 +27,14 @@ PageLoadMetricsEmbedder::~PageLoadMetricsEmbedder() {}
void PageLoadMetricsEmbedder::RegisterObservers(
page_load_metrics::PageLoadTracker* tracker) {
// These classes are owned by the metrics.
+ tracker->AddObserver(make_scoped_ptr(new AbortsPageLoadMetricsObserver()));
+ tracker->AddObserver(make_scoped_ptr(new CorePageLoadMetricsObserver()));
tracker->AddObserver(make_scoped_ptr(new FromGWSPageLoadMetricsObserver()));
tracker->AddObserver(
make_scoped_ptr(new google_captcha_observer::GoogleCaptchaObserver()));
// TODO(ricea): Remove this in April 2016 or before. crbug.com/348877
tracker->AddObserver(
make_scoped_ptr(new chrome::StaleWhileRevalidateMetricsObserver()));
- tracker->AddObserver(make_scoped_ptr(new AbortsPageLoadMetricsObserver()));
-}
-
-rappor::RapporService*
-PageLoadMetricsEmbedder::GetRapporService() {
- // During the browser process shutdown path, calling this getter can
- // reinitialize multiple destroyed objects. This alters shutdown ordering.
- if (g_browser_process->IsShuttingDown())
- return nullptr;
- return g_browser_process->rappor_service();
}
bool PageLoadMetricsEmbedder::IsPrerendering(
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_initialize.h b/chrome/browser/page_load_metrics/page_load_metrics_initialize.h
index e3aaa79..4ffca06 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_initialize.h
+++ b/chrome/browser/page_load_metrics/page_load_metrics_initialize.h
@@ -11,10 +11,6 @@ namespace content {
class WebContents;
}
-namespace rappor {
-class RapporService;
-}
-
namespace chrome {
void InitializePageLoadMetricsForWebContents(
@@ -25,7 +21,6 @@ class PageLoadMetricsEmbedder
public:
// PageLoadMetricsEmbedderInterface:
~PageLoadMetricsEmbedder() override;
- rappor::RapporService* GetRapporService() override;
bool IsPrerendering(content::WebContents* web_contents) override;
void RegisterObservers(page_load_metrics::PageLoadTracker* tracker) override;
};
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 8e00aef..859490d 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -398,6 +398,8 @@
'browser/ntp_snippets/ntp_snippets_service_factory.h',
'browser/page_load_metrics/observers/aborts_page_load_metrics_observer.cc',
'browser/page_load_metrics/observers/aborts_page_load_metrics_observer.h',
+ 'browser/page_load_metrics/observers/core_page_load_metrics_observer.cc',
+ 'browser/page_load_metrics/observers/core_page_load_metrics_observer.h',
'browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.cc',
'browser/page_load_metrics/observers/from_gws_page_load_metrics_observer.h',
'browser/page_load_metrics/observers/google_captcha_observer.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index 06dd478..225ccb9 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -158,6 +158,7 @@
'browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.cc',
'browser/page_load_metrics/observers/page_load_metrics_observer_test_harness.h',
'browser/page_load_metrics/observers/aborts_page_load_metrics_observer_unittest.cc',
+ 'browser/page_load_metrics/observers/core_page_load_metrics_observer_unittest.cc',
'browser/page_load_metrics/observers/from_gws_page_load_metrics_observer_unittest.cc',
'browser/page_load_metrics/observers/google_captcha_observer_unittest.cc',
'browser/password_manager/chrome_password_manager_client_unittest.cc',
diff --git a/chrome/test/base/testing_browser_process.cc b/chrome/test/base/testing_browser_process.cc
index c799f31..69a89d928 100644
--- a/chrome/test/base/testing_browser_process.cc
+++ b/chrome/test/base/testing_browser_process.cc
@@ -73,6 +73,7 @@ TestingBrowserProcess::TestingBrowserProcess()
local_state_(nullptr),
io_thread_(nullptr),
system_request_context_(nullptr),
+ rappor_service_(nullptr),
platform_part_(new TestingBrowserProcessPlatformPart()) {
#if defined(ENABLE_EXTENSIONS)
extensions_browser_client_.reset(
@@ -112,7 +113,7 @@ metrics::MetricsService* TestingBrowserProcess::metrics_service() {
}
rappor::RapporService* TestingBrowserProcess::rappor_service() {
- return nullptr;
+ return rappor_service_;
}
IOThread* TestingBrowserProcess::io_thread() {
@@ -453,6 +454,11 @@ void TestingBrowserProcess::SetSafeBrowsingService(
#endif
}
+void TestingBrowserProcess::SetRapporService(
+ rappor::RapporService* rappor_service) {
+ rappor_service_ = rappor_service;
+}
+
///////////////////////////////////////////////////////////////////////////////
TestingBrowserProcessInitializer::TestingBrowserProcessInitializer() {
diff --git a/chrome/test/base/testing_browser_process.h b/chrome/test/base/testing_browser_process.h
index e63c13a..0a185e8 100644
--- a/chrome/test/base/testing_browser_process.h
+++ b/chrome/test/base/testing_browser_process.h
@@ -139,6 +139,7 @@ class TestingBrowserProcess : public BrowserProcess {
void SetSystemRequestContext(net::URLRequestContextGetter* context_getter);
void SetNotificationUIManager(
scoped_ptr<NotificationUIManager> notification_ui_manager);
+ void SetRapporService(rappor::RapporService* rappor_service);
void ShutdownBrowserPolicyConnector();
private:
@@ -180,6 +181,7 @@ class TestingBrowserProcess : public BrowserProcess {
PrefService* local_state_;
IOThread* io_thread_;
net::URLRequestContextGetter* system_request_context_;
+ rappor::RapporService* rappor_service_;
scoped_ptr<BrowserProcessPlatformPart> platform_part_;
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.cc b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
index ab15c52..d2decce 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
@@ -4,8 +4,6 @@
#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
-#include <stddef.h>
-#include <stdint.h>
#include <utility>
#include "base/location.h"
@@ -15,8 +13,6 @@
#include "components/page_load_metrics/browser/page_load_metrics_util.h"
#include "components/page_load_metrics/common/page_load_metrics_messages.h"
#include "components/page_load_metrics/common/page_load_timing.h"
-#include "components/rappor/rappor_service.h"
-#include "components/rappor/rappor_utils.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_handle.h"
@@ -38,10 +34,9 @@ namespace {
// The url we see from the renderer side is not always the same as what
// we see from the browser side (e.g. chrome://newtab). We want to be
// sure here that we aren't logging UMA for internal pages.
-bool IsRelevantNavigation(
- content::NavigationHandle* navigation_handle,
- const GURL& browser_url,
- const std::string& mime_type) {
+bool IsRelevantNavigation(content::NavigationHandle* navigation_handle,
+ const GURL& browser_url,
+ const std::string& mime_type) {
DCHECK(navigation_handle->HasCommitted());
return navigation_handle->IsInMainFrame() &&
!navigation_handle->IsSamePage() &&
@@ -83,7 +78,7 @@ bool IsValidPageLoadTiming(const PageLoadTiming& timing) {
}
void RecordInternalError(InternalErrorLoadEvent event) {
- UMA_HISTOGRAM_ENUMERATION(kErrorEvents, event, ERR_LAST_ENTRY);
+ UMA_HISTOGRAM_ENUMERATION(internal::kErrorEvents, event, ERR_LAST_ENTRY);
}
UserAbortType AbortTypeForPageTransition(ui::PageTransition transition) {
@@ -97,31 +92,17 @@ UserAbortType AbortTypeForPageTransition(ui::PageTransition transition) {
return ABORT_OTHER;
}
-// The number of buckets in the bitfield histogram. These buckets are described
-// in rappor.xml in PageLoad.CoarseTiming.NavigationToFirstContentfulPaint.
-// The bucket flag is defined by 1 << bucket_index, and is the bitfield
-// representing which timing bucket the page load falls into, i.e. 000010
-// would be the bucket flag showing that the page took between 2 and 4 seconds
-// to load.
-const size_t kNumRapporHistogramBuckets = 6;
-
-uint64_t RapporHistogramBucketIndex(const base::TimeDelta& time) {
- int64_t seconds = time.InSeconds();
- if (seconds < 2)
- return 0;
- if (seconds < 4)
- return 1;
- if (seconds < 8)
- return 2;
- if (seconds < 16)
- return 3;
- if (seconds < 32)
- return 4;
- return 5;
-}
-
} // namespace
+namespace internal {
+
+const char kProvisionalEvents[] = "PageLoad.Events.Provisional";
+const char kBackgroundProvisionalEvents[] =
+ "PageLoad.Events.Provisional.Background";
+const char kErrorEvents[] = "PageLoad.Events.InternalError";
+
+} // namespace internal
+
PageLoadTracker::PageLoadTracker(
bool in_foreground,
PageLoadMetricsEmbedderInterface* embedder_interface,
@@ -138,9 +119,11 @@ PageLoadTracker::PageLoadTracker(
}
PageLoadTracker::~PageLoadTracker() {
- PageLoadExtraInfo info = GetPageLoadMetricsInfo();
- RecordRappor(info);
- RecordTimingHistograms(info);
+ const PageLoadExtraInfo info = GetPageLoadMetricsInfo();
+ if (!info.time_to_commit.is_zero() && renderer_tracked() &&
+ timing_.IsEmpty()) {
+ RecordInternalError(ERR_NO_IPCS_RECEIVED);
+ }
for (const auto& observer : observers_) {
observer->OnComplete(timing_, info);
}
@@ -163,7 +146,7 @@ void PageLoadTracker::Commit(content::NavigationHandle* navigation_handle) {
// TODO(bmcquade): To improve accuracy, consider adding commit time to
// NavigationHandle. Taking a timestamp here should be close enough for now.
commit_time_ = base::TimeTicks::Now();
- url_ = navigation_handle->GetURL();
+ committed_url_ = navigation_handle->GetURL();
for (const auto& observer : observers_) {
observer->OnCommit(navigation_handle);
}
@@ -218,18 +201,15 @@ PageLoadExtraInfo PageLoadTracker::GetPageLoadMetricsInfo() {
} else {
DCHECK(abort_time_.is_null());
}
- if (!commit_time_.is_null()) {
+ if (!committed_url_.is_empty()) {
DCHECK_GT(commit_time_, navigation_start_);
time_to_commit = commit_time_ - navigation_start_;
+ } else {
+ DCHECK(commit_time_.is_null());
}
return PageLoadExtraInfo(first_background_time, first_foreground_time,
- started_in_foreground_, time_to_commit, abort_type_,
- time_to_abort);
-}
-
-const GURL& PageLoadTracker::committed_url() {
- DCHECK(!commit_time_.is_null());
- return url_;
+ started_in_foreground_, committed_url_,
+ time_to_commit, abort_type_, time_to_abort);
}
void PageLoadTracker::NotifyAbort(UserAbortType abort_type,
@@ -275,149 +255,16 @@ void PageLoadTracker::UpdateAbortInternal(UserAbortType abort_type,
abort_time_ = timestamp;
}
-void PageLoadTracker::RecordTimingHistograms(const PageLoadExtraInfo& info) {
- if (!info.first_background_time.is_zero() &&
- !EventOccurredInForeground(timing_.first_paint, info)) {
- if (!info.time_to_commit.is_zero()) {
- PAGE_LOAD_HISTOGRAM(kHistogramBackgroundBeforePaint,
- info.first_background_time);
- } else {
- PAGE_LOAD_HISTOGRAM(kHistogramBackgroundBeforeCommit,
- info.first_background_time);
- }
- }
-
- // The rest of the histograms require the load to have commit and be relevant.
- if (info.time_to_commit.is_zero() || !renderer_tracked())
- return;
-
- if (EventOccurredInForeground(info.time_to_commit, info)) {
- PAGE_LOAD_HISTOGRAM(kHistogramCommit, info.time_to_commit);
- } else {
- PAGE_LOAD_HISTOGRAM(kBackgroundHistogramCommit, info.time_to_commit);
- }
-
- // The rest of the timing histograms require us to have received IPCs from the
- // renderer. Record UMA for how often this occurs (usually for quickly aborted
- // loads). For now, don't update observers if this is the case.
- if (timing_.IsEmpty()) {
- RecordInternalError(ERR_NO_IPCS_RECEIVED);
- return;
- }
-
- if (!timing_.dom_content_loaded_event_start.is_zero()) {
- if (EventOccurredInForeground(timing_.dom_content_loaded_event_start,
- info)) {
- PAGE_LOAD_HISTOGRAM(kHistogramDomContentLoaded,
- timing_.dom_content_loaded_event_start);
- } else {
- PAGE_LOAD_HISTOGRAM(kBackgroundHistogramDomContentLoaded,
- timing_.dom_content_loaded_event_start);
- }
- }
- if (!timing_.load_event_start.is_zero()) {
- if (EventOccurredInForeground(timing_.load_event_start, info)) {
- PAGE_LOAD_HISTOGRAM(kHistogramLoad, timing_.load_event_start);
- } else {
- PAGE_LOAD_HISTOGRAM(kBackgroundHistogramLoad, timing_.load_event_start);
- }
- }
- if (!timing_.first_layout.is_zero()) {
- if (EventOccurredInForeground(timing_.first_layout, info)) {
- PAGE_LOAD_HISTOGRAM(kHistogramFirstLayout, timing_.first_layout);
- } else {
- PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstLayout,
- timing_.first_layout);
- }
- }
- if (!timing_.first_paint.is_zero()) {
- if (EventOccurredInForeground(timing_.first_paint, info)) {
- PAGE_LOAD_HISTOGRAM(kHistogramFirstPaint, timing_.first_paint);
- } else {
- PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstPaint, timing_.first_paint);
- }
- }
- if (!timing_.first_text_paint.is_zero()) {
- if (EventOccurredInForeground(timing_.first_text_paint, info)) {
- PAGE_LOAD_HISTOGRAM(kHistogramFirstTextPaint, timing_.first_text_paint);
- } else {
- PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstTextPaint,
- timing_.first_text_paint);
- }
- }
- if (!timing_.first_image_paint.is_zero()) {
- if (EventOccurredInForeground(timing_.first_image_paint, info)) {
- PAGE_LOAD_HISTOGRAM(kHistogramFirstImagePaint, timing_.first_image_paint);
- } else {
- PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstImagePaint,
- timing_.first_image_paint);
- }
- }
- base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing_);
- if (!first_contentful_paint.is_zero()) {
- if (EventOccurredInForeground(first_contentful_paint, info)) {
- PAGE_LOAD_HISTOGRAM(kHistogramFirstContentfulPaint,
- first_contentful_paint);
- // Bucket these histograms into high/low resolution clock systems. This
- // might point us to directions that will de-noise some UMA.
- if (base::TimeTicks::IsHighResolution()) {
- PAGE_LOAD_HISTOGRAM(kHistogramFirstContentfulPaintHigh,
- first_contentful_paint);
- } else {
- PAGE_LOAD_HISTOGRAM(kHistogramFirstContentfulPaintLow,
- first_contentful_paint);
- }
- } else {
- PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstContentfulPaint,
- first_contentful_paint);
- }
- }
-
- // Log time to first foreground / time to first background. Log counts that we
- // started a relevant page load in the foreground / background.
- if (!info.first_background_time.is_zero())
- PAGE_LOAD_HISTOGRAM(kHistogramFirstBackground, info.first_background_time);
- else if (!info.first_foreground_time.is_zero())
- PAGE_LOAD_HISTOGRAM(kHistogramFirstForeground, info.first_foreground_time);
-}
-
void PageLoadTracker::RecordProvisionalEvent(ProvisionalLoadEvent event) {
if (HasBackgrounded()) {
- UMA_HISTOGRAM_ENUMERATION(kBackgroundProvisionalEvents, event,
+ UMA_HISTOGRAM_ENUMERATION(internal::kBackgroundProvisionalEvents, event,
PROVISIONAL_LOAD_LAST_ENTRY);
} else {
- UMA_HISTOGRAM_ENUMERATION(kProvisionalEvents, event,
+ UMA_HISTOGRAM_ENUMERATION(internal::kProvisionalEvents, event,
PROVISIONAL_LOAD_LAST_ENTRY);
}
}
-void PageLoadTracker::RecordRappor(const PageLoadExtraInfo& info) {
- if (info.time_to_commit.is_zero())
- return;
- DCHECK(!committed_url().is_empty());
- rappor::RapporService* rappor_service =
- embedder_interface_->GetRapporService();
- if (!rappor_service)
- return;
- base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing_);
- // Log the eTLD+1 of sites that show poor loading performance.
- if (EventOccurredInForeground(first_contentful_paint, info)) {
- scoped_ptr<rappor::Sample> sample =
- rappor_service->CreateSample(rappor::UMA_RAPPOR_TYPE);
- sample->SetStringField(
- "Domain", rappor::GetDomainAndRegistrySampleFromGURL(committed_url()));
- uint64_t bucket_index = RapporHistogramBucketIndex(first_contentful_paint);
- sample->SetFlagsField("Bucket", uint64_t(1) << bucket_index,
- kNumRapporHistogramBuckets);
- // The IsSlow flag is just a one bit boolean if the first contentful paint
- // was > 10s.
- sample->SetFlagsField("IsSlow", first_contentful_paint.InSecondsF() >= 10,
- 1);
- rappor_service->RecordSampleObj(kRapporMetricsNameCoarseTiming,
- std::move(sample));
- }
-}
-
// static
MetricsWebContentsObserver::MetricsWebContentsObserver(
content::WebContents* web_contents,
@@ -496,10 +343,19 @@ void MetricsWebContentsObserver::DidFinishNavigation(
// TODO(csharrison): Track changes to NavigationHandle for signals when this
// is the case (HTTP response headers).
if (!navigation_handle->HasCommitted()) {
- net::Error error = navigation_handle->GetNetErrorCode();
- ProvisionalLoadEvent event = error == net::OK ? PROVISIONAL_LOAD_STOPPED
- : error == net::ERR_ABORTED ? PROVISIONAL_LOAD_ERR_ABORTED
- : PROVISIONAL_LOAD_ERR_FAILED_NON_ABORT;
+ const ProvisionalLoadEvent event = [](net::Error error) {
+ switch (error) {
+ case net::OK:
+ // When a finished navigation that didn't commit has a net error code
+ // of OK, it indicates that the provisional load was stopped by the
+ // user.
+ return PROVISIONAL_LOAD_STOPPED;
+ case net::ERR_ABORTED:
+ return PROVISIONAL_LOAD_ERR_ABORTED;
+ default:
+ return PROVISIONAL_LOAD_ERR_FAILED_NON_ABORT;
+ }
+ }(navigation_handle->GetNetErrorCode());
finished_nav->RecordProvisionalEvent(event);
if (event != PROVISIONAL_LOAD_ERR_FAILED_NON_ABORT) {
finished_nav->NotifyAbort(ABORT_OTHER, base::TimeTicks::Now());
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.h b/components/page_load_metrics/browser/metrics_web_contents_observer.h
index 403bae9..a1e0cb3 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.h
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.h
@@ -16,8 +16,6 @@
#include "content/public/browser/web_contents_user_data.h"
#include "net/base/net_errors.h"
-class PageLoadMetricsObserverTest;
-
namespace content {
class NavigationHandle;
class RenderFrameHost;
@@ -27,72 +25,17 @@ namespace IPC {
class Message;
} // namespace IPC
-namespace rappor {
-class RapporService;
-}
-
namespace page_load_metrics {
class PageLoadTracker;
-// These constants are for keeping the tests in sync.
-const char kHistogramCommit[] = "PageLoad.Timing2.NavigationToCommit";
-const char kHistogramFirstLayout[] = "PageLoad.Timing2.NavigationToFirstLayout";
-const char kHistogramFirstTextPaint[] =
- "PageLoad.Timing2.NavigationToFirstTextPaint";
-const char kHistogramDomContentLoaded[] =
- "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired";
-const char kHistogramLoad[] = "PageLoad.Timing2.NavigationToLoadEventFired";
-const char kHistogramFirstPaint[] = "PageLoad.Timing2.NavigationToFirstPaint";
-const char kHistogramFirstImagePaint[] =
- "PageLoad.Timing2.NavigationToFirstImagePaint";
-const char kHistogramFirstContentfulPaint[] =
- "PageLoad.Timing2.NavigationToFirstContentfulPaint";
-const char kBackgroundHistogramCommit[] =
- "PageLoad.Timing2.NavigationToCommit.Background";
-const char kBackgroundHistogramFirstLayout[] =
- "PageLoad.Timing2.NavigationToFirstLayout.Background";
-const char kBackgroundHistogramFirstTextPaint[] =
- "PageLoad.Timing2.NavigationToFirstTextPaint.Background";
-const char kBackgroundHistogramDomContentLoaded[] =
- "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired.Background";
-const char kBackgroundHistogramLoad[] =
- "PageLoad.Timing2.NavigationToLoadEventFired.Background";
-const char kBackgroundHistogramFirstPaint[] =
- "PageLoad.Timing2.NavigationToFirstPaint.Background";
-const char kBackgroundHistogramFirstImagePaint[] =
- "PageLoad.Timing2.NavigationToFirstImagePaint.Background.";
-const char kBackgroundHistogramFirstContentfulPaint[] =
- "PageLoad.Timing2.NavigationToFirstContentfulPaint.Background";
-
-const char kHistogramFirstContentfulPaintHigh[] =
- "PageLoad.Timing2.NavigationToFirstContentfulPaint.HighResolutionClock";
-const char kHistogramFirstContentfulPaintLow[] =
- "PageLoad.Timing2.NavigationToFirstContentfulPaint.LowResolutionClock";
-
-const char kHistogramFirstBackground[] =
- "PageLoad.Timing2.NavigationToFirstBackground";
-const char kHistogramFirstForeground[] =
- "PageLoad.Timing2.NavigationToFirstForeground";
-
-const char kHistogramBackgroundBeforePaint[] =
- "PageLoad.Timing2.NavigationToFirstBackground.AfterCommit.BeforePaint";
-const char kHistogramBackgroundBeforeCommit[] =
- "PageLoad.Timing2.NavigationToFirstBackground.BeforeCommit";
-
-const char kProvisionalEvents[] = "PageLoad.Events.Provisional";
-const char kBackgroundProvisionalEvents[] =
- "PageLoad.Events.Provisional.Background";
-
-const char kErrorEvents[] = "PageLoad.Events.InternalError";
-
-const char kRapporMetricsNameCoarseTiming[] =
- "PageLoad.CoarseTiming.NavigationToFirstContentfulPaint";
-
-// NOTE: Some of these histograms are separated into a separate histogram
-// specified by the ".Background" suffix. For these events, we put them into the
-// background histogram if the web contents was ever in the background from
-// navigation start to the event in question.
+namespace internal {
+
+extern const char kProvisionalEvents[];
+extern const char kBackgroundProvisionalEvents[];
+extern const char kErrorEvents[];
+
+} // namespace internal
// ProvisionalLoadEvents count all main frame navigations before they commit.
// The events in this enum are all disjoint, and summing them yields the total
@@ -171,14 +114,12 @@ enum InternalErrorLoadEvent {
class PageLoadMetricsEmbedderInterface {
public:
virtual ~PageLoadMetricsEmbedderInterface() {}
- virtual rappor::RapporService* GetRapporService() = 0;
virtual bool IsPrerendering(content::WebContents* web_contents) = 0;
virtual void RegisterObservers(PageLoadTracker* metrics) = 0;
};
// This class tracks a given page load, starting from navigation start /
-// provisional load, until a new navigation commits or the navigation fails. It
-// also records RAPPOR/UMA about the page load.
+// provisional load, until a new navigation commits or the navigation fails.
// MetricsWebContentsObserver manages a set of provisional PageLoadTrackers, as
// well as a committed PageLoadTracker.
class PageLoadTracker {
@@ -219,7 +160,6 @@ class PageLoadTracker {
const GURL& committed_url();
void RecordTimingHistograms(const PageLoadExtraInfo& info);
- void RecordRappor(const PageLoadExtraInfo& info);
void UpdateAbortInternal(UserAbortType abort_type,
const base::TimeTicks& timestamp);
@@ -229,8 +169,9 @@ class PageLoadTracker {
// The navigation start in TimeTicks, not the wall time reported by Blink.
const base::TimeTicks navigation_start_;
- // Time this navigation was committed, or zero if this navigation hasn't
- // committed yet.
+ // URL and time this page load was committed. If this page load hasn't
+ // committed, |committed_url_| will be empty, and |commit_time_| will be zero.
+ GURL committed_url_;
base::TimeTicks commit_time_;
// Will be ABORT_NONE if we have not aborted this load yet. Otherwise will
@@ -246,7 +187,6 @@ class PageLoadTracker {
bool started_in_foreground_;
PageLoadTiming timing_;
- GURL url_;
// Interface to chrome features. Must outlive the class.
PageLoadMetricsEmbedderInterface* const embedder_interface_;
@@ -263,8 +203,6 @@ class MetricsWebContentsObserver
public content::WebContentsUserData<MetricsWebContentsObserver> {
public:
// Note that the returned metrics is owned by the web contents.
- // The caller must guarantee that the RapporService (if non-null) will
- // outlive the WebContents.
static MetricsWebContentsObserver* CreateForWebContents(
content::WebContents* web_contents,
scoped_ptr<PageLoadMetricsEmbedderInterface> embedder_interface);
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
index 668282a..16bffa7 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
@@ -4,14 +4,15 @@
#include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
+#include <vector>
+
#include "base/macros.h"
#include "base/memory/scoped_ptr.h"
#include "base/process/kill.h"
#include "base/test/histogram_tester.h"
#include "base/time/time.h"
+#include "components/page_load_metrics/browser/page_load_metrics_observer.h"
#include "components/page_load_metrics/common/page_load_metrics_messages.h"
-#include "components/rappor/rappor_utils.h"
-#include "components/rappor/test_rappor_service.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/test/test_renderer_host.h"
@@ -26,28 +27,49 @@ const char kDefaultTestUrl[] = "https://google.com";
const char kDefaultTestUrlAnchor[] = "https://google.com#samepage";
const char kDefaultTestUrl2[] = "https://whatever.com";
-} // namespace
+// Simple PageLoadMetricsObserver that copies observed PageLoadTimings into the
+// provided std::vector, so they can be analyzed by unit tests.
+class TestPageLoadMetricsObserver : public PageLoadMetricsObserver {
+ public:
+ explicit TestPageLoadMetricsObserver(
+ std::vector<PageLoadTiming>* observed_timings)
+ : observed_timings_(observed_timings) {}
+
+ void OnComplete(const PageLoadTiming& timing,
+ const PageLoadExtraInfo&) override {
+ observed_timings_->push_back(timing);
+ }
+
+ private:
+ std::vector<PageLoadTiming>* const observed_timings_;
+};
class TestPageLoadMetricsEmbedderInterface
: public PageLoadMetricsEmbedderInterface {
public:
TestPageLoadMetricsEmbedderInterface() : is_prerendering_(false) {}
- rappor::TestRapporService* GetRapporService() override {
- return &rappor_tester_;
- }
+
bool IsPrerendering(content::WebContents* web_contents) override {
return is_prerendering_;
}
- void RegisterObservers(PageLoadTracker* tracker) override {}
void set_is_prerendering(bool is_prerendering) {
is_prerendering_ = is_prerendering;
}
+ void RegisterObservers(PageLoadTracker* tracker) override {
+ tracker->AddObserver(
+ make_scoped_ptr(new TestPageLoadMetricsObserver(&observed_timings_)));
+ }
+ const std::vector<PageLoadTiming>& observed_timings() const {
+ return observed_timings_;
+ }
private:
+ std::vector<PageLoadTiming> observed_timings_;
bool is_prerendering_;
- rappor::TestRapporService rappor_tester_;
};
+} // namespace
+
class MetricsWebContentsObserverTest
: public content::RenderViewHostTestHarness {
public:
@@ -68,37 +90,42 @@ class MetricsWebContentsObserverTest
observer_->WasShown();
}
- void AssertNoHistogramsLogged() {
- histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0);
- histogram_tester_.ExpectTotalCount(kHistogramLoad, 0);
- histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 0);
- histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0);
- }
-
void CheckProvisionalEvent(ProvisionalLoadEvent event,
int count,
bool background) {
if (background) {
- histogram_tester_.ExpectBucketCount(kBackgroundProvisionalEvents, event,
- count);
+ histogram_tester_.ExpectBucketCount(
+ internal::kBackgroundProvisionalEvents, event, count);
num_provisional_events_bg_ += count;
} else {
- histogram_tester_.ExpectBucketCount(kProvisionalEvents, event, count);
+ histogram_tester_.ExpectBucketCount(internal::kProvisionalEvents, event,
+ count);
num_provisional_events_ += count;
}
}
void CheckErrorEvent(InternalErrorLoadEvent error, int count) {
- histogram_tester_.ExpectBucketCount(kErrorEvents, error, count);
+ histogram_tester_.ExpectBucketCount(internal::kErrorEvents, error, count);
num_errors_ += count;
}
void CheckTotalEvents() {
- histogram_tester_.ExpectTotalCount(kProvisionalEvents,
+ histogram_tester_.ExpectTotalCount(internal::kProvisionalEvents,
num_provisional_events_);
- histogram_tester_.ExpectTotalCount(kBackgroundProvisionalEvents,
+ histogram_tester_.ExpectTotalCount(internal::kBackgroundProvisionalEvents,
num_provisional_events_bg_);
- histogram_tester_.ExpectTotalCount(kErrorEvents, num_errors_);
+ histogram_tester_.ExpectTotalCount(internal::kErrorEvents, num_errors_);
+ }
+
+ void AssertNoNonEmptyTimingReported() {
+ ASSERT_FALSE(embedder_interface_->observed_timings().empty());
+ for (const auto& timing : embedder_interface_->observed_timings()) {
+ ASSERT_TRUE(timing.IsEmpty());
+ }
+ }
+
+ void AssertNoTimingReported() {
+ ASSERT_TRUE(embedder_interface_->observed_timings().empty());
}
protected:
@@ -114,10 +141,6 @@ class MetricsWebContentsObserverTest
DISALLOW_COPY_AND_ASSIGN(MetricsWebContentsObserverTest);
};
-TEST_F(MetricsWebContentsObserverTest, NoMetrics) {
- AssertNoHistogramsLogged();
-}
-
TEST_F(MetricsWebContentsObserverTest, NotInMainFrame) {
base::TimeDelta first_layout = base::TimeDelta::FromMilliseconds(1);
@@ -145,7 +168,7 @@ TEST_F(MetricsWebContentsObserverTest, NotInMainFrame) {
// Navigate again to see if the timing updated for a subframe message.
web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
- AssertNoHistogramsLogged();
+ AssertNoNonEmptyTimingReported();
}
TEST_F(MetricsWebContentsObserverTest, SamePageNoTrigger) {
@@ -164,163 +187,7 @@ TEST_F(MetricsWebContentsObserverTest, SamePageNoTrigger) {
web_contents()->GetMainFrame());
web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrlAnchor));
// A same page navigation shouldn't trigger logging UMA for the original.
- AssertNoHistogramsLogged();
-}
-
-TEST_F(MetricsWebContentsObserverTest, SamePageNoTriggerUntilTrueNavCommit) {
- base::TimeDelta first_layout = base::TimeDelta::FromMilliseconds(1);
-
- PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(1);
- timing.first_layout = first_layout;
-
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
-
- observer_->OnMessageReceived(
- PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing),
- web_contents()->GetMainFrame());
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrlAnchor));
- // A same page navigation shouldn't trigger logging UMA for the original.
- AssertNoHistogramsLogged();
-
- // But we should keep the timing info and log it when we get another
- // navigation.
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
- histogram_tester_.ExpectTotalCount(kHistogramCommit, 1);
- histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0);
- histogram_tester_.ExpectTotalCount(kHistogramLoad, 0);
- histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 1);
- histogram_tester_.ExpectBucketCount(kHistogramFirstLayout,
- first_layout.InMilliseconds(), 1);
- histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0);
-}
-
-TEST_F(MetricsWebContentsObserverTest, SingleMetricAfterCommit) {
- base::TimeDelta first_layout = base::TimeDelta::FromMilliseconds(1);
-
- PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(1);
- timing.first_layout = first_layout;
-
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
-
- observer_->OnMessageReceived(
- PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing),
- web_contents()->GetMainFrame());
-
- AssertNoHistogramsLogged();
-
- // Navigate again to force histogram recording.
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
-
- histogram_tester_.ExpectTotalCount(kHistogramCommit, 1);
- histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0);
- histogram_tester_.ExpectTotalCount(kHistogramLoad, 0);
- histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 1);
- histogram_tester_.ExpectBucketCount(kHistogramFirstLayout,
- first_layout.InMilliseconds(), 1);
- histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0);
-}
-
-TEST_F(MetricsWebContentsObserverTest, MultipleMetricsAfterCommits) {
- base::TimeDelta first_layout_1 = base::TimeDelta::FromMilliseconds(1);
- base::TimeDelta first_layout_2 = base::TimeDelta::FromMilliseconds(20);
- base::TimeDelta response = base::TimeDelta::FromMilliseconds(10);
- base::TimeDelta first_text_paint = base::TimeDelta::FromMilliseconds(30);
- base::TimeDelta dom_content = base::TimeDelta::FromMilliseconds(40);
- base::TimeDelta load = base::TimeDelta::FromMilliseconds(100);
-
- PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(1);
- timing.first_layout = first_layout_1;
- timing.response_start = response;
- timing.first_text_paint = first_text_paint;
- timing.dom_content_loaded_event_start = dom_content;
- timing.load_event_start = load;
-
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
-
- observer_->OnMessageReceived(
- PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing),
- web_contents()->GetMainFrame());
-
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
-
- PageLoadTiming timing2;
- timing2.navigation_start = base::Time::FromDoubleT(200);
- timing2.first_layout = first_layout_2;
-
- observer_->OnMessageReceived(
- PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing2),
- web_contents()->GetMainFrame());
-
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
-
- histogram_tester_.ExpectTotalCount(kHistogramCommit, 2);
- histogram_tester_.ExpectBucketCount(kHistogramFirstLayout,
- first_layout_1.InMilliseconds(), 1);
- histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 2);
- histogram_tester_.ExpectBucketCount(kHistogramFirstLayout,
- first_layout_1.InMilliseconds(), 1);
- histogram_tester_.ExpectBucketCount(kHistogramFirstLayout,
- first_layout_2.InMilliseconds(), 1);
-
- histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 1);
- histogram_tester_.ExpectBucketCount(kHistogramFirstTextPaint,
- first_text_paint.InMilliseconds(), 1);
-
- histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 1);
- histogram_tester_.ExpectBucketCount(kHistogramDomContentLoaded,
- dom_content.InMilliseconds(), 1);
-
- histogram_tester_.ExpectTotalCount(kHistogramLoad, 1);
- histogram_tester_.ExpectBucketCount(kHistogramLoad, load.InMilliseconds(), 1);
-}
-
-TEST_F(MetricsWebContentsObserverTest, BackgroundDifferentHistogram) {
- base::TimeDelta first_layout = base::TimeDelta::FromSeconds(2);
-
- PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(1);
- timing.first_layout = first_layout;
-
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
-
- // Simulate "Open link in new tab."
- observer_->WasHidden();
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
-
- observer_->OnMessageReceived(
- PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing),
- web_contents()->GetMainFrame());
-
- // Simulate switching to the tab and making another navigation.
- observer_->WasShown();
- AssertNoHistogramsLogged();
-
- // Navigate again to force histogram recording.
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
-
- histogram_tester_.ExpectTotalCount(kBackgroundHistogramCommit, 1);
- histogram_tester_.ExpectTotalCount(kBackgroundHistogramDomContentLoaded, 0);
- histogram_tester_.ExpectTotalCount(kBackgroundHistogramLoad, 0);
- histogram_tester_.ExpectTotalCount(kBackgroundHistogramFirstLayout, 1);
- histogram_tester_.ExpectBucketCount(kBackgroundHistogramFirstLayout,
- first_layout.InMilliseconds(), 1);
- histogram_tester_.ExpectTotalCount(kBackgroundHistogramFirstTextPaint, 0);
-
- histogram_tester_.ExpectTotalCount(kHistogramCommit, 0);
- histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0);
- histogram_tester_.ExpectTotalCount(kHistogramLoad, 0);
- histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 0);
- histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0);
+ AssertNoNonEmptyTimingReported();
}
TEST_F(MetricsWebContentsObserverTest, DontLogPrerender) {
@@ -337,99 +204,7 @@ TEST_F(MetricsWebContentsObserverTest, DontLogPrerender) {
web_contents()->GetMainFrame());
web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
- AssertNoHistogramsLogged();
-}
-
-TEST_F(MetricsWebContentsObserverTest, OnlyBackgroundLaterEvents) {
- PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(1);
- // Set these events at 1 microsecond so they are definitely occur before we
- // background the tab later in the test.
- timing.response_start = base::TimeDelta::FromMicroseconds(1);
- timing.dom_content_loaded_event_start = base::TimeDelta::FromMicroseconds(1);
-
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
-
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
- observer_->OnMessageReceived(
- PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing),
- web_contents()->GetMainFrame());
-
- // Background the tab, then forground it.
- observer_->WasHidden();
- observer_->WasShown();
- timing.first_layout = base::TimeDelta::FromSeconds(3);
- timing.first_text_paint = base::TimeDelta::FromSeconds(4);
- observer_->OnMessageReceived(
- PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing),
- web_contents()->GetMainFrame());
-
- // Navigate again to force histogram recording.
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
-
- histogram_tester_.ExpectTotalCount(kBackgroundHistogramCommit, 0);
- histogram_tester_.ExpectTotalCount(kBackgroundHistogramDomContentLoaded, 0);
- histogram_tester_.ExpectTotalCount(kBackgroundHistogramLoad, 0);
- histogram_tester_.ExpectTotalCount(kBackgroundHistogramFirstLayout, 1);
- histogram_tester_.ExpectBucketCount(kBackgroundHistogramFirstLayout,
- timing.first_layout.InMilliseconds(), 1);
- histogram_tester_.ExpectTotalCount(kBackgroundHistogramFirstTextPaint, 1);
- histogram_tester_.ExpectBucketCount(kBackgroundHistogramFirstTextPaint,
- timing.first_text_paint.InMilliseconds(),
- 1);
-
- histogram_tester_.ExpectTotalCount(kHistogramCommit, 1);
- histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 1);
- histogram_tester_.ExpectBucketCount(
- kHistogramDomContentLoaded,
- timing.dom_content_loaded_event_start.InMilliseconds(), 1);
- histogram_tester_.ExpectTotalCount(kHistogramLoad, 0);
- histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 0);
- histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0);
-}
-
-TEST_F(MetricsWebContentsObserverTest, DontBackgroundQuickerLoad) {
- // Set this event at 1 microsecond so it occurs before we foreground later in
- // the test.
- base::TimeDelta first_layout = base::TimeDelta::FromMicroseconds(1);
-
- PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(1);
- timing.first_layout = first_layout;
-
- observer_->WasHidden();
-
- // Open in new tab
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
-
- web_contents_tester->StartNavigation(GURL(kDefaultTestUrl));
-
- content::RenderFrameHostTester* rfh_tester =
- content::RenderFrameHostTester::For(main_rfh());
-
- // Switch to the tab
- observer_->WasShown();
-
- // Start another provisional load
- web_contents_tester->StartNavigation(GURL(kDefaultTestUrl2));
- rfh_tester->SimulateNavigationCommit(GURL(kDefaultTestUrl2));
- observer_->OnMessageReceived(
- PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing),
- main_rfh());
- rfh_tester->SimulateNavigationStop();
-
- // Navigate again to see if the timing updated for the foregrounded load.
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
-
- histogram_tester_.ExpectTotalCount(kHistogramCommit, 1);
- histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0);
- histogram_tester_.ExpectTotalCount(kHistogramLoad, 0);
- histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 1);
- histogram_tester_.ExpectBucketCount(kHistogramFirstLayout,
- first_layout.InMilliseconds(), 1);
- histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0);
+ AssertNoTimingReported();
}
TEST_F(MetricsWebContentsObserverTest, FailProvisionalLoad) {
@@ -463,25 +238,6 @@ TEST_F(MetricsWebContentsObserverTest, AbortProvisionalLoad) {
CheckTotalEvents();
}
-TEST_F(MetricsWebContentsObserverTest, BackgroundBeforePaint) {
- page_load_metrics::PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(1);
- timing.first_paint = base::TimeDelta::FromSeconds(10);
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
- web_contents_tester->NavigateAndCommit(GURL("https://www.google.com"));
- // Background the tab and go for a coffee or something.
- observer_->WasHidden();
- observer_->OnMessageReceived(
- PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing),
- main_rfh());
- // Come back and start browsing again.
- observer_->WasShown();
- // Simulate the user performaning another navigation.
- web_contents_tester->NavigateAndCommit(GURL("https://www.example.com"));
- histogram_tester_.ExpectTotalCount(kHistogramBackgroundBeforePaint, 1);
-}
-
TEST_F(MetricsWebContentsObserverTest, AbortProvisionalLoadInBackground) {
content::WebContentsTester* web_contents_tester =
content::WebContentsTester::For(web_contents());
@@ -588,70 +344,7 @@ TEST_F(MetricsWebContentsObserverTest, ObservePartialNavigation) {
main_rfh());
// Navigate again to force histogram logging.
web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
- AssertNoHistogramsLogged();
-}
-
-TEST_F(MetricsWebContentsObserverTest, NoRappor) {
- rappor::TestSample::Shadow* sample_obj =
- embedder_interface_->GetRapporService()->GetRecordedSampleForMetric(
- kRapporMetricsNameCoarseTiming);
- EXPECT_EQ(sample_obj, nullptr);
-}
-
-TEST_F(MetricsWebContentsObserverTest, RapporLongPageLoad) {
- PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(1);
- timing.first_image_paint = base::TimeDelta::FromSeconds(40);
-
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
-
- observer_->OnMessageReceived(
- PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing),
- main_rfh());
-
- // Navigate again to force logging RAPPOR.
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
- rappor::TestSample::Shadow* sample_obj =
- embedder_interface_->GetRapporService()->GetRecordedSampleForMetric(
- kRapporMetricsNameCoarseTiming);
- const auto& string_it = sample_obj->string_fields.find("Domain");
- EXPECT_NE(string_it, sample_obj->string_fields.end());
- EXPECT_EQ(rappor::GetDomainAndRegistrySampleFromGURL(GURL(kDefaultTestUrl)),
- string_it->second);
-
- const auto& flag_it = sample_obj->flag_fields.find("IsSlow");
- EXPECT_NE(flag_it, sample_obj->flag_fields.end());
- EXPECT_EQ(1u, flag_it->second);
-}
-
-TEST_F(MetricsWebContentsObserverTest, RapporQuickPageLoad) {
- PageLoadTiming timing;
- timing.navigation_start = base::Time::FromDoubleT(1);
- timing.first_text_paint = base::TimeDelta::FromSeconds(1);
-
- content::WebContentsTester* web_contents_tester =
- content::WebContentsTester::For(web_contents());
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
-
- observer_->OnMessageReceived(
- PageLoadMetricsMsg_TimingUpdated(observer_->routing_id(), timing),
- main_rfh());
-
- // Navigate again to force logging RAPPOR.
- web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
- rappor::TestSample::Shadow* sample_obj =
- embedder_interface_->GetRapporService()->GetRecordedSampleForMetric(
- kRapporMetricsNameCoarseTiming);
- const auto& string_it = sample_obj->string_fields.find("Domain");
- EXPECT_NE(string_it, sample_obj->string_fields.end());
- EXPECT_EQ(rappor::GetDomainAndRegistrySampleFromGURL(GURL(kDefaultTestUrl)),
- string_it->second);
-
- const auto& flag_it = sample_obj->flag_fields.find("IsSlow");
- EXPECT_NE(flag_it, sample_obj->flag_fields.end());
- EXPECT_EQ(0u, flag_it->second);
+ AssertNoTimingReported();
}
} // namespace page_load_metrics
diff --git a/components/page_load_metrics/browser/page_load_metrics_observer.cc b/components/page_load_metrics/browser/page_load_metrics_observer.cc
index 6c5015c..b41c347 100644
--- a/components/page_load_metrics/browser/page_load_metrics_observer.cc
+++ b/components/page_load_metrics/browser/page_load_metrics_observer.cc
@@ -10,15 +10,16 @@ PageLoadExtraInfo::PageLoadExtraInfo(
const base::TimeDelta& first_background_time,
const base::TimeDelta& first_foreground_time,
bool started_in_foreground,
+ const GURL& committed_url,
const base::TimeDelta& time_to_commit,
UserAbortType abort_type,
const base::TimeDelta& time_to_abort)
: first_background_time(first_background_time),
first_foreground_time(first_foreground_time),
started_in_foreground(started_in_foreground),
+ committed_url(committed_url),
time_to_commit(time_to_commit),
abort_type(abort_type),
- time_to_abort(time_to_abort) {
-}
+ time_to_abort(time_to_abort) {}
} // namespace page_load_metrics
diff --git a/components/page_load_metrics/browser/page_load_metrics_observer.h b/components/page_load_metrics/browser/page_load_metrics_observer.h
index d8c50a5..7e01f37 100644
--- a/components/page_load_metrics/browser/page_load_metrics_observer.h
+++ b/components/page_load_metrics/browser/page_load_metrics_observer.h
@@ -8,6 +8,7 @@
#include "base/macros.h"
#include "components/page_load_metrics/common/page_load_timing.h"
#include "content/public/browser/navigation_handle.h"
+#include "url/gurl.h"
namespace page_load_metrics {
@@ -49,6 +50,7 @@ struct PageLoadExtraInfo {
PageLoadExtraInfo(const base::TimeDelta& first_background_time,
const base::TimeDelta& first_foreground_time,
bool started_in_foreground,
+ const GURL& committed_url,
const base::TimeDelta& time_to_commit,
UserAbortType abort_type,
const base::TimeDelta& time_to_abort);
@@ -66,6 +68,10 @@ struct PageLoadExtraInfo {
// True if the page load started in the foreground.
const bool started_in_foreground;
+ // Committed URL. If the page load did not commit, |committed_url| will be
+ // empty.
+ const GURL committed_url;
+
// Time from navigation start until commit. If the page load did not commit,
// |time_to_commit| will be zero.
const base::TimeDelta time_to_commit;