| 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 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 75 | 75 |
| 76 return true; | 76 return true; |
| 77 } | 77 } |
| 78 | 78 |
| 79 base::Time WallTimeFromTimeTicks(const base::TimeTicks& time) { | 79 base::Time WallTimeFromTimeTicks(const base::TimeTicks& time) { |
| 80 return base::Time::FromDoubleT( | 80 return base::Time::FromDoubleT( |
| 81 (time - base::TimeTicks::UnixEpoch()).InSecondsF()); | 81 (time - base::TimeTicks::UnixEpoch()).InSecondsF()); |
| 82 } | 82 } |
| 83 | 83 |
| 84 void RecordInternalError(InternalErrorLoadEvent event) { | 84 void RecordInternalError(InternalErrorLoadEvent event) { |
| 85 UMA_HISTOGRAM_ENUMERATION( | 85 UMA_HISTOGRAM_ENUMERATION(kErrorEvents, event, ERR_LAST_ENTRY); |
| 86 "PageLoad.Events.InternalError", event, ERR_LAST_ENTRY); | |
| 87 } | 86 } |
| 88 | 87 |
| 89 base::TimeDelta GetFirstContentfulPaint(const PageLoadTiming& timing) { | 88 base::TimeDelta GetFirstContentfulPaint(const PageLoadTiming& timing) { |
| 90 if (timing.first_text_paint.is_zero()) | 89 if (timing.first_text_paint.is_zero()) |
| 91 return timing.first_image_paint; | 90 return timing.first_image_paint; |
| 92 if (timing.first_image_paint.is_zero()) | 91 if (timing.first_image_paint.is_zero()) |
| 93 return timing.first_text_paint; | 92 return timing.first_text_paint; |
| 94 return std::min(timing.first_text_paint, timing.first_image_paint); | 93 return std::min(timing.first_text_paint, timing.first_image_paint); |
| 95 } | 94 } |
| 96 | 95 |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 228 } | 227 } |
| 229 | 228 |
| 230 PageLoadExtraInfo info = GetPageLoadMetricsInfo(); | 229 PageLoadExtraInfo info = GetPageLoadMetricsInfo(); |
| 231 FOR_EACH_OBSERVER(PageLoadMetricsObserver, *observers_, | 230 FOR_EACH_OBSERVER(PageLoadMetricsObserver, *observers_, |
| 232 OnComplete(timing_, info)); | 231 OnComplete(timing_, info)); |
| 233 | 232 |
| 234 base::TimeDelta background_delta = GetBackgroundDelta(); | 233 base::TimeDelta background_delta = GetBackgroundDelta(); |
| 235 | 234 |
| 236 if (!timing_.dom_content_loaded_event_start.is_zero()) { | 235 if (!timing_.dom_content_loaded_event_start.is_zero()) { |
| 237 if (timing_.dom_content_loaded_event_start < background_delta) { | 236 if (timing_.dom_content_loaded_event_start < background_delta) { |
| 238 PAGE_LOAD_HISTOGRAM( | 237 PAGE_LOAD_HISTOGRAM(kHistogramDomContentLoaded, |
| 239 "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired", | 238 timing_.dom_content_loaded_event_start); |
| 240 timing_.dom_content_loaded_event_start); | |
| 241 } else { | 239 } else { |
| 242 PAGE_LOAD_HISTOGRAM( | 240 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramDomContentLoaded, |
| 243 "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired.Background", | 241 timing_.dom_content_loaded_event_start); |
| 244 timing_.dom_content_loaded_event_start); | |
| 245 } | 242 } |
| 246 } | 243 } |
| 247 if (!timing_.load_event_start.is_zero()) { | 244 if (!timing_.load_event_start.is_zero()) { |
| 248 if (timing_.load_event_start < background_delta) { | 245 if (timing_.load_event_start < background_delta) { |
| 249 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToLoadEventFired", | 246 PAGE_LOAD_HISTOGRAM(kHistogramLoad, timing_.load_event_start); |
| 250 timing_.load_event_start); | |
| 251 } else { | 247 } else { |
| 252 PAGE_LOAD_HISTOGRAM( | 248 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramLoad, timing_.load_event_start); |
| 253 "PageLoad.Timing2.NavigationToLoadEventFired.Background", | |
| 254 timing_.load_event_start); | |
| 255 } | 249 } |
| 256 } | 250 } |
| 257 if (timing_.first_layout.is_zero()) { | 251 if (timing_.first_layout.is_zero()) { |
| 258 RecordCommittedEvent(COMMITTED_LOAD_FAILED_BEFORE_FIRST_LAYOUT, | 252 RecordCommittedEvent(COMMITTED_LOAD_FAILED_BEFORE_FIRST_LAYOUT, |
| 259 HasBackgrounded()); | 253 HasBackgrounded()); |
| 260 } else { | 254 } else { |
| 261 if (timing_.first_layout < background_delta) { | 255 if (timing_.first_layout < background_delta) { |
| 262 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstLayout", | 256 PAGE_LOAD_HISTOGRAM(kHistogramFirstLayout, timing_.first_layout); |
| 263 timing_.first_layout); | |
| 264 RecordCommittedEvent(COMMITTED_LOAD_SUCCESSFUL_FIRST_LAYOUT, false); | 257 RecordCommittedEvent(COMMITTED_LOAD_SUCCESSFUL_FIRST_LAYOUT, false); |
| 265 } else { | 258 } else { |
| 266 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstLayout.Background", | 259 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstLayout, |
| 267 timing_.first_layout); | 260 timing_.first_layout); |
| 268 RecordCommittedEvent(COMMITTED_LOAD_SUCCESSFUL_FIRST_LAYOUT, true); | 261 RecordCommittedEvent(COMMITTED_LOAD_SUCCESSFUL_FIRST_LAYOUT, true); |
| 269 } | 262 } |
| 270 } | 263 } |
| 271 if (!timing_.first_paint.is_zero()) { | 264 if (!timing_.first_paint.is_zero()) { |
| 272 if (timing_.first_paint < background_delta) { | 265 if (timing_.first_paint < background_delta) { |
| 273 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstPaint", | 266 PAGE_LOAD_HISTOGRAM(kHistogramFirstPaint, timing_.first_paint); |
| 274 timing_.first_paint); | |
| 275 } else { | 267 } else { |
| 276 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstPaint.Background", | 268 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstPaint, timing_.first_paint); |
| 277 timing_.first_paint); | |
| 278 } | 269 } |
| 279 } | 270 } |
| 280 if (!timing_.first_text_paint.is_zero()) { | 271 if (!timing_.first_text_paint.is_zero()) { |
| 281 if (timing_.first_text_paint < background_delta) { | 272 if (timing_.first_text_paint < background_delta) { |
| 282 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstTextPaint", | 273 PAGE_LOAD_HISTOGRAM(kHistogramFirstTextPaint, timing_.first_text_paint); |
| 274 } else { |
| 275 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstTextPaint, |
| 283 timing_.first_text_paint); | 276 timing_.first_text_paint); |
| 284 } else { | |
| 285 PAGE_LOAD_HISTOGRAM( | |
| 286 "PageLoad.Timing2.NavigationToFirstTextPaint.Background", | |
| 287 timing_.first_text_paint); | |
| 288 } | 277 } |
| 289 } | 278 } |
| 290 if (!timing_.first_image_paint.is_zero()) { | 279 if (!timing_.first_image_paint.is_zero()) { |
| 291 if (timing_.first_image_paint < background_delta) { | 280 if (timing_.first_image_paint < background_delta) { |
| 292 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstImagePaint", | 281 PAGE_LOAD_HISTOGRAM(kHistogramFirstImagePaint, timing_.first_image_paint); |
| 282 } else { |
| 283 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstImagePaint, |
| 293 timing_.first_image_paint); | 284 timing_.first_image_paint); |
| 294 } else { | |
| 295 PAGE_LOAD_HISTOGRAM( | |
| 296 "PageLoad.Timing2.NavigationToFirstImagePaint.Background", | |
| 297 timing_.first_image_paint); | |
| 298 } | 285 } |
| 299 } | 286 } |
| 300 base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing_); | 287 base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing_); |
| 301 if (!first_contentful_paint.is_zero()) { | 288 if (!first_contentful_paint.is_zero()) { |
| 302 if (first_contentful_paint < background_delta) { | 289 if (first_contentful_paint < background_delta) { |
| 303 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstContentfulPaint", | 290 PAGE_LOAD_HISTOGRAM(kHistogramFirstContentfulPaint, |
| 304 first_contentful_paint); | 291 first_contentful_paint); |
| 305 } else { | 292 } else { |
| 306 PAGE_LOAD_HISTOGRAM( | 293 PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstContentfulPaint, |
| 307 "PageLoad.Timing2.NavigationToFirstContentfulPaint.Background", | 294 first_contentful_paint); |
| 308 first_contentful_paint); | |
| 309 } | 295 } |
| 310 } | 296 } |
| 311 | 297 |
| 312 // Log time to first foreground / time to first background. Log counts that we | 298 // Log time to first foreground / time to first background. Log counts that we |
| 313 // started a relevant page load in the foreground / background. | 299 // started a relevant page load in the foreground / background. |
| 314 if (!background_time_.is_null()) { | 300 if (!background_time_.is_null()) { |
| 315 PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstBackground", | 301 PAGE_LOAD_HISTOGRAM(kHistogramFirstBackground, background_delta); |
| 316 background_delta); | |
| 317 } else if (!foreground_time_.is_null()) { | 302 } else if (!foreground_time_.is_null()) { |
| 318 PAGE_LOAD_HISTOGRAM( | 303 PAGE_LOAD_HISTOGRAM( |
| 319 "PageLoad.Timing2.NavigationToFirstForeground", | 304 kHistogramFirstForeground, |
| 320 WallTimeFromTimeTicks(foreground_time_) - timing_.navigation_start); | 305 WallTimeFromTimeTicks(foreground_time_) - timing_.navigation_start); |
| 321 } | 306 } |
| 322 } | 307 } |
| 323 | 308 |
| 324 void PageLoadTracker::RecordProvisionalEvent(ProvisionalLoadEvent event) { | 309 void PageLoadTracker::RecordProvisionalEvent(ProvisionalLoadEvent event) { |
| 325 if (HasBackgrounded()) { | 310 if (HasBackgrounded()) { |
| 326 UMA_HISTOGRAM_ENUMERATION("PageLoad.Events.Provisional.Background", event, | 311 UMA_HISTOGRAM_ENUMERATION(kBackgroundProvisionalEvents, event, |
| 327 PROVISIONAL_LOAD_LAST_ENTRY); | 312 PROVISIONAL_LOAD_LAST_ENTRY); |
| 328 } else { | 313 } else { |
| 329 UMA_HISTOGRAM_ENUMERATION("PageLoad.Events.Provisional", event, | 314 UMA_HISTOGRAM_ENUMERATION(kProvisionalEvents, event, |
| 330 PROVISIONAL_LOAD_LAST_ENTRY); | 315 PROVISIONAL_LOAD_LAST_ENTRY); |
| 331 } | 316 } |
| 332 } | 317 } |
| 333 | 318 |
| 334 // RecordCommittedEvent needs a backgrounded input because we need to special | 319 // RecordCommittedEvent needs a backgrounded input because we need to special |
| 335 // case a few events that need either precise timing measurements, or different | 320 // case a few events that need either precise timing measurements, or different |
| 336 // logic than simply "Did I background before logging this event?" | 321 // logic than simply "Did I background before logging this event?" |
| 337 void PageLoadTracker::RecordCommittedEvent(CommittedLoadEvent event, | 322 void PageLoadTracker::RecordCommittedEvent(CommittedLoadEvent event, |
| 338 bool backgrounded) { | 323 bool backgrounded) { |
| 339 if (backgrounded) { | 324 if (backgrounded) { |
| 340 UMA_HISTOGRAM_ENUMERATION("PageLoad.Events.Committed.Background", event, | 325 UMA_HISTOGRAM_ENUMERATION(kBackgroundCommittedEvents, event, |
| 341 COMMITTED_LOAD_LAST_ENTRY); | 326 COMMITTED_LOAD_LAST_ENTRY); |
| 342 } else { | 327 } else { |
| 343 UMA_HISTOGRAM_ENUMERATION("PageLoad.Events.Committed", event, | 328 UMA_HISTOGRAM_ENUMERATION(kCommittedEvents, event, |
| 344 COMMITTED_LOAD_LAST_ENTRY); | 329 COMMITTED_LOAD_LAST_ENTRY); |
| 345 } | 330 } |
| 346 } | 331 } |
| 347 | 332 |
| 348 void PageLoadTracker::RecordRappor() { | 333 void PageLoadTracker::RecordRappor() { |
| 349 DCHECK(!GetCommittedURL().is_empty()); | 334 DCHECK(!GetCommittedURL().is_empty()); |
| 350 rappor::RapporService* rappor_service = | 335 rappor::RapporService* rappor_service = |
| 351 embedder_interface_->GetRapporService(); | 336 embedder_interface_->GetRapporService(); |
| 352 if (!rappor_service) | 337 if (!rappor_service) |
| 353 return; | 338 return; |
| 354 base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing_); | 339 base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing_); |
| 355 // Log the eTLD+1 of sites that show poor loading performance. | 340 // Log the eTLD+1 of sites that show poor loading performance. |
| 356 if (!first_contentful_paint.is_zero() && | 341 if (!first_contentful_paint.is_zero() && |
| 357 first_contentful_paint < GetBackgroundDelta()) { | 342 first_contentful_paint < GetBackgroundDelta()) { |
| 358 scoped_ptr<rappor::Sample> sample = | 343 scoped_ptr<rappor::Sample> sample = |
| 359 rappor_service->CreateSample(rappor::UMA_RAPPOR_TYPE); | 344 rappor_service->CreateSample(rappor::UMA_RAPPOR_TYPE); |
| 360 sample->SetStringField("Domain", rappor::GetDomainAndRegistrySampleFromGURL( | 345 sample->SetStringField("Domain", rappor::GetDomainAndRegistrySampleFromGURL( |
| 361 GetCommittedURL())); | 346 GetCommittedURL())); |
| 362 uint64_t bucket_index = RapporHistogramBucketIndex(first_contentful_paint); | 347 uint64_t bucket_index = RapporHistogramBucketIndex(first_contentful_paint); |
| 363 sample->SetFlagsField("Bucket", uint64_t(1) << bucket_index, | 348 sample->SetFlagsField("Bucket", uint64_t(1) << bucket_index, |
| 364 kNumRapporHistogramBuckets); | 349 kNumRapporHistogramBuckets); |
| 365 // The IsSlow flag is just a one bit boolean if the first layout was > 10s. | 350 // The IsSlow flag is just a one bit boolean if the first layout was > 10s. |
| 366 sample->SetFlagsField("IsSlow", first_contentful_paint.InSecondsF() >= 10, | 351 sample->SetFlagsField("IsSlow", first_contentful_paint.InSecondsF() >= 10, |
| 367 1); | 352 1); |
| 368 rappor_service->RecordSampleObj( | 353 rappor_service->RecordSampleObj(kRapporMetricsNameCoarseTiming, |
| 369 "PageLoad.CoarseTiming.NavigationToFirstContentfulPaint", | 354 sample.Pass()); |
| 370 sample.Pass()); | |
| 371 } | 355 } |
| 372 } | 356 } |
| 373 | 357 |
| 374 // static | 358 // static |
| 375 MetricsWebContentsObserver::MetricsWebContentsObserver( | 359 MetricsWebContentsObserver::MetricsWebContentsObserver( |
| 376 content::WebContents* web_contents, | 360 content::WebContents* web_contents, |
| 377 scoped_ptr<PageLoadMetricsEmbedderInterface> embedder_interface) | 361 scoped_ptr<PageLoadMetricsEmbedderInterface> embedder_interface) |
| 378 : content::WebContentsObserver(web_contents), | 362 : content::WebContentsObserver(web_contents), |
| 379 in_foreground_(false), | 363 in_foreground_(false), |
| 380 embedder_interface_(embedder_interface.Pass()) {} | 364 embedder_interface_(embedder_interface.Pass()) {} |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 542 | 526 |
| 543 if (!committed_load_->UpdateTiming(timing)) { | 527 if (!committed_load_->UpdateTiming(timing)) { |
| 544 // If the page load tracker cannot update its timing, something is wrong | 528 // If the page load tracker cannot update its timing, something is wrong |
| 545 // with the IPC (it's from another load, or it's invalid in some other way). | 529 // with the IPC (it's from another load, or it's invalid in some other way). |
| 546 // We expect this to be a rare occurrence. | 530 // We expect this to be a rare occurrence. |
| 547 RecordInternalError(ERR_BAD_TIMING_IPC); | 531 RecordInternalError(ERR_BAD_TIMING_IPC); |
| 548 } | 532 } |
| 549 } | 533 } |
| 550 | 534 |
| 551 } // namespace page_load_metrics | 535 } // namespace page_load_metrics |
| OLD | NEW |