Commit 648288e2 authored by Mike Wittman's avatar Mike Wittman Committed by Commit Bot

[Sampling profiler] Apply metadata to samples before first contentful paint

Requests that the sampling profiler apply metadata to samples between
navigation start and first contentful paint, at the time when first
contentful paint is sent to the browser process. This metadata will
support analysis of execution during page load.

This change introduces monotonic time interfaces for the required metrics
because the existing interfaces are limited to 1ms resolution. If used
they would result in up to 2% of samples being misidentified as occurring
during loading when they weren't, or vice versa.

Bug: 1034756
Change-Id: Ibb39877ecfc52a1e5327204c39c3b0ce0f1b8ccd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2042324Reviewed-by: default avatarStephen Chenney <schenney@chromium.org>
Reviewed-by: default avatarNicolás Peña Moreno <npm@chromium.org>
Reviewed-by: default avatarBryan McQuade <bmcquade@chromium.org>
Reviewed-by: default avatarAnnie Sullivan <sullivan@chromium.org>
Commit-Queue: Mike Wittman <wittman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#742717}
parent 9e89e35e
...@@ -8,6 +8,8 @@ source_set("renderer") { ...@@ -8,6 +8,8 @@ source_set("renderer") {
"metrics_render_frame_observer.h", "metrics_render_frame_observer.h",
"page_resource_data_use.cc", "page_resource_data_use.cc",
"page_resource_data_use.h", "page_resource_data_use.h",
"page_timing_metadata_recorder.cc",
"page_timing_metadata_recorder.h",
"page_timing_metrics_sender.cc", "page_timing_metrics_sender.cc",
"page_timing_metrics_sender.h", "page_timing_metrics_sender.h",
"page_timing_sender.h", "page_timing_sender.h",
......
...@@ -32,6 +32,10 @@ base::TimeDelta ClampDelta(double event, double start) { ...@@ -32,6 +32,10 @@ base::TimeDelta ClampDelta(double event, double start) {
return base::Time::FromDoubleT(event) - base::Time::FromDoubleT(start); return base::Time::FromDoubleT(event) - base::Time::FromDoubleT(start);
} }
base::TimeTicks ClampToStart(base::TimeTicks event, base::TimeTicks start) {
return event < start ? start : event;
}
class MojoPageTimingSender : public PageTimingSender { class MojoPageTimingSender : public PageTimingSender {
public: public:
explicit MojoPageTimingSender(content::RenderFrame* render_frame) { explicit MojoPageTimingSender(content::RenderFrame* render_frame) {
...@@ -252,8 +256,10 @@ void MetricsRenderFrameObserver::DidCommitProvisionalLoad( ...@@ -252,8 +256,10 @@ void MetricsRenderFrameObserver::DidCommitProvisionalLoad(
provisional_frame_resource_id_ = provisional_frame_resource_id_ =
provisional_frame_resource_data_use_->resource_id(); provisional_frame_resource_data_use_->resource_id();
Timing timing = GetTiming();
page_timing_metrics_sender_ = std::make_unique<PageTimingMetricsSender>( page_timing_metrics_sender_ = std::make_unique<PageTimingMetricsSender>(
CreatePageTimingSender(), CreateTimer(), GetTiming(), CreatePageTimingSender(), CreateTimer(),
std::move(timing.relative_timing), timing.monotonic_timing,
std::move(provisional_frame_resource_data_use_)); std::move(provisional_frame_resource_data_use_));
} }
...@@ -295,6 +301,18 @@ void MetricsRenderFrameObserver::MaybeSetCompletedBeforeFCP(int request_id) { ...@@ -295,6 +301,18 @@ void MetricsRenderFrameObserver::MaybeSetCompletedBeforeFCP(int request_id) {
before_fcp_request_ids_.insert(request_id); before_fcp_request_ids_.insert(request_id);
} }
MetricsRenderFrameObserver::Timing::Timing(
mojom::PageLoadTimingPtr relative_timing,
const PageTimingMetadataRecorder::MonotonicTiming& monotonic_timing)
: relative_timing(std::move(relative_timing)),
monotonic_timing(monotonic_timing) {}
MetricsRenderFrameObserver::Timing::~Timing() = default;
MetricsRenderFrameObserver::Timing::Timing(Timing&&) = default;
MetricsRenderFrameObserver::Timing& MetricsRenderFrameObserver::Timing::
operator=(Timing&&) = default;
void MetricsRenderFrameObserver::UpdateResourceMetadata(int request_id) { void MetricsRenderFrameObserver::UpdateResourceMetadata(int request_id) {
if (!page_timing_metrics_sender_) if (!page_timing_metrics_sender_)
return; return;
...@@ -336,16 +354,21 @@ void MetricsRenderFrameObserver::SendMetrics() { ...@@ -336,16 +354,21 @@ void MetricsRenderFrameObserver::SendMetrics() {
return; return;
if (HasNoRenderFrame()) if (HasNoRenderFrame())
return; return;
page_timing_metrics_sender_->SendSoon(GetTiming()); Timing timing = GetTiming();
page_timing_metrics_sender_->Update(std::move(timing.relative_timing),
timing.monotonic_timing);
} }
mojom::PageLoadTimingPtr MetricsRenderFrameObserver::GetTiming() const { MetricsRenderFrameObserver::Timing MetricsRenderFrameObserver::GetTiming()
const {
const blink::WebPerformance& perf = const blink::WebPerformance& perf =
render_frame()->GetWebFrame()->Performance(); render_frame()->GetWebFrame()->Performance();
mojom::PageLoadTimingPtr timing(CreatePageLoadTiming()); mojom::PageLoadTimingPtr timing(CreatePageLoadTiming());
PageTimingMetadataRecorder::MonotonicTiming monotonic_timing;
double start = perf.NavigationStart(); double start = perf.NavigationStart();
timing->navigation_start = base::Time::FromDoubleT(start); timing->navigation_start = base::Time::FromDoubleT(start);
monotonic_timing.navigation_start = perf.NavigationStartAsMonotonicTime();
if (perf.InputForNavigationStart() > 0.0) { if (perf.InputForNavigationStart() > 0.0) {
timing->input_to_navigation_start = timing->input_to_navigation_start =
ClampDelta(start, perf.InputForNavigationStart()); ClampDelta(start, perf.InputForNavigationStart());
...@@ -398,6 +421,9 @@ mojom::PageLoadTimingPtr MetricsRenderFrameObserver::GetTiming() const { ...@@ -398,6 +421,9 @@ mojom::PageLoadTimingPtr MetricsRenderFrameObserver::GetTiming() const {
if (perf.FirstContentfulPaint() > 0.0) { if (perf.FirstContentfulPaint() > 0.0) {
timing->paint_timing->first_contentful_paint = timing->paint_timing->first_contentful_paint =
ClampDelta(perf.FirstContentfulPaint(), start); ClampDelta(perf.FirstContentfulPaint(), start);
monotonic_timing.first_contentful_paint =
ClampToStart(perf.FirstContentfulPaintAsMonotonicTime(),
perf.NavigationStartAsMonotonicTime());
} }
if (perf.FirstMeaningfulPaint() > 0.0) { if (perf.FirstMeaningfulPaint() > 0.0) {
timing->paint_timing->first_meaningful_paint = timing->paint_timing->first_meaningful_paint =
...@@ -447,7 +473,7 @@ mojom::PageLoadTimingPtr MetricsRenderFrameObserver::GetTiming() const { ...@@ -447,7 +473,7 @@ mojom::PageLoadTimingPtr MetricsRenderFrameObserver::GetTiming() const {
perf.ParseBlockedOnScriptExecutionFromDocumentWriteDuration()); perf.ParseBlockedOnScriptExecutionFromDocumentWriteDuration());
} }
return timing; return Timing(std::move(timing), monotonic_timing);
} }
std::unique_ptr<base::OneShotTimer> MetricsRenderFrameObserver::CreateTimer() { std::unique_ptr<base::OneShotTimer> MetricsRenderFrameObserver::CreateTimer() {
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/scoped_observer.h" #include "base/scoped_observer.h"
#include "components/page_load_metrics/common/page_load_timing.h" #include "components/page_load_metrics/common/page_load_timing.h"
#include "components/page_load_metrics/renderer/page_resource_data_use.h" #include "components/page_load_metrics/renderer/page_resource_data_use.h"
#include "components/page_load_metrics/renderer/page_timing_metadata_recorder.h"
#include "components/subresource_filter/content/renderer/ad_resource_tracker.h" #include "components/subresource_filter/content/renderer/ad_resource_tracker.h"
#include "content/public/renderer/render_frame_observer.h" #include "content/public/renderer/render_frame_observer.h"
#include "third_party/blink/public/common/loader/loading_behavior_flag.h" #include "third_party/blink/public/common/loader/loading_behavior_flag.h"
...@@ -86,6 +87,22 @@ class MetricsRenderFrameObserver ...@@ -86,6 +87,22 @@ class MetricsRenderFrameObserver
void OnAdResourceTrackerGoingAway() override; void OnAdResourceTrackerGoingAway() override;
void OnAdResourceObserved(int request_id) override; void OnAdResourceObserved(int request_id) override;
protected:
// The relative and monotonic page load timings.
struct Timing {
Timing(mojom::PageLoadTimingPtr relative_timing,
const PageTimingMetadataRecorder::MonotonicTiming& monotonic_timing);
~Timing();
Timing(const Timing&) = delete;
Timing& operator=(const Timing&) = delete;
Timing(Timing&&);
Timing& operator=(Timing&&);
mojom::PageLoadTimingPtr relative_timing;
PageTimingMetadataRecorder::MonotonicTiming monotonic_timing;
};
private: private:
// Updates the metadata for the page resource associated with the given // Updates the metadata for the page resource associated with the given
// request_id. Removes the request_id from the list of known ads if it is an // request_id. Removes the request_id from the list of known ads if it is an
...@@ -97,7 +114,7 @@ class MetricsRenderFrameObserver ...@@ -97,7 +114,7 @@ class MetricsRenderFrameObserver
void MaybeSetCompletedBeforeFCP(int request_id); void MaybeSetCompletedBeforeFCP(int request_id);
void SendMetrics(); void SendMetrics();
virtual mojom::PageLoadTimingPtr GetTiming() const; virtual Timing GetTiming() const;
virtual std::unique_ptr<base::OneShotTimer> CreateTimer(); virtual std::unique_ptr<base::OneShotTimer> CreateTimer();
virtual std::unique_ptr<PageTimingSender> CreatePageTimingSender(); virtual std::unique_ptr<PageTimingSender> CreatePageTimingSender();
virtual bool HasNoRenderFrame() const; virtual bool HasNoRenderFrame() const;
......
...@@ -51,9 +51,10 @@ class TestMetricsRenderFrameObserver : public MetricsRenderFrameObserver, ...@@ -51,9 +51,10 @@ class TestMetricsRenderFrameObserver : public MetricsRenderFrameObserver,
fake_timing_ = timing.Clone(); fake_timing_ = timing.Clone();
} }
mojom::PageLoadTimingPtr GetTiming() const override { Timing GetTiming() const override {
EXPECT_NE(nullptr, fake_timing_.get()); EXPECT_NE(nullptr, fake_timing_.get());
return std::move(fake_timing_); return Timing(std::move(fake_timing_),
PageTimingMetadataRecorder::MonotonicTiming());
} }
void VerifyExpectedTimings() const { void VerifyExpectedTimings() const {
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/page_load_metrics/renderer/page_timing_metadata_recorder.h"
#include "base/profiler/sample_metadata.h"
namespace page_load_metrics {
// The next instance id to use for a PageTimingMetadataRecorder.
int g_next_instance_id = 1;
PageTimingMetadataRecorder::MonotonicTiming::MonotonicTiming() = default;
PageTimingMetadataRecorder::MonotonicTiming::MonotonicTiming(
const MonotonicTiming&) = default;
PageTimingMetadataRecorder::MonotonicTiming&
PageTimingMetadataRecorder::MonotonicTiming::operator=(const MonotonicTiming&) =
default;
PageTimingMetadataRecorder::MonotonicTiming::MonotonicTiming(
MonotonicTiming&&) = default;
PageTimingMetadataRecorder::MonotonicTiming&
PageTimingMetadataRecorder::MonotonicTiming::operator=(MonotonicTiming&&) =
default;
PageTimingMetadataRecorder::PageTimingMetadataRecorder(
const MonotonicTiming& initial_timing)
: instance_id_(g_next_instance_id++) {
UpdateMetadata(initial_timing);
}
PageTimingMetadataRecorder::~PageTimingMetadataRecorder() = default;
void PageTimingMetadataRecorder::UpdateMetadata(const MonotonicTiming& timing) {
// Applying metadata to past samples has non-trivial cost so only do so if
// the relevant values changed.
const bool should_apply_metadata =
timing.navigation_start.has_value() &&
timing.first_contentful_paint.has_value() &&
(timing_.navigation_start != timing.navigation_start ||
timing_.first_contentful_paint != timing.first_contentful_paint);
if (should_apply_metadata) {
base::ApplyMetadataToPastSamples(
*timing.navigation_start, *timing.first_contentful_paint,
"PageLoad.PaintTiming.NavigationToFirstContentfulPaint", instance_id_,
1);
}
timing_ = timing;
}
} // namespace page_load_metrics
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_PAGE_LOAD_METRICS_RENDERER_PAGE_TIMING_METADATA_RECORDER_H_
#define COMPONENTS_PAGE_LOAD_METRICS_RENDERER_PAGE_TIMING_METADATA_RECORDER_H_
#include "base/optional.h"
#include "base/time/time.h"
namespace page_load_metrics {
// Records metadata corresponding to page load metrics on sampling profiler
// stack samples. PageTimingMetadataRecorder is currently only intended to be
// used for the sampling profiler. If you have a new use case in mind, please
// reach out to page_load_metrics owners to discuss it.
class PageTimingMetadataRecorder {
public:
// Records the monotonic times that define first contentful paint.
struct MonotonicTiming {
MonotonicTiming();
MonotonicTiming(const MonotonicTiming&);
MonotonicTiming& operator=(const MonotonicTiming&);
MonotonicTiming(MonotonicTiming&&);
MonotonicTiming& operator=(MonotonicTiming&&);
base::Optional<base::TimeTicks> navigation_start;
base::Optional<base::TimeTicks> first_contentful_paint;
};
PageTimingMetadataRecorder(const MonotonicTiming& initial_timing);
~PageTimingMetadataRecorder();
PageTimingMetadataRecorder(const PageTimingMetadataRecorder&) = delete;
PageTimingMetadataRecorder& operator=(const PageTimingMetadataRecorder&) =
delete;
void UpdateMetadata(const MonotonicTiming& timing);
private:
// Uniquely identifies an instance of the PageTimingMetadataRecorder. Used to
// distinguish page loads for different documents when applying sample
// metadata.
const int instance_id_;
// Records the monotonic times that define first contentful paint.
MonotonicTiming timing_;
};
} // namespace page_load_metrics
#endif // COMPONENTS_PAGE_LOAD_METRICS_RENDERER_PAGE_TIMING_METADATA_RECORDER_H_
...@@ -30,6 +30,7 @@ PageTimingMetricsSender::PageTimingMetricsSender( ...@@ -30,6 +30,7 @@ PageTimingMetricsSender::PageTimingMetricsSender(
std::unique_ptr<PageTimingSender> sender, std::unique_ptr<PageTimingSender> sender,
std::unique_ptr<base::OneShotTimer> timer, std::unique_ptr<base::OneShotTimer> timer,
mojom::PageLoadTimingPtr initial_timing, mojom::PageLoadTimingPtr initial_timing,
const PageTimingMetadataRecorder::MonotonicTiming& initial_monotonic_timing,
std::unique_ptr<PageResourceDataUse> initial_request) std::unique_ptr<PageResourceDataUse> initial_request)
: sender_(std::move(sender)), : sender_(std::move(sender)),
timer_(std::move(timer)), timer_(std::move(timer)),
...@@ -39,7 +40,8 @@ PageTimingMetricsSender::PageTimingMetricsSender( ...@@ -39,7 +40,8 @@ PageTimingMetricsSender::PageTimingMetricsSender(
new_features_(mojom::PageLoadFeatures::New()), new_features_(mojom::PageLoadFeatures::New()),
render_data_(), render_data_(),
new_deferred_resource_data_(mojom::DeferredResourceCounts::New()), new_deferred_resource_data_(mojom::DeferredResourceCounts::New()),
buffer_timer_delay_ms_(kBufferTimerDelayMillis) { buffer_timer_delay_ms_(kBufferTimerDelayMillis),
metadata_recorder_(initial_monotonic_timing) {
page_resource_data_use_.emplace( page_resource_data_use_.emplace(
std::piecewise_construct, std::piecewise_construct,
std::forward_as_tuple(initial_request->resource_id()), std::forward_as_tuple(initial_request->resource_id()),
...@@ -226,7 +228,9 @@ void PageTimingMetricsSender::UpdateResourceMetadata( ...@@ -226,7 +228,9 @@ void PageTimingMetricsSender::UpdateResourceMetadata(
it->second->SetIsMainFrameResource(is_main_frame_resource); it->second->SetIsMainFrameResource(is_main_frame_resource);
} }
void PageTimingMetricsSender::SendSoon(mojom::PageLoadTimingPtr timing) { void PageTimingMetricsSender::Update(
mojom::PageLoadTimingPtr timing,
const PageTimingMetadataRecorder::MonotonicTiming& monotonic_timing) {
if (last_timing_->Equals(*timing)) { if (last_timing_->Equals(*timing)) {
return; return;
} }
...@@ -240,6 +244,7 @@ void PageTimingMetricsSender::SendSoon(mojom::PageLoadTimingPtr timing) { ...@@ -240,6 +244,7 @@ void PageTimingMetricsSender::SendSoon(mojom::PageLoadTimingPtr timing) {
} }
last_timing_ = std::move(timing); last_timing_ = std::move(timing);
metadata_recorder_.UpdateMetadata(monotonic_timing);
EnsureSendTimer(); EnsureSendTimer();
} }
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "components/page_load_metrics/common/page_load_timing.h" #include "components/page_load_metrics/common/page_load_timing.h"
#include "components/page_load_metrics/renderer/page_resource_data_use.h" #include "components/page_load_metrics/renderer/page_resource_data_use.h"
#include "components/page_load_metrics/renderer/page_timing_metadata_recorder.h"
#include "content/public/common/previews_state.h" #include "content/public/common/previews_state.h"
#include "services/network/public/mojom/url_response_head.mojom-forward.h" #include "services/network/public/mojom/url_response_head.mojom-forward.h"
#include "third_party/blink/public/common/loader/loading_behavior_flag.h" #include "third_party/blink/public/common/loader/loading_behavior_flag.h"
...@@ -42,6 +43,8 @@ class PageTimingMetricsSender { ...@@ -42,6 +43,8 @@ class PageTimingMetricsSender {
PageTimingMetricsSender(std::unique_ptr<PageTimingSender> sender, PageTimingMetricsSender(std::unique_ptr<PageTimingSender> sender,
std::unique_ptr<base::OneShotTimer> timer, std::unique_ptr<base::OneShotTimer> timer,
mojom::PageLoadTimingPtr initial_timing, mojom::PageLoadTimingPtr initial_timing,
const PageTimingMetadataRecorder::MonotonicTiming&
initial_monotonic_timing,
std::unique_ptr<PageResourceDataUse> initial_request); std::unique_ptr<PageResourceDataUse> initial_request);
~PageTimingMetricsSender(); ~PageTimingMetricsSender();
...@@ -67,8 +70,11 @@ class PageTimingMetricsSender { ...@@ -67,8 +70,11 @@ class PageTimingMetricsSender {
int64_t encoded_body_length, int64_t encoded_body_length,
const std::string& mime_type); const std::string& mime_type);
// Queues the send by starting the send timer. // Updates the timing information. Buffers |timing| to be sent over mojo
void SendSoon(mojom::PageLoadTimingPtr timing); // sometime 'soon'.
void Update(
mojom::PageLoadTimingPtr timing,
const PageTimingMetadataRecorder::MonotonicTiming& monotonic_timing);
// Sends any queued timing data immediately and stops the send timer. // Sends any queued timing data immediately and stops the send timer.
void SendLatest(); void SendLatest();
...@@ -125,6 +131,10 @@ class PageTimingMetricsSender { ...@@ -125,6 +131,10 @@ class PageTimingMetricsSender {
// https://crbug.com/847269. // https://crbug.com/847269.
int buffer_timer_delay_ms_; int buffer_timer_delay_ms_;
// Responsible for recording sampling profiler metadata corresponding to page
// timing.
PageTimingMetadataRecorder metadata_recorder_;
DISALLOW_COPY_AND_ASSIGN(PageTimingMetricsSender); DISALLOW_COPY_AND_ASSIGN(PageTimingMetricsSender);
}; };
......
...@@ -20,10 +20,12 @@ class TestPageTimingMetricsSender : public PageTimingMetricsSender { ...@@ -20,10 +20,12 @@ class TestPageTimingMetricsSender : public PageTimingMetricsSender {
public: public:
explicit TestPageTimingMetricsSender( explicit TestPageTimingMetricsSender(
std::unique_ptr<PageTimingSender> page_timing_sender, std::unique_ptr<PageTimingSender> page_timing_sender,
mojom::PageLoadTimingPtr initial_timing) mojom::PageLoadTimingPtr initial_timing,
const PageTimingMetadataRecorder::MonotonicTiming& monotonic_timing)
: PageTimingMetricsSender(std::move(page_timing_sender), : PageTimingMetricsSender(std::move(page_timing_sender),
std::make_unique<base::MockOneShotTimer>(), std::make_unique<base::MockOneShotTimer>(),
std::move(initial_timing), std::move(initial_timing),
monotonic_timing,
std::make_unique<PageResourceDataUse>()) {} std::make_unique<PageResourceDataUse>()) {}
base::MockOneShotTimer* mock_timer() const { base::MockOneShotTimer* mock_timer() const {
...@@ -36,7 +38,8 @@ class PageTimingMetricsSenderTest : public testing::Test { ...@@ -36,7 +38,8 @@ class PageTimingMetricsSenderTest : public testing::Test {
PageTimingMetricsSenderTest() PageTimingMetricsSenderTest()
: metrics_sender_(new TestPageTimingMetricsSender( : metrics_sender_(new TestPageTimingMetricsSender(
std::make_unique<FakePageTimingSender>(&validator_), std::make_unique<FakePageTimingSender>(&validator_),
mojom::PageLoadTiming::New())) {} mojom::PageLoadTiming::New(),
PageTimingMetadataRecorder::MonotonicTiming())) {}
protected: protected:
FakePageTimingSender::PageTimingValidator validator_; FakePageTimingSender::PageTimingValidator validator_;
...@@ -50,7 +53,8 @@ TEST_F(PageTimingMetricsSenderTest, Basic) { ...@@ -50,7 +53,8 @@ TEST_F(PageTimingMetricsSenderTest, Basic) {
InitPageLoadTimingForTest(&timing); InitPageLoadTimingForTest(&timing);
timing.navigation_start = nav_start; timing.navigation_start = nav_start;
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
// Firing the timer should trigger sending of an SendTiming call. // Firing the timer should trigger sending of an SendTiming call.
validator_.ExpectPageLoadTiming(timing); validator_.ExpectPageLoadTiming(timing);
...@@ -63,7 +67,8 @@ TEST_F(PageTimingMetricsSenderTest, Basic) { ...@@ -63,7 +67,8 @@ TEST_F(PageTimingMetricsSenderTest, Basic) {
// Attempt to send the same timing instance again. The send should be // Attempt to send the same timing instance again. The send should be
// suppressed, since the timing instance hasn't changed since the last send. // suppressed, since the timing instance hasn't changed since the last send.
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
EXPECT_FALSE(metrics_sender_->mock_timer()->IsRunning()); EXPECT_FALSE(metrics_sender_->mock_timer()->IsRunning());
} }
...@@ -75,13 +80,15 @@ TEST_F(PageTimingMetricsSenderTest, CoalesceMultipleTimings) { ...@@ -75,13 +80,15 @@ TEST_F(PageTimingMetricsSenderTest, CoalesceMultipleTimings) {
InitPageLoadTimingForTest(&timing); InitPageLoadTimingForTest(&timing);
timing.navigation_start = nav_start; timing.navigation_start = nav_start;
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning()); ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
// Send an updated PageLoadTiming before the timer has fired. When the timer // Send an updated PageLoadTiming before the timer has fired. When the timer
// fires, the updated PageLoadTiming should be sent. // fires, the updated PageLoadTiming should be sent.
timing.document_timing->load_event_start = load_event; timing.document_timing->load_event_start = load_event;
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
// Firing the timer should trigger sending of the SendTiming call with // Firing the timer should trigger sending of the SendTiming call with
// the most recently provided PageLoadTiming instance. // the most recently provided PageLoadTiming instance.
...@@ -98,7 +105,8 @@ TEST_F(PageTimingMetricsSenderTest, MultipleTimings) { ...@@ -98,7 +105,8 @@ TEST_F(PageTimingMetricsSenderTest, MultipleTimings) {
InitPageLoadTimingForTest(&timing); InitPageLoadTimingForTest(&timing);
timing.navigation_start = nav_start; timing.navigation_start = nav_start;
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning()); ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
validator_.ExpectPageLoadTiming(timing); validator_.ExpectPageLoadTiming(timing);
metrics_sender_->mock_timer()->Fire(); metrics_sender_->mock_timer()->Fire();
...@@ -108,7 +116,8 @@ TEST_F(PageTimingMetricsSenderTest, MultipleTimings) { ...@@ -108,7 +116,8 @@ TEST_F(PageTimingMetricsSenderTest, MultipleTimings) {
// Send an updated PageLoadTiming after the timer for the first send request // Send an updated PageLoadTiming after the timer for the first send request
// has fired, and verify that a second timing is sent. // has fired, and verify that a second timing is sent.
timing.document_timing->load_event_start = load_event; timing.document_timing->load_event_start = load_event;
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning()); ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
validator_.ExpectPageLoadTiming(timing); validator_.ExpectPageLoadTiming(timing);
metrics_sender_->mock_timer()->Fire(); metrics_sender_->mock_timer()->Fire();
...@@ -123,7 +132,8 @@ TEST_F(PageTimingMetricsSenderTest, SendTimingOnSendLatest) { ...@@ -123,7 +132,8 @@ TEST_F(PageTimingMetricsSenderTest, SendTimingOnSendLatest) {
// This test wants to verify behavior in the PageTimingMetricsSender // This test wants to verify behavior in the PageTimingMetricsSender
// destructor. The EXPECT_CALL will be satisfied when the |metrics_sender_| // destructor. The EXPECT_CALL will be satisfied when the |metrics_sender_|
// is destroyed below. // is destroyed below.
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
validator_.ExpectPageLoadTiming(timing); validator_.ExpectPageLoadTiming(timing);
ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning()); ASSERT_TRUE(metrics_sender_->mock_timer()->IsRunning());
...@@ -135,7 +145,8 @@ TEST_F(PageTimingMetricsSenderTest, SendSingleFeature) { ...@@ -135,7 +145,8 @@ TEST_F(PageTimingMetricsSenderTest, SendSingleFeature) {
InitPageLoadTimingForTest(&timing); InitPageLoadTimingForTest(&timing);
blink::mojom::WebFeature feature = blink::mojom::WebFeature::kFetch; blink::mojom::WebFeature feature = blink::mojom::WebFeature::kFetch;
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
validator_.ExpectPageLoadTiming(timing); validator_.ExpectPageLoadTiming(timing);
// Observe a single feature, update expected features sent across IPC. // Observe a single feature, update expected features sent across IPC.
metrics_sender_->DidObserveNewFeatureUsage(feature); metrics_sender_->DidObserveNewFeatureUsage(feature);
...@@ -152,7 +163,8 @@ TEST_F(PageTimingMetricsSenderTest, SendMultipleFeatures) { ...@@ -152,7 +163,8 @@ TEST_F(PageTimingMetricsSenderTest, SendMultipleFeatures) {
blink::mojom::WebFeature feature_1 = blink::mojom::WebFeature feature_1 =
blink::mojom::WebFeature::kFetchBodyStream; blink::mojom::WebFeature::kFetchBodyStream;
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
validator_.ExpectPageLoadTiming(timing); validator_.ExpectPageLoadTiming(timing);
// Observe the first feature, update expected features sent across IPC. // Observe the first feature, update expected features sent across IPC.
metrics_sender_->DidObserveNewFeatureUsage(feature_0); metrics_sender_->DidObserveNewFeatureUsage(feature_0);
...@@ -170,7 +182,8 @@ TEST_F(PageTimingMetricsSenderTest, SendDuplicatedFeatures) { ...@@ -170,7 +182,8 @@ TEST_F(PageTimingMetricsSenderTest, SendDuplicatedFeatures) {
InitPageLoadTimingForTest(&timing); InitPageLoadTimingForTest(&timing);
blink::mojom::WebFeature feature = blink::mojom::WebFeature::kFetch; blink::mojom::WebFeature feature = blink::mojom::WebFeature::kFetch;
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
validator_.ExpectPageLoadTiming(timing); validator_.ExpectPageLoadTiming(timing);
metrics_sender_->DidObserveNewFeatureUsage(feature); metrics_sender_->DidObserveNewFeatureUsage(feature);
validator_.UpdateExpectPageLoadFeatures(feature); validator_.UpdateExpectPageLoadFeatures(feature);
...@@ -190,7 +203,8 @@ TEST_F(PageTimingMetricsSenderTest, SendMultipleFeaturesTwice) { ...@@ -190,7 +203,8 @@ TEST_F(PageTimingMetricsSenderTest, SendMultipleFeaturesTwice) {
blink::mojom::WebFeature::kFetchBodyStream; blink::mojom::WebFeature::kFetchBodyStream;
blink::mojom::WebFeature feature_2 = blink::mojom::WebFeature::kWindowFind; blink::mojom::WebFeature feature_2 = blink::mojom::WebFeature::kWindowFind;
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
validator_.ExpectPageLoadTiming(timing); validator_.ExpectPageLoadTiming(timing);
// Observe the first feature, update expected features sent across IPC. // Observe the first feature, update expected features sent across IPC.
metrics_sender_->DidObserveNewFeatureUsage(feature_0); metrics_sender_->DidObserveNewFeatureUsage(feature_0);
...@@ -209,7 +223,8 @@ TEST_F(PageTimingMetricsSenderTest, SendMultipleFeaturesTwice) { ...@@ -209,7 +223,8 @@ TEST_F(PageTimingMetricsSenderTest, SendMultipleFeaturesTwice) {
// Send an updated PageLoadTiming after the timer for the first send request // Send an updated PageLoadTiming after the timer for the first send request
// has fired, and verify that a second list of features is sent. // has fired, and verify that a second list of features is sent.
timing.document_timing->load_event_start = load_event; timing.document_timing->load_event_start = load_event;
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
validator_.ExpectPageLoadTiming(timing); validator_.ExpectPageLoadTiming(timing);
// Observe duplicated feature usage, without updating expected features sent // Observe duplicated feature usage, without updating expected features sent
// across IPC. // across IPC.
...@@ -229,7 +244,8 @@ TEST_F(PageTimingMetricsSenderTest, SendSingleCssProperty) { ...@@ -229,7 +244,8 @@ TEST_F(PageTimingMetricsSenderTest, SendSingleCssProperty) {
mojom::PageLoadTiming timing; mojom::PageLoadTiming timing;
InitPageLoadTimingForTest(&timing); InitPageLoadTimingForTest(&timing);
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
validator_.ExpectPageLoadTiming(timing); validator_.ExpectPageLoadTiming(timing);
// Observe a single CSS property, update expected CSS properties sent across // Observe a single CSS property, update expected CSS properties sent across
// IPC. // IPC.
...@@ -245,7 +261,8 @@ TEST_F(PageTimingMetricsSenderTest, SendCssPropertiesInRange) { ...@@ -245,7 +261,8 @@ TEST_F(PageTimingMetricsSenderTest, SendCssPropertiesInRange) {
mojom::PageLoadTiming timing; mojom::PageLoadTiming timing;
InitPageLoadTimingForTest(&timing); InitPageLoadTimingForTest(&timing);
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
validator_.ExpectPageLoadTiming(timing); validator_.ExpectPageLoadTiming(timing);
// Observe the smallest CSS property ID. // Observe the smallest CSS property ID.
metrics_sender_->DidObserveNewCssPropertyUsage(CSSSampleId::kColor, metrics_sender_->DidObserveNewCssPropertyUsage(CSSSampleId::kColor,
...@@ -264,7 +281,8 @@ TEST_F(PageTimingMetricsSenderTest, SendMultipleCssProperties) { ...@@ -264,7 +281,8 @@ TEST_F(PageTimingMetricsSenderTest, SendMultipleCssProperties) {
mojom::PageLoadTiming timing; mojom::PageLoadTiming timing;
InitPageLoadTimingForTest(&timing); InitPageLoadTimingForTest(&timing);
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
validator_.ExpectPageLoadTiming(timing); validator_.ExpectPageLoadTiming(timing);
// Observe the first CSS property, update expected CSS properties sent across // Observe the first CSS property, update expected CSS properties sent across
// IPC. // IPC.
...@@ -285,7 +303,8 @@ TEST_F(PageTimingMetricsSenderTest, SendDuplicatedCssProperties) { ...@@ -285,7 +303,8 @@ TEST_F(PageTimingMetricsSenderTest, SendDuplicatedCssProperties) {
mojom::PageLoadTiming timing; mojom::PageLoadTiming timing;
InitPageLoadTimingForTest(&timing); InitPageLoadTimingForTest(&timing);
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
validator_.ExpectPageLoadTiming(timing); validator_.ExpectPageLoadTiming(timing);
metrics_sender_->DidObserveNewCssPropertyUsage(CSSSampleId::kDirection, metrics_sender_->DidObserveNewCssPropertyUsage(CSSSampleId::kDirection,
false /*is_animated*/); false /*is_animated*/);
...@@ -303,7 +322,8 @@ TEST_F(PageTimingMetricsSenderTest, SendMultipleCssPropertiesTwice) { ...@@ -303,7 +322,8 @@ TEST_F(PageTimingMetricsSenderTest, SendMultipleCssPropertiesTwice) {
mojom::PageLoadTiming timing; mojom::PageLoadTiming timing;
InitPageLoadTimingForTest(&timing); InitPageLoadTimingForTest(&timing);
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
validator_.ExpectPageLoadTiming(timing); validator_.ExpectPageLoadTiming(timing);
// Observe the first CSS property, update expected CSS properties sent across // Observe the first CSS property, update expected CSS properties sent across
// IPC. // IPC.
...@@ -327,7 +347,8 @@ TEST_F(PageTimingMetricsSenderTest, SendMultipleCssPropertiesTwice) { ...@@ -327,7 +347,8 @@ TEST_F(PageTimingMetricsSenderTest, SendMultipleCssPropertiesTwice) {
// Send an updated PageLoadTiming after the timer for the first send request // Send an updated PageLoadTiming after the timer for the first send request
// has fired, and verify that a second list of CSS properties is sent. // has fired, and verify that a second list of CSS properties is sent.
timing.document_timing->load_event_start = load_event; timing.document_timing->load_event_start = load_event;
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
validator_.ExpectPageLoadTiming(timing); validator_.ExpectPageLoadTiming(timing);
// Observe duplicated usage, without updating expected features sent across // Observe duplicated usage, without updating expected features sent across
// IPC. // IPC.
...@@ -353,7 +374,8 @@ TEST_F(PageTimingMetricsSenderTest, SendPageRenderData) { ...@@ -353,7 +374,8 @@ TEST_F(PageTimingMetricsSenderTest, SendPageRenderData) {
// related to the PageRenderData. This is because metrics_sender_ sends // related to the PageRenderData. This is because metrics_sender_ sends
// its last_timing_ when the mock timer fires, causing the validator to // its last_timing_ when the mock timer fires, causing the validator to
// look for a matching expectation. // look for a matching expectation.
metrics_sender_->SendSoon(timing.Clone()); metrics_sender_->Update(timing.Clone(),
PageTimingMetadataRecorder::MonotonicTiming());
validator_.ExpectPageLoadTiming(timing); validator_.ExpectPageLoadTiming(timing);
metrics_sender_->DidObserveLayoutShift(0.5, false); metrics_sender_->DidObserveLayoutShift(0.5, false);
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_PERFORMANCE_H_ #ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_PERFORMANCE_H_
#define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_PERFORMANCE_H_ #define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_PERFORMANCE_H_
#include "base/time/time.h"
#include "third_party/blink/public/platform/web_common.h" #include "third_party/blink/public/platform/web_common.h"
#include "third_party/blink/public/platform/web_private_ptr.h" #include "third_party/blink/public/platform/web_private_ptr.h"
#include "third_party/blink/public/web/web_navigation_type.h" #include "third_party/blink/public/web/web_navigation_type.h"
...@@ -66,6 +67,7 @@ class WebPerformance { ...@@ -66,6 +67,7 @@ class WebPerformance {
// These functions return time in seconds (not milliseconds) since the epoch. // These functions return time in seconds (not milliseconds) since the epoch.
BLINK_EXPORT double InputForNavigationStart() const; BLINK_EXPORT double InputForNavigationStart() const;
BLINK_EXPORT double NavigationStart() const; BLINK_EXPORT double NavigationStart() const;
BLINK_EXPORT base::TimeTicks NavigationStartAsMonotonicTime() const;
BLINK_EXPORT double UnloadEventEnd() const; BLINK_EXPORT double UnloadEventEnd() const;
BLINK_EXPORT double RedirectStart() const; BLINK_EXPORT double RedirectStart() const;
BLINK_EXPORT double RedirectEnd() const; BLINK_EXPORT double RedirectEnd() const;
...@@ -88,6 +90,7 @@ class WebPerformance { ...@@ -88,6 +90,7 @@ class WebPerformance {
BLINK_EXPORT double FirstPaint() const; BLINK_EXPORT double FirstPaint() const;
BLINK_EXPORT double FirstImagePaint() const; BLINK_EXPORT double FirstImagePaint() const;
BLINK_EXPORT double FirstContentfulPaint() const; BLINK_EXPORT double FirstContentfulPaint() const;
BLINK_EXPORT base::TimeTicks FirstContentfulPaintAsMonotonicTime() const;
BLINK_EXPORT double FirstMeaningfulPaint() const; BLINK_EXPORT double FirstMeaningfulPaint() const;
BLINK_EXPORT double FirstMeaningfulPaintCandidate() const; BLINK_EXPORT double FirstMeaningfulPaintCandidate() const;
BLINK_EXPORT double LargestImagePaint() const; BLINK_EXPORT double LargestImagePaint() const;
......
...@@ -65,6 +65,10 @@ double WebPerformance::NavigationStart() const { ...@@ -65,6 +65,10 @@ double WebPerformance::NavigationStart() const {
return MillisecondsToSeconds(private_->timing()->navigationStart()); return MillisecondsToSeconds(private_->timing()->navigationStart());
} }
base::TimeTicks WebPerformance::NavigationStartAsMonotonicTime() const {
return private_->timing()->NavigationStartAsMonotonicTime();
}
double WebPerformance::InputForNavigationStart() const { double WebPerformance::InputForNavigationStart() const {
return MillisecondsToSeconds(private_->timing()->inputStart()); return MillisecondsToSeconds(private_->timing()->inputStart());
} }
...@@ -158,6 +162,10 @@ double WebPerformance::FirstContentfulPaint() const { ...@@ -158,6 +162,10 @@ double WebPerformance::FirstContentfulPaint() const {
return MillisecondsToSeconds(private_->timing()->FirstContentfulPaint()); return MillisecondsToSeconds(private_->timing()->FirstContentfulPaint());
} }
base::TimeTicks WebPerformance::FirstContentfulPaintAsMonotonicTime() const {
return private_->timing()->FirstContentfulPaintAsMonotonicTime();
}
double WebPerformance::FirstMeaningfulPaint() const { double WebPerformance::FirstMeaningfulPaint() const {
return MillisecondsToSeconds(private_->timing()->FirstMeaningfulPaint()); return MillisecondsToSeconds(private_->timing()->FirstMeaningfulPaint());
} }
......
...@@ -311,6 +311,14 @@ uint64_t PerformanceTiming::loadEventEnd() const { ...@@ -311,6 +311,14 @@ uint64_t PerformanceTiming::loadEventEnd() const {
return MonotonicTimeToIntegerMilliseconds(timing->LoadEventEnd()); return MonotonicTimeToIntegerMilliseconds(timing->LoadEventEnd());
} }
base::TimeTicks PerformanceTiming::NavigationStartAsMonotonicTime() const {
DocumentLoadTiming* timing = GetDocumentLoadTiming();
if (!timing)
return base::TimeTicks();
return timing->NavigationStart();
}
uint64_t PerformanceTiming::FirstPaint() const { uint64_t PerformanceTiming::FirstPaint() const {
const PaintTiming* timing = GetPaintTiming(); const PaintTiming* timing = GetPaintTiming();
if (!timing) if (!timing)
...@@ -335,6 +343,14 @@ uint64_t PerformanceTiming::FirstContentfulPaint() const { ...@@ -335,6 +343,14 @@ uint64_t PerformanceTiming::FirstContentfulPaint() const {
return MonotonicTimeToIntegerMilliseconds(timing->FirstContentfulPaint()); return MonotonicTimeToIntegerMilliseconds(timing->FirstContentfulPaint());
} }
base::TimeTicks PerformanceTiming::FirstContentfulPaintAsMonotonicTime() const {
const PaintTiming* timing = GetPaintTiming();
if (!timing)
return base::TimeTicks();
return timing->FirstContentfulPaint();
}
uint64_t PerformanceTiming::FirstMeaningfulPaint() const { uint64_t PerformanceTiming::FirstMeaningfulPaint() const {
const PaintTiming* timing = GetPaintTiming(); const PaintTiming* timing = GetPaintTiming();
if (!timing) if (!timing)
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_PERFORMANCE_TIMING_H_ #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_PERFORMANCE_TIMING_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_PERFORMANCE_TIMING_H_ #define THIRD_PARTY_BLINK_RENDERER_CORE_TIMING_PERFORMANCE_TIMING_H_
#include "base/time/time.h"
#include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h" #include "third_party/blink/renderer/core/execution_context/execution_context_lifecycle_observer.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
...@@ -86,6 +87,11 @@ class CORE_EXPORT PerformanceTiming final : public ScriptWrappable, ...@@ -86,6 +87,11 @@ class CORE_EXPORT PerformanceTiming final : public ScriptWrappable,
// The below are non-spec timings, for Page Load UMA metrics. // The below are non-spec timings, for Page Load UMA metrics.
// The time immediately after the user agent finishes prompting to unload the
// previous document, or if there is no previous document, the same value as
// fetchStart. Intended to be used for correlation with other events internal
// to blink. Not to be exposed to JavaScript.
base::TimeTicks NavigationStartAsMonotonicTime() const;
// The time the first paint operation was performed. // The time the first paint operation was performed.
uint64_t FirstPaint() const; uint64_t FirstPaint() const;
// The time the first paint operation for image was performed. // The time the first paint operation for image was performed.
...@@ -93,6 +99,10 @@ class CORE_EXPORT PerformanceTiming final : public ScriptWrappable, ...@@ -93,6 +99,10 @@ class CORE_EXPORT PerformanceTiming final : public ScriptWrappable,
// The time of the first 'contentful' paint. A contentful paint is a paint // The time of the first 'contentful' paint. A contentful paint is a paint
// that includes content of some kind (for example, text or image content). // that includes content of some kind (for example, text or image content).
uint64_t FirstContentfulPaint() const; uint64_t FirstContentfulPaint() const;
// The first 'contentful' paint as full-resolution monotonic time. Intended to
// be used for correlation with other events internal to blink. Not to be
// exposed to JavaScript.
base::TimeTicks FirstContentfulPaintAsMonotonicTime() const;
// The time of the first 'meaningful' paint, A meaningful paint is a paint // The time of the first 'meaningful' paint, A meaningful paint is a paint
// where the page's primary content is visible. // where the page's primary content is visible.
uint64_t FirstMeaningfulPaint() const; uint64_t FirstMeaningfulPaint() const;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment