diff options
Diffstat (limited to 'chrome')
5 files changed, 231 insertions, 2 deletions
diff --git a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc index 5ca78d2c..3d5e9e7 100644 --- a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc +++ b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc @@ -264,6 +264,14 @@ void ChromeBrowserMainExtraPartsMetrics::PostBrowserStart() { UMA_HISTOGRAM_COUNTS_100("Hardware.Display.Count.OnStartup", display_count_); gfx::Screen::GetNativeScreen()->AddObserver(this); is_screen_observer_ = true; + +#if !defined(OS_ANDROID) + if (FirstWebContentsProfiler::ShouldCollectMetrics()) { + first_web_contents_profiler_ = + FirstWebContentsProfiler::CreateProfilerForFirstWebContents(this) + .Pass(); + } +#endif // !defined(OS_ANDROID) } void ChromeBrowserMainExtraPartsMetrics::OnDisplayAdded( @@ -281,6 +289,10 @@ void ChromeBrowserMainExtraPartsMetrics::OnDisplayMetricsChanged( uint32_t changed_metrics) { } +void ChromeBrowserMainExtraPartsMetrics::ProfilerFinishedCollectingMetrics() { + first_web_contents_profiler_.reset(); +} + void ChromeBrowserMainExtraPartsMetrics::EmitDisplaysChangedMetric() { int display_count = gfx::Screen::GetNativeScreen()->GetNumDisplays(); if (display_count != display_count_) { diff --git a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h index 91b904d..7d9eceb 100644 --- a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h +++ b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.h @@ -9,6 +9,7 @@ #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" #include "chrome/browser/chrome_browser_main_extra_parts.h" +#include "chrome/browser/metrics/first_web_contents_profiler.h" #include "ui/gfx/display_observer.h" class ChromeBrowserMainParts; @@ -17,8 +18,10 @@ namespace chrome { void AddMetricsExtraParts(ChromeBrowserMainParts* main_parts); } -class ChromeBrowserMainExtraPartsMetrics : public ChromeBrowserMainExtraParts, - public gfx::DisplayObserver { +class ChromeBrowserMainExtraPartsMetrics + : public ChromeBrowserMainExtraParts, + public gfx::DisplayObserver, + public FirstWebContentsProfiler::Delegate { public: ChromeBrowserMainExtraPartsMetrics(); ~ChromeBrowserMainExtraPartsMetrics() override; @@ -40,6 +43,9 @@ class ChromeBrowserMainExtraPartsMetrics : public ChromeBrowserMainExtraParts, virtual void OnDisplayMetricsChanged(const gfx::Display& display, uint32_t changed_metrics) override; + // FirstWebContentsProfilerDelegate overrides. + void ProfilerFinishedCollectingMetrics() override; + // If the number of displays has changed, emit a UMA metric. void EmitDisplaysChangedMetric(); @@ -50,6 +56,9 @@ class ChromeBrowserMainExtraPartsMetrics : public ChromeBrowserMainExtraParts, // screen. bool is_screen_observer_; + // Measures start up performance of the first active web contents. + scoped_ptr<FirstWebContentsProfiler> first_web_contents_profiler_; + DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainExtraPartsMetrics); }; diff --git a/chrome/browser/metrics/first_web_contents_profiler.cc b/chrome/browser/metrics/first_web_contents_profiler.cc new file mode 100644 index 0000000..ea6399c --- /dev/null +++ b/chrome/browser/metrics/first_web_contents_profiler.cc @@ -0,0 +1,130 @@ +// Copyright 2014 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. + +#if !defined(OS_ANDROID) + +#include "chrome/browser/metrics/first_web_contents_profiler.h" + +#include "base/metrics/histogram_macros.h" +#include "base/process/process_info.h" +#include "base/time/time.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/browser_iterator.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/common/chrome_version_info.h" + +namespace { + +const int kHistogramMinTimeMilliseconds = 200; +const int kHistogramMaxTimeSeconds = 45; + +// There is a lot of noise in the dev channel. One possible cause is that the +// bucket ranges are too wide. The bucket count is chosen such that the size of +// the bucket is 1% of its minimum. Notice that this also means that +// subsequent buckets will satisfy Min(bucket N + 1) / Min(bucket N) = 1.01. +// Then we want X, such that 1.01 ^ X = 45 * 1000 / 200. Some quick math shows +// that X = 544. +const int kHistogramBucketCount = 544; + +} // namespace + +scoped_ptr<FirstWebContentsProfiler> +FirstWebContentsProfiler::CreateProfilerForFirstWebContents( + Delegate* delegate) { + DCHECK(delegate); + for (chrome::BrowserIterator iterator; !iterator.done(); iterator.Next()) { + Browser* browser = *iterator; + content::WebContents* web_contents = + browser->tab_strip_model()->GetActiveWebContents(); + if (web_contents) { + return scoped_ptr<FirstWebContentsProfiler>( + new FirstWebContentsProfiler(web_contents, delegate)); + } + } + return nullptr; +} + +bool FirstWebContentsProfiler::ShouldCollectMetrics() { + chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel(); + return channel == chrome::VersionInfo::CHANNEL_CANARY || + channel == chrome::VersionInfo::CHANNEL_DEV; +} + +FirstWebContentsProfiler::FirstWebContentsProfiler( + content::WebContents* web_contents, + Delegate* delegate) + : content::WebContentsObserver(web_contents), + collected_paint_metric_(false), + collected_load_metric_(false), + delegate_(delegate) { + process_creation_time_ = base::CurrentProcessInfo::CreationTime(); +} + +void FirstWebContentsProfiler::DidFirstVisuallyNonEmptyPaint() { + if (collected_paint_metric_) + return; + + collected_paint_metric_ = true; + if (!process_creation_time_.is_null()) { + base::TimeDelta elapsed = base::Time::Now() - process_creation_time_; + + // TODO(erikchen): Revisit these metrics once data has been collected to + // determine whether using more buckets reduces noise and provides higher + // quality information. + UMA_HISTOGRAM_CUSTOM_TIMES( + "Startup.Experimental.FirstWebContents.NonEmptyPaint." + "ManyBuckets", + elapsed, + base::TimeDelta::FromMilliseconds(kHistogramMinTimeMilliseconds), + base::TimeDelta::FromSeconds(kHistogramMaxTimeSeconds), + kHistogramBucketCount); + UMA_HISTOGRAM_LONG_TIMES_100( + "Startup.Experimental.FirstWebContents.NonEmptyPaint.StandardBuckets", + elapsed); + } + + if (IsFinishedCollectingMetrics()) + FinishedCollectingMetrics(); +} + +void FirstWebContentsProfiler::DocumentOnLoadCompletedInMainFrame() { + if (collected_load_metric_) + return; + + collected_load_metric_ = true; + if (!process_creation_time_.is_null()) { + base::TimeDelta elapsed = base::Time::Now() - process_creation_time_; + + // TODO(erikchen): Revisit these metrics once data has been collected to + // determine whether using more buckets reduces noise and provides higher + // quality information. + UMA_HISTOGRAM_CUSTOM_TIMES( + "Startup.Experimental.FirstWebContents.MainFrameLoad." + "ManyBuckets", + elapsed, + base::TimeDelta::FromMilliseconds(kHistogramMinTimeMilliseconds), + base::TimeDelta::FromSeconds(kHistogramMaxTimeSeconds), + kHistogramBucketCount); + UMA_HISTOGRAM_LONG_TIMES_100( + "Startup.Experimental.FirstWebContents.MainFrameLoad.StandardBuckets", + elapsed); + } + + if (IsFinishedCollectingMetrics()) + FinishedCollectingMetrics(); +} + +void FirstWebContentsProfiler::WebContentsDestroyed() { + FinishedCollectingMetrics(); +} + +bool FirstWebContentsProfiler::IsFinishedCollectingMetrics() { + return collected_paint_metric_ && collected_load_metric_; +} + +void FirstWebContentsProfiler::FinishedCollectingMetrics() { + delegate_->ProfilerFinishedCollectingMetrics(); +} + +#endif // !defined(OS_ANDROID) diff --git a/chrome/browser/metrics/first_web_contents_profiler.h b/chrome/browser/metrics/first_web_contents_profiler.h new file mode 100644 index 0000000..a3bbfe5 --- /dev/null +++ b/chrome/browser/metrics/first_web_contents_profiler.h @@ -0,0 +1,76 @@ +// Copyright 2014 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_METRICS_FIRST_WEB_CONTENTS_PROFILER_H_ +#define CHROME_BROWSER_METRICS_FIRST_WEB_CONTENTS_PROFILER_H_ + +#include "base/memory/scoped_ptr.h" +#include "content/public/browser/web_contents_observer.h" + +namespace content { +class WebContents; +} // namespace content + +// Measures start up performance of the first active web contents. +// This class is declared on all platforms, but only defined on non-Android +// platforms. Android code should not call any non-trivial methods on this +// class. +class FirstWebContentsProfiler : public content::WebContentsObserver { + public: + class Delegate { + public: + // Called by the FirstWebContentsProfiler when it is finished collecting + // metrics. The delegate should take this opportunity to destroy the + // FirstWebContentsProfiler. + virtual void ProfilerFinishedCollectingMetrics() = 0; + }; + + // Creates a profiler for the active web contents. If there are multiple + // browsers, the first one is chosen. If there are no browsers, returns + // nullptr. + static scoped_ptr<FirstWebContentsProfiler> CreateProfilerForFirstWebContents( + Delegate* delegate); + + // These metrics are currently experimental, and are only collected in the + // dev and canary channels. + static bool ShouldCollectMetrics(); + + private: + FirstWebContentsProfiler(content::WebContents* web_contents, + Delegate* delegate); + + // content::WebContentsObserver: + void DidFirstVisuallyNonEmptyPaint() override; + void DocumentOnLoadCompletedInMainFrame() override; + void WebContentsDestroyed() override; + + // Whether this instance has finished collecting all of its metrics. + bool IsFinishedCollectingMetrics(); + + // Informs the delegate that this instance has finished collecting all of its + // metrics. + void FinishedCollectingMetrics(); + + // Whether the "NonEmptyPaint" metric has been collected. If an attempt is + // made to collect the metric but the attempt fails, this member is set to + // true to prevent this class from sitting around forever attempting to + // collect the metric. + bool collected_paint_metric_; + + // Whether the "MainFrameLoad" metric has been collected. If an attempt is + // made to collect the metric but the attempt fails, this member is set to + // true to prevent this class from sitting around forever attempting to + // collect the metric. + bool collected_load_metric_; + + // The time at which the process was created. + base::Time process_creation_time_; + + // |delegate_| owns |this|. + Delegate* delegate_; + + DISALLOW_COPY_AND_ASSIGN(FirstWebContentsProfiler); +}; + +#endif // CHROME_BROWSER_METRICS_FIRST_WEB_CONTENTS_PROFILER_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 700517a..90663e9 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1146,6 +1146,8 @@ 'browser/metrics/chrome_stability_metrics_provider.h', 'browser/metrics/field_trial_synchronizer.cc', 'browser/metrics/field_trial_synchronizer.h', + 'browser/metrics/first_web_contents_profiler.cc', + 'browser/metrics/first_web_contents_profiler.h', 'browser/metrics/google_update_metrics_provider_win.cc', 'browser/metrics/google_update_metrics_provider_win.h', 'browser/metrics/jumplist_metrics_win.cc', |