Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Side by Side Diff: chrome/browser/metrics/first_web_contents_profiler.cc

Issue 2651823002: Add .SingleTab and .MultiTabs suffix to Startup.FirstWebContents.MainNavigationStart histogram. (Closed)
Patch Set: Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #if !defined(OS_ANDROID) 5 #if !defined(OS_ANDROID)
6 6
7 #include "chrome/browser/metrics/first_web_contents_profiler.h" 7 #include "chrome/browser/metrics/first_web_contents_profiler.h"
8 8
9 #include <string> 9 #include <string>
10 10
11 #include "base/location.h" 11 #include "base/location.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/metrics/histogram_macros.h" 13 #include "base/metrics/histogram_macros.h"
14 #include "base/time/time.h" 14 #include "base/time/time.h"
15 #include "build/build_config.h" 15 #include "build/build_config.h"
16 #include "chrome/browser/ui/browser.h" 16 #include "chrome/browser/ui/browser.h"
17 #include "chrome/browser/ui/browser_list.h" 17 #include "chrome/browser/ui/browser_list.h"
18 #include "chrome/browser/ui/tabs/tab_strip_model.h" 18 #include "chrome/browser/ui/tabs/tab_strip_model.h"
19 #include "components/metrics/profiler/tracking_synchronizer.h" 19 #include "components/metrics/profiler/tracking_synchronizer.h"
20 #include "components/metrics/proto/profiler_event.pb.h" 20 #include "components/metrics/proto/profiler_event.pb.h"
21 #include "components/startup_metric_utils/browser/startup_metric_utils.h" 21 #include "components/startup_metric_utils/browser/startup_metric_utils.h"
22 #include "content/public/browser/navigation_handle.h" 22 #include "content/public/browser/navigation_handle.h"
23 #include "content/public/browser/web_contents.h"
24 #include "content/public/browser/web_contents_observer.h"
23 #include "content/public/common/browser_side_navigation_policy.h" 25 #include "content/public/common/browser_side_navigation_policy.h"
24 26
25 // static 27 namespace {
26 void FirstWebContentsProfiler::Start() {
27 for (auto* browser : *BrowserList::GetInstance()) {
28 content::WebContents* web_contents =
29 browser->tab_strip_model()->GetActiveWebContents();
30 if (web_contents) {
31 // FirstWebContentsProfiler owns itself and is also bound to
32 // |web_contents|'s lifetime by observing WebContentsDestroyed().
33 new FirstWebContentsProfiler(web_contents);
34 return;
35 }
36 }
37 }
38 28
39 FirstWebContentsProfiler::FirstWebContentsProfiler( 29 class FirstWebContentsProfilerImpl : public content::WebContentsObserver {
40 content::WebContents* web_contents) 30 public:
31 FirstWebContentsProfilerImpl(
32 content::WebContents* web_contents,
33 startup_metric_utils::WebContentsWorkload workload);
34
35 private:
36 // Reasons for which profiling is deemed complete. Logged in UMA (do not re-
37 // order or re-assign).
38 enum FinishReason {
39 // All metrics were successfully gathered.
40 DONE = 0,
41 // Abandon if blocking UI was shown during startup.
42 ABANDON_BLOCKING_UI = 1,
43 // Abandon if the content is hidden (lowers scheduling priority).
44 ABANDON_CONTENT_HIDDEN = 2,
45 // Abandon if the content is destroyed.
46 ABANDON_CONTENT_DESTROYED = 3,
47 // Abandon if the WebContents navigates away from its initial page.
48 ABANDON_NEW_NAVIGATION = 4,
49 // Abandon if the WebContents fails to load (e.g. network error, etc.).
50 ABANDON_NAVIGATION_ERROR = 5,
51 ENUM_MAX
52 };
53
54 ~FirstWebContentsProfilerImpl() override = default;
55
56 // content::WebContentsObserver:
57 void DidFirstVisuallyNonEmptyPaint() override;
58 void DocumentOnLoadCompletedInMainFrame() override;
59 void DidStartNavigation(
60 content::NavigationHandle* navigation_handle) override;
61 void DidFinishNavigation(
62 content::NavigationHandle* navigation_handle) override;
63 void WasHidden() override;
64 void WebContentsDestroyed() override;
65
66 // Whether this instance has finished collecting first-paint and main-frame-
67 // load metrics (navigation metrics are recorded on a best effort but don't
68 // prevent the FirstWebContentsProfilerImpl from calling it).
69 bool IsFinishedCollectingMetrics();
70
71 // Logs |finish_reason| to UMA and deletes this FirstWebContentsProfilerImpl.
72 void FinishedCollectingMetrics(FinishReason finish_reason);
73
74 // Whether an attempt was made to collect the "NonEmptyPaint" metric.
75 bool collected_paint_metric_;
76
77 // Whether an attempt was made to collect the "MainFrameLoad" metric.
78 bool collected_load_metric_;
79
80 // Whether an attempt was made to collect the "MainNavigationStart" metric.
81 bool collected_main_navigation_start_metric_;
82
83 // Whether an attempt was made to collect the "MainNavigationFinished" metric.
84 bool collected_main_navigation_finished_metric_;
85
86 const startup_metric_utils::WebContentsWorkload workload_;
87
88 DISALLOW_COPY_AND_ASSIGN(FirstWebContentsProfilerImpl);
89 };
90
91 FirstWebContentsProfilerImpl::FirstWebContentsProfilerImpl(
92 content::WebContents* web_contents,
93 startup_metric_utils::WebContentsWorkload workload)
41 : content::WebContentsObserver(web_contents), 94 : content::WebContentsObserver(web_contents),
42 collected_paint_metric_(false), 95 collected_paint_metric_(false),
43 collected_load_metric_(false), 96 collected_load_metric_(false),
44 collected_main_navigation_start_metric_(false), 97 collected_main_navigation_start_metric_(false),
45 collected_main_navigation_finished_metric_(false) {} 98 collected_main_navigation_finished_metric_(false),
99 workload_(workload) {}
46 100
47 void FirstWebContentsProfiler::DidFirstVisuallyNonEmptyPaint() { 101 void FirstWebContentsProfilerImpl::DidFirstVisuallyNonEmptyPaint() {
48 if (collected_paint_metric_) 102 if (collected_paint_metric_)
49 return; 103 return;
50 if (startup_metric_utils::WasNonBrowserUIDisplayed()) { 104 if (startup_metric_utils::WasNonBrowserUIDisplayed()) {
51 FinishedCollectingMetrics(FinishReason::ABANDON_BLOCKING_UI); 105 FinishedCollectingMetrics(FinishReason::ABANDON_BLOCKING_UI);
52 return; 106 return;
53 } 107 }
54 108
55 collected_paint_metric_ = true; 109 collected_paint_metric_ = true;
56 startup_metric_utils::RecordFirstWebContentsNonEmptyPaint( 110 startup_metric_utils::RecordFirstWebContentsNonEmptyPaint(
57 base::TimeTicks::Now()); 111 base::TimeTicks::Now());
58 112
59 metrics::TrackingSynchronizer::OnProfilingPhaseCompleted( 113 metrics::TrackingSynchronizer::OnProfilingPhaseCompleted(
60 metrics::ProfilerEventProto::EVENT_FIRST_NONEMPTY_PAINT); 114 metrics::ProfilerEventProto::EVENT_FIRST_NONEMPTY_PAINT);
61 115
62 if (IsFinishedCollectingMetrics()) 116 if (IsFinishedCollectingMetrics())
63 FinishedCollectingMetrics(FinishReason::DONE); 117 FinishedCollectingMetrics(FinishReason::DONE);
64 } 118 }
65 119
66 void FirstWebContentsProfiler::DocumentOnLoadCompletedInMainFrame() { 120 void FirstWebContentsProfilerImpl::DocumentOnLoadCompletedInMainFrame() {
67 if (collected_load_metric_) 121 if (collected_load_metric_)
68 return; 122 return;
69 if (startup_metric_utils::WasNonBrowserUIDisplayed()) { 123 if (startup_metric_utils::WasNonBrowserUIDisplayed()) {
70 FinishedCollectingMetrics(FinishReason::ABANDON_BLOCKING_UI); 124 FinishedCollectingMetrics(FinishReason::ABANDON_BLOCKING_UI);
71 return; 125 return;
72 } 126 }
73 127
74 collected_load_metric_ = true; 128 collected_load_metric_ = true;
75 startup_metric_utils::RecordFirstWebContentsMainFrameLoad( 129 startup_metric_utils::RecordFirstWebContentsMainFrameLoad(
76 base::TimeTicks::Now()); 130 base::TimeTicks::Now());
77 131
78 if (IsFinishedCollectingMetrics()) 132 if (IsFinishedCollectingMetrics())
79 FinishedCollectingMetrics(FinishReason::DONE); 133 FinishedCollectingMetrics(FinishReason::DONE);
80 } 134 }
81 135
82 void FirstWebContentsProfiler::DidStartNavigation( 136 void FirstWebContentsProfilerImpl::DidStartNavigation(
83 content::NavigationHandle* navigation_handle) { 137 content::NavigationHandle* navigation_handle) {
84 if (collected_main_navigation_start_metric_) 138 if (collected_main_navigation_start_metric_)
85 return; 139 return;
86 if (startup_metric_utils::WasNonBrowserUIDisplayed()) { 140 if (startup_metric_utils::WasNonBrowserUIDisplayed()) {
87 FinishedCollectingMetrics(FinishReason::ABANDON_BLOCKING_UI); 141 FinishedCollectingMetrics(FinishReason::ABANDON_BLOCKING_UI);
88 return; 142 return;
89 } 143 }
90 144
91 if (content::IsBrowserSideNavigationEnabled()) { 145 if (content::IsBrowserSideNavigationEnabled()) {
92 // With PlzNavigate, DidStartNavigation is called synchronously on 146 // With PlzNavigate, DidStartNavigation is called synchronously on
93 // browser-initiated loads instead of through an IPC. This means that we 147 // browser-initiated loads instead of through an IPC. This means that we
94 // will miss this signal. Instead we record it when the commit completes. 148 // will miss this signal. Instead we record it when the commit completes.
95 return; 149 return;
96 } 150 }
97 151
98 // The first navigation has to be the main frame's. 152 // The first navigation has to be the main frame's.
99 DCHECK(navigation_handle->IsInMainFrame()); 153 DCHECK(navigation_handle->IsInMainFrame());
100 154
101 collected_main_navigation_start_metric_ = true; 155 collected_main_navigation_start_metric_ = true;
102 startup_metric_utils::RecordFirstWebContentsMainNavigationStart( 156 startup_metric_utils::RecordFirstWebContentsMainNavigationStart(
103 base::TimeTicks::Now()); 157 base::TimeTicks::Now(), workload_);
104 } 158 }
105 159
106 void FirstWebContentsProfiler::DidFinishNavigation( 160 void FirstWebContentsProfilerImpl::DidFinishNavigation(
107 content::NavigationHandle* navigation_handle) { 161 content::NavigationHandle* navigation_handle) {
108 if (collected_main_navigation_finished_metric_) { 162 if (collected_main_navigation_finished_metric_) {
109 // Abandon profiling on a top-level navigation to a different page as it: 163 // Abandon profiling on a top-level navigation to a different page as it:
110 // (1) is no longer a fair timing; and 164 // (1) is no longer a fair timing; and
111 // (2) can cause http://crbug.com/525209 where one of the timing 165 // (2) can cause http://crbug.com/525209 where one of the timing
112 // heuristics (e.g. first paint) didn't fire for the initial content 166 // heuristics (e.g. first paint) didn't fire for the initial content
113 // but fires after a lot of idle time when the user finally navigates 167 // but fires after a lot of idle time when the user finally navigates
114 // to another page that does trigger it. 168 // to another page that does trigger it.
115 if (navigation_handle->IsInMainFrame() && 169 if (navigation_handle->IsInMainFrame() &&
116 navigation_handle->HasCommitted() && 170 navigation_handle->HasCommitted() &&
(...skipping 12 matching lines...) Expand all
129 DCHECK(navigation_handle->IsInMainFrame()); 183 DCHECK(navigation_handle->IsInMainFrame());
130 184
131 if (!navigation_handle->HasCommitted() || 185 if (!navigation_handle->HasCommitted() ||
132 navigation_handle->IsErrorPage()) { 186 navigation_handle->IsErrorPage()) {
133 FinishedCollectingMetrics(FinishReason::ABANDON_NAVIGATION_ERROR); 187 FinishedCollectingMetrics(FinishReason::ABANDON_NAVIGATION_ERROR);
134 return; 188 return;
135 } 189 }
136 190
137 if (content::IsBrowserSideNavigationEnabled()) { 191 if (content::IsBrowserSideNavigationEnabled()) {
138 startup_metric_utils::RecordFirstWebContentsMainNavigationStart( 192 startup_metric_utils::RecordFirstWebContentsMainNavigationStart(
139 navigation_handle->NavigationStart()); 193 navigation_handle->NavigationStart(), workload_);
140 collected_main_navigation_start_metric_ = true; 194 collected_main_navigation_start_metric_ = true;
141 } 195 }
142 196
143 collected_main_navigation_finished_metric_ = true; 197 collected_main_navigation_finished_metric_ = true;
144 startup_metric_utils::RecordFirstWebContentsMainNavigationFinished( 198 startup_metric_utils::RecordFirstWebContentsMainNavigationFinished(
145 base::TimeTicks::Now()); 199 base::TimeTicks::Now());
146 } 200 }
147 201
148 void FirstWebContentsProfiler::WasHidden() { 202 void FirstWebContentsProfilerImpl::WasHidden() {
149 // Stop profiling if the content gets hidden as its load may be deprioritized 203 // Stop profiling if the content gets hidden as its load may be deprioritized
150 // and timing it becomes meaningless. 204 // and timing it becomes meaningless.
151 FinishedCollectingMetrics(FinishReason::ABANDON_CONTENT_HIDDEN); 205 FinishedCollectingMetrics(FinishReason::ABANDON_CONTENT_HIDDEN);
152 } 206 }
153 207
154 void FirstWebContentsProfiler::WebContentsDestroyed() { 208 void FirstWebContentsProfilerImpl::WebContentsDestroyed() {
155 FinishedCollectingMetrics(FinishReason::ABANDON_CONTENT_DESTROYED); 209 FinishedCollectingMetrics(FinishReason::ABANDON_CONTENT_DESTROYED);
156 } 210 }
157 211
158 bool FirstWebContentsProfiler::IsFinishedCollectingMetrics() { 212 bool FirstWebContentsProfilerImpl::IsFinishedCollectingMetrics() {
159 return collected_paint_metric_ && collected_load_metric_; 213 return collected_paint_metric_ && collected_load_metric_;
160 } 214 }
161 215
162 void FirstWebContentsProfiler::FinishedCollectingMetrics( 216 void FirstWebContentsProfilerImpl::FinishedCollectingMetrics(
163 FinishReason finish_reason) { 217 FinishReason finish_reason) {
164 UMA_HISTOGRAM_ENUMERATION("Startup.FirstWebContents.FinishReason", 218 UMA_HISTOGRAM_ENUMERATION("Startup.FirstWebContents.FinishReason",
165 finish_reason, FinishReason::ENUM_MAX); 219 finish_reason, FinishReason::ENUM_MAX);
166 if (!collected_paint_metric_) { 220 if (!collected_paint_metric_) {
167 UMA_HISTOGRAM_ENUMERATION("Startup.FirstWebContents.FinishReason_NoPaint", 221 UMA_HISTOGRAM_ENUMERATION("Startup.FirstWebContents.FinishReason_NoPaint",
168 finish_reason, FinishReason::ENUM_MAX); 222 finish_reason, FinishReason::ENUM_MAX);
169 } 223 }
170 if (!collected_load_metric_) { 224 if (!collected_load_metric_) {
171 UMA_HISTOGRAM_ENUMERATION("Startup.FirstWebContents.FinishReason_NoLoad", 225 UMA_HISTOGRAM_ENUMERATION("Startup.FirstWebContents.FinishReason_NoLoad",
172 finish_reason, FinishReason::ENUM_MAX); 226 finish_reason, FinishReason::ENUM_MAX);
173 } 227 }
174 228
175 delete this; 229 delete this;
176 } 230 }
177 231
232 } // namespace
233
234 // static
235 void FirstWebContentsProfiler::Start() {
236 using startup_metric_utils::WebContentsWorkload;
237
238 const BrowserList* browser_list = BrowserList::GetInstance();
239
240 const auto first_browser = browser_list->begin();
241 if (first_browser == browser_list->end())
242 return;
243
244 const TabStripModel* tab_strip = (*first_browser)->tab_strip_model();
245 DCHECK(!tab_strip->empty());
246
247 content::WebContents* web_contents = tab_strip->GetActiveWebContents();
248 DCHECK(web_contents);
249
250 const bool single_tab = browser_list->size() == 1 && tab_strip->count() == 1;
251
252 // FirstWebContentsProfilerImpl owns itself and is also bound to
253 // |web_contents|'s lifetime by observing WebContentsDestroyed().
254 new FirstWebContentsProfilerImpl(
255 web_contents, single_tab ? WebContentsWorkload::SINGLE_TAB
256 : WebContentsWorkload::MULTI_TABS);
257 }
258
178 #endif // !defined(OS_ANDROID) 259 #endif // !defined(OS_ANDROID)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698