OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |