OLD | NEW |
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/location.h" | 7 #include "base/location.h" |
8 #include "base/logging.h" | 8 #include "base/logging.h" |
9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
10 #include "components/page_load_metrics/browser/page_load_metrics_macros.h" | 10 #include "components/page_load_metrics/browser/page_load_metrics_macros.h" |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 if (!timing.load_event_start.is_zero() && | 69 if (!timing.load_event_start.is_zero() && |
70 (timing.dom_content_loaded_event_start.is_zero() || | 70 (timing.dom_content_loaded_event_start.is_zero() || |
71 timing.response_start > timing.load_event_start || | 71 timing.response_start > timing.load_event_start || |
72 timing.dom_content_loaded_event_start > timing.load_event_start)) { | 72 timing.dom_content_loaded_event_start > timing.load_event_start)) { |
73 return false; | 73 return false; |
74 } | 74 } |
75 | 75 |
76 return true; | 76 return true; |
77 } | 77 } |
78 | 78 |
79 base::Time WallTimeFromTimeTicks(const base::TimeTicks& time) { | |
80 return base::Time::FromDoubleT( | |
81 (time - base::TimeTicks::UnixEpoch()).InSecondsF()); | |
82 } | |
83 | |
84 void RecordInternalError(InternalErrorLoadEvent event) { | 79 void RecordInternalError(InternalErrorLoadEvent event) { |
85 UMA_HISTOGRAM_ENUMERATION(kErrorEvents, event, ERR_LAST_ENTRY); | 80 UMA_HISTOGRAM_ENUMERATION(kErrorEvents, event, ERR_LAST_ENTRY); |
86 } | 81 } |
87 | 82 |
88 base::TimeDelta GetFirstContentfulPaint(const PageLoadTiming& timing) { | 83 base::TimeDelta GetFirstContentfulPaint(const PageLoadTiming& timing) { |
89 if (timing.first_text_paint.is_zero()) | 84 if (timing.first_text_paint.is_zero()) |
90 return timing.first_image_paint; | 85 return timing.first_image_paint; |
91 if (timing.first_image_paint.is_zero()) | 86 if (timing.first_image_paint.is_zero()) |
92 return timing.first_text_paint; | 87 return timing.first_text_paint; |
93 return std::min(timing.first_text_paint, timing.first_image_paint); | 88 return std::min(timing.first_text_paint, timing.first_image_paint); |
(...skipping 20 matching lines...) Expand all Loading... |
114 if (seconds < 32) | 109 if (seconds < 32) |
115 return 4; | 110 return 4; |
116 return 5; | 111 return 5; |
117 } | 112 } |
118 | 113 |
119 } // namespace | 114 } // namespace |
120 | 115 |
121 PageLoadTracker::PageLoadTracker( | 116 PageLoadTracker::PageLoadTracker( |
122 bool in_foreground, | 117 bool in_foreground, |
123 PageLoadMetricsEmbedderInterface* embedder_interface, | 118 PageLoadMetricsEmbedderInterface* embedder_interface, |
| 119 content::NavigationHandle* navigation_handle, |
124 base::ObserverList<PageLoadMetricsObserver, true>* observers) | 120 base::ObserverList<PageLoadMetricsObserver, true>* observers) |
125 : has_commit_(false), | 121 : has_commit_(false), |
| 122 navigation_start_(navigation_handle->NavigationStart()), |
126 started_in_foreground_(in_foreground), | 123 started_in_foreground_(in_foreground), |
127 embedder_interface_(embedder_interface), | 124 embedder_interface_(embedder_interface), |
128 observers_(observers) {} | 125 observers_(observers) {} |
129 | 126 |
130 PageLoadTracker::~PageLoadTracker() { | 127 PageLoadTracker::~PageLoadTracker() { |
131 if (has_commit_) { | 128 if (has_commit_) { |
132 RecordTimingHistograms(); | 129 RecordTimingHistograms(); |
133 RecordRappor(); | 130 RecordRappor(); |
134 } | 131 } |
135 } | 132 } |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
174 return false; | 171 return false; |
175 } | 172 } |
176 | 173 |
177 bool PageLoadTracker::HasBackgrounded() { | 174 bool PageLoadTracker::HasBackgrounded() { |
178 return !started_in_foreground_ || !background_time_.is_null(); | 175 return !started_in_foreground_ || !background_time_.is_null(); |
179 } | 176 } |
180 | 177 |
181 PageLoadExtraInfo PageLoadTracker::GetPageLoadMetricsInfo() { | 178 PageLoadExtraInfo PageLoadTracker::GetPageLoadMetricsInfo() { |
182 base::TimeDelta first_background_time; | 179 base::TimeDelta first_background_time; |
183 base::TimeDelta first_foreground_time; | 180 base::TimeDelta first_foreground_time; |
184 if (!background_time_.is_null() && started_in_foreground_) { | 181 if (!background_time_.is_null() && started_in_foreground_) |
185 first_background_time = | 182 first_background_time = background_time_ - navigation_start_; |
186 WallTimeFromTimeTicks(background_time_) - timing_.navigation_start; | 183 if (!foreground_time_.is_null() && !started_in_foreground_) |
187 } | 184 first_foreground_time = foreground_time_ - navigation_start_; |
188 if (!foreground_time_.is_null() && !started_in_foreground_) { | |
189 first_foreground_time = | |
190 WallTimeFromTimeTicks(foreground_time_) - timing_.navigation_start; | |
191 } | |
192 return PageLoadExtraInfo(first_background_time, first_foreground_time, | 185 return PageLoadExtraInfo(first_background_time, first_foreground_time, |
193 started_in_foreground_); | 186 started_in_foreground_); |
194 } | 187 } |
195 | 188 |
196 const GURL& PageLoadTracker::GetCommittedURL() { | 189 const GURL& PageLoadTracker::GetCommittedURL() { |
197 DCHECK(has_commit_); | 190 DCHECK(has_commit_); |
198 return url_; | 191 return url_; |
199 } | 192 } |
200 | 193 |
201 // Blink calculates navigation start using TimeTicks, but converts to epoch time | 194 // Blink calculates navigation start using TimeTicks, but converts to epoch time |
202 // in its public API. Thus, to compare time values to navigation start, we | 195 // in its public API. Thus, to compare time values to navigation start, we |
203 // calculate the current time since the epoch using TimeTicks, and convert to | 196 // calculate the current time since the epoch using TimeTicks, and convert to |
204 // Time. This method is similar to how blink converts TimeTicks to epoch time. | 197 // Time. This method is similar to how blink converts TimeTicks to epoch time. |
205 // There may be slight inaccuracies due to inter-process timestamps, but | 198 // There may be slight inaccuracies due to inter-process timestamps, but |
206 // this solution is the best we have right now. | 199 // this solution is the best we have right now. |
207 // | 200 // |
208 // returns a TimeDelta which is | 201 // returns a TimeDelta which is |
209 // - Infinity if we were never backgrounded | 202 // - Infinity if we were never backgrounded |
210 // - null (TimeDelta()) if we started backgrounded | 203 // - null (TimeDelta()) if we started backgrounded |
211 // - elapsed time to first background if we started in the foreground and | 204 // - elapsed time to first background if we started in the foreground and |
212 // backgrounded. | 205 // backgrounded. |
213 base::TimeDelta PageLoadTracker::GetBackgroundDelta() { | 206 base::TimeDelta PageLoadTracker::GetBackgroundDelta() { |
214 if (started_in_foreground_) { | 207 if (started_in_foreground_) { |
215 if (background_time_.is_null()) | 208 return background_time_.is_null() ? base::TimeDelta::Max() |
216 return base::TimeDelta::Max(); | 209 : background_time_ - navigation_start_; |
217 return WallTimeFromTimeTicks(background_time_) - timing_.navigation_start; | |
218 } | 210 } |
219 return base::TimeDelta(); | 211 return base::TimeDelta(); |
220 } | 212 } |
221 | 213 |
222 void PageLoadTracker::RecordTimingHistograms() { | 214 void PageLoadTracker::RecordTimingHistograms() { |
223 DCHECK(has_commit_); | 215 DCHECK(has_commit_); |
224 if (timing_.IsEmpty()) { | 216 if (timing_.IsEmpty()) { |
225 RecordInternalError(ERR_NO_IPCS_RECEIVED); | 217 RecordInternalError(ERR_NO_IPCS_RECEIVED); |
226 return; | 218 return; |
227 } | 219 } |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
293 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstContentfulPaint, | 285 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstContentfulPaint, |
294 first_contentful_paint); | 286 first_contentful_paint); |
295 } | 287 } |
296 } | 288 } |
297 | 289 |
298 // Log time to first foreground / time to first background. Log counts that we | 290 // Log time to first foreground / time to first background. Log counts that we |
299 // started a relevant page load in the foreground / background. | 291 // started a relevant page load in the foreground / background. |
300 if (!background_time_.is_null()) { | 292 if (!background_time_.is_null()) { |
301 PAGE_LOAD_HISTOGRAM(kHistogramFirstBackground, background_delta); | 293 PAGE_LOAD_HISTOGRAM(kHistogramFirstBackground, background_delta); |
302 } else if (!foreground_time_.is_null()) { | 294 } else if (!foreground_time_.is_null()) { |
303 PAGE_LOAD_HISTOGRAM( | 295 PAGE_LOAD_HISTOGRAM(kHistogramFirstForeground, |
304 kHistogramFirstForeground, | 296 foreground_time_ - navigation_start_); |
305 WallTimeFromTimeTicks(foreground_time_) - timing_.navigation_start); | |
306 } | 297 } |
307 } | 298 } |
308 | 299 |
309 void PageLoadTracker::RecordProvisionalEvent(ProvisionalLoadEvent event) { | 300 void PageLoadTracker::RecordProvisionalEvent(ProvisionalLoadEvent event) { |
310 if (HasBackgrounded()) { | 301 if (HasBackgrounded()) { |
311 UMA_HISTOGRAM_ENUMERATION(kBackgroundProvisionalEvents, event, | 302 UMA_HISTOGRAM_ENUMERATION(kBackgroundProvisionalEvents, event, |
312 PROVISIONAL_LOAD_LAST_ENTRY); | 303 PROVISIONAL_LOAD_LAST_ENTRY); |
313 } else { | 304 } else { |
314 UMA_HISTOGRAM_ENUMERATION(kProvisionalEvents, event, | 305 UMA_HISTOGRAM_ENUMERATION(kProvisionalEvents, event, |
315 PROVISIONAL_LOAD_LAST_ENTRY); | 306 PROVISIONAL_LOAD_LAST_ENTRY); |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
414 return; | 405 return; |
415 if (embedder_interface_->IsPrerendering(web_contents())) | 406 if (embedder_interface_->IsPrerendering(web_contents())) |
416 return; | 407 return; |
417 // We can have two provisional loads in some cases. E.g. a same-site | 408 // We can have two provisional loads in some cases. E.g. a same-site |
418 // navigation can have a concurrent cross-process navigation started | 409 // navigation can have a concurrent cross-process navigation started |
419 // from the omnibox. | 410 // from the omnibox. |
420 DCHECK_GT(2ul, provisional_loads_.size()); | 411 DCHECK_GT(2ul, provisional_loads_.size()); |
421 // Passing raw pointers to observers_ and embedder_interface_ is safe because | 412 // Passing raw pointers to observers_ and embedder_interface_ is safe because |
422 // the MetricsWebContentsObserver owns them both list and they are torn down | 413 // the MetricsWebContentsObserver owns them both list and they are torn down |
423 // after the PageLoadTracker. | 414 // after the PageLoadTracker. |
424 provisional_loads_.insert( | 415 provisional_loads_.insert(navigation_handle, |
425 navigation_handle, | 416 make_scoped_ptr(new PageLoadTracker( |
426 make_scoped_ptr(new PageLoadTracker( | 417 in_foreground_, embedder_interface_.get(), |
427 in_foreground_, embedder_interface_.get(), &observers_))); | 418 navigation_handle, &observers_))); |
428 } | 419 } |
429 | 420 |
430 void MetricsWebContentsObserver::DidFinishNavigation( | 421 void MetricsWebContentsObserver::DidFinishNavigation( |
431 content::NavigationHandle* navigation_handle) { | 422 content::NavigationHandle* navigation_handle) { |
432 if (!navigation_handle->IsInMainFrame()) | 423 if (!navigation_handle->IsInMainFrame()) |
433 return; | 424 return; |
434 | 425 |
435 scoped_ptr<PageLoadTracker> finished_nav( | 426 scoped_ptr<PageLoadTracker> finished_nav( |
436 provisional_loads_.take_and_erase(navigation_handle)); | 427 provisional_loads_.take_and_erase(navigation_handle)); |
437 // There's a chance a navigation could have started before we were added to a | 428 // There's a chance a navigation could have started before we were added to a |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
526 | 517 |
527 if (!committed_load_->UpdateTiming(timing)) { | 518 if (!committed_load_->UpdateTiming(timing)) { |
528 // If the page load tracker cannot update its timing, something is wrong | 519 // If the page load tracker cannot update its timing, something is wrong |
529 // with the IPC (it's from another load, or it's invalid in some other way). | 520 // with the IPC (it's from another load, or it's invalid in some other way). |
530 // We expect this to be a rare occurrence. | 521 // We expect this to be a rare occurrence. |
531 RecordInternalError(ERR_BAD_TIMING_IPC); | 522 RecordInternalError(ERR_BAD_TIMING_IPC); |
532 } | 523 } |
533 } | 524 } |
534 | 525 |
535 } // namespace page_load_metrics | 526 } // namespace page_load_metrics |
OLD | NEW |