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

Side by Side Diff: components/page_load_metrics/browser/metrics_web_contents_observer.cc

Issue 1384213002: Page Abort Events for relevant navigations (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Mirror histogram for backgrounded events. New test. Created 5 years, 2 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 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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 #include "components/page_load_metrics/browser/metrics_web_contents_observer.h" 5 #include "components/page_load_metrics/browser/metrics_web_contents_observer.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/metrics/histogram.h" 8 #include "base/metrics/histogram.h"
9 #include "components/page_load_metrics/common/page_load_metrics_messages.h" 9 #include "components/page_load_metrics/common/page_load_metrics_messages.h"
10 #include "components/page_load_metrics/common/page_load_timing.h" 10 #include "components/page_load_metrics/common/page_load_timing.h"
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
57 } 57 }
58 58
59 } // namespace 59 } // namespace
60 60
61 #define PAGE_LOAD_HISTOGRAM(name, sample) \ 61 #define PAGE_LOAD_HISTOGRAM(name, sample) \
62 UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, \ 62 UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, \
63 base::TimeDelta::FromMilliseconds(10), \ 63 base::TimeDelta::FromMilliseconds(10), \
64 base::TimeDelta::FromMinutes(10), 100) 64 base::TimeDelta::FromMinutes(10), 100)
65 65
66 PageLoadTracker::PageLoadTracker(bool in_foreground) 66 PageLoadTracker::PageLoadTracker(bool in_foreground)
67 : has_commit_(false), started_in_foreground_(in_foreground) { 67 : has_commit_(false), started_in_foreground_(in_foreground) {}
68 RecordEvent(PAGE_LOAD_STARTED);
69 }
70 68
71 PageLoadTracker::~PageLoadTracker() { 69 PageLoadTracker::~PageLoadTracker() {
72 // Even a load that failed a provisional load should log
73 // that it aborted before first layout.
74 if (timing_.first_layout.is_zero())
75 RecordEvent(PAGE_LOAD_ABORTED_BEFORE_FIRST_LAYOUT);
76
77 if (has_commit_) 70 if (has_commit_)
78 RecordTimingHistograms(); 71 RecordTimingHistograms();
79 } 72 }
80 73
81 void PageLoadTracker::WebContentsHidden() { 74 void PageLoadTracker::WebContentsHidden() {
82 // Only log the first time we background in a given page load. 75 // Only log the first time we background in a given page load.
83 if (background_time_.is_null()) { 76 if (started_in_foreground_ && background_time_.is_null())
84 background_time_ = base::TimeTicks::Now(); 77 background_time_ = base::TimeTicks::Now();
85 } 78 }
79
80 void PageLoadTracker::WebContentsShown() {
81 // Only log the first time we foreground in a given page load.
82 // Don't log foreground time if we started foregrounded.
83 if (!started_in_foreground_ && foreground_time_.is_null())
84 foreground_time_ = base::TimeTicks::Now();
86 } 85 }
87 86
88 void PageLoadTracker::Commit() { 87 void PageLoadTracker::Commit() {
89 has_commit_ = true; 88 has_commit_ = true;
89 // This is one special case where we aren't checking if we backgrounded NOW,
90 // but at the start of the navigation.
Randy Smith (Not in Mondays) 2015/10/08 19:07:11 Scanning the rest of the file for the usage of the
Charlie Harrison 2015/10/08 21:27:02 I think it adds a little more context to the backg
91 RecordCommittedEvent(COMMITTED_LOAD_STARTED, !started_in_foreground_);
90 } 92 }
91 93
92 bool PageLoadTracker::UpdateTiming(const PageLoadTiming& timing) { 94 bool PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing) {
93 // Throw away IPCs that are not relevant to the current navigation. 95 // Throw away IPCs that are not relevant to the current navigation.
94 if (!timing_.navigation_start.is_null() && 96 // A valid timing struct is one that has the same navigation start as the
95 timing_.navigation_start != timing.navigation_start) { 97 // previous one (if the previous one had a navigation start at all).
Randy Smith (Not in Mondays) 2015/10/08 19:07:11 This mostly just duplicates what the code says. T
Charlie Harrison 2015/10/08 21:27:02 Done.
96 // TODO(csharrison) uma log a counter here 98 bool valid_timing_descendent =
97 return false; 99 timing_.navigation_start.is_null() ||
98 } 100 timing_.navigation_start == new_timing.navigation_start;
99 if (IsValidPageLoadTiming(timing)) { 101 if (IsValidPageLoadTiming(new_timing) && valid_timing_descendent) {
100 timing_ = timing; 102 timing_ = new_timing;
101 return true; 103 return true;
102 } 104 }
105 RecordCommittedEvent(COMMITTED_LOAD_BAD_IPC, HasBackgrounded());
Randy Smith (Not in Mondays) 2015/10/08 19:07:10 I'm a bit uncomfortable within recording this even
Charlie Harrison 2015/10/08 21:27:02 Done.
103 return false; 106 return false;
104 } 107 }
105 108
109 bool PageLoadTracker::HasBackgrounded() {
110 return !(started_in_foreground_ && background_time_.is_null());
111 }
112
106 void PageLoadTracker::RecordTimingHistograms() { 113 void PageLoadTracker::RecordTimingHistograms() {
107 DCHECK(has_commit_); 114 DCHECK(has_commit_);
108 // This method is similar to how blink converts TimeTicks to epoch time. 115 // This method is similar to how blink converts TimeTicks to epoch time.
109 // There may be slight inaccuracies due to inter-process timestamps, but 116 // There may be slight inaccuracies due to inter-process timestamps, but
110 // this solution is the best we have right now. 117 // this solution is the best we have right now.
Randy Smith (Not in Mondays) 2015/10/08 19:07:10 I continue to be confused by background_delta when
Charlie Harrison 2015/10/08 21:27:02 See what you're saying. Can I update this in my RA
Randy Smith (Not in Mondays) 2015/10/12 15:45:22 Sure, SG.
111 base::TimeDelta background_delta; 118 base::TimeDelta background_delta;
112 if (started_in_foreground_) { 119 if (started_in_foreground_) {
113 background_delta = background_time_.is_null() 120 background_delta = background_time_.is_null()
114 ? base::TimeDelta::Max() 121 ? base::TimeDelta::Max()
115 : WallTimeFromTimeTicks(background_time_) - timing_.navigation_start; 122 : WallTimeFromTimeTicks(background_time_) - timing_.navigation_start;
116 } 123 }
117 124
118 if (!timing_.dom_content_loaded_event_start.is_zero()) { 125 if (!timing_.dom_content_loaded_event_start.is_zero()) {
119 if (timing_.dom_content_loaded_event_start < background_delta) { 126 if (timing_.dom_content_loaded_event_start < background_delta) {
120 PAGE_LOAD_HISTOGRAM( 127 PAGE_LOAD_HISTOGRAM(
121 "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired", 128 "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired",
122 timing_.dom_content_loaded_event_start); 129 timing_.dom_content_loaded_event_start);
123 } else { 130 } else {
124 PAGE_LOAD_HISTOGRAM( 131 PAGE_LOAD_HISTOGRAM(
125 "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired.BG", 132 "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired.BG",
126 timing_.dom_content_loaded_event_start); 133 timing_.dom_content_loaded_event_start);
127 } 134 }
128 } 135 }
129 if (!timing_.load_event_start.is_zero()) { 136 if (!timing_.load_event_start.is_zero()) {
130 if (timing_.load_event_start < background_delta) { 137 if (timing_.load_event_start < background_delta) {
131 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToLoadEventFired", 138 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToLoadEventFired",
132 timing_.load_event_start); 139 timing_.load_event_start);
133 } else { 140 } else {
134 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToLoadEventFired.BG", 141 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToLoadEventFired.BG",
135 timing_.load_event_start); 142 timing_.load_event_start);
136 } 143 }
137 } 144 }
138 if (!timing_.first_layout.is_zero()) { 145 if (timing_.first_layout.is_zero()) {
146 RecordCommittedEvent(COMMITTED_LOAD_ABORTED_BEFORE_FIRST_LAYOUT,
147 HasBackgrounded());
148 } else {
139 if (timing_.first_layout < background_delta) { 149 if (timing_.first_layout < background_delta) {
140 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstLayout", 150 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstLayout",
141 timing_.first_layout); 151 timing_.first_layout);
142 RecordEvent(PAGE_LOAD_SUCCESSFUL_FIRST_LAYOUT_FOREGROUND); 152 RecordCommittedEvent(COMMITTED_LOAD_SUCCESSFUL_FIRST_LAYOUT, false);
143 } else { 153 } else {
144 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstLayout.BG", 154 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstLayout.BG",
145 timing_.first_layout); 155 timing_.first_layout);
146 RecordEvent(PAGE_LOAD_SUCCESSFUL_FIRST_LAYOUT_BACKGROUND); 156 RecordCommittedEvent(COMMITTED_LOAD_SUCCESSFUL_FIRST_LAYOUT, true);
147 } 157 }
148 } 158 }
149 if (!timing_.first_text_paint.is_zero()) { 159 if (!timing_.first_text_paint.is_zero()) {
150 if (timing_.first_text_paint < background_delta) { 160 if (timing_.first_text_paint < background_delta) {
151 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstTextPaint", 161 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstTextPaint",
152 timing_.first_text_paint); 162 timing_.first_text_paint);
153 } else { 163 } else {
154 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstTextPaint.BG", 164 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstTextPaint.BG",
155 timing_.first_text_paint); 165 timing_.first_text_paint);
156 } 166 }
157 } 167 }
168 // Log time to first foreground / time to first background. Log counts that we
169 // started a relevant page load in the foreground / background.
170 if (!background_time_.is_null()) {
171 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstBackground",
172 background_delta);
173 } else if (!foreground_time_.is_null()) {
174 PAGE_LOAD_HISTOGRAM(
175 "PageLoad.Timing2.NavigationToFirstForeground",
176 WallTimeFromTimeTicks(foreground_time_) - timing_.navigation_start);
177 }
158 } 178 }
159 179
160 void PageLoadTracker::RecordEvent(PageLoadEvent event) { 180 void PageLoadTracker::RecordProvisionalEvent(ProvisionalLoadEvent event) {
161 UMA_HISTOGRAM_ENUMERATION( 181 if (HasBackgrounded()) {
162 "PageLoad.EventCounts", event, PAGE_LOAD_LAST_ENTRY); 182 UMA_HISTOGRAM_ENUMERATION("PageLoad.Events.Provisional.BG", event,
Randy Smith (Not in Mondays) 2015/10/08 19:07:10 I'd like to get rid of "BG" and use "Background" a
Charlie Harrison 2015/10/08 21:27:02 Is it worth it to have to deprecate the PageLoad.T
Randy Smith (Not in Mondays) 2015/10/12 15:45:22 I think I'd say "No, but I still think we should d
183 PROVISIONAL_LOAD_LAST_ENTRY);
184 } else {
185 UMA_HISTOGRAM_ENUMERATION("PageLoad.Events.Provisional", event,
186 PROVISIONAL_LOAD_LAST_ENTRY);
187 }
188 }
189
190 // RecordCommittedEvent needs a backgrounded input because we need to special
191 // case a few events that need either precise timing measurements, or different
192 // logic than simply "Did I background before logging this event?"
193 void PageLoadTracker::RecordCommittedEvent(CommittedLoadEvent event,
194 bool backgrounded) {
195 if (backgrounded) {
196 UMA_HISTOGRAM_ENUMERATION("PageLoad.Events.Committed.BG", event,
197 COMMITTED_LOAD_LAST_ENTRY);
198 } else {
199 UMA_HISTOGRAM_ENUMERATION("PageLoad.Events.Committed", event,
200 COMMITTED_LOAD_LAST_ENTRY);
201 }
163 } 202 }
164 203
165 MetricsWebContentsObserver::MetricsWebContentsObserver( 204 MetricsWebContentsObserver::MetricsWebContentsObserver(
166 content::WebContents* web_contents) 205 content::WebContents* web_contents)
167 : content::WebContentsObserver(web_contents), in_foreground_(false) {} 206 : content::WebContentsObserver(web_contents), in_foreground_(false) {}
168 207
169 MetricsWebContentsObserver::~MetricsWebContentsObserver() {} 208 MetricsWebContentsObserver::~MetricsWebContentsObserver() {}
170 209
171 bool MetricsWebContentsObserver::OnMessageReceived( 210 bool MetricsWebContentsObserver::OnMessageReceived(
172 const IPC::Message& message, 211 const IPC::Message& message,
(...skipping 25 matching lines...) Expand all
198 if (!navigation_handle->IsInMainFrame()) 237 if (!navigation_handle->IsInMainFrame())
199 return; 238 return;
200 239
201 scoped_ptr<PageLoadTracker> finished_nav( 240 scoped_ptr<PageLoadTracker> finished_nav(
202 provisional_loads_.take_and_erase(navigation_handle)); 241 provisional_loads_.take_and_erase(navigation_handle));
203 DCHECK(finished_nav); 242 DCHECK(finished_nav);
204 243
205 // Handle a pre-commit error here. Navigations that result in an error page 244 // Handle a pre-commit error here. Navigations that result in an error page
206 // will be ignored. 245 // will be ignored.
207 if (!navigation_handle->HasCommitted()) { 246 if (!navigation_handle->HasCommitted()) {
208 finished_nav->RecordEvent(PAGE_LOAD_FAILED_BEFORE_COMMIT);
209 if (navigation_handle->GetNetErrorCode() == net::ERR_ABORTED) 247 if (navigation_handle->GetNetErrorCode() == net::ERR_ABORTED)
210 finished_nav->RecordEvent(PAGE_LOAD_ABORTED_BEFORE_COMMIT); 248 finished_nav->RecordProvisionalEvent(PROVISIONAL_LOAD_ABORTED);
249 else
250 finished_nav->RecordProvisionalEvent(PROVISIONAL_LOAD_FAILED_NON_ABORT);
211 return; 251 return;
212 } 252 }
253 finished_nav->RecordProvisionalEvent(PROVISIONAL_LOAD_COMMITTED);
213 254
214 // Don't treat a same-page nav as a new page load. 255 // Don't treat a same-page nav as a new page load.
215 if (navigation_handle->IsSamePage()) 256 if (navigation_handle->IsSamePage())
216 return; 257 return;
217 258
218 // Eagerly log the previous UMA even if we don't care about the current 259 // Eagerly log the previous UMA even if we don't care about the current
219 // navigation. 260 // navigation.
220 committed_load_.reset(); 261 committed_load_.reset();
221 262
222 if (!IsRelevantNavigation(navigation_handle)) 263 if (!IsRelevantNavigation(navigation_handle))
223 return; 264 return;
224 265
225 committed_load_ = finished_nav.Pass(); 266 committed_load_ = finished_nav.Pass();
226 committed_load_->Commit(); 267 committed_load_->Commit();
227 } 268 }
228 269
229 void MetricsWebContentsObserver::WasShown() { 270 void MetricsWebContentsObserver::WasShown() {
230 in_foreground_ = true; 271 in_foreground_ = true;
272 if (committed_load_)
273 committed_load_->WebContentsShown();
274 for (const auto& kv : provisional_loads_) {
275 kv.second->WebContentsShown();
276 }
231 } 277 }
232 278
233 void MetricsWebContentsObserver::WasHidden() { 279 void MetricsWebContentsObserver::WasHidden() {
234 in_foreground_ = false; 280 in_foreground_ = false;
235 if (committed_load_) 281 if (committed_load_)
236 committed_load_->WebContentsHidden(); 282 committed_load_->WebContentsHidden();
237 for (const auto& kv : provisional_loads_) { 283 for (const auto& kv : provisional_loads_) {
238 kv.second->WebContentsHidden(); 284 kv.second->WebContentsHidden();
239 } 285 }
240 } 286 }
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 // sure here that we aren't logging UMA for internal pages. 320 // sure here that we aren't logging UMA for internal pages.
275 const GURL& browser_url = web_contents()->GetLastCommittedURL(); 321 const GURL& browser_url = web_contents()->GetLastCommittedURL();
276 return navigation_handle->IsInMainFrame() && 322 return navigation_handle->IsInMainFrame() &&
277 !navigation_handle->IsSamePage() && 323 !navigation_handle->IsSamePage() &&
278 !navigation_handle->IsErrorPage() && 324 !navigation_handle->IsErrorPage() &&
279 navigation_handle->GetURL().SchemeIsHTTPOrHTTPS() && 325 navigation_handle->GetURL().SchemeIsHTTPOrHTTPS() &&
280 browser_url.SchemeIsHTTPOrHTTPS(); 326 browser_url.SchemeIsHTTPOrHTTPS();
281 } 327 }
282 328
283 } // namespace page_load_metrics 329 } // namespace page_load_metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698