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_, |
| 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 |