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

Side by Side Diff: chrome/browser/page_load_metrics/page_load_tracker.cc

Issue 2859393002: Report page load timing information for child frames. (Closed)
Patch Set: add comment Created 3 years, 7 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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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 "chrome/browser/page_load_metrics/page_load_tracker.h" 5 #include "chrome/browser/page_load_metrics/page_load_tracker.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <ostream> 8 #include <ostream>
9 #include <string> 9 #include <string>
10 #include <utility> 10 #include <utility>
11 11
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/memory/ptr_util.h" 13 #include "base/memory/ptr_util.h"
14 #include "base/metrics/histogram_macros.h" 14 #include "base/metrics/histogram_macros.h"
15 #include "chrome/browser/page_load_metrics/browser_page_track_decider.h"
15 #include "chrome/browser/page_load_metrics/page_load_metrics_embedder_interface. h" 16 #include "chrome/browser/page_load_metrics/page_load_metrics_embedder_interface. h"
16 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h" 17 #include "chrome/browser/page_load_metrics/page_load_metrics_util.h"
17 #include "chrome/browser/prerender/prerender_contents.h" 18 #include "chrome/browser/prerender/prerender_contents.h"
18 #include "chrome/common/page_load_metrics/page_load_timing.h" 19 #include "chrome/common/page_load_metrics/page_load_timing.h"
19 #include "content/public/browser/navigation_details.h" 20 #include "content/public/browser/navigation_details.h"
20 #include "content/public/browser/navigation_handle.h" 21 #include "content/public/browser/navigation_handle.h"
22 #include "content/public/browser/render_frame_host.h"
21 #include "content/public/browser/web_contents.h" 23 #include "content/public/browser/web_contents.h"
22 #include "content/public/browser/web_contents_observer.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 #include "ui/base/page_transition_types.h" 26 #include "ui/base/page_transition_types.h"
25 27
26 // This macro invokes the specified method on each observer, passing the 28 // This macro invokes the specified method on each observer, passing the
27 // variable length arguments as the method's arguments, and removes the observer 29 // variable length arguments as the method's arguments, and removes the observer
28 // from the list of observers if the given method returns STOP_OBSERVING. 30 // from the list of observers if the given method returns STOP_OBSERVING.
29 #define INVOKE_AND_PRUNE_OBSERVERS(observers, Method, ...) \ 31 #define INVOKE_AND_PRUNE_OBSERVERS(observers, Method, ...) \
30 for (auto it = observers.begin(); it != observers.end();) { \ 32 for (auto it = observers.begin(); it != observers.end();) { \
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
98 // HasUserGesture() set to true. In the meantime, we consider all 100 // HasUserGesture() set to true. In the meantime, we consider all
99 // browser-initiated navigations to be user initiated. 101 // browser-initiated navigations to be user initiated.
100 // 102 //
101 // TODO(crbug.com/637345): Some browser-initiated navigations incorrectly 103 // TODO(crbug.com/637345): Some browser-initiated navigations incorrectly
102 // report that they are renderer-initiated. We will currently report that 104 // report that they are renderer-initiated. We will currently report that
103 // these navigations are not user initiated, when in fact they are user 105 // these navigations are not user initiated, when in fact they are user
104 // initiated. 106 // initiated.
105 return handle->HasUserGesture() || !handle->IsRendererInitiated(); 107 return handle->HasUserGesture() || !handle->IsRendererInitiated();
106 } 108 }
107 109
110 content::RenderFrameHost* GetMainFrame(content::RenderFrameHost* rfh) {
111 // Don't use rfh->GetRenderViewHost()->GetMainFrame() here because
112 // RenderViewHost is being deprecated and because in OOPIF,
113 // RenderViewHost::GetMainFrame() returns nullptr for child frames hosted in a
114 // different process from the main frame.
115 while (rfh->GetParent() != nullptr)
116 rfh = rfh->GetParent();
117 return rfh;
118 }
119
108 namespace { 120 namespace {
109 121
110 // Helper to allow use of Optional<> values in LOG() messages. 122 // Helper to allow use of Optional<> values in LOG() messages.
111 std::ostream& operator<<(std::ostream& os, 123 std::ostream& operator<<(std::ostream& os,
112 const base::Optional<base::TimeDelta>& opt) { 124 const base::Optional<base::TimeDelta>& opt) {
113 if (opt) 125 if (opt)
114 os << opt.value(); 126 os << opt.value();
115 else 127 else
116 os << "(unset)"; 128 os << "(unset)";
117 return os; 129 return os;
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
263 timing.paint_timing.first_meaningful_paint)) { 275 timing.paint_timing.first_meaningful_paint)) {
264 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing.first_paint 276 LOG(ERROR) << "Invalid first_paint " << timing.paint_timing.first_paint
265 << " for first_meaningful_paint " 277 << " for first_meaningful_paint "
266 << timing.paint_timing.first_meaningful_paint; 278 << timing.paint_timing.first_meaningful_paint;
267 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_MEANINGFUL_PAINT; 279 return internal::INVALID_ORDER_FIRST_PAINT_FIRST_MEANINGFUL_PAINT;
268 } 280 }
269 281
270 return internal::VALID; 282 return internal::VALID;
271 } 283 }
272 284
285 // Updates *|inout_existing_value| with |optional_candidate_new_value|, if
286 // either *|inout_existing_value| isn't set, or |optional_candidate_new_value| <
287 // |inout_existing_value|.
288 void MaybeUpdateTimeDelta(
289 base::Optional<base::TimeDelta>* inout_existing_value,
290 base::TimeDelta navigation_start_offset,
291 const base::Optional<base::TimeDelta>& optional_candidate_new_value) {
292 // If we don't get a new value, there's nothing to do
293 if (!optional_candidate_new_value)
294 return;
295
296 // optional_candidate_new_value is relative to navigation start in its
297 // frame. We need to adjust it to be relative to navigation start in the main
298 // frame, so offset it by navigation_start_offset.
299 base::TimeDelta candidate_new_value =
300 navigation_start_offset + optional_candidate_new_value.value();
301
302 if (*inout_existing_value) {
303 // If we have a new value, but it is after the existing value, then keep the
304 // existing value.
305 if (*inout_existing_value <= candidate_new_value)
306 return;
307
308 // We received a new timing event, but with a timestamp before the timestamp
309 // of a timing update we had received previously. We expect this to happen
310 // occasionally, as inter-frame updates can arrive out of order. Record a
311 // histogram to track how frequently it happens, along with the magnitude
312 // of the delta.
313 PAGE_LOAD_HISTOGRAM("PageLoad.Internal.OutOfOrderInterFrameTiming",
314 inout_existing_value->value() - candidate_new_value);
315 }
316
317 *inout_existing_value = candidate_new_value;
318 }
319
273 void RecordAppBackgroundPageLoadCompleted(bool completed_after_background) { 320 void RecordAppBackgroundPageLoadCompleted(bool completed_after_background) {
274 UMA_HISTOGRAM_BOOLEAN(internal::kPageLoadCompletedAfterAppBackground, 321 UMA_HISTOGRAM_BOOLEAN(internal::kPageLoadCompletedAfterAppBackground,
275 completed_after_background); 322 completed_after_background);
276 } 323 }
277 324
278 void DispatchObserverTimingCallbacks(PageLoadMetricsObserver* observer, 325 void DispatchObserverTimingCallbacks(PageLoadMetricsObserver* observer,
279 const PageLoadTiming& last_timing, 326 const PageLoadTiming& last_timing,
280 const PageLoadTiming& new_timing, 327 const PageLoadTiming& new_timing,
281 const PageLoadMetadata& last_metadata, 328 const PageLoadMetadata& last_metadata,
282 const PageLoadExtraInfo& extra_info) { 329 const PageLoadExtraInfo& extra_info) {
283 if (extra_info.main_frame_metadata.behavior_flags != 330 if (extra_info.main_frame_metadata.behavior_flags !=
284 last_metadata.behavior_flags) 331 last_metadata.behavior_flags)
285 observer->OnLoadingBehaviorObserved(extra_info); 332 observer->OnLoadingBehaviorObserved(extra_info);
286 if (last_timing != new_timing) 333 if (last_timing != new_timing)
287 observer->OnTimingUpdate(new_timing, extra_info); 334 observer->OnTimingUpdate(new_timing, extra_info);
288 if (new_timing.document_timing.dom_content_loaded_event_start && 335 if (new_timing.document_timing.dom_content_loaded_event_start &&
289 !last_timing.document_timing.dom_content_loaded_event_start) 336 !last_timing.document_timing.dom_content_loaded_event_start)
290 observer->OnDomContentLoadedEventStart(new_timing, extra_info); 337 observer->OnDomContentLoadedEventStart(new_timing, extra_info);
291 if (new_timing.document_timing.load_event_start && 338 if (new_timing.document_timing.load_event_start &&
292 !last_timing.document_timing.load_event_start) 339 !last_timing.document_timing.load_event_start)
293 observer->OnLoadEventStart(new_timing, extra_info); 340 observer->OnLoadEventStart(new_timing, extra_info);
294 if (new_timing.document_timing.first_layout && 341 if (new_timing.document_timing.first_layout &&
295 !last_timing.document_timing.first_layout) 342 !last_timing.document_timing.first_layout)
296 observer->OnFirstLayout(new_timing, extra_info); 343 observer->OnFirstLayout(new_timing, extra_info);
297 if (new_timing.paint_timing.first_paint && 344 if (new_timing.paint_timing.first_paint &&
298 !last_timing.paint_timing.first_paint) 345 !last_timing.paint_timing.first_paint)
299 observer->OnFirstPaint(new_timing, extra_info); 346 observer->OnFirstPaintInPage(new_timing, extra_info);
300 if (new_timing.paint_timing.first_text_paint && 347 if (new_timing.paint_timing.first_text_paint &&
301 !last_timing.paint_timing.first_text_paint) 348 !last_timing.paint_timing.first_text_paint)
302 observer->OnFirstTextPaint(new_timing, extra_info); 349 observer->OnFirstTextPaintInPage(new_timing, extra_info);
303 if (new_timing.paint_timing.first_image_paint && 350 if (new_timing.paint_timing.first_image_paint &&
304 !last_timing.paint_timing.first_image_paint) 351 !last_timing.paint_timing.first_image_paint)
305 observer->OnFirstImagePaint(new_timing, extra_info); 352 observer->OnFirstImagePaintInPage(new_timing, extra_info);
306 if (new_timing.paint_timing.first_contentful_paint && 353 if (new_timing.paint_timing.first_contentful_paint &&
307 !last_timing.paint_timing.first_contentful_paint) 354 !last_timing.paint_timing.first_contentful_paint)
308 observer->OnFirstContentfulPaint(new_timing, extra_info); 355 observer->OnFirstContentfulPaintInPage(new_timing, extra_info);
309 if (new_timing.paint_timing.first_meaningful_paint && 356 if (new_timing.paint_timing.first_meaningful_paint &&
310 !last_timing.paint_timing.first_meaningful_paint) 357 !last_timing.paint_timing.first_meaningful_paint)
311 observer->OnFirstMeaningfulPaint(new_timing, extra_info); 358 observer->OnFirstMeaningfulPaintInMainFrameDocument(new_timing, extra_info);
312 if (new_timing.parse_timing.parse_start && 359 if (new_timing.parse_timing.parse_start &&
313 !last_timing.parse_timing.parse_start) 360 !last_timing.parse_timing.parse_start)
314 observer->OnParseStart(new_timing, extra_info); 361 observer->OnParseStart(new_timing, extra_info);
315 if (new_timing.parse_timing.parse_stop && 362 if (new_timing.parse_timing.parse_stop &&
316 !last_timing.parse_timing.parse_stop) 363 !last_timing.parse_timing.parse_stop)
317 observer->OnParseStop(new_timing, extra_info); 364 observer->OnParseStop(new_timing, extra_info);
318 } 365 }
319 366
320 } // namespace 367 } // namespace
321 368
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
376 if (!failed_provisional_load_info_) 423 if (!failed_provisional_load_info_)
377 RecordInternalError(ERR_NO_COMMIT_OR_FAILED_PROVISIONAL_LOAD); 424 RecordInternalError(ERR_NO_COMMIT_OR_FAILED_PROVISIONAL_LOAD);
378 425
379 // Don't include any aborts that resulted in a new navigation, as the chain 426 // Don't include any aborts that resulted in a new navigation, as the chain
380 // length will be included in the aborter PageLoadTracker. 427 // length will be included in the aborter PageLoadTracker.
381 if (page_end_reason_ != END_RELOAD && 428 if (page_end_reason_ != END_RELOAD &&
382 page_end_reason_ != END_FORWARD_BACK && 429 page_end_reason_ != END_FORWARD_BACK &&
383 page_end_reason_ != END_NEW_NAVIGATION) { 430 page_end_reason_ != END_NEW_NAVIGATION) {
384 LogAbortChainHistograms(nullptr); 431 LogAbortChainHistograms(nullptr);
385 } 432 }
386 } else if (timing_.IsEmpty()) { 433 } else if (merged_page_timing_.IsEmpty()) {
387 RecordInternalError(ERR_NO_IPCS_RECEIVED); 434 RecordInternalError(ERR_NO_IPCS_RECEIVED);
388 } 435 }
389 436
390 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); 437 const PageLoadExtraInfo info = ComputePageLoadExtraInfo();
391 for (const auto& observer : observers_) { 438 for (const auto& observer : observers_) {
392 if (failed_provisional_load_info_) { 439 if (failed_provisional_load_info_) {
393 observer->OnFailedProvisionalLoad(*failed_provisional_load_info_, info); 440 observer->OnFailedProvisionalLoad(*failed_provisional_load_info_, info);
394 } else if (did_commit_) { 441 } else if (did_commit_) {
395 observer->OnComplete(timing_, info); 442 observer->OnComplete(merged_page_timing_, info);
396 } 443 }
397 } 444 }
398 } 445 }
399 446
400 void PageLoadTracker::LogAbortChainHistograms( 447 void PageLoadTracker::LogAbortChainHistograms(
401 content::NavigationHandle* final_navigation) { 448 content::NavigationHandle* final_navigation) {
402 if (aborted_chain_size_ == 0) 449 if (aborted_chain_size_ == 0)
403 return; 450 return;
404 // Note that this could be broken out by this navigation's abort type, if more 451 // Note that this could be broken out by this navigation's abort type, if more
405 // granularity is needed. Add one to the chain size to count the current 452 // granularity is needed. Add one to the chain size to count the current
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
452 // Only log the first time we background in a given page load. 499 // Only log the first time we background in a given page load.
453 if (background_time_.is_null()) { 500 if (background_time_.is_null()) {
454 // Make sure we either started in the foreground and haven't been 501 // Make sure we either started in the foreground and haven't been
455 // foregrounded yet, or started in the background and have already been 502 // foregrounded yet, or started in the background and have already been
456 // foregrounded. 503 // foregrounded.
457 DCHECK_EQ(started_in_foreground_, foreground_time_.is_null()); 504 DCHECK_EQ(started_in_foreground_, foreground_time_.is_null());
458 background_time_ = base::TimeTicks::Now(); 505 background_time_ = base::TimeTicks::Now();
459 ClampBrowserTimestampIfInterProcessTimeTickSkew(&background_time_); 506 ClampBrowserTimestampIfInterProcessTimeTickSkew(&background_time_);
460 } 507 }
461 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); 508 const PageLoadExtraInfo info = ComputePageLoadExtraInfo();
462 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnHidden, timing_, info); 509 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnHidden, merged_page_timing_, info);
463 } 510 }
464 511
465 void PageLoadTracker::WebContentsShown() { 512 void PageLoadTracker::WebContentsShown() {
466 // Only log the first time we foreground in a given page load. 513 // Only log the first time we foreground in a given page load.
467 if (foreground_time_.is_null()) { 514 if (foreground_time_.is_null()) {
468 // Make sure we either started in the background and haven't been 515 // Make sure we either started in the background and haven't been
469 // backgrounded yet, or started in the foreground and have already been 516 // backgrounded yet, or started in the foreground and have already been
470 // backgrounded. 517 // backgrounded.
471 DCHECK_NE(started_in_foreground_, background_time_.is_null()); 518 DCHECK_NE(started_in_foreground_, background_time_.is_null());
472 foreground_time_ = base::TimeTicks::Now(); 519 foreground_time_ = base::TimeTicks::Now();
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
504 navigation_handle->GetWebContents()->GetContentsMimeType()); 551 navigation_handle->GetWebContents()->GetContentsMimeType());
505 552
506 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnCommit, navigation_handle); 553 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnCommit, navigation_handle);
507 LogAbortChainHistograms(navigation_handle); 554 LogAbortChainHistograms(navigation_handle);
508 } 555 }
509 556
510 void PageLoadTracker::DidFinishSubFrameNavigation( 557 void PageLoadTracker::DidFinishSubFrameNavigation(
511 content::NavigationHandle* navigation_handle) { 558 content::NavigationHandle* navigation_handle) {
512 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnDidFinishSubFrameNavigation, 559 INVOKE_AND_PRUNE_OBSERVERS(observers_, OnDidFinishSubFrameNavigation,
513 navigation_handle); 560 navigation_handle);
561
562 if (!navigation_handle->HasCommitted())
563 return;
564
565 // We have a new committed navigation, so discard information about the
566 // previously committed navigation.
567 child_frame_navigation_start_offset_.erase(
568 navigation_handle->GetFrameTreeNodeId());
569
570 if (GetMainFrame(navigation_handle->GetRenderFrameHost()) !=
571 navigation_handle->GetWebContents()->GetMainFrame()) {
572 // Ignore navigations for a main frame that was navigated away from.
573 return;
574 }
575
576 BrowserPageTrackDecider decider(embedder_interface_,
577 navigation_handle->GetWebContents(),
578 navigation_handle);
579 if (!decider.ShouldTrack())
580 return;
581
582 if (navigation_start_ > navigation_handle->NavigationStart()) {
583 RecordInternalError(ERR_SUBFRAME_NAVIGATION_START_BEFORE_MAIN_FRAME);
584 return;
585 }
586 base::TimeDelta navigation_delta =
587 navigation_handle->NavigationStart() - navigation_start_;
588 child_frame_navigation_start_offset_.insert(std::make_pair(
589 navigation_handle->GetFrameTreeNodeId(), navigation_delta));
514 } 590 }
515 591
516 void PageLoadTracker::FailedProvisionalLoad( 592 void PageLoadTracker::FailedProvisionalLoad(
517 content::NavigationHandle* navigation_handle, 593 content::NavigationHandle* navigation_handle,
518 base::TimeTicks failed_load_time) { 594 base::TimeTicks failed_load_time) {
519 DCHECK(!failed_provisional_load_info_); 595 DCHECK(!failed_provisional_load_info_);
520 failed_provisional_load_info_.reset(new FailedProvisionalLoadInfo( 596 failed_provisional_load_info_.reset(new FailedProvisionalLoadInfo(
521 failed_load_time - navigation_handle->NavigationStart(), 597 failed_load_time - navigation_handle->NavigationStart(),
522 navigation_handle->GetNetErrorCode())); 598 navigation_handle->GetNetErrorCode()));
523 } 599 }
(...skipping 11 matching lines...) Expand all
535 } 611 }
536 612
537 void PageLoadTracker::FlushMetricsOnAppEnterBackground() { 613 void PageLoadTracker::FlushMetricsOnAppEnterBackground() {
538 if (!app_entered_background_) { 614 if (!app_entered_background_) {
539 RecordAppBackgroundPageLoadCompleted(false); 615 RecordAppBackgroundPageLoadCompleted(false);
540 app_entered_background_ = true; 616 app_entered_background_ = true;
541 } 617 }
542 618
543 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); 619 const PageLoadExtraInfo info = ComputePageLoadExtraInfo();
544 INVOKE_AND_PRUNE_OBSERVERS(observers_, FlushMetricsOnAppEnterBackground, 620 INVOKE_AND_PRUNE_OBSERVERS(observers_, FlushMetricsOnAppEnterBackground,
545 timing_, info); 621 merged_page_timing_, info);
546 } 622 }
547 623
548 void PageLoadTracker::NotifyClientRedirectTo( 624 void PageLoadTracker::NotifyClientRedirectTo(
549 const PageLoadTracker& destination) { 625 const PageLoadTracker& destination) {
550 if (timing_.paint_timing.first_paint) { 626 if (merged_page_timing_.paint_timing.first_paint) {
551 base::TimeTicks first_paint_time = 627 base::TimeTicks first_paint_time =
552 navigation_start() + timing_.paint_timing.first_paint.value(); 628 navigation_start() +
629 merged_page_timing_.paint_timing.first_paint.value();
553 base::TimeDelta first_paint_to_navigation; 630 base::TimeDelta first_paint_to_navigation;
554 if (destination.navigation_start() > first_paint_time) 631 if (destination.navigation_start() > first_paint_time)
555 first_paint_to_navigation = 632 first_paint_to_navigation =
556 destination.navigation_start() - first_paint_time; 633 destination.navigation_start() - first_paint_time;
557 PAGE_LOAD_HISTOGRAM(internal::kClientRedirectFirstPaintToNavigation, 634 PAGE_LOAD_HISTOGRAM(internal::kClientRedirectFirstPaintToNavigation,
558 first_paint_to_navigation); 635 first_paint_to_navigation);
559 } else { 636 } else {
560 UMA_HISTOGRAM_BOOLEAN(internal::kClientRedirectWithoutPaint, true); 637 UMA_HISTOGRAM_BOOLEAN(internal::kClientRedirectWithoutPaint, true);
561 } 638 }
562 } 639 }
563 640
564 void PageLoadTracker::UpdateChildFrameMetadata( 641 void PageLoadTracker::UpdateSubFrameTiming(
642 content::RenderFrameHost* render_frame_host,
643 const PageLoadTiming& new_timing,
644 const PageLoadMetadata& new_metadata) {
645 UpdateSubFrameMetadata(new_metadata);
646 const auto it = child_frame_navigation_start_offset_.find(
647 render_frame_host->GetFrameTreeNodeId());
648 if (it == child_frame_navigation_start_offset_.end()) {
649 // We received timing information for an untracked load. Ignore it.
650 RecordInternalError(ERR_SUBFRAME_IPC_WITH_NO_RELEVANT_LOAD);
651 return;
652 }
653
654 base::TimeDelta navigation_start_offset = it->second;
655 const PageLoadTiming last_timing = merged_page_timing_;
656 MergePaintTiming(navigation_start_offset, new_timing.paint_timing,
657 false /* is_main_frame */);
658
659 const PageLoadExtraInfo info = ComputePageLoadExtraInfo();
660 for (const auto& observer : observers_) {
661 observer->OnSubFrameTimingUpdate(render_frame_host->GetFrameTreeNodeId(),
662 navigation_start_offset, new_timing,
663 new_metadata, info);
664 DispatchObserverTimingCallbacks(observer.get(), last_timing,
jkarlin 2017/05/10 16:55:28 It's potentially expensive to call all the observe
Bryan McQuade 2017/05/10 18:06:15 done
665 merged_page_timing_, main_frame_metadata_,
666 info);
667 }
668 }
669
670 void PageLoadTracker::MergePaintTiming(
671 base::TimeDelta navigation_start_offset,
672 const page_load_metrics::PaintTiming& new_paint_timing,
673 bool is_main_frame) {
674 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_paint,
675 navigation_start_offset, new_paint_timing.first_paint);
676 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_text_paint,
677 navigation_start_offset,
678 new_paint_timing.first_text_paint);
679 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_image_paint,
680 navigation_start_offset,
681 new_paint_timing.first_image_paint);
682 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_contentful_paint,
683 navigation_start_offset,
684 new_paint_timing.first_contentful_paint);
685 if (is_main_frame) {
686 // first meaningful paint is only tracked in the main frame.
687 merged_page_timing_.paint_timing.first_meaningful_paint =
688 new_paint_timing.first_meaningful_paint;
689 }
690 }
691
692 void PageLoadTracker::UpdateSubFrameMetadata(
565 const PageLoadMetadata& child_metadata) { 693 const PageLoadMetadata& child_metadata) {
566 // Merge the child loading behavior flags with any we've already observed, 694 // Merge the child loading behavior flags with any we've already observed,
567 // possibly from other child frames. 695 // possibly from other child frames.
568 const int last_child_loading_behavior_flags = 696 const int last_child_loading_behavior_flags =
569 child_frame_metadata_.behavior_flags; 697 child_frame_metadata_.behavior_flags;
570 child_frame_metadata_.behavior_flags |= child_metadata.behavior_flags; 698 child_frame_metadata_.behavior_flags |= child_metadata.behavior_flags;
571 if (last_child_loading_behavior_flags == child_frame_metadata_.behavior_flags) 699 if (last_child_loading_behavior_flags == child_frame_metadata_.behavior_flags)
572 return; 700 return;
573 701
574 PageLoadExtraInfo extra_info(ComputePageLoadExtraInfo()); 702 PageLoadExtraInfo extra_info(ComputePageLoadExtraInfo());
575 for (const auto& observer : observers_) { 703 for (const auto& observer : observers_) {
576 observer->OnLoadingBehaviorObserved(extra_info); 704 observer->OnLoadingBehaviorObserved(extra_info);
577 } 705 }
578 } 706 }
579 707
580 void PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing, 708 void PageLoadTracker::UpdateTiming(const PageLoadTiming& new_timing,
581 const PageLoadMetadata& new_metadata) { 709 const PageLoadMetadata& new_metadata) {
582 // Throw away IPCs that are not relevant to the current navigation. 710 // Throw away IPCs that are not relevant to the current navigation.
583 // Two timing structures cannot refer to the same navigation if they indicate 711 // Two timing structures cannot refer to the same navigation if they indicate
584 // that a navigation started at different times, so a new timing struct with a 712 // that a navigation started at different times, so a new timing struct with a
585 // different start time from an earlier struct is considered invalid. 713 // different start time from an earlier struct is considered invalid.
586 const bool valid_timing_descendent = 714 const bool valid_timing_descendent =
587 timing_.navigation_start.is_null() || 715 merged_page_timing_.navigation_start.is_null() ||
588 timing_.navigation_start == new_timing.navigation_start; 716 merged_page_timing_.navigation_start == new_timing.navigation_start;
589 if (!valid_timing_descendent) { 717 if (!valid_timing_descendent) {
590 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING_DESCENDENT); 718 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING_DESCENDENT);
591 return; 719 return;
592 } 720 }
593 721
594 // Ensure flags sent previously are still present in the new metadata fields. 722 // Ensure flags sent previously are still present in the new metadata fields.
595 const bool valid_behavior_descendent = 723 const bool valid_behavior_descendent =
596 (main_frame_metadata_.behavior_flags & new_metadata.behavior_flags) == 724 (main_frame_metadata_.behavior_flags & new_metadata.behavior_flags) ==
597 main_frame_metadata_.behavior_flags; 725 main_frame_metadata_.behavior_flags;
598 if (!valid_behavior_descendent) { 726 if (!valid_behavior_descendent) {
599 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_BEHAVIOR_DESCENDENT); 727 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_BEHAVIOR_DESCENDENT);
600 return; 728 return;
601 } 729 }
602 internal::PageLoadTimingStatus status = IsValidPageLoadTiming(new_timing); 730 internal::PageLoadTimingStatus status = IsValidPageLoadTiming(new_timing);
603 UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingStatus, status, 731 UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingStatus, status,
604 internal::LAST_PAGE_LOAD_TIMING_STATUS); 732 internal::LAST_PAGE_LOAD_TIMING_STATUS);
605 if (status != internal::VALID) { 733 if (status != internal::VALID) {
606 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING); 734 RecordInternalError(ERR_BAD_TIMING_IPC_INVALID_TIMING);
607 return; 735 return;
608 } 736 }
609 737
610 DCHECK(did_commit_); // OnCommit() must be called first. 738 DCHECK(did_commit_); // OnCommit() must be called first.
611 // There are some subtle ordering constraints here. GetPageLoadMetricsInfo() 739 // There are some subtle ordering constraints here. GetPageLoadMetricsInfo()
612 // must be called before DispatchObserverTimingCallbacks, but its 740 // must be called before DispatchObserverTimingCallbacks, but its
613 // implementation depends on the state of main_frame_metadata_, so we need 741 // implementation depends on the state of main_frame_metadata_, so we need
614 // to update main_frame_metadata_ before calling GetPageLoadMetricsInfo. 742 // to update main_frame_metadata_ before calling GetPageLoadMetricsInfo.
615 // Thus, we make a copy of timing here, update timing_ and 743 // Thus, we make a copy of timing here, update timing_ and
616 // main_frame_metadata_, and then proceed to dispatch the observer timing 744 // main_frame_metadata_, and then proceed to dispatch the observer timing
617 // callbacks. 745 // callbacks.
618 const PageLoadTiming last_timing = timing_; 746 const PageLoadTiming last_timing = merged_page_timing_;
619 timing_ = new_timing; 747
748 // Update the merged_page_timing_, making sure to merge the previously
749 // observed |paint_timing|, which is tracked across all frames in the page.
750 merged_page_timing_ = new_timing;
751 merged_page_timing_.paint_timing = last_timing.paint_timing;
752 MergePaintTiming(base::TimeDelta(), new_timing.paint_timing,
753 true /* is_main_frame */);
620 754
621 const PageLoadMetadata last_metadata = main_frame_metadata_; 755 const PageLoadMetadata last_metadata = main_frame_metadata_;
622 main_frame_metadata_ = new_metadata; 756 main_frame_metadata_ = new_metadata;
623 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); 757 const PageLoadExtraInfo info = ComputePageLoadExtraInfo();
624 for (const auto& observer : observers_) { 758 for (const auto& observer : observers_) {
625 DispatchObserverTimingCallbacks(observer.get(), last_timing, new_timing, 759 DispatchObserverTimingCallbacks(observer.get(), last_timing,
626 last_metadata, info); 760 merged_page_timing_, last_metadata, info);
627 } 761 }
628 } 762 }
629 763
630 void PageLoadTracker::OnStartedResource( 764 void PageLoadTracker::OnStartedResource(
631 const ExtraRequestStartInfo& extra_request_start_info) { 765 const ExtraRequestStartInfo& extra_request_start_info) {
632 for (const auto& observer : observers_) { 766 for (const auto& observer : observers_) {
633 observer->OnStartedResource(extra_request_start_info); 767 observer->OnStartedResource(extra_request_start_info);
634 } 768 }
635 } 769 }
636 770
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after
812 observer->MediaStartedPlaying(video_type, is_in_main_frame); 946 observer->MediaStartedPlaying(video_type, is_in_main_frame);
813 } 947 }
814 948
815 void PageLoadTracker::OnNavigationDelayComplete(base::TimeDelta scheduled_delay, 949 void PageLoadTracker::OnNavigationDelayComplete(base::TimeDelta scheduled_delay,
816 base::TimeDelta actual_delay) { 950 base::TimeDelta actual_delay) {
817 for (const auto& observer : observers_) 951 for (const auto& observer : observers_)
818 observer->OnNavigationDelayComplete(scheduled_delay, actual_delay); 952 observer->OnNavigationDelayComplete(scheduled_delay, actual_delay);
819 } 953 }
820 954
821 } // namespace page_load_metrics 955 } // namespace page_load_metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698