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

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

Issue 2885053002: Buffer timing callbacks until timing state converges. (Closed)
Patch Set: add test 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>
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
56 const char kClientRedirectFirstPaintToNavigation[] = 56 const char kClientRedirectFirstPaintToNavigation[] =
57 "PageLoad.Internal.ClientRedirect.FirstPaintToNavigation"; 57 "PageLoad.Internal.ClientRedirect.FirstPaintToNavigation";
58 const char kClientRedirectWithoutPaint[] = 58 const char kClientRedirectWithoutPaint[] =
59 "PageLoad.Internal.ClientRedirect.NavigationWithoutPaint"; 59 "PageLoad.Internal.ClientRedirect.NavigationWithoutPaint";
60 const char kPageLoadCompletedAfterAppBackground[] = 60 const char kPageLoadCompletedAfterAppBackground[] =
61 "PageLoad.Internal.PageLoadCompleted.AfterAppBackground"; 61 "PageLoad.Internal.PageLoadCompleted.AfterAppBackground";
62 const char kPageLoadStartedInForeground[] = 62 const char kPageLoadStartedInForeground[] =
63 "PageLoad.Internal.NavigationStartedInForeground"; 63 "PageLoad.Internal.NavigationStartedInForeground";
64 const char kPageLoadPrerender[] = "PageLoad.Internal.Prerender"; 64 const char kPageLoadPrerender[] = "PageLoad.Internal.Prerender";
65 const char kPageLoadTimingStatus[] = "PageLoad.Internal.PageLoadTimingStatus"; 65 const char kPageLoadTimingStatus[] = "PageLoad.Internal.PageLoadTimingStatus";
66 const char kPageLoadTimingDispatchStatus[] =
67 "PageLoad.Internal.PageLoadTimingStatus.AtTimingCallbackDispatch";
66 68
67 } // namespace internal 69 } // namespace internal
68 70
69 void RecordInternalError(InternalErrorLoadEvent event) { 71 void RecordInternalError(InternalErrorLoadEvent event) {
70 UMA_HISTOGRAM_ENUMERATION(internal::kErrorEvents, event, ERR_LAST_ENTRY); 72 UMA_HISTOGRAM_ENUMERATION(internal::kErrorEvents, event, ERR_LAST_ENTRY);
71 } 73 }
72 74
73 // TODO(csharrison): Add a case for client side redirects, which is what JS 75 // TODO(csharrison): Add a case for client side redirects, which is what JS
74 // initiated window.location / window.history navigations get set to. 76 // initiated window.location / window.history navigations get set to.
75 PageEndReason EndReasonForPageTransition(ui::PageTransition transition) { 77 PageEndReason EndReasonForPageTransition(ui::PageTransition transition) {
(...skipping 559 matching lines...) Expand 10 before | Expand all | Expand 10 after
635 const PageLoadMetadata& new_metadata) { 637 const PageLoadMetadata& new_metadata) {
636 UpdateSubFrameMetadata(new_metadata); 638 UpdateSubFrameMetadata(new_metadata);
637 const auto it = subframe_navigation_start_offset_.find( 639 const auto it = subframe_navigation_start_offset_.find(
638 render_frame_host->GetFrameTreeNodeId()); 640 render_frame_host->GetFrameTreeNodeId());
639 if (it == subframe_navigation_start_offset_.end()) { 641 if (it == subframe_navigation_start_offset_.end()) {
640 // We received timing information for an untracked load. Ignore it. 642 // We received timing information for an untracked load. Ignore it.
641 return; 643 return;
642 } 644 }
643 645
644 base::TimeDelta navigation_start_offset = it->second; 646 base::TimeDelta navigation_start_offset = it->second;
645 const PageLoadTiming last_timing = merged_page_timing_;
646 MergePaintTiming(navigation_start_offset, new_timing.paint_timing, 647 MergePaintTiming(navigation_start_offset, new_timing.paint_timing,
647 false /* is_main_frame */); 648 false /* is_main_frame */);
648 649
649 if (last_timing == merged_page_timing_) 650 DispatchTimingUpdates();
650 return;
651
652 const PageLoadExtraInfo info = ComputePageLoadExtraInfo();
653 for (const auto& observer : observers_) {
654 DispatchObserverTimingCallbacks(observer.get(), last_timing,
655 merged_page_timing_, main_frame_metadata_,
656 info);
657 }
658 } 651 }
659 652
660 void PageLoadTracker::MergePaintTiming( 653 void PageLoadTracker::MergePaintTiming(
661 base::TimeDelta navigation_start_offset, 654 base::TimeDelta navigation_start_offset,
662 const page_load_metrics::PaintTiming& new_paint_timing, 655 const page_load_metrics::PaintTiming& new_paint_timing,
663 bool is_main_frame) { 656 bool is_main_frame) {
664 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_paint, 657 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_paint,
665 navigation_start_offset, new_paint_timing.first_paint); 658 navigation_start_offset, new_paint_timing.first_paint);
666 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_text_paint, 659 MaybeUpdateTimeDelta(&merged_page_timing_.paint_timing.first_text_paint,
667 navigation_start_offset, 660 navigation_start_offset,
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
726 } 719 }
727 720
728 DCHECK(did_commit_); // OnCommit() must be called first. 721 DCHECK(did_commit_); // OnCommit() must be called first.
729 // There are some subtle ordering constraints here. GetPageLoadMetricsInfo() 722 // There are some subtle ordering constraints here. GetPageLoadMetricsInfo()
730 // must be called before DispatchObserverTimingCallbacks, but its 723 // must be called before DispatchObserverTimingCallbacks, but its
731 // implementation depends on the state of main_frame_metadata_, so we need 724 // implementation depends on the state of main_frame_metadata_, so we need
732 // to update main_frame_metadata_ before calling GetPageLoadMetricsInfo. 725 // to update main_frame_metadata_ before calling GetPageLoadMetricsInfo.
733 // Thus, we make a copy of timing here, update timing_ and 726 // Thus, we make a copy of timing here, update timing_ and
734 // main_frame_metadata_, and then proceed to dispatch the observer timing 727 // main_frame_metadata_, and then proceed to dispatch the observer timing
735 // callbacks. 728 // callbacks.
736 const PageLoadTiming last_timing = merged_page_timing_; 729 const PaintTiming last_paint_timing = merged_page_timing_.paint_timing;
737 730
738 // Update the merged_page_timing_, making sure to merge the previously 731 // Update the merged_page_timing_, making sure to merge the previously
739 // observed |paint_timing|, which is tracked across all frames in the page. 732 // observed |paint_timing|, which is tracked across all frames in the page.
740 merged_page_timing_ = new_timing; 733 merged_page_timing_ = new_timing;
741 merged_page_timing_.paint_timing = last_timing.paint_timing; 734 merged_page_timing_.paint_timing = last_paint_timing;
742 MergePaintTiming(base::TimeDelta(), new_timing.paint_timing, 735 MergePaintTiming(base::TimeDelta(), new_timing.paint_timing,
743 true /* is_main_frame */); 736 true /* is_main_frame */);
744 737
745 const PageLoadMetadata last_metadata = main_frame_metadata_;
746 main_frame_metadata_ = new_metadata; 738 main_frame_metadata_ = new_metadata;
739
740 DispatchTimingUpdates();
741 }
742
743 void PageLoadTracker::DispatchTimingUpdates() {
744 if (last_dispatched_merged_page_timing_ == merged_page_timing_ &&
745 last_dispatched_main_frame_metadata_ == main_frame_metadata_) {
746 return;
747 }
748
749 if (merged_page_timing_.paint_timing.first_paint) {
750 if (!merged_page_timing_.parse_timing.parse_start ||
751 !merged_page_timing_.document_timing.first_layout) {
752 // When merging paint events across frames, we can sometimes encounter
753 // cases where we've received a first paint event for a child frame before
754 // receiving required earlier events in the main frame, due to buffering
755 // in the render process which results in out of order delivery. For
756 // example, we may receive a notification for a first paint in a child
757 // frame before we've received a notification for parse start or first
758 // layout in the main frame. In these cases, we delay sending timing
759 // updates until we've received all expected events (e.g. wait to receive
760 // a parse or layout event before dispatching a paint event), so observers
761 // can make assumptions about ordering of these events in their callbacks.
762 return;
763 }
764 }
765
766 internal::PageLoadTimingStatus status =
767 IsValidPageLoadTiming(merged_page_timing_);
768 UMA_HISTOGRAM_ENUMERATION(internal::kPageLoadTimingDispatchStatus, status,
769 internal::LAST_PAGE_LOAD_TIMING_STATUS);
770
747 const PageLoadExtraInfo info = ComputePageLoadExtraInfo(); 771 const PageLoadExtraInfo info = ComputePageLoadExtraInfo();
748 for (const auto& observer : observers_) { 772 for (const auto& observer : observers_) {
749 DispatchObserverTimingCallbacks(observer.get(), last_timing, 773 DispatchObserverTimingCallbacks(
750 merged_page_timing_, last_metadata, info); 774 observer.get(), last_dispatched_merged_page_timing_,
jkarlin 2017/05/16 16:23:11 Do you really want to dispatch the last observed t
Bryan McQuade 2017/05/16 16:33:48 DispatchObserverTimingCallbacks takes both the old
jkarlin 2017/05/16 17:07:14 Completely missed that merged_paint_timing_ was go
775 merged_page_timing_, last_dispatched_main_frame_metadata_, info);
751 } 776 }
777 last_dispatched_merged_page_timing_ = merged_page_timing_;
778 last_dispatched_main_frame_metadata_ = main_frame_metadata_;
752 } 779 }
753 780
754 void PageLoadTracker::OnStartedResource( 781 void PageLoadTracker::OnStartedResource(
755 const ExtraRequestStartInfo& extra_request_start_info) { 782 const ExtraRequestStartInfo& extra_request_start_info) {
756 for (const auto& observer : observers_) { 783 for (const auto& observer : observers_) {
757 observer->OnStartedResource(extra_request_start_info); 784 observer->OnStartedResource(extra_request_start_info);
758 } 785 }
759 } 786 }
760 787
761 void PageLoadTracker::OnLoadedResource( 788 void PageLoadTracker::OnLoadedResource(
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
936 observer->MediaStartedPlaying(video_type, is_in_main_frame); 963 observer->MediaStartedPlaying(video_type, is_in_main_frame);
937 } 964 }
938 965
939 void PageLoadTracker::OnNavigationDelayComplete(base::TimeDelta scheduled_delay, 966 void PageLoadTracker::OnNavigationDelayComplete(base::TimeDelta scheduled_delay,
940 base::TimeDelta actual_delay) { 967 base::TimeDelta actual_delay) {
941 for (const auto& observer : observers_) 968 for (const auto& observer : observers_)
942 observer->OnNavigationDelayComplete(scheduled_delay, actual_delay); 969 observer->OnNavigationDelayComplete(scheduled_delay, actual_delay);
943 } 970 }
944 971
945 } // namespace page_load_metrics 972 } // namespace page_load_metrics
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698