| Index: chrome/browser/metrics/first_web_contents_profiler.cc
|
| diff --git a/chrome/browser/metrics/first_web_contents_profiler.cc b/chrome/browser/metrics/first_web_contents_profiler.cc
|
| index dcff83a5e2d9247a5307b811832ce65a239e8d4a..0954dbb05f9fc65547307572ea52eb48009e11e9 100644
|
| --- a/chrome/browser/metrics/first_web_contents_profiler.cc
|
| +++ b/chrome/browser/metrics/first_web_contents_profiler.cc
|
| @@ -20,31 +20,85 @@
|
| #include "components/metrics/proto/profiler_event.pb.h"
|
| #include "components/startup_metric_utils/browser/startup_metric_utils.h"
|
| #include "content/public/browser/navigation_handle.h"
|
| +#include "content/public/browser/web_contents.h"
|
| +#include "content/public/browser/web_contents_observer.h"
|
| #include "content/public/common/browser_side_navigation_policy.h"
|
|
|
| -// static
|
| -void FirstWebContentsProfiler::Start() {
|
| - for (auto* browser : *BrowserList::GetInstance()) {
|
| - content::WebContents* web_contents =
|
| - browser->tab_strip_model()->GetActiveWebContents();
|
| - if (web_contents) {
|
| - // FirstWebContentsProfiler owns itself and is also bound to
|
| - // |web_contents|'s lifetime by observing WebContentsDestroyed().
|
| - new FirstWebContentsProfiler(web_contents);
|
| - return;
|
| - }
|
| - }
|
| -}
|
| +namespace {
|
| +
|
| +class FirstWebContentsProfilerImpl : public content::WebContentsObserver {
|
| + public:
|
| + FirstWebContentsProfilerImpl(
|
| + content::WebContents* web_contents,
|
| + startup_metric_utils::WebContentsWorkload workload);
|
| +
|
| + private:
|
| + // Reasons for which profiling is deemed complete. Logged in UMA (do not re-
|
| + // order or re-assign).
|
| + enum FinishReason {
|
| + // All metrics were successfully gathered.
|
| + DONE = 0,
|
| + // Abandon if blocking UI was shown during startup.
|
| + ABANDON_BLOCKING_UI = 1,
|
| + // Abandon if the content is hidden (lowers scheduling priority).
|
| + ABANDON_CONTENT_HIDDEN = 2,
|
| + // Abandon if the content is destroyed.
|
| + ABANDON_CONTENT_DESTROYED = 3,
|
| + // Abandon if the WebContents navigates away from its initial page.
|
| + ABANDON_NEW_NAVIGATION = 4,
|
| + // Abandon if the WebContents fails to load (e.g. network error, etc.).
|
| + ABANDON_NAVIGATION_ERROR = 5,
|
| + ENUM_MAX
|
| + };
|
| +
|
| + ~FirstWebContentsProfilerImpl() override = default;
|
| +
|
| + // content::WebContentsObserver:
|
| + void DidFirstVisuallyNonEmptyPaint() override;
|
| + void DocumentOnLoadCompletedInMainFrame() override;
|
| + void DidStartNavigation(
|
| + content::NavigationHandle* navigation_handle) override;
|
| + void DidFinishNavigation(
|
| + content::NavigationHandle* navigation_handle) override;
|
| + void WasHidden() override;
|
| + void WebContentsDestroyed() override;
|
| +
|
| + // Whether this instance has finished collecting first-paint and main-frame-
|
| + // load metrics (navigation metrics are recorded on a best effort but don't
|
| + // prevent the FirstWebContentsProfilerImpl from calling it).
|
| + bool IsFinishedCollectingMetrics();
|
| +
|
| + // Logs |finish_reason| to UMA and deletes this FirstWebContentsProfilerImpl.
|
| + void FinishedCollectingMetrics(FinishReason finish_reason);
|
| +
|
| + // Whether an attempt was made to collect the "NonEmptyPaint" metric.
|
| + bool collected_paint_metric_;
|
| +
|
| + // Whether an attempt was made to collect the "MainFrameLoad" metric.
|
| + bool collected_load_metric_;
|
| +
|
| + // Whether an attempt was made to collect the "MainNavigationStart" metric.
|
| + bool collected_main_navigation_start_metric_;
|
| +
|
| + // Whether an attempt was made to collect the "MainNavigationFinished" metric.
|
| + bool collected_main_navigation_finished_metric_;
|
|
|
| -FirstWebContentsProfiler::FirstWebContentsProfiler(
|
| - content::WebContents* web_contents)
|
| + const startup_metric_utils::WebContentsWorkload workload_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(FirstWebContentsProfilerImpl);
|
| +};
|
| +
|
| +FirstWebContentsProfilerImpl::FirstWebContentsProfilerImpl(
|
| + content::WebContents* web_contents,
|
| + startup_metric_utils::WebContentsWorkload workload)
|
| : content::WebContentsObserver(web_contents),
|
| collected_paint_metric_(false),
|
| collected_load_metric_(false),
|
| collected_main_navigation_start_metric_(false),
|
| - collected_main_navigation_finished_metric_(false) {}
|
| + collected_main_navigation_finished_metric_(false),
|
| + workload_(workload) {}
|
|
|
| -void FirstWebContentsProfiler::DidFirstVisuallyNonEmptyPaint() {
|
| +void FirstWebContentsProfilerImpl::DidFirstVisuallyNonEmptyPaint() {
|
| if (collected_paint_metric_)
|
| return;
|
| if (startup_metric_utils::WasNonBrowserUIDisplayed()) {
|
| @@ -63,7 +117,7 @@ void FirstWebContentsProfiler::DidFirstVisuallyNonEmptyPaint() {
|
| FinishedCollectingMetrics(FinishReason::DONE);
|
| }
|
|
|
| -void FirstWebContentsProfiler::DocumentOnLoadCompletedInMainFrame() {
|
| +void FirstWebContentsProfilerImpl::DocumentOnLoadCompletedInMainFrame() {
|
| if (collected_load_metric_)
|
| return;
|
| if (startup_metric_utils::WasNonBrowserUIDisplayed()) {
|
| @@ -79,7 +133,7 @@ void FirstWebContentsProfiler::DocumentOnLoadCompletedInMainFrame() {
|
| FinishedCollectingMetrics(FinishReason::DONE);
|
| }
|
|
|
| -void FirstWebContentsProfiler::DidStartNavigation(
|
| +void FirstWebContentsProfilerImpl::DidStartNavigation(
|
| content::NavigationHandle* navigation_handle) {
|
| if (collected_main_navigation_start_metric_)
|
| return;
|
| @@ -100,10 +154,10 @@ void FirstWebContentsProfiler::DidStartNavigation(
|
|
|
| collected_main_navigation_start_metric_ = true;
|
| startup_metric_utils::RecordFirstWebContentsMainNavigationStart(
|
| - base::TimeTicks::Now());
|
| + base::TimeTicks::Now(), workload_);
|
| }
|
|
|
| -void FirstWebContentsProfiler::DidFinishNavigation(
|
| +void FirstWebContentsProfilerImpl::DidFinishNavigation(
|
| content::NavigationHandle* navigation_handle) {
|
| if (collected_main_navigation_finished_metric_) {
|
| // Abandon profiling on a top-level navigation to a different page as it:
|
| @@ -136,7 +190,7 @@ void FirstWebContentsProfiler::DidFinishNavigation(
|
|
|
| if (content::IsBrowserSideNavigationEnabled()) {
|
| startup_metric_utils::RecordFirstWebContentsMainNavigationStart(
|
| - navigation_handle->NavigationStart());
|
| + navigation_handle->NavigationStart(), workload_);
|
| collected_main_navigation_start_metric_ = true;
|
| }
|
|
|
| @@ -145,21 +199,21 @@ void FirstWebContentsProfiler::DidFinishNavigation(
|
| base::TimeTicks::Now());
|
| }
|
|
|
| -void FirstWebContentsProfiler::WasHidden() {
|
| +void FirstWebContentsProfilerImpl::WasHidden() {
|
| // Stop profiling if the content gets hidden as its load may be deprioritized
|
| // and timing it becomes meaningless.
|
| FinishedCollectingMetrics(FinishReason::ABANDON_CONTENT_HIDDEN);
|
| }
|
|
|
| -void FirstWebContentsProfiler::WebContentsDestroyed() {
|
| +void FirstWebContentsProfilerImpl::WebContentsDestroyed() {
|
| FinishedCollectingMetrics(FinishReason::ABANDON_CONTENT_DESTROYED);
|
| }
|
|
|
| -bool FirstWebContentsProfiler::IsFinishedCollectingMetrics() {
|
| +bool FirstWebContentsProfilerImpl::IsFinishedCollectingMetrics() {
|
| return collected_paint_metric_ && collected_load_metric_;
|
| }
|
|
|
| -void FirstWebContentsProfiler::FinishedCollectingMetrics(
|
| +void FirstWebContentsProfilerImpl::FinishedCollectingMetrics(
|
| FinishReason finish_reason) {
|
| UMA_HISTOGRAM_ENUMERATION("Startup.FirstWebContents.FinishReason",
|
| finish_reason, FinishReason::ENUM_MAX);
|
| @@ -175,4 +229,31 @@ void FirstWebContentsProfiler::FinishedCollectingMetrics(
|
| delete this;
|
| }
|
|
|
| +} // namespace
|
| +
|
| +// static
|
| +void FirstWebContentsProfiler::Start() {
|
| + using startup_metric_utils::WebContentsWorkload;
|
| +
|
| + const BrowserList* browser_list = BrowserList::GetInstance();
|
| +
|
| + const auto first_browser = browser_list->begin();
|
| + if (first_browser == browser_list->end())
|
| + return;
|
| +
|
| + const TabStripModel* tab_strip = (*first_browser)->tab_strip_model();
|
| + DCHECK(!tab_strip->empty());
|
| +
|
| + content::WebContents* web_contents = tab_strip->GetActiveWebContents();
|
| + DCHECK(web_contents);
|
| +
|
| + const bool single_tab = browser_list->size() == 1 && tab_strip->count() == 1;
|
| +
|
| + // FirstWebContentsProfilerImpl owns itself and is also bound to
|
| + // |web_contents|'s lifetime by observing WebContentsDestroyed().
|
| + new FirstWebContentsProfilerImpl(
|
| + web_contents, single_tab ? WebContentsWorkload::SINGLE_TAB
|
| + : WebContentsWorkload::MULTI_TABS);
|
| +}
|
| +
|
| #endif // !defined(OS_ANDROID)
|
|
|