diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/components/page_load_metrics/renderer | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/components/page_load_metrics/renderer')
4 files changed, 185 insertions, 30 deletions
diff --git a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc b/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc index f0d615cfac0..da17af31f96 100644 --- a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc +++ b/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.cc @@ -39,12 +39,16 @@ base::TimeTicks ClampToStart(base::TimeTicks event, base::TimeTicks start) { class MojoPageTimingSender : public PageTimingSender { public: - explicit MojoPageTimingSender(content::RenderFrame* render_frame) { + explicit MojoPageTimingSender(content::RenderFrame* render_frame, + bool limited_sending_mode) + : limited_sending_mode_(limited_sending_mode) { DCHECK(render_frame); render_frame->GetRemoteAssociatedInterfaces()->GetInterface( &page_load_metrics_); } + ~MojoPageTimingSender() override = default; + void SendTiming(const mojom::PageLoadTimingPtr& timing, const mojom::FrameMetadataPtr& metadata, mojom::PageLoadFeaturesPtr new_features, @@ -55,12 +59,34 @@ class MojoPageTimingSender : public PageTimingSender { mojom::InputTimingPtr input_timing_delta) override { DCHECK(page_load_metrics_); page_load_metrics_->UpdateTiming( - timing->Clone(), metadata->Clone(), std::move(new_features), - std::move(resources), render_data.Clone(), cpu_timing->Clone(), + limited_sending_mode_ ? CreatePageLoadTiming() : timing->Clone(), + metadata->Clone(), std::move(new_features), std::move(resources), + render_data.Clone(), cpu_timing->Clone(), std::move(new_deferred_resource_data), std::move(input_timing_delta)); } + void SubmitThroughputData(ukm::SourceId source_id, + int aggregated_percent, + int impl_percent, + base::Optional<int> main_percent) { + DCHECK(page_load_metrics_); + mojom::PercentOptionalPtr main_ptr = + main_percent.has_value() + ? mojom::PercentOptional::New(main_percent.value()) + : nullptr; + mojom::ThroughputUkmDataPtr throughput_data = mojom::ThroughputUkmData::New( + source_id, aggregated_percent, impl_percent, std::move(main_ptr)); + page_load_metrics_->SubmitThroughputData(std::move(throughput_data)); + } + private: + // Indicates that this sender should not send timing updates or frame render + // data updates. + // TODO(https://crbug.com/1097127): When timing updates are handled for cases + // where we have a subframe document and no committed navigation, this can be + // removed. + bool limited_sending_mode_ = false; + // Use associated interface to make sure mojo messages are ordered with regard // to legacy IPC messages. mojo::AssociatedRemote<mojom::PageLoadMetrics> page_load_metrics_; @@ -246,17 +272,49 @@ void MetricsRenderFrameObserver::DidFailProvisionalLoad() { provisional_frame_resource_data_use_.reset(); } -void MetricsRenderFrameObserver::DidCommitProvisionalLoad( - bool is_same_document_navigation, - ui::PageTransition transition) { - // Same-document navigations (e.g. a navigation from a fragment link) aren't - // full page loads, since they don't go to network to load the main HTML - // resource. DidStartProvisionalLoad doesn't get invoked for same document - // navigations, so we may still have an active page_timing_metrics_sender_ at - // this point. - if (is_same_document_navigation) +void MetricsRenderFrameObserver::DidCreateDocumentElement() { + // If we do not have a render frame or are already tracking this frame, ignore + // the new document element. + if (HasNoRenderFrame() || page_timing_metrics_sender_) + return; + + // We should only track committed navigations for the main frame so ignore new + // document elements in the main frame. + if (render_frame()->IsMainFrame()) return; + // Every frame creates an initial about:blank document element prior to + // receiving a navigation to about:blank. Ignore this initial document + // element. + if (!first_document_observed_) { + first_document_observed_ = true; + return; + } + + // A new document element was created in a frame that did not commit a + // provisional load. This can be due to a doc.write in the frame that aborted + // a navigation. Create a page timing sender to track this load. This sender + // will only send resource usage updates to the browser process. There + // currently is not infrastructure in the browser process to monitor this case + // and properly handle timing updates without a committed load. + // TODO(https://crbug.com/1097127): Implement proper handling of timing + // updates in the browser process and create a normal page timing sender. + + // It should not be possible to have a |provisional_frame_resource_data_use_| + // object at this point. If we did, it means we reached + // ReadyToCommitNavigation() and aborted prior to load commit which should not + // be possible. + DCHECK(!provisional_frame_resource_data_use_); + + Timing timing = GetTiming(); + page_timing_metrics_sender_ = std::make_unique<PageTimingMetricsSender>( + CreatePageTimingSender(true /* limited_sending_mode */), CreateTimer(), + std::move(timing.relative_timing), timing.monotonic_timing, + std::make_unique<PageResourceDataUse>()); +} + +void MetricsRenderFrameObserver::DidCommitProvisionalLoad( + ui::PageTransition transition) { // Make sure to release the sender for a previous navigation, if we have one. page_timing_metrics_sender_.reset(); @@ -274,7 +332,7 @@ void MetricsRenderFrameObserver::DidCommitProvisionalLoad( Timing timing = GetTiming(); page_timing_metrics_sender_ = std::make_unique<PageTimingMetricsSender>( - CreatePageTimingSender(), CreateTimer(), + CreatePageTimingSender(false /* limited_sending_mode*/), CreateTimer(), std::move(timing.relative_timing), timing.monotonic_timing, std::move(provisional_frame_resource_data_use_)); } @@ -301,6 +359,18 @@ void MetricsRenderFrameObserver::OnMainFrameDocumentIntersectionChanged( main_frame_document_intersection); } +void MetricsRenderFrameObserver::OnThroughputDataAvailable( + ukm::SourceId source_id, + int aggregated_percent, + int impl_percent, + base::Optional<int> main_percent) { + std::unique_ptr<MojoPageTimingSender> sender = + std::make_unique<MojoPageTimingSender>(render_frame(), + false /* limited_sending_mode */); + sender->SubmitThroughputData(source_id, aggregated_percent, impl_percent, + main_percent); +} + void MetricsRenderFrameObserver::MaybeSetCompletedBeforeFCP(int request_id) { if (HasNoRenderFrame()) return; @@ -410,6 +480,17 @@ MetricsRenderFrameObserver::Timing MetricsRenderFrameObserver::GetTiming() timing->interactive_timing->longest_input_timestamp = ClampDelta((*perf.LongestInputTimestamp()).InSecondsF(), start); } + if (perf.FirstInputProcessingTime().has_value()) { + timing->interactive_timing->first_input_processing_time = + *perf.FirstInputProcessingTime(); + } + if (perf.FirstScrollDelay().has_value()) { + timing->interactive_timing->first_scroll_delay = *perf.FirstScrollDelay(); + } + if (perf.FirstScrollTimestamp().has_value()) { + timing->interactive_timing->first_scroll_timestamp = + ClampDelta((*perf.FirstScrollTimestamp()).InSecondsF(), start); + } if (perf.ResponseStart() > 0.0) timing->response_start = ClampDelta(perf.ResponseStart(), start); if (perf.DomContentLoadedEventStart() > 0.0) { @@ -422,11 +503,36 @@ MetricsRenderFrameObserver::Timing MetricsRenderFrameObserver::GetTiming() } if (perf.FirstPaint() > 0.0) timing->paint_timing->first_paint = ClampDelta(perf.FirstPaint(), start); + if (!perf.BackForwardCacheRestore().empty()) { + blink::WebPerformance::BackForwardCacheRestoreTimings restore_timings = + perf.BackForwardCacheRestore(); + for (const auto& restore_timing : restore_timings) { + double navigation_start = restore_timing.navigation_start; + double first_paint = restore_timing.first_paint; + base::Optional<base::TimeDelta> first_input_delay = + restore_timing.first_input_delay; + + auto back_forward_cache_timing = mojom::BackForwardCacheTiming::New(); + if (first_paint) { + back_forward_cache_timing + ->first_paint_after_back_forward_cache_restore = + ClampDelta(first_paint, navigation_start); + } + if (first_input_delay.has_value()) { + back_forward_cache_timing + ->first_input_delay_after_back_forward_cache_restore = + ClampDelta(first_input_delay->InSecondsF(), navigation_start); + } + timing->back_forward_cache_timings.push_back( + std::move(back_forward_cache_timing)); + } + } if (perf.FirstImagePaint() > 0.0) { timing->paint_timing->first_image_paint = ClampDelta(perf.FirstImagePaint(), start); } if (perf.FirstContentfulPaint() > 0.0) { + DCHECK(perf.FirstEligibleToPaint() > 0); timing->paint_timing->first_contentful_paint = ClampDelta(perf.FirstContentfulPaint(), start); monotonic_timing.first_contentful_paint = @@ -438,13 +544,13 @@ MetricsRenderFrameObserver::Timing MetricsRenderFrameObserver::GetTiming() ClampDelta(perf.FirstMeaningfulPaint(), start); } if (perf.LargestImagePaintSize() > 0) { - timing->paint_timing->largest_image_paint_size = + timing->paint_timing->largest_contentful_paint->largest_image_paint_size = perf.LargestImagePaintSize(); // Note that size can be nonzero while the time is 0 since a time of 0 is // sent when the image is painting. We assign the time even when it is 0 so // that it's not ignored, but need to be careful when doing operations on // the value. - timing->paint_timing->largest_image_paint = + timing->paint_timing->largest_contentful_paint->largest_image_paint = perf.LargestImagePaint() == 0.0 ? base::TimeDelta() : ClampDelta(perf.LargestImagePaint(), start); @@ -453,9 +559,43 @@ MetricsRenderFrameObserver::Timing MetricsRenderFrameObserver::GetTiming() // LargestTextPaint and LargestTextPaintSize should be available at the // same time. This is a renderer side DCHECK to ensure this. DCHECK(perf.LargestTextPaint()); - timing->paint_timing->largest_text_paint = + timing->paint_timing->largest_contentful_paint->largest_text_paint = ClampDelta(perf.LargestTextPaint(), start); - timing->paint_timing->largest_text_paint_size = perf.LargestTextPaintSize(); + timing->paint_timing->largest_contentful_paint->largest_text_paint_size = + perf.LargestTextPaintSize(); + } + if (perf.ExperimentalLargestImagePaintSize() > 0) { + timing->paint_timing->experimental_largest_contentful_paint + ->largest_image_paint_size = perf.ExperimentalLargestImagePaintSize(); + // Note that size can be nonzero while the time is 0 since a time of 0 is + // sent when the image is painting. We assign the time even when it is 0 so + // that it's not ignored, but need to be careful when doing operations on + // the value. + timing->paint_timing->experimental_largest_contentful_paint + ->largest_image_paint = + perf.ExperimentalLargestImagePaint() == 0.0 + ? base::TimeDelta() + : ClampDelta(perf.ExperimentalLargestImagePaint(), start); + } + if (perf.ExperimentalLargestTextPaintSize() > 0) { + // ExperimentalLargestTextPaint and ExperimentalLargestTextPaintSize should + // be available at the same time. This is a renderer side DCHECK to ensure + // this. + DCHECK(perf.ExperimentalLargestTextPaint()); + timing->paint_timing->experimental_largest_contentful_paint + ->largest_text_paint = + ClampDelta(perf.ExperimentalLargestTextPaint(), start); + timing->paint_timing->experimental_largest_contentful_paint + ->largest_text_paint_size = perf.ExperimentalLargestTextPaintSize(); + } + // It is possible for a frame to switch from eligible for painting to + // ineligible for it prior to the first paint. If this occurs, we need to + // propagate the null value. + if (perf.FirstEligibleToPaint() > 0) { + timing->paint_timing->first_eligible_to_paint = + ClampDelta(perf.FirstEligibleToPaint(), start); + } else { + timing->paint_timing->first_eligible_to_paint.reset(); } if (perf.FirstInputOrScrollNotifiedTimestamp() > 0) { timing->paint_timing->first_input_or_scroll_notified_timestamp = @@ -482,6 +622,10 @@ MetricsRenderFrameObserver::Timing MetricsRenderFrameObserver::GetTiming() base::TimeDelta::FromSecondsD( perf.ParseBlockedOnScriptExecutionFromDocumentWriteDuration()); } + if (perf.LastPortalActivatedPaint().has_value()) { + timing->paint_timing->portal_activated_paint = + *perf.LastPortalActivatedPaint(); + } return Timing(std::move(timing), monotonic_timing); } @@ -491,9 +635,9 @@ std::unique_ptr<base::OneShotTimer> MetricsRenderFrameObserver::CreateTimer() { } std::unique_ptr<PageTimingSender> -MetricsRenderFrameObserver::CreatePageTimingSender() { +MetricsRenderFrameObserver::CreatePageTimingSender(bool limited_sending_mode) { return base::WrapUnique<PageTimingSender>( - new MojoPageTimingSender(render_frame())); + new MojoPageTimingSender(render_frame(), limited_sending_mode)); } bool MetricsRenderFrameObserver::HasNoRenderFrame() const { diff --git a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h b/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h index 9dc048cb1a4..c37e1cf91f9 100644 --- a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h +++ b/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer.h @@ -77,8 +77,8 @@ class MetricsRenderFrameObserver void ReadyToCommitNavigation( blink::WebDocumentLoader* document_loader) override; void DidFailProvisionalLoad() override; - void DidCommitProvisionalLoad(bool is_same_document_navigation, - ui::PageTransition transition) override; + void DidCommitProvisionalLoad(ui::PageTransition transition) override; + void DidCreateDocumentElement() override; void OnDestruct() override; // Invoked when a frame is going away. This is our last chance to send IPCs @@ -96,6 +96,11 @@ class MetricsRenderFrameObserver void OnMainFrameDocumentIntersectionChanged( const blink::WebRect& main_frame_document_intersection) override; + void OnThroughputDataAvailable(ukm::SourceId source_id, + int aggregated_percent, + int impl_percent, + base::Optional<int> main_percent) override; + protected: // The relative and monotonic page load timings. struct Timing { @@ -125,9 +130,14 @@ class MetricsRenderFrameObserver void SendMetrics(); virtual Timing GetTiming() const; virtual std::unique_ptr<base::OneShotTimer> CreateTimer(); - virtual std::unique_ptr<PageTimingSender> CreatePageTimingSender(); + virtual std::unique_ptr<PageTimingSender> CreatePageTimingSender( + bool limited_sending_mode); virtual bool HasNoRenderFrame() const; + // Whether the initial about:blank document loaded into every frame was + // observed. + bool first_document_observed_ = false; + // Collects the data use of the frame request for a provisional load until the // load is committed. We want to collect data use for completed navigations in // this class, but the various navigation callbacks do not provide enough data diff --git a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer_unittest.cc b/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer_unittest.cc index 6bc88c9ef83..a4789646bb0 100644 --- a/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer_unittest.cc +++ b/chromium/components/page_load_metrics/renderer/metrics_render_frame_observer_unittest.cc @@ -32,7 +32,8 @@ class TestMetricsRenderFrameObserver : public MetricsRenderFrameObserver, return std::move(timer); } - std::unique_ptr<PageTimingSender> CreatePageTimingSender() override { + std::unique_ptr<PageTimingSender> CreatePageTimingSender( + bool limited_sending_mode) override { return base::WrapUnique<PageTimingSender>( new FakePageTimingSender(&validator_)); } @@ -88,7 +89,7 @@ TEST_F(MetricsRenderFrameObserverTest, SingleMetric) { observer.ExpectPageLoadTiming(timing); observer.DidStartNavigation(GURL(), base::nullopt); observer.ReadyToCommitNavigation(nullptr); - observer.DidCommitProvisionalLoad(false, ui::PAGE_TRANSITION_LINK); + observer.DidCommitProvisionalLoad(ui::PAGE_TRANSITION_LINK); observer.GetMockTimer()->Fire(); timing.parse_timing->parse_start = base::TimeDelta::FromMilliseconds(10); @@ -111,7 +112,7 @@ TEST_F(MetricsRenderFrameObserverTest, SingleCpuMetric) { observer.ExpectPageLoadTiming(timing); observer.DidStartNavigation(GURL(), base::nullopt); observer.ReadyToCommitNavigation(nullptr); - observer.DidCommitProvisionalLoad(false, ui::PAGE_TRANSITION_LINK); + observer.DidCommitProvisionalLoad(ui::PAGE_TRANSITION_LINK); // Send cpu timing updates and verify the expected result. observer.DidChangeCpuTiming(base::TimeDelta::FromMilliseconds(110)); @@ -133,7 +134,7 @@ TEST_F(MetricsRenderFrameObserverTest, MultipleMetrics) { observer.ExpectPageLoadTiming(timing); observer.DidStartNavigation(GURL(), base::nullopt); observer.ReadyToCommitNavigation(nullptr); - observer.DidCommitProvisionalLoad(false, ui::PAGE_TRANSITION_LINK); + observer.DidCommitProvisionalLoad(ui::PAGE_TRANSITION_LINK); observer.GetMockTimer()->Fire(); timing.document_timing->dom_content_loaded_event_start = dom_event; @@ -179,7 +180,7 @@ TEST_F(MetricsRenderFrameObserverTest, MultipleNavigations) { observer.ExpectPageLoadTiming(timing); observer.DidStartNavigation(GURL(), base::nullopt); observer.ReadyToCommitNavigation(nullptr); - observer.DidCommitProvisionalLoad(false, ui::PAGE_TRANSITION_LINK); + observer.DidCommitProvisionalLoad(ui::PAGE_TRANSITION_LINK); observer.GetMockTimer()->Fire(); timing.document_timing->dom_content_loaded_event_start = dom_event; @@ -205,7 +206,7 @@ TEST_F(MetricsRenderFrameObserverTest, MultipleNavigations) { observer.ExpectPageLoadTiming(timing_2); observer.DidStartNavigation(GURL(), base::nullopt); observer.ReadyToCommitNavigation(nullptr); - observer.DidCommitProvisionalLoad(false, ui::PAGE_TRANSITION_LINK); + observer.DidCommitProvisionalLoad(ui::PAGE_TRANSITION_LINK); observer.GetMockTimer()->Fire(); timing_2.document_timing->dom_content_loaded_event_start = dom_event_2; diff --git a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc b/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc index 36625df9f45..3cd64fefc99 100644 --- a/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc +++ b/chromium/components/page_load_metrics/renderer/page_timing_metrics_sender.cc @@ -44,9 +44,9 @@ PageTimingMetricsSender::PageTimingMetricsSender( new_deferred_resource_data_(mojom::DeferredResourceCounts::New()), buffer_timer_delay_ms_(kBufferTimerDelayMillis), metadata_recorder_(initial_monotonic_timing) { + const auto resource_id = initial_request->resource_id(); page_resource_data_use_.emplace( - std::piecewise_construct, - std::forward_as_tuple(initial_request->resource_id()), + std::piecewise_construct, std::forward_as_tuple(resource_id), std::forward_as_tuple(std::move(initial_request))); buffer_timer_delay_ms_ = base::GetFieldTrialParamByFeatureAsInt( kPageLoadMetricsTimerDelayFeature, "BufferTimerDelayMillis", |