| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "cc/metrics/compositor_frame_reporter.h" |
| |
| #include <memory> |
| #include <utility> |
| #include <vector> |
| |
| #include "base/rand_util.h" |
| #include "base/ranges/algorithm.h" |
| #include "base/strings/strcat.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/simple_test_tick_clock.h" |
| #include "base/time/time.h" |
| #include "cc/metrics/compositor_frame_reporting_controller.h" |
| #include "cc/metrics/dropped_frame_counter.h" |
| #include "cc/metrics/event_metrics.h" |
| #include "cc/metrics/total_frame_counter.h" |
| #include "components/viz/common/frame_timing_details.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/events/types/scroll_input_type.h" |
| |
| namespace cc { |
| namespace { |
| |
| using ::testing::Each; |
| using ::testing::IsEmpty; |
| using ::testing::NotNull; |
| |
| class CompositorFrameReporterTest : public testing::Test { |
| public: |
| CompositorFrameReporterTest() : pipeline_reporter_(CreatePipelineReporter()) { |
| AdvanceNowByUs(1); |
| dropped_frame_counter_.set_total_counter(&total_frame_counter_); |
| } |
| |
| protected: |
| base::TimeTicks AdvanceNowByUs(int advance_ms) { |
| test_tick_clock_.Advance(base::Microseconds(advance_ms)); |
| return test_tick_clock_.NowTicks(); |
| } |
| |
| base::TimeTicks Now() { return test_tick_clock_.NowTicks(); } |
| |
| std::unique_ptr<BeginMainFrameMetrics> BuildBlinkBreakdown() { |
| auto breakdown = std::make_unique<BeginMainFrameMetrics>(); |
| breakdown->handle_input_events = base::Microseconds(10); |
| breakdown->animate = base::Microseconds(9); |
| breakdown->style_update = base::Microseconds(8); |
| breakdown->layout_update = base::Microseconds(7); |
| breakdown->compositing_inputs = base::Microseconds(6); |
| breakdown->prepaint = base::Microseconds(5); |
| breakdown->paint = base::Microseconds(3); |
| breakdown->composite_commit = base::Microseconds(2); |
| breakdown->update_layers = base::Microseconds(1); |
| |
| // Advance now by the sum of the breakdowns. |
| AdvanceNowByUs(10 + 9 + 8 + 7 + 6 + 5 + 3 + 2 + 1); |
| |
| return breakdown; |
| } |
| |
| viz::FrameTimingDetails BuildVizBreakdown() { |
| viz::FrameTimingDetails viz_breakdown; |
| viz_breakdown.received_compositor_frame_timestamp = AdvanceNowByUs(1); |
| viz_breakdown.draw_start_timestamp = AdvanceNowByUs(2); |
| viz_breakdown.swap_timings.swap_start = AdvanceNowByUs(3); |
| viz_breakdown.swap_timings.swap_end = AdvanceNowByUs(4); |
| viz_breakdown.presentation_feedback.timestamp = AdvanceNowByUs(5); |
| return viz_breakdown; |
| } |
| |
| std::unique_ptr<EventMetrics> SetupEventMetrics( |
| std::unique_ptr<EventMetrics> metrics) { |
| if (metrics) { |
| AdvanceNowByUs(3); |
| metrics->SetDispatchStageTimestamp( |
| EventMetrics::DispatchStage::kRendererCompositorStarted); |
| AdvanceNowByUs(3); |
| metrics->SetDispatchStageTimestamp( |
| EventMetrics::DispatchStage::kRendererCompositorFinished); |
| } |
| return metrics; |
| } |
| |
| // Sets up the dispatch durations of each EventMetrics according to |
| // stage_durations. Stages with a duration of -1 will be skipped. |
| std::unique_ptr<EventMetrics> SetupEventMetricsWithDispatchTimes( |
| std::unique_ptr<EventMetrics> metrics, |
| const std::vector<int>& stage_durations) { |
| if (metrics) { |
| int num_stages = stage_durations.size(); |
| int max_num_stages = |
| static_cast<int>(EventMetrics::DispatchStage::kMaxValue) + 1; |
| CHECK(num_stages <= max_num_stages) |
| << num_stages << " > " << max_num_stages; |
| // Start indexing from 2 because the 0th index held duration from |
| // kGenerated to kArrivedInRendererCompositor, which was already used in |
| // when the EventMetrics was created. |
| for (int i = 2; i < num_stages; i++) { |
| if (stage_durations[i] >= 0) { |
| AdvanceNowByUs(stage_durations[i]); |
| metrics->SetDispatchStageTimestamp( |
| EventMetrics::DispatchStage(i + 2)); |
| } |
| } |
| } |
| return metrics; |
| } |
| |
| std::unique_ptr<EventMetrics> CreateEventMetrics(ui::EventType type) { |
| const base::TimeTicks event_time = AdvanceNowByUs(3); |
| const base::TimeTicks arrived_in_browser_main_timestamp = AdvanceNowByUs(2); |
| AdvanceNowByUs(3); |
| return SetupEventMetrics(EventMetrics::CreateForTesting( |
| type, event_time, arrived_in_browser_main_timestamp, &test_tick_clock_, |
| std::nullopt)); |
| } |
| |
| // Creates EventMetrics with elements in stage_durations representing each |
| // dispatch stage's desired duration respectively, with the 0th index |
| // representing the duration from kGenerated to kArrivedInRendererCompositor. |
| // stage_durations must have at least 1 element for the first required stage |
| // Use -1 for stages that want to be skipped. |
| std::unique_ptr<EventMetrics> CreateScrollUpdateEventMetricsWithDispatchTimes( |
| bool is_inertial, |
| ScrollUpdateEventMetrics::ScrollUpdateType scroll_update_type, |
| const std::vector<int>& stage_durations) { |
| CHECK_GE(stage_durations.size(), 2u); |
| |
| const base::TimeTicks event_time = AdvanceNowByUs(3); |
| |
| // kGenerated -> kArrivedInBrowserMain |
| int begin_rwh_latency_ms = stage_durations[0]; |
| const base::TimeTicks arrived_in_browser_main_timestamp = |
| AdvanceNowByUs(begin_rwh_latency_ms); |
| |
| // kArrivedInBrowserMain -> kArrivedInRendererCompositor |
| AdvanceNowByUs(stage_durations[1]); |
| |
| // Creates a kGestureScrollUpdate event. |
| return SetupEventMetricsWithDispatchTimes( |
| ScrollUpdateEventMetrics::CreateForTesting( |
| ui::ET_GESTURE_SCROLL_UPDATE, ui::ScrollInputType::kWheel, |
| is_inertial, scroll_update_type, /*delta=*/10.0f, event_time, |
| arrived_in_browser_main_timestamp, &test_tick_clock_, std::nullopt), |
| stage_durations); |
| } |
| |
| std::unique_ptr<EventMetrics> CreateScrollBeginMetrics( |
| ui::ScrollInputType input_type) { |
| const base::TimeTicks event_time = AdvanceNowByUs(3); |
| const base::TimeTicks arrived_in_browser_main_timestamp = AdvanceNowByUs(2); |
| AdvanceNowByUs(3); |
| return SetupEventMetrics(ScrollEventMetrics::CreateForTesting( |
| ui::ET_GESTURE_SCROLL_BEGIN, input_type, |
| /*is_inertial=*/false, event_time, arrived_in_browser_main_timestamp, |
| &test_tick_clock_)); |
| } |
| |
| std::unique_ptr<EventMetrics> CreateScrollUpdateEventMetrics( |
| ui::ScrollInputType input_type, |
| bool is_inertial, |
| ScrollUpdateEventMetrics::ScrollUpdateType scroll_update_type) { |
| const base::TimeTicks event_time = AdvanceNowByUs(3); |
| const base::TimeTicks arrived_in_browser_main_timestamp = AdvanceNowByUs(2); |
| AdvanceNowByUs(3); |
| return SetupEventMetrics(ScrollUpdateEventMetrics::CreateForTesting( |
| ui::ET_GESTURE_SCROLL_UPDATE, input_type, is_inertial, |
| scroll_update_type, /*delta=*/10.0f, event_time, |
| arrived_in_browser_main_timestamp, &test_tick_clock_, std::nullopt)); |
| } |
| |
| std::unique_ptr<EventMetrics> CreatePinchEventMetrics( |
| ui::EventType type, |
| ui::ScrollInputType input_type) { |
| const base::TimeTicks event_time = AdvanceNowByUs(3); |
| AdvanceNowByUs(3); |
| return SetupEventMetrics(PinchEventMetrics::CreateForTesting( |
| type, input_type, event_time, &test_tick_clock_)); |
| } |
| |
| std::vector<base::TimeTicks> GetEventTimestamps( |
| const EventMetrics::List& events_metrics) { |
| std::vector<base::TimeTicks> event_times; |
| event_times.reserve(events_metrics.size()); |
| base::ranges::transform(events_metrics, std::back_inserter(event_times), |
| [](const auto& event_metrics) { |
| return event_metrics->GetDispatchStageTimestamp( |
| EventMetrics::DispatchStage::kGenerated); |
| }); |
| return event_times; |
| } |
| |
| std::unique_ptr<CompositorFrameReporter> CreatePipelineReporter() { |
| GlobalMetricsTrackers trackers{&dropped_frame_counter_, nullptr, nullptr, |
| nullptr, nullptr}; |
| auto reporter = std::make_unique<CompositorFrameReporter>( |
| ActiveTrackers(), viz::BeginFrameArgs(), |
| /*should_report_metrics=*/true, |
| CompositorFrameReporter::SmoothThread::kSmoothBoth, |
| FrameInfo::SmoothEffectDrivingThread::kUnknown, |
| /*layer_tree_host_id=*/1, trackers); |
| reporter->set_tick_clock(&test_tick_clock_); |
| return reporter; |
| } |
| |
| void IntToTimeDeltaVector(std::vector<base::TimeDelta>& timedelta_vector, |
| std::vector<int> int_vector) { |
| size_t vector_size = int_vector.size(); |
| for (size_t i = 0; i < vector_size; i++) { |
| timedelta_vector[i] = base::Microseconds(int_vector[i]); |
| } |
| } |
| |
| void VerifyLatencyInfo( |
| const CompositorFrameReporter::CompositorLatencyInfo& expected_info, |
| const CompositorFrameReporter::CompositorLatencyInfo& actual_info) { |
| EXPECT_EQ(expected_info.top_level_stages, actual_info.top_level_stages); |
| EXPECT_EQ(expected_info.blink_breakdown_stages, |
| actual_info.blink_breakdown_stages); |
| EXPECT_EQ(expected_info.viz_breakdown_stages, |
| actual_info.viz_breakdown_stages); |
| EXPECT_EQ(expected_info.total_latency, actual_info.total_latency); |
| EXPECT_EQ(expected_info.total_blink_latency, |
| actual_info.total_blink_latency); |
| EXPECT_EQ(expected_info.total_viz_latency, actual_info.total_viz_latency); |
| } |
| |
| // Disable sub-sampling to deterministically record histograms under test. |
| base::MetricsSubSampler::ScopedAlwaysSampleForTesting no_subsampling_; |
| |
| // This should be defined before |pipeline_reporter_| so it is created before |
| // and destroyed after that. |
| base::SimpleTestTickClock test_tick_clock_; |
| |
| DroppedFrameCounter dropped_frame_counter_; |
| TotalFrameCounter total_frame_counter_; |
| std::unique_ptr<CompositorFrameReporter> pipeline_reporter_; |
| |
| // Number of breakdown stages of the current PipelineReporter |
| const int kNumOfCompositorStages = |
| static_cast<int>(CompositorFrameReporter::StageType::kStageTypeCount) - 1; |
| const int kNumDispatchStages = |
| static_cast<int>(EventMetrics::DispatchStage::kMaxValue); |
| const base::TimeDelta kLatencyPredictionDeviationThreshold = |
| base::Milliseconds(8.33); |
| }; |
| |
| TEST_F(CompositorFrameReporterTest, MainFrameAbortedReportingTest) { |
| base::HistogramTester histogram_tester; |
| |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, |
| Now()); |
| EXPECT_EQ(0u, pipeline_reporter_->stage_history_size_for_testing()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now()); |
| EXPECT_EQ(1u, pipeline_reporter_->stage_history_size_for_testing()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| EXPECT_EQ(2u, pipeline_reporter_->stage_history_size_for_testing()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| EXPECT_EQ(3u, pipeline_reporter_->stage_history_size_for_testing()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now()); |
| EXPECT_EQ(4u, pipeline_reporter_->stage_history_size_for_testing()); |
| |
| pipeline_reporter_ = nullptr; |
| histogram_tester.ExpectTotalCount( |
| "CompositorLatency.BeginImplFrameToSendBeginMainFrame", 1); |
| histogram_tester.ExpectTotalCount( |
| "CompositorLatency.SendBeginMainFrameToCommit", 1); |
| histogram_tester.ExpectTotalCount("CompositorLatency.Commit", 0); |
| histogram_tester.ExpectTotalCount("CompositorLatency.EndCommitToActivation", |
| 0); |
| histogram_tester.ExpectTotalCount( |
| "CompositorLatency.EndActivateToSubmitCompositorFrame", 1); |
| histogram_tester.ExpectTotalCount( |
| "CompositorLatency.SubmitCompositorFrameToPresentationCompositorFrame", |
| 1); |
| } |
| |
| TEST_F(CompositorFrameReporterTest, ReplacedByNewReporterReportingTest) { |
| base::HistogramTester histogram_tester; |
| |
| pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit, |
| Now()); |
| EXPECT_EQ(0u, pipeline_reporter_->stage_history_size_for_testing()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndCommitToActivation, Now()); |
| EXPECT_EQ(1u, pipeline_reporter_->stage_history_size_for_testing()); |
| |
| AdvanceNowByUs(2); |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kReplacedByNewReporter, |
| Now()); |
| EXPECT_EQ(2u, pipeline_reporter_->stage_history_size_for_testing()); |
| |
| pipeline_reporter_ = nullptr; |
| histogram_tester.ExpectTotalCount("CompositorLatency.Commit", 0); |
| histogram_tester.ExpectTotalCount("CompositorLatency.EndCommitToActivation", |
| 0); |
| } |
| |
| TEST_F(CompositorFrameReporterTest, SubmittedFrameReportingTest) { |
| base::HistogramTester histogram_tester; |
| |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kActivation, Now()); |
| EXPECT_EQ(0u, pipeline_reporter_->stage_history_size_for_testing()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| EXPECT_EQ(1u, pipeline_reporter_->stage_history_size_for_testing()); |
| |
| AdvanceNowByUs(2); |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now()); |
| EXPECT_EQ(2u, pipeline_reporter_->stage_history_size_for_testing()); |
| |
| pipeline_reporter_ = nullptr; |
| histogram_tester.ExpectTotalCount("CompositorLatency.Activation", 1); |
| histogram_tester.ExpectTotalCount( |
| "CompositorLatency.EndActivateToSubmitCompositorFrame", 1); |
| histogram_tester.ExpectTotalCount("CompositorLatency.TotalLatency", 1); |
| histogram_tester.ExpectTotalCount("CompositorLatency.DroppedFrame.Activation", |
| 0); |
| histogram_tester.ExpectTotalCount( |
| "CompositorLatency.DroppedFrame.EndActivateToSubmitCompositorFrame", 0); |
| histogram_tester.ExpectTotalCount( |
| "CompositorLatency.DroppedFrame.TotalLatency", 0); |
| |
| histogram_tester.ExpectBucketCount("CompositorLatency.Activation", 3, 1); |
| histogram_tester.ExpectBucketCount( |
| "CompositorLatency.EndActivateToSubmitCompositorFrame", 2, 1); |
| histogram_tester.ExpectBucketCount("CompositorLatency.TotalLatency", 5, 1); |
| } |
| |
| TEST_F(CompositorFrameReporterTest, SubmittedDroppedFrameReportingTest) { |
| base::HistogramTester histogram_tester; |
| |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now()); |
| EXPECT_EQ(0u, pipeline_reporter_->stage_history_size_for_testing()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit, |
| Now()); |
| EXPECT_EQ(1u, pipeline_reporter_->stage_history_size_for_testing()); |
| |
| AdvanceNowByUs(2); |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kDidNotPresentFrame, |
| Now()); |
| EXPECT_EQ(2u, pipeline_reporter_->stage_history_size_for_testing()); |
| |
| pipeline_reporter_ = nullptr; |
| histogram_tester.ExpectTotalCount( |
| "CompositorLatency.DroppedFrame.SendBeginMainFrameToCommit", 1); |
| histogram_tester.ExpectTotalCount("CompositorLatency.DroppedFrame.Commit", 1); |
| histogram_tester.ExpectTotalCount( |
| "CompositorLatency.DroppedFrame.TotalLatency", 1); |
| histogram_tester.ExpectTotalCount( |
| "CompositorLatency.SendBeginMainFrameToCommit", 0); |
| histogram_tester.ExpectTotalCount("CompositorLatency.Commit", 0); |
| histogram_tester.ExpectTotalCount("CompositorLatency.TotalLatency", 0); |
| |
| histogram_tester.ExpectBucketCount( |
| "CompositorLatency.DroppedFrame.SendBeginMainFrameToCommit", 3, 1); |
| histogram_tester.ExpectBucketCount("CompositorLatency.DroppedFrame.Commit", 2, |
| 1); |
| histogram_tester.ExpectBucketCount( |
| "CompositorLatency.DroppedFrame.TotalLatency", 5, 1); |
| } |
| |
| // Tests that when a frame is presented to the user, total event latency metrics |
| // are reported properly. |
| TEST_F(CompositorFrameReporterTest, |
| EventLatencyTotalForPresentedFrameReported) { |
| base::HistogramTester histogram_tester; |
| |
| std::unique_ptr<EventMetrics> event_metrics_ptrs[] = { |
| CreateEventMetrics(ui::ET_TOUCH_PRESSED), |
| CreateEventMetrics(ui::ET_TOUCH_MOVED), |
| CreateEventMetrics(ui::ET_TOUCH_MOVED), |
| }; |
| EXPECT_THAT(event_metrics_ptrs, Each(NotNull())); |
| EventMetrics::List events_metrics( |
| std::make_move_iterator(std::begin(event_metrics_ptrs)), |
| std::make_move_iterator(std::end(event_metrics_ptrs))); |
| std::vector<base::TimeTicks> event_times = GetEventTimestamps(events_metrics); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, |
| Now()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| pipeline_reporter_->AddEventsMetrics(std::move(events_metrics)); |
| |
| const base::TimeTicks presentation_time = AdvanceNowByUs(3); |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, |
| presentation_time); |
| |
| pipeline_reporter_ = nullptr; |
| |
| struct { |
| const char* name; |
| const base::HistogramBase::Count count; |
| } expected_counts[] = { |
| {"EventLatency.TouchPressed.TotalLatency", 1}, |
| {"EventLatency.TouchMoved.TotalLatency", 2}, |
| {"EventLatency.TotalLatency", 3}, |
| }; |
| for (const auto& expected_count : expected_counts) { |
| histogram_tester.ExpectTotalCount(expected_count.name, |
| expected_count.count); |
| } |
| |
| struct { |
| const char* name; |
| const base::HistogramBase::Sample latency_ms; |
| } expected_latencies[] = { |
| {"EventLatency.TouchPressed.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[0]).InMicroseconds())}, |
| {"EventLatency.TouchMoved.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[1]).InMicroseconds())}, |
| {"EventLatency.TouchMoved.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[2]).InMicroseconds())}, |
| {"EventLatency.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[0]).InMicroseconds())}, |
| {"EventLatency.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[1]).InMicroseconds())}, |
| {"EventLatency.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[2]).InMicroseconds())}, |
| }; |
| for (const auto& expected_latency : expected_latencies) { |
| histogram_tester.ExpectBucketCount(expected_latency.name, |
| expected_latency.latency_ms, 1); |
| } |
| } |
| |
| // Tests that when a frame is presented to the user, total scroll event latency |
| // metrics are reported properly. |
| TEST_F(CompositorFrameReporterTest, |
| EventLatencyScrollTotalForPresentedFrameReported) { |
| base::HistogramTester histogram_tester; |
| |
| const bool kScrollIsInertial = true; |
| const bool kScrollIsNotInertial = false; |
| std::unique_ptr<EventMetrics> event_metrics_ptrs[] = { |
| CreateScrollBeginMetrics(ui::ScrollInputType::kWheel), |
| CreateScrollUpdateEventMetrics( |
| ui::ScrollInputType::kWheel, kScrollIsNotInertial, |
| ScrollUpdateEventMetrics::ScrollUpdateType::kStarted), |
| CreateScrollUpdateEventMetrics( |
| ui::ScrollInputType::kWheel, kScrollIsNotInertial, |
| ScrollUpdateEventMetrics::ScrollUpdateType::kContinued), |
| CreateScrollUpdateEventMetrics( |
| ui::ScrollInputType::kWheel, kScrollIsInertial, |
| ScrollUpdateEventMetrics::ScrollUpdateType::kContinued), |
| CreateScrollBeginMetrics(ui::ScrollInputType::kTouchscreen), |
| CreateScrollUpdateEventMetrics( |
| ui::ScrollInputType::kTouchscreen, kScrollIsNotInertial, |
| ScrollUpdateEventMetrics::ScrollUpdateType::kStarted), |
| CreateScrollUpdateEventMetrics( |
| ui::ScrollInputType::kTouchscreen, kScrollIsNotInertial, |
| ScrollUpdateEventMetrics::ScrollUpdateType::kContinued), |
| CreateScrollUpdateEventMetrics( |
| ui::ScrollInputType::kTouchscreen, kScrollIsInertial, |
| ScrollUpdateEventMetrics::ScrollUpdateType::kContinued), |
| }; |
| EXPECT_THAT(event_metrics_ptrs, Each(NotNull())); |
| EventMetrics::List events_metrics( |
| std::make_move_iterator(std::begin(event_metrics_ptrs)), |
| std::make_move_iterator(std::end(event_metrics_ptrs))); |
| std::vector<base::TimeTicks> event_times = GetEventTimestamps(events_metrics); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, |
| Now()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| pipeline_reporter_->AddEventsMetrics(std::move(events_metrics)); |
| |
| AdvanceNowByUs(3); |
| viz::FrameTimingDetails viz_breakdown = BuildVizBreakdown(); |
| pipeline_reporter_->SetVizBreakdown(viz_breakdown); |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, |
| viz_breakdown.presentation_feedback.timestamp); |
| |
| pipeline_reporter_ = nullptr; |
| |
| struct { |
| const char* name; |
| const base::HistogramBase::Count count; |
| } expected_counts[] = { |
| {"EventLatency.GestureScrollBegin.Wheel.TotalLatency", 1}, |
| {"EventLatency.GestureScrollBegin.Wheel.TotalLatency2", 1}, |
| {"EventLatency.FirstGestureScrollUpdate.Wheel.TotalLatency", 1}, |
| {"EventLatency.FirstGestureScrollUpdate.Wheel.TotalLatency2", 1}, |
| {"EventLatency.GestureScrollUpdate.Wheel.TotalLatency", 1}, |
| {"EventLatency.GestureScrollUpdate.Wheel.TotalLatency2", 1}, |
| {"EventLatency.InertialGestureScrollUpdate.Wheel.TotalLatency", 1}, |
| {"EventLatency.InertialGestureScrollUpdate.Wheel.TotalLatency2", 1}, |
| {"EventLatency.GestureScrollBegin.Touchscreen.TotalLatency", 1}, |
| {"EventLatency.GestureScrollBegin.Touchscreen.TotalLatency2", 1}, |
| {"EventLatency.FirstGestureScrollUpdate.Touchscreen.TotalLatency", 1}, |
| {"EventLatency.FirstGestureScrollUpdate.Touchscreen.TotalLatency2", 1}, |
| {"EventLatency.GestureScrollUpdate.Touchscreen.TotalLatency", 1}, |
| {"EventLatency.GestureScrollUpdate.Touchscreen.TotalLatency2", 1}, |
| {"EventLatency.InertialGestureScrollUpdate.Touchscreen.TotalLatency", 1}, |
| {"EventLatency.InertialGestureScrollUpdate.Touchscreen.TotalLatency2", 1}, |
| {"EventLatency.GestureScrollBegin.TotalLatency", 2}, |
| {"EventLatency.GestureScrollBegin.TotalLatency2", 2}, |
| {"EventLatency.GestureScrollBegin.GenerationToBrowserMain", 2}, |
| {"EventLatency.FirstGestureScrollUpdate.TotalLatency", 2}, |
| {"EventLatency.FirstGestureScrollUpdate.TotalLatency2", 2}, |
| {"EventLatency.FirstGestureScrollUpdate.GenerationToBrowserMain", 2}, |
| {"EventLatency.GestureScrollUpdate.TotalLatency", 2}, |
| {"EventLatency.GestureScrollUpdate.TotalLatency2", 2}, |
| {"EventLatency.GestureScrollUpdate.GenerationToBrowserMain", 2}, |
| {"EventLatency.InertialGestureScrollUpdate.TotalLatency", 2}, |
| {"EventLatency.InertialGestureScrollUpdate.TotalLatency2", 2}, |
| {"EventLatency.InertialGestureScrollUpdate.GenerationToBrowserMain", 2}, |
| {"EventLatency.TotalLatency", 8}, |
| }; |
| for (const auto& expected_count : expected_counts) { |
| histogram_tester.ExpectTotalCount(expected_count.name, |
| expected_count.count); |
| } |
| |
| const base::TimeTicks presentation_time = |
| viz_breakdown.presentation_feedback.timestamp; |
| struct { |
| const char* name; |
| const base::HistogramBase::Sample latency_ms; |
| } expected_latencies[] = { |
| {"EventLatency.GestureScrollBegin.Wheel.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[0]).InMicroseconds())}, |
| {"EventLatency.GestureScrollBegin.Wheel.TotalLatency2", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[0]).InMicroseconds())}, |
| {"EventLatency.FirstGestureScrollUpdate.Wheel.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[1]).InMicroseconds())}, |
| {"EventLatency.FirstGestureScrollUpdate.Wheel.TotalLatency2", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[1]).InMicroseconds())}, |
| {"EventLatency.GestureScrollUpdate.Wheel.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[2]).InMicroseconds())}, |
| {"EventLatency.GestureScrollUpdate.Wheel.TotalLatency2", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[2]).InMicroseconds())}, |
| {"EventLatency.InertialGestureScrollUpdate.Wheel.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[3]).InMicroseconds())}, |
| {"EventLatency.InertialGestureScrollUpdate.Wheel.TotalLatency2", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[3]).InMicroseconds())}, |
| {"EventLatency.GestureScrollBegin.Touchscreen.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[4]).InMicroseconds())}, |
| {"EventLatency.GestureScrollBegin.Touchscreen.TotalLatency2", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[4]).InMicroseconds())}, |
| {"EventLatency.FirstGestureScrollUpdate.Touchscreen.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[5]).InMicroseconds())}, |
| {"EventLatency.FirstGestureScrollUpdate.Touchscreen.TotalLatency2", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[5]).InMicroseconds())}, |
| {"EventLatency.GestureScrollUpdate.Touchscreen.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[6]).InMicroseconds())}, |
| {"EventLatency.GestureScrollUpdate.Touchscreen.TotalLatency2", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[6]).InMicroseconds())}, |
| {"EventLatency.InertialGestureScrollUpdate.Touchscreen.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[7]).InMicroseconds())}, |
| {"EventLatency.InertialGestureScrollUpdate.Touchscreen.TotalLatency2", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[7]).InMicroseconds())}, |
| }; |
| for (const auto& expected_latency : expected_latencies) { |
| histogram_tester.ExpectBucketCount(expected_latency.name, |
| expected_latency.latency_ms, 1); |
| } |
| } |
| |
| // Tests that when a frame is presented to the user, total pinch event latency |
| // metrics are reported properly. |
| TEST_F(CompositorFrameReporterTest, |
| EventLatencyPinchTotalForPresentedFrameReported) { |
| base::HistogramTester histogram_tester; |
| |
| std::unique_ptr<EventMetrics> event_metrics_ptrs[] = { |
| CreatePinchEventMetrics(ui::ET_GESTURE_PINCH_BEGIN, |
| ui::ScrollInputType::kWheel), |
| CreatePinchEventMetrics(ui::ET_GESTURE_PINCH_UPDATE, |
| ui::ScrollInputType::kWheel), |
| CreatePinchEventMetrics(ui::ET_GESTURE_PINCH_BEGIN, |
| ui::ScrollInputType::kTouchscreen), |
| CreatePinchEventMetrics(ui::ET_GESTURE_PINCH_UPDATE, |
| ui::ScrollInputType::kTouchscreen), |
| }; |
| EXPECT_THAT(event_metrics_ptrs, Each(NotNull())); |
| EventMetrics::List events_metrics( |
| std::make_move_iterator(std::begin(event_metrics_ptrs)), |
| std::make_move_iterator(std::end(event_metrics_ptrs))); |
| std::vector<base::TimeTicks> event_times = GetEventTimestamps(events_metrics); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, |
| Now()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| pipeline_reporter_->AddEventsMetrics(std::move(events_metrics)); |
| |
| AdvanceNowByUs(3); |
| viz::FrameTimingDetails viz_breakdown = BuildVizBreakdown(); |
| pipeline_reporter_->SetVizBreakdown(viz_breakdown); |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, |
| viz_breakdown.presentation_feedback.timestamp); |
| |
| pipeline_reporter_ = nullptr; |
| |
| struct { |
| const char* name; |
| const base::HistogramBase::Count count; |
| } expected_counts[] = { |
| {"EventLatency.GesturePinchBegin.Touchscreen.TotalLatency", 1}, |
| {"EventLatency.GesturePinchUpdate.Touchscreen.TotalLatency", 1}, |
| {"EventLatency.GesturePinchBegin.Touchpad.TotalLatency", 1}, |
| {"EventLatency.GesturePinchUpdate.Touchpad.TotalLatency", 1}, |
| {"EventLatency.TotalLatency", 4}, |
| }; |
| for (const auto& expected_count : expected_counts) { |
| histogram_tester.ExpectTotalCount(expected_count.name, |
| expected_count.count); |
| } |
| |
| const base::TimeTicks presentation_time = |
| viz_breakdown.presentation_feedback.timestamp; |
| struct { |
| const char* name; |
| const base::HistogramBase::Sample latency_ms; |
| } expected_latencies[] = { |
| {"EventLatency.GesturePinchBegin.Touchpad.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[0]).InMicroseconds())}, |
| {"EventLatency.GesturePinchUpdate.Touchpad.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[1]).InMicroseconds())}, |
| {"EventLatency.GesturePinchBegin.Touchscreen.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[2]).InMicroseconds())}, |
| {"EventLatency.GesturePinchUpdate.Touchscreen.TotalLatency", |
| static_cast<base::HistogramBase::Sample>( |
| (presentation_time - event_times[3]).InMicroseconds())}, |
| }; |
| for (const auto& expected_latency : expected_latencies) { |
| histogram_tester.ExpectBucketCount(expected_latency.name, |
| expected_latency.latency_ms, 1); |
| } |
| } |
| |
| // Tests that when the frame is not presented to the user, event latency metrics |
| // are not reported. |
| TEST_F(CompositorFrameReporterTest, |
| EventLatencyForDidNotPresentFrameNotReported) { |
| base::HistogramTester histogram_tester; |
| |
| std::unique_ptr<EventMetrics> event_metrics_ptrs[] = { |
| CreateEventMetrics(ui::ET_TOUCH_PRESSED), |
| CreateEventMetrics(ui::ET_TOUCH_MOVED), |
| CreateEventMetrics(ui::ET_TOUCH_MOVED), |
| }; |
| EXPECT_THAT(event_metrics_ptrs, Each(NotNull())); |
| EventMetrics::List events_metrics( |
| std::make_move_iterator(std::begin(event_metrics_ptrs)), |
| std::make_move_iterator(std::end(event_metrics_ptrs))); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, |
| Now()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| pipeline_reporter_->AddEventsMetrics(std::move(events_metrics)); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kDidNotPresentFrame, |
| Now()); |
| |
| pipeline_reporter_ = nullptr; |
| |
| EXPECT_THAT(histogram_tester.GetTotalCountsForPrefix("EventLaterncy."), |
| IsEmpty()); |
| } |
| |
| // Verifies that partial update dependent queues are working as expected when |
| // they reach their maximum capacity. |
| TEST_F(CompositorFrameReporterTest, PartialUpdateDependentQueues) { |
| // This constant should match the constant with the same name in |
| // compositor_frame_reporter.cc. |
| const size_t kMaxOwnedPartialUpdateDependents = 300u; |
| |
| // The first three dependent reporters for the front of the queue. |
| std::unique_ptr<CompositorFrameReporter> deps[] = { |
| CreatePipelineReporter(), |
| CreatePipelineReporter(), |
| CreatePipelineReporter(), |
| }; |
| |
| // Set `deps[0]` as a dependent of the main reporter and adopt it at the same |
| // time. This should enqueue it in both non-owned and owned dependents queues. |
| deps[0]->SetPartialUpdateDecider(pipeline_reporter_.get()); |
| pipeline_reporter_->AdoptReporter(std::move(deps[0])); |
| DCHECK_EQ(1u, |
| pipeline_reporter_->partial_update_dependents_size_for_testing()); |
| DCHECK_EQ( |
| 1u, |
| pipeline_reporter_->owned_partial_update_dependents_size_for_testing()); |
| |
| // Set `deps[1]` as a dependent of the main reporter, but don't adopt it yet. |
| // This should enqueue it in non-owned dependents queue only. |
| deps[1]->SetPartialUpdateDecider(pipeline_reporter_.get()); |
| DCHECK_EQ(2u, |
| pipeline_reporter_->partial_update_dependents_size_for_testing()); |
| DCHECK_EQ( |
| 1u, |
| pipeline_reporter_->owned_partial_update_dependents_size_for_testing()); |
| |
| // Set `deps[2]` as a dependent of the main reporter and adopt it at the same |
| // time. This should enqueue it in both non-owned and owned dependents queues. |
| deps[2]->SetPartialUpdateDecider(pipeline_reporter_.get()); |
| pipeline_reporter_->AdoptReporter(std::move(deps[2])); |
| DCHECK_EQ(3u, |
| pipeline_reporter_->partial_update_dependents_size_for_testing()); |
| DCHECK_EQ( |
| 2u, |
| pipeline_reporter_->owned_partial_update_dependents_size_for_testing()); |
| |
| // Now adopt `deps[1]` to enqueue it in the owned dependents queue. |
| pipeline_reporter_->AdoptReporter(std::move(deps[1])); |
| DCHECK_EQ(3u, |
| pipeline_reporter_->partial_update_dependents_size_for_testing()); |
| DCHECK_EQ( |
| 3u, |
| pipeline_reporter_->owned_partial_update_dependents_size_for_testing()); |
| |
| // Fill the queues with more dependent reporters until the capacity is |
| // reached. After this, the queues should look like this (assuming n equals |
| // `kMaxOwnedPartialUpdateDependents`): |
| // Partial Update Dependents: [0, 1, 2, 3, 4, ..., n-1] |
| // Owned Partial Update Dependents: [0, 2, 1, 3, 4, ..., n-1] |
| while ( |
| pipeline_reporter_->owned_partial_update_dependents_size_for_testing() < |
| kMaxOwnedPartialUpdateDependents) { |
| std::unique_ptr<CompositorFrameReporter> dependent = |
| CreatePipelineReporter(); |
| dependent->SetPartialUpdateDecider(pipeline_reporter_.get()); |
| pipeline_reporter_->AdoptReporter(std::move(dependent)); |
| } |
| DCHECK_EQ(kMaxOwnedPartialUpdateDependents, |
| pipeline_reporter_->partial_update_dependents_size_for_testing()); |
| DCHECK_EQ( |
| kMaxOwnedPartialUpdateDependents, |
| pipeline_reporter_->owned_partial_update_dependents_size_for_testing()); |
| |
| // Enqueue a new dependent reporter. This should pop `deps[0]` from the front |
| // of the owned dependents queue and destroy it. Since the same one is in |
| // front of the non-owned dependents queue, it will be popped out of that |
| // queue, too. The queues will look like this: |
| // Partial Update Dependents: [1, 2, 3, 4, ..., n] |
| // Owned Partial Update Dependents: [2, 1, 3, 4, ..., n] |
| auto new_dep = CreatePipelineReporter(); |
| new_dep->SetPartialUpdateDecider(pipeline_reporter_.get()); |
| pipeline_reporter_->AdoptReporter(std::move(new_dep)); |
| DCHECK_EQ(kMaxOwnedPartialUpdateDependents, |
| pipeline_reporter_->partial_update_dependents_size_for_testing()); |
| DCHECK_EQ( |
| kMaxOwnedPartialUpdateDependents, |
| pipeline_reporter_->owned_partial_update_dependents_size_for_testing()); |
| |
| // Enqueue another new dependent reporter. This should pop `deps[2]` from the |
| // front of the owned dependents queue and destroy it. It should be removed |
| // from the non-owned dependents queue as well. |
| // Partial Update Dependents: [2, 3, 4, ..., n+1] |
| // Owned Partial Update Dependents: [2, 3, 4, ..., n+1] |
| new_dep = CreatePipelineReporter(); |
| new_dep->SetPartialUpdateDecider(pipeline_reporter_.get()); |
| pipeline_reporter_->AdoptReporter(std::move(new_dep)); |
| DCHECK_EQ(kMaxOwnedPartialUpdateDependents, |
| pipeline_reporter_->partial_update_dependents_size_for_testing()); |
| DCHECK_EQ( |
| kMaxOwnedPartialUpdateDependents, |
| pipeline_reporter_->owned_partial_update_dependents_size_for_testing()); |
| |
| // Enqueue yet another new dependent reporter. This should pop `deps[1]` from |
| // the front of the owned dependents queue and destroy it. Since the same one |
| // is in front of the non-owned dependents queue followed by `deps[2]` which |
| // was destroyed in the previous step, they will be popped out of that queue, |
| // too. The queues will look like this: |
| // Partial Update Dependents: [3, 4, ..., n+2] |
| // Owned Partial Update Dependents: [3, 4, ..., n+2] |
| new_dep = CreatePipelineReporter(); |
| new_dep->SetPartialUpdateDecider(pipeline_reporter_.get()); |
| pipeline_reporter_->AdoptReporter(std::move(new_dep)); |
| DCHECK_EQ(kMaxOwnedPartialUpdateDependents, |
| pipeline_reporter_->partial_update_dependents_size_for_testing()); |
| DCHECK_EQ( |
| kMaxOwnedPartialUpdateDependents, |
| pipeline_reporter_->owned_partial_update_dependents_size_for_testing()); |
| } |
| |
| TEST_F(CompositorFrameReporterTest, StageLatencyGeneralPrediction) { |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, |
| Now()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now()); |
| AdvanceNowByUs(4); |
| base::TimeTicks begin_main_frame_start_time = Now(); |
| std::unique_ptr<BeginMainFrameMetrics> blink_breakdown = |
| BuildBlinkBreakdown(); |
| pipeline_reporter_->SetBlinkBreakdown(std::move(blink_breakdown), |
| begin_main_frame_start_time); |
| |
| pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit, |
| Now()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndCommitToActivation, Now()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kActivation, Now()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(3); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| viz::FrameTimingDetails viz_breakdown = BuildVizBreakdown(); |
| pipeline_reporter_->SetVizBreakdown(viz_breakdown); |
| |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, |
| viz_breakdown.presentation_feedback.timestamp); |
| |
| // predictions when this is the very first prediction |
| CompositorFrameReporter::CompositorLatencyInfo expected_latency_predictions1; |
| expected_latency_predictions1.top_level_stages = { |
| base::Microseconds(3), base::Microseconds(55), base::Microseconds(3), |
| base::Microseconds(3), base::Microseconds(3), base::Microseconds(3), |
| base::Microseconds(15)}; |
| expected_latency_predictions1.blink_breakdown_stages = { |
| base::Microseconds(10), base::Microseconds(9), base::Microseconds(8), |
| base::Microseconds(7), base::Microseconds(0), base::Microseconds(5), |
| base::Microseconds(6), base::Microseconds(3), base::Microseconds(2), |
| base::Microseconds(1), base::Microseconds(4)}; |
| expected_latency_predictions1.viz_breakdown_stages = { |
| base::Microseconds(1), base::Microseconds(2), base::Microseconds(3), |
| base::Microseconds(4), base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), base::Microseconds(5)}; |
| expected_latency_predictions1.total_latency = base::Microseconds(85); |
| expected_latency_predictions1.total_blink_latency = base::Microseconds(55); |
| expected_latency_predictions1.total_viz_latency = base::Microseconds(15); |
| |
| // predictions when there exists a previous prediction |
| CompositorFrameReporter::CompositorLatencyInfo expected_latency_predictions2( |
| base::Microseconds(0)); |
| expected_latency_predictions2.top_level_stages = { |
| base::Microseconds(1), base::Microseconds(13), base::Microseconds(3), |
| base::Microseconds(0), base::Microseconds(2), base::Microseconds(3), |
| base::Microseconds(3)}; |
| expected_latency_predictions2.blink_breakdown_stages = { |
| base::Microseconds(10), base::Microseconds(9), base::Microseconds(8), |
| base::Microseconds(7), base::Microseconds(0), base::Microseconds(5), |
| base::Microseconds(6), base::Microseconds(3), base::Microseconds(2), |
| base::Microseconds(1), base::Microseconds(4)}; |
| expected_latency_predictions2.viz_breakdown_stages = { |
| base::Microseconds(1), base::Microseconds(2), base::Microseconds(3), |
| base::Microseconds(4), base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), base::Microseconds(5)}; |
| expected_latency_predictions2.total_latency = base::Microseconds(28); |
| expected_latency_predictions2.total_blink_latency = base::Microseconds(55); |
| expected_latency_predictions2.total_viz_latency = base::Microseconds(15); |
| |
| // expected attribution for all 3 cases above |
| std::vector<std::string> expected_latency_attributions = {}; |
| |
| CompositorFrameReporter::CompositorLatencyInfo actual_latency_predictions1( |
| base::Microseconds(-1)); |
| pipeline_reporter_->CalculateCompositorLatencyPrediction( |
| actual_latency_predictions1, kLatencyPredictionDeviationThreshold); |
| std::vector<std::string> actual_latency_attributions1 = |
| pipeline_reporter_->high_latency_substages_for_testing(); |
| pipeline_reporter_->ClearHighLatencySubstagesForTesting(); |
| |
| CompositorFrameReporter::CompositorLatencyInfo actual_latency_predictions2( |
| base::Microseconds(0)); |
| actual_latency_predictions2.top_level_stages = { |
| base::Microseconds(1), base::Microseconds(0), base::Microseconds(4), |
| base::Microseconds(0), base::Microseconds(2), base::Microseconds(3), |
| base::Microseconds(0)}; |
| actual_latency_predictions2.total_latency = base::Microseconds(10); |
| pipeline_reporter_->CalculateCompositorLatencyPrediction( |
| actual_latency_predictions2, kLatencyPredictionDeviationThreshold); |
| std::vector<std::string> actual_latency_attributions2 = |
| pipeline_reporter_->high_latency_substages_for_testing(); |
| pipeline_reporter_->ClearHighLatencySubstagesForTesting(); |
| |
| VerifyLatencyInfo(expected_latency_predictions1, actual_latency_predictions1); |
| VerifyLatencyInfo(expected_latency_predictions2, actual_latency_predictions2); |
| |
| EXPECT_EQ(expected_latency_attributions, actual_latency_attributions1); |
| EXPECT_EQ(expected_latency_attributions, actual_latency_attributions2); |
| |
| pipeline_reporter_ = nullptr; |
| } |
| |
| TEST_F(CompositorFrameReporterTest, StageLatencyAllZeroPrediction) { |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, |
| Now()); |
| |
| AdvanceNowByUs(0); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now()); |
| |
| AdvanceNowByUs(0); |
| pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit, |
| Now()); |
| |
| AdvanceNowByUs(0); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndCommitToActivation, Now()); |
| |
| AdvanceNowByUs(0); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kActivation, Now()); |
| |
| AdvanceNowByUs(0); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(0); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(0); |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kDidNotProduceFrame, |
| Now()); |
| |
| // predictions when this is the very first prediction |
| CompositorFrameReporter::CompositorLatencyInfo expected_latency_predictions1( |
| base::Microseconds(-1)); |
| |
| // predictions when there exists a previous prediction |
| CompositorFrameReporter::CompositorLatencyInfo expected_latency_predictions2( |
| base::Microseconds(0)); |
| expected_latency_predictions2.top_level_stages = { |
| base::Microseconds(1), base::Microseconds(0), base::Microseconds(4), |
| base::Microseconds(0), base::Microseconds(2), base::Microseconds(3), |
| base::Microseconds(0)}; |
| expected_latency_predictions2.total_latency = base::Microseconds(10); |
| |
| // expected attribution for all 3 cases above |
| std::vector<std::string> expected_latency_attributions = {}; |
| |
| CompositorFrameReporter::CompositorLatencyInfo actual_latency_predictions1( |
| base::Microseconds(-1)); |
| pipeline_reporter_->CalculateCompositorLatencyPrediction( |
| actual_latency_predictions1, kLatencyPredictionDeviationThreshold); |
| std::vector<std::string> actual_latency_attributions1 = |
| pipeline_reporter_->high_latency_substages_for_testing(); |
| pipeline_reporter_->ClearHighLatencySubstagesForTesting(); |
| |
| CompositorFrameReporter::CompositorLatencyInfo actual_latency_predictions2( |
| base::Microseconds(0)); |
| actual_latency_predictions2.top_level_stages = { |
| base::Microseconds(1), base::Microseconds(0), base::Microseconds(4), |
| base::Microseconds(0), base::Microseconds(2), base::Microseconds(3), |
| base::Microseconds(0)}; |
| actual_latency_predictions2.total_latency = base::Microseconds(10); |
| |
| pipeline_reporter_->CalculateCompositorLatencyPrediction( |
| actual_latency_predictions2, kLatencyPredictionDeviationThreshold); |
| std::vector<std::string> actual_latency_attributions2 = |
| pipeline_reporter_->high_latency_substages_for_testing(); |
| pipeline_reporter_->ClearHighLatencySubstagesForTesting(); |
| |
| VerifyLatencyInfo(expected_latency_predictions1, actual_latency_predictions1); |
| VerifyLatencyInfo(expected_latency_predictions2, actual_latency_predictions2); |
| |
| EXPECT_EQ(expected_latency_attributions, actual_latency_attributions1); |
| EXPECT_EQ(expected_latency_attributions, actual_latency_attributions2); |
| |
| pipeline_reporter_ = nullptr; |
| } |
| |
| TEST_F(CompositorFrameReporterTest, StageLatencyLargeDurationPrediction) { |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, |
| Now()); |
| |
| AdvanceNowByUs(10000000); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now()); |
| AdvanceNowByUs(400000); |
| base::TimeTicks begin_main_frame_start_time = Now(); |
| |
| auto blink_breakdown = std::make_unique<BeginMainFrameMetrics>(); |
| blink_breakdown->handle_input_events = base::Microseconds(1000000); |
| blink_breakdown->animate = base::Microseconds(900000); |
| blink_breakdown->style_update = base::Microseconds(800000); |
| blink_breakdown->layout_update = base::Microseconds(300000); |
| blink_breakdown->accessibility = base::Microseconds(400000); |
| blink_breakdown->prepaint = base::Microseconds(500000); |
| blink_breakdown->compositing_inputs = base::Microseconds(600000); |
| blink_breakdown->paint = base::Microseconds(300000); |
| blink_breakdown->composite_commit = base::Microseconds(200000); |
| blink_breakdown->update_layers = base::Microseconds(100000); |
| AdvanceNowByUs(5100000); |
| |
| pipeline_reporter_->SetBlinkBreakdown(std::move(blink_breakdown), |
| begin_main_frame_start_time); |
| |
| pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit, |
| Now()); |
| |
| AdvanceNowByUs(6000000); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndCommitToActivation, Now()); |
| |
| AdvanceNowByUs(10000000); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kActivation, Now()); |
| |
| AdvanceNowByUs(0); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(2000000); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| |
| viz::FrameTimingDetails viz_breakdown; |
| viz_breakdown.received_compositor_frame_timestamp = AdvanceNowByUs(1000000); |
| viz_breakdown.draw_start_timestamp = AdvanceNowByUs(2000000); |
| viz_breakdown.swap_timings.swap_start = AdvanceNowByUs(3000000); |
| viz_breakdown.presentation_feedback.available_timestamp = |
| AdvanceNowByUs(15000000); |
| viz_breakdown.presentation_feedback.ready_timestamp = AdvanceNowByUs(700000); |
| viz_breakdown.presentation_feedback.latch_timestamp = AdvanceNowByUs(800000); |
| viz_breakdown.swap_timings.swap_end = AdvanceNowByUs(1000000); |
| viz_breakdown.presentation_feedback.timestamp = AdvanceNowByUs(5000000); |
| |
| pipeline_reporter_->SetVizBreakdown(viz_breakdown); |
| |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now()); |
| |
| // predictions when this is the very first prediction |
| CompositorFrameReporter::CompositorLatencyInfo expected_latency_predictions1; |
| expected_latency_predictions1.top_level_stages = { |
| base::Microseconds(10000000), base::Microseconds(5500000), |
| base::Microseconds(6000000), base::Microseconds(10000000), |
| base::Microseconds(0), base::Microseconds(2000000), |
| base::Microseconds(28500000)}; |
| expected_latency_predictions1.blink_breakdown_stages = { |
| base::Microseconds(1000000), base::Microseconds(900000), |
| base::Microseconds(800000), base::Microseconds(300000), |
| base::Microseconds(400000), base::Microseconds(500000), |
| base::Microseconds(600000), base::Microseconds(300000), |
| base::Microseconds(200000), base::Microseconds(100000), |
| base::Microseconds(400000)}; |
| expected_latency_predictions1.viz_breakdown_stages = { |
| base::Microseconds(1000000), base::Microseconds(2000000), |
| base::Microseconds(3000000), base::Microseconds(0), |
| base::Microseconds(15000000), base::Microseconds(700000), |
| base::Microseconds(800000), base::Microseconds(1000000), |
| base::Microseconds(5000000)}; |
| expected_latency_predictions1.total_latency = base::Microseconds(62000000); |
| expected_latency_predictions1.total_blink_latency = |
| base::Microseconds(5500000); |
| expected_latency_predictions1.total_viz_latency = |
| base::Microseconds(28500000); |
| |
| // predictions when there exists a previous prediction |
| CompositorFrameReporter::CompositorLatencyInfo expected_latency_predictions2; |
| expected_latency_predictions2.top_level_stages = { |
| base::Microseconds(8500000), base::Microseconds(4375000), |
| base::Microseconds(4875000), base::Microseconds(5252650), |
| base::Microseconds(750000), base::Microseconds(1850000), |
| base::Microseconds(18375000)}; |
| expected_latency_predictions2.blink_breakdown_stages = { |
| base::Microseconds(1000000), base::Microseconds(225000), |
| base::Microseconds(500000), base::Microseconds(75000), |
| base::Microseconds(250000), base::Microseconds(350000), |
| base::Microseconds(150000), base::Microseconds(750000), |
| base::Microseconds(650000), base::Microseconds(250000), |
| base::Microseconds(175000)}; |
| expected_latency_predictions2.viz_breakdown_stages = { |
| base::Microseconds(625000), base::Microseconds(875000), |
| base::Microseconds(1500000), base::Microseconds(0), |
| base::Microseconds(9750000), base::Microseconds(925000), |
| base::Microseconds(1100000), base::Microseconds(1893925), |
| base::Microseconds(1706075)}; |
| expected_latency_predictions2.total_latency = base::Microseconds(43977650); |
| expected_latency_predictions2.total_blink_latency = |
| base::Microseconds(4375000); |
| expected_latency_predictions2.total_viz_latency = |
| base::Microseconds(18375000); |
| |
| // expected attribution for cases 1 above |
| std::vector<std::string> expected_latency_attributions1 = {}; |
| |
| // expected attribution for case 2 above |
| std::vector<std::string> expected_latency_attributions2 = { |
| "EndCommitToActivation", |
| "SubmitCompositorFrameToPresentationCompositorFrame." |
| "SwapEndToPresentationCompositorFrame"}; |
| |
| CompositorFrameReporter::CompositorLatencyInfo actual_latency_predictions1( |
| base::Microseconds(-1)); |
| pipeline_reporter_->CalculateCompositorLatencyPrediction( |
| actual_latency_predictions1, kLatencyPredictionDeviationThreshold); |
| std::vector<std::string> actual_latency_attributions1 = |
| pipeline_reporter_->high_latency_substages_for_testing(); |
| pipeline_reporter_->ClearHighLatencySubstagesForTesting(); |
| |
| CompositorFrameReporter::CompositorLatencyInfo actual_latency_predictions2; |
| actual_latency_predictions2.top_level_stages = { |
| base::Microseconds(8000000), base::Microseconds(4000000), |
| base::Microseconds(4500000), base::Microseconds(3670200), |
| base::Microseconds(1000000), base::Microseconds(1800000), |
| base::Microseconds(15000000)}; |
| actual_latency_predictions2.blink_breakdown_stages = { |
| base::Microseconds(1000000), base::Microseconds(0), |
| base::Microseconds(400000), base::Microseconds(0), |
| base::Microseconds(200000), base::Microseconds(300000), |
| base::Microseconds(0), base::Microseconds(900000), |
| base::Microseconds(800000), base::Microseconds(300000), |
| base::Microseconds(100000)}; |
| actual_latency_predictions2.viz_breakdown_stages = { |
| base::Microseconds(500000), base::Microseconds(500000), |
| base::Microseconds(1000000), base::Microseconds(0), |
| base::Microseconds(8000000), base::Microseconds(1000000), |
| base::Microseconds(1200000), base::Microseconds(2191900), |
| base::Microseconds(608100)}; |
| actual_latency_predictions2.total_latency = base::Microseconds(37970200); |
| actual_latency_predictions2.total_blink_latency = base::Microseconds(4000000); |
| actual_latency_predictions2.total_viz_latency = base::Microseconds(15000000); |
| |
| pipeline_reporter_->CalculateCompositorLatencyPrediction( |
| actual_latency_predictions2, kLatencyPredictionDeviationThreshold); |
| std::vector<std::string> actual_latency_attributions2 = |
| pipeline_reporter_->high_latency_substages_for_testing(); |
| pipeline_reporter_->ClearHighLatencySubstagesForTesting(); |
| |
| VerifyLatencyInfo(expected_latency_predictions1, actual_latency_predictions1); |
| VerifyLatencyInfo(expected_latency_predictions2, actual_latency_predictions2); |
| |
| EXPECT_EQ(expected_latency_attributions1, actual_latency_attributions1); |
| EXPECT_EQ(expected_latency_attributions2, actual_latency_attributions2); |
| |
| pipeline_reporter_ = nullptr; |
| } |
| |
| TEST_F(CompositorFrameReporterTest, StageLatencyMultiplePrediction) { |
| CompositorFrameReporter::CompositorLatencyInfo actual_latency_predictions( |
| base::Microseconds(-1)); |
| CompositorFrameReporter::CompositorLatencyInfo expected_latency_predictions( |
| base::Microseconds(-1)); |
| |
| // First compositor reporter (general) |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, |
| Now()); |
| |
| AdvanceNowByUs(16000); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(1500); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| |
| viz::FrameTimingDetails viz_breakdown; |
| viz_breakdown.received_compositor_frame_timestamp = AdvanceNowByUs(330000); |
| viz_breakdown.draw_start_timestamp = AdvanceNowByUs(23000); |
| viz_breakdown.swap_timings.swap_start = AdvanceNowByUs(170000); |
| viz_breakdown.swap_timings.swap_end = AdvanceNowByUs(280000); |
| viz_breakdown.presentation_feedback.timestamp = AdvanceNowByUs(30000); |
| |
| pipeline_reporter_->SetVizBreakdown(viz_breakdown); |
| |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now()); |
| |
| expected_latency_predictions.top_level_stages = { |
| base::Microseconds(16000), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(1500), |
| base::Microseconds(833000)}; |
| expected_latency_predictions.blink_breakdown_stages = { |
| base::Microseconds(0), base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0)}; |
| expected_latency_predictions.viz_breakdown_stages = { |
| base::Microseconds(330000), base::Microseconds(23000), |
| base::Microseconds(170000), base::Microseconds(280000), |
| base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(30000)}; |
| expected_latency_predictions.total_latency = base::Microseconds(850500); |
| expected_latency_predictions.total_blink_latency = base::Microseconds(0); |
| expected_latency_predictions.total_viz_latency = base::Microseconds(833000); |
| |
| pipeline_reporter_->CalculateCompositorLatencyPrediction( |
| actual_latency_predictions, kLatencyPredictionDeviationThreshold); |
| |
| VerifyLatencyInfo(expected_latency_predictions, actual_latency_predictions); |
| |
| // Second compositor reporter (without subtmit stage) |
| pipeline_reporter_ = CreatePipelineReporter(); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, |
| Now()); |
| |
| AdvanceNowByUs(16000); |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kDidNotProduceFrame, |
| Now()); |
| |
| expected_latency_predictions.top_level_stages = { |
| base::Microseconds(16000), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(1500), |
| base::Microseconds(833000)}; |
| expected_latency_predictions.blink_breakdown_stages = { |
| base::Microseconds(0), base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0)}; |
| expected_latency_predictions.viz_breakdown_stages = { |
| base::Microseconds(330000), base::Microseconds(23000), |
| base::Microseconds(170000), base::Microseconds(280000), |
| base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(30000)}; |
| expected_latency_predictions.total_latency = base::Microseconds(850500); |
| expected_latency_predictions.total_blink_latency = base::Microseconds(0); |
| expected_latency_predictions.total_viz_latency = base::Microseconds(833000); |
| |
| pipeline_reporter_->CalculateCompositorLatencyPrediction( |
| actual_latency_predictions, kLatencyPredictionDeviationThreshold); |
| |
| VerifyLatencyInfo(expected_latency_predictions, actual_latency_predictions); |
| |
| // Third compositor reporter (prediction and actual latency does not differ |
| // by 8) |
| pipeline_reporter_ = CreatePipelineReporter(); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, |
| Now()); |
| |
| AdvanceNowByUs(16500); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(2000); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| |
| viz_breakdown.received_compositor_frame_timestamp = AdvanceNowByUs(330000); |
| viz_breakdown.draw_start_timestamp = AdvanceNowByUs(23000); |
| viz_breakdown.swap_timings.swap_start = AdvanceNowByUs(170000); |
| viz_breakdown.swap_timings.swap_end = AdvanceNowByUs(280000); |
| viz_breakdown.presentation_feedback.timestamp = AdvanceNowByUs(30000); |
| |
| pipeline_reporter_->SetVizBreakdown(viz_breakdown); |
| |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now()); |
| |
| expected_latency_predictions.top_level_stages = { |
| base::Microseconds(16125), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(1625), |
| base::Microseconds(833000)}; |
| expected_latency_predictions.blink_breakdown_stages = { |
| base::Microseconds(0), base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0)}; |
| expected_latency_predictions.viz_breakdown_stages = { |
| base::Microseconds(330000), base::Microseconds(23000), |
| base::Microseconds(170000), base::Microseconds(280000), |
| base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(30000)}; |
| expected_latency_predictions.total_latency = base::Microseconds(850750); |
| expected_latency_predictions.total_blink_latency = base::Microseconds(0); |
| expected_latency_predictions.total_viz_latency = base::Microseconds(833000); |
| |
| pipeline_reporter_->CalculateCompositorLatencyPrediction( |
| actual_latency_predictions, kLatencyPredictionDeviationThreshold); |
| |
| VerifyLatencyInfo(expected_latency_predictions, actual_latency_predictions); |
| |
| // Fourth compositor reporter (total duration is 0) |
| pipeline_reporter_ = CreatePipelineReporter(); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, |
| Now()); |
| |
| AdvanceNowByUs(0); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now()); |
| |
| AdvanceNowByUs(0); |
| pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit, |
| Now()); |
| |
| AdvanceNowByUs(0); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndCommitToActivation, Now()); |
| |
| AdvanceNowByUs(0); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(0); |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kDidNotProduceFrame, |
| Now()); |
| |
| expected_latency_predictions.top_level_stages = { |
| base::Microseconds(16125), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(1625), |
| base::Microseconds(833000)}; |
| expected_latency_predictions.blink_breakdown_stages = { |
| base::Microseconds(0), base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0)}; |
| expected_latency_predictions.viz_breakdown_stages = { |
| base::Microseconds(330000), base::Microseconds(23000), |
| base::Microseconds(170000), base::Microseconds(280000), |
| base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(30000)}; |
| expected_latency_predictions.total_latency = base::Microseconds(850750); |
| expected_latency_predictions.total_blink_latency = base::Microseconds(0); |
| expected_latency_predictions.total_viz_latency = base::Microseconds(833000); |
| |
| pipeline_reporter_->CalculateCompositorLatencyPrediction( |
| actual_latency_predictions, kLatencyPredictionDeviationThreshold); |
| |
| VerifyLatencyInfo(expected_latency_predictions, actual_latency_predictions); |
| |
| // Fifth compositor reporter (prediction and actual latency differ by a lot) |
| pipeline_reporter_ = CreatePipelineReporter(); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, |
| Now()); |
| |
| AdvanceNowByUs(16000); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kSendBeginMainFrameToCommit, Now()); |
| |
| AdvanceNowByUs(4000); |
| base::TimeTicks begin_main_frame_start_time = Now(); |
| |
| auto blink_breakdown = std::make_unique<BeginMainFrameMetrics>(); |
| blink_breakdown->handle_input_events = base::Microseconds(12000); |
| blink_breakdown->animate = base::Microseconds(3000); |
| blink_breakdown->style_update = base::Microseconds(7000); |
| blink_breakdown->layout_update = base::Microseconds(19000); |
| blink_breakdown->accessibility = base::Microseconds(800); |
| blink_breakdown->prepaint = base::Microseconds(4100); |
| blink_breakdown->compositing_inputs = base::Microseconds(5100); |
| blink_breakdown->paint = base::Microseconds(1500); |
| blink_breakdown->composite_commit = base::Microseconds(1500); |
| blink_breakdown->update_layers = base::Microseconds(2000); |
| AdvanceNowByUs(56000); |
| |
| pipeline_reporter_->SetBlinkBreakdown(std::move(blink_breakdown), |
| begin_main_frame_start_time); |
| |
| pipeline_reporter_->StartStage(CompositorFrameReporter::StageType::kCommit, |
| Now()); |
| |
| AdvanceNowByUs(6000); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndCommitToActivation, Now()); |
| |
| AdvanceNowByUs(3000); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kActivation, Now()); |
| |
| AdvanceNowByUs(300); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(39000); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| |
| viz_breakdown.received_compositor_frame_timestamp = AdvanceNowByUs(340000); |
| viz_breakdown.draw_start_timestamp = AdvanceNowByUs(20000); |
| viz_breakdown.swap_timings.swap_start = AdvanceNowByUs(160000); |
| viz_breakdown.swap_timings.swap_end = AdvanceNowByUs(283000); |
| viz_breakdown.presentation_feedback.timestamp = AdvanceNowByUs(30000); |
| |
| pipeline_reporter_->SetVizBreakdown(viz_breakdown); |
| |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now()); |
| |
| expected_latency_predictions.top_level_stages = { |
| base::Microseconds(16093), base::Microseconds(15000), |
| base::Microseconds(1500), base::Microseconds(750), |
| base::Microseconds(75), base::Microseconds(10968), |
| base::Microseconds(833000)}; |
| expected_latency_predictions.blink_breakdown_stages = { |
| base::Microseconds(12000), base::Microseconds(3000), |
| base::Microseconds(7000), base::Microseconds(19000), |
| base::Microseconds(800), base::Microseconds(4100), |
| base::Microseconds(5100), base::Microseconds(1500), |
| base::Microseconds(1500), base::Microseconds(2000), |
| base::Microseconds(4000)}; |
| expected_latency_predictions.viz_breakdown_stages = { |
| base::Microseconds(332500), base::Microseconds(22250), |
| base::Microseconds(167500), base::Microseconds(280750), |
| base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(0), base::Microseconds(0), |
| base::Microseconds(30000)}; |
| expected_latency_predictions.total_latency = base::Microseconds(877387); |
| expected_latency_predictions.total_blink_latency = base::Microseconds(60000); |
| expected_latency_predictions.total_viz_latency = base::Microseconds(833000); |
| |
| std::vector<std::string> expected_latency_attributions = { |
| "EndActivateToSubmitCompositorFrame"}; |
| |
| pipeline_reporter_->CalculateCompositorLatencyPrediction( |
| actual_latency_predictions, kLatencyPredictionDeviationThreshold); |
| std::vector<std::string> actual_latency_attributions = |
| pipeline_reporter_->high_latency_substages_for_testing(); |
| |
| VerifyLatencyInfo(expected_latency_predictions, actual_latency_predictions); |
| EXPECT_EQ(expected_latency_attributions, actual_latency_attributions); |
| |
| pipeline_reporter_ = nullptr; |
| } |
| |
| // Tests that when a frame is presented to the user, event latency predictions |
| // are reported properly. |
| TEST_F(CompositorFrameReporterTest, EventLatencyDispatchPredictions) { |
| base::HistogramTester histogram_tester; |
| std::vector<int> dispatch_times = { |
| /*[kGenerated, kArrivedInBrowserMain]=*/300, |
| /*[kArrivedInBrowserMain, kArrivedInRendererCompositor]=*/300, |
| /*[kArrivedInRendererCompositor, kRendererCompositorStarted]=*/300, |
| /*[kRendererCompositorStarted, kRendererCompositorFinished]=*/300, |
| /*[kRendererCompositorFinished, kRendererMainStarted]=*/300, |
| /*[kRendererMainStarted, kRendererMainFinished]=*/300}; |
| std::unique_ptr<EventMetrics> event_metrics_ptrs[] = { |
| CreateScrollUpdateEventMetricsWithDispatchTimes( |
| false, ScrollUpdateEventMetrics::ScrollUpdateType::kContinued, |
| dispatch_times)}; |
| EXPECT_THAT(event_metrics_ptrs, Each(NotNull())); |
| EventMetrics::List events_metrics = { |
| std::make_move_iterator(std::begin(event_metrics_ptrs)), |
| std::make_move_iterator(std::end(event_metrics_ptrs))}; |
| |
| AdvanceNowByUs(300); // Transition time |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(300); // kEndActivateToSubmitCompositorFrame stage duration |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| |
| pipeline_reporter_->AddEventsMetrics(std::move(events_metrics)); |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now()); |
| |
| // Test with no previous stage predictions. |
| std::vector<base::TimeDelta> expected_predictions1(kNumDispatchStages, |
| base::Microseconds(-1)); |
| IntToTimeDeltaVector( |
| expected_predictions1, |
| std::vector<int>{/*kScrollsBlockingTouchDispatchedToRenderer=*/-1, |
| /*kArrivedInBrowserMain=*/300, |
| /*kArrivedInRendererCompositor=*/300, |
| /*kRendererCompositorStarted=*/300, |
| /*kRendererCompositorFinished=*/300, |
| /*kRendererMainStarted=*/300, |
| /*kRendererMainFinished=*/300}); |
| base::TimeDelta expected_transition1 = base::Microseconds(300); |
| base::TimeDelta expected_total1 = base::Microseconds(2400); |
| CompositorFrameReporter::EventLatencyInfo actual_predictions1 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| pipeline_reporter_->CalculateEventLatencyPrediction( |
| actual_predictions1, kLatencyPredictionDeviationThreshold); |
| |
| // Test with all previous stage predictions. |
| std::vector<base::TimeDelta> expected_predictions2(kNumDispatchStages, |
| base::Microseconds(-1)); |
| IntToTimeDeltaVector(expected_predictions2, |
| std::vector<int>{300, 262, 262, 300, 412, 225, 450}); |
| base::TimeDelta expected_transition2 = base::Microseconds(390); |
| base::TimeDelta expected_total2 = base::Microseconds(2901); |
| CompositorFrameReporter::EventLatencyInfo actual_predictions2 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| IntToTimeDeltaVector(actual_predictions2.dispatch_durations, |
| std::vector<int>{300, 250, 250, 300, 450, 200, 500}); |
| actual_predictions2.transition_duration = base::Microseconds(420); |
| pipeline_reporter_->CalculateEventLatencyPrediction( |
| actual_predictions2, kLatencyPredictionDeviationThreshold); |
| |
| // Test with some previous stage predictions. |
| std::vector<base::TimeDelta> expected_predictions3(kNumDispatchStages, |
| base::Microseconds(-1)); |
| IntToTimeDeltaVector(expected_predictions3, |
| std::vector<int>{300, 300, 375, 450, 300, 300, 300}); |
| base::TimeDelta expected_transition3 = base::Microseconds(270); |
| base::TimeDelta expected_total3 = base::Microseconds(2895); |
| CompositorFrameReporter::EventLatencyInfo actual_predictions3 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| IntToTimeDeltaVector(actual_predictions3.dispatch_durations, |
| std::vector<int>{300, -1, 400, 500, 300, -1, -1}); |
| actual_predictions3.transition_duration = base::Microseconds(260); |
| pipeline_reporter_->CalculateEventLatencyPrediction( |
| actual_predictions3, kLatencyPredictionDeviationThreshold); |
| |
| for (int i = 0; i < kNumDispatchStages; i++) { |
| EXPECT_EQ(expected_predictions1[i], |
| actual_predictions1.dispatch_durations[i]); |
| EXPECT_EQ(expected_predictions2[i], |
| actual_predictions2.dispatch_durations[i]); |
| EXPECT_EQ(expected_predictions3[i], |
| actual_predictions3.dispatch_durations[i]); |
| } |
| EXPECT_EQ(expected_transition1, actual_predictions1.transition_duration); |
| EXPECT_EQ(expected_total1, actual_predictions1.total_duration); |
| EXPECT_EQ(expected_transition2, actual_predictions2.transition_duration); |
| EXPECT_EQ(expected_total2, actual_predictions2.total_duration); |
| EXPECT_EQ(expected_transition3, actual_predictions3.transition_duration); |
| EXPECT_EQ(expected_total3, actual_predictions3.total_duration); |
| |
| pipeline_reporter_ = nullptr; |
| histogram_tester.ExpectTotalCount( |
| "EventLatency.GestureScrollUpdate.GenerationToBrowserMain", 1); |
| } |
| |
| // Tests that when a new frame with missing dispatch stages is presented to |
| // the user, event latency predictions are reported properly. |
| TEST_F(CompositorFrameReporterTest, |
| EventLatencyDispatchPredictionsWithMissingStages) { |
| base::HistogramTester histogram_tester; |
| // Invalid EventLatency stage durations will cause program to crash, validity |
| // checked in event_latency_tracing_recorder.cc. |
| std::vector<int> dispatch_times = { |
| /*[kGenerated, kArrivedInBrowserMain]=*/200, |
| /*[kArrivedInBrowserMain, kArrivedInRendererCompositor]=*/400, |
| /*[kArrivedInRendererCompositor, kRendererCompositorStarted]=*/600, |
| /*[kRendererCompositorStarted, kRendererCompositorFinished]=*/700, |
| /*[kRendererCompositorFinished, kRendererMainStarted]=*/-1, |
| /*[kRendererMainStarted, kRendererMainFinished]=*/-1}; |
| std::unique_ptr<EventMetrics> event_metrics_ptrs[] = { |
| CreateScrollUpdateEventMetricsWithDispatchTimes( |
| false, ScrollUpdateEventMetrics::ScrollUpdateType::kContinued, |
| dispatch_times)}; |
| EXPECT_THAT(event_metrics_ptrs, Each(NotNull())); |
| EventMetrics::List events_metrics = { |
| std::make_move_iterator(std::begin(event_metrics_ptrs)), |
| std::make_move_iterator(std::end(event_metrics_ptrs))}; |
| |
| AdvanceNowByUs(470); // Transition time |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(300); // kEndActivateToSubmitCompositorFrame stage duration |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| |
| pipeline_reporter_->AddEventsMetrics(std::move(events_metrics)); |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now()); |
| |
| // Test with no previous stage predictions. |
| std::vector<base::TimeDelta> expected_predictions1(kNumDispatchStages, |
| base::Microseconds(-1)); |
| IntToTimeDeltaVector(expected_predictions1, |
| std::vector<int>{-1, 200, 400, 600, 700, -1, -1}); |
| base::TimeDelta expected_transition1 = base::Microseconds(470); |
| base::TimeDelta expected_total1 = base::Microseconds(2670); |
| CompositorFrameReporter::EventLatencyInfo actual_predictions1 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| pipeline_reporter_->CalculateEventLatencyPrediction( |
| actual_predictions1, kLatencyPredictionDeviationThreshold); |
| |
| // Test with all previous stage predictions. |
| std::vector<base::TimeDelta> expected_predictions2(kNumDispatchStages, |
| base::Microseconds(-1)); |
| IntToTimeDeltaVector(expected_predictions2, |
| std::vector<int>{100, 125, 250, 375, 475, 200, 500}); |
| base::TimeDelta expected_transition2 = base::Microseconds(402); |
| base::TimeDelta expected_total2 = base::Microseconds(2727); |
| CompositorFrameReporter::EventLatencyInfo actual_predictions2 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| IntToTimeDeltaVector(actual_predictions2.dispatch_durations, |
| std::vector<int>{100, 100, 200, 300, 400, 200, 500}); |
| actual_predictions2.transition_duration = base::Microseconds(380); |
| pipeline_reporter_->CalculateEventLatencyPrediction( |
| actual_predictions2, kLatencyPredictionDeviationThreshold); |
| |
| // Test with some previous stage predictions. |
| std::vector<base::TimeDelta> expected_predictions3(kNumDispatchStages, |
| base::Microseconds(-1)); |
| IntToTimeDeltaVector(expected_predictions3, |
| std::vector<int>{125, 143, 400, 525, 745, -1, -1}); |
| base::TimeDelta expected_transition3 = base::Microseconds(492); |
| base::TimeDelta expected_total3 = base::Microseconds(2730); |
| CompositorFrameReporter::EventLatencyInfo actual_predictions3 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| IntToTimeDeltaVector(actual_predictions3.dispatch_durations, |
| std::vector<int>{125, 125, 400, 500, 760, -1, -1}); |
| actual_predictions3.transition_duration = base::Microseconds(500); |
| pipeline_reporter_->CalculateEventLatencyPrediction( |
| actual_predictions3, kLatencyPredictionDeviationThreshold); |
| |
| for (int i = 0; i < kNumDispatchStages; i++) { |
| EXPECT_EQ(expected_predictions1[i], |
| actual_predictions1.dispatch_durations[i]); |
| EXPECT_EQ(expected_predictions2[i], |
| actual_predictions2.dispatch_durations[i]); |
| EXPECT_EQ(expected_predictions3[i], |
| actual_predictions3.dispatch_durations[i]); |
| } |
| EXPECT_EQ(expected_transition1, actual_predictions1.transition_duration); |
| EXPECT_EQ(expected_total1, actual_predictions1.total_duration); |
| EXPECT_EQ(expected_transition2, actual_predictions2.transition_duration); |
| EXPECT_EQ(expected_total2, actual_predictions2.total_duration); |
| EXPECT_EQ(expected_transition3, actual_predictions3.transition_duration); |
| EXPECT_EQ(expected_total3, actual_predictions3.total_duration); |
| |
| pipeline_reporter_ = nullptr; |
| histogram_tester.ExpectTotalCount( |
| "EventLatency.GestureScrollUpdate.GenerationToBrowserMain", 1); |
| } |
| |
| // Tests that when a frame is presented to the user, event latency predictions |
| // are reported properly. |
| TEST_F(CompositorFrameReporterTest, EventLatencyCompositorPredictions) { |
| base::HistogramTester histogram_tester; |
| std::vector<int> dispatch_times = { |
| /*[kGenerated, kArrivedInBrowserMain]=*/300, |
| /*[kArrivedInBrowserMain, kArrivedInRendererCompositor]=*/300, |
| /*[kArrivedInRendererCompositor, kRendererCompositorStarted]=*/300, |
| /*[kRendererCompositorStarted, kRendererCompositorFinished]=*/300, |
| /*[kRendererCompositorFinished, kRendererMainStarted]=*/300, |
| /*[kRendererMainStarted, kRendererMainFinished]=*/300}; |
| |
| std::unique_ptr<EventMetrics> event_metrics_ptrs[] = { |
| CreateScrollUpdateEventMetricsWithDispatchTimes( |
| false, ScrollUpdateEventMetrics::ScrollUpdateType::kContinued, |
| dispatch_times)}; |
| EXPECT_THAT(event_metrics_ptrs, Each(NotNull())); |
| EventMetrics::List events_metrics = { |
| std::make_move_iterator(std::begin(event_metrics_ptrs)), |
| std::make_move_iterator(std::end(event_metrics_ptrs))}; |
| |
| AdvanceNowByUs(300); // Transition time |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, |
| Now()); |
| |
| // For this test there are only 3 compositor substages updated which reflects |
| // a more realistic scenario. |
| |
| AdvanceNowByUs(300); // kBeginImplFrameToSendBeginMainFrame duration |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(300); // kEndActivateToSubmitCompositorFrame duration |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| |
| // kSubmitCompositorFrameToPresentationCompositorFrame duration |
| AdvanceNowByUs(300); |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now()); |
| |
| pipeline_reporter_->AddEventsMetrics(std::move(events_metrics)); |
| |
| // Test with no previous stage predictions. |
| std::vector<base::TimeDelta> expected_dispatch1(kNumDispatchStages, |
| base::Microseconds(-1)); |
| IntToTimeDeltaVector( |
| expected_dispatch1, |
| std::vector<int>{/*kScrollsBlockingTouchDispatchedToRenderer=*/-1, |
| /*kArrivedInBrowserMain=*/300, |
| /*kArrivedInRendererCompositor=*/300, |
| /*kRendererCompositorStarted=*/300, |
| /*kRendererCompositorFinished=*/300, |
| /*kRendererMainStarted=*/300, |
| /*kRendererMainFinished=*/300}); |
| base::TimeDelta expected_transition1 = base::Microseconds(300); |
| std::vector<base::TimeDelta> expected_compositor1(kNumOfCompositorStages, |
| base::Microseconds(-1)); |
| IntToTimeDeltaVector(expected_compositor1, |
| std::vector<int>{300, -1, -1, -1, -1, 300, 300}); |
| base::TimeDelta expected_total1 = base::Microseconds(3000); |
| CompositorFrameReporter::EventLatencyInfo actual_predictions1 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| pipeline_reporter_->CalculateEventLatencyPrediction( |
| actual_predictions1, kLatencyPredictionDeviationThreshold); |
| |
| // Test with all previous stage predictions. |
| std::vector<base::TimeDelta> expected_dispatch2(kNumDispatchStages, |
| base::Microseconds(-1)); |
| IntToTimeDeltaVector(expected_dispatch2, |
| std::vector<int>{250, 262, 262, 300, 412, 225, 450}); |
| base::TimeDelta expected_transition2 = base::Microseconds(390); |
| std::vector<base::TimeDelta> expected_compositor2(kNumOfCompositorStages, |
| base::Microseconds(-1)); |
| IntToTimeDeltaVector(expected_compositor2, |
| std::vector<int>{465, 500, 90, 720, 410, 742, 390}); |
| base::TimeDelta expected_total2 = base::Microseconds(5868); |
| CompositorFrameReporter::EventLatencyInfo actual_predictions2 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| IntToTimeDeltaVector(actual_predictions2.dispatch_durations, |
| std::vector<int>{250, 250, 250, 300, 450, 200, 500}); |
| actual_predictions2.transition_duration = base::Microseconds(420); |
| IntToTimeDeltaVector(actual_predictions2.compositor_durations, |
| std::vector<int>{520, 500, 90, 720, 410, 890, 420}); |
| pipeline_reporter_->CalculateEventLatencyPrediction( |
| actual_predictions2, kLatencyPredictionDeviationThreshold); |
| |
| // Test with some previous stage predictions. |
| std::vector<base::TimeDelta> expected_dispatch3(kNumDispatchStages, |
| base::Microseconds(-1)); |
| IntToTimeDeltaVector(expected_dispatch3, |
| std::vector<int>{400, 375, 375, 450, 300, 300, 300}); |
| base::TimeDelta expected_transition3 = base::Microseconds(270); |
| std::vector<base::TimeDelta> expected_compositor3(kNumOfCompositorStages, |
| base::Microseconds(-1)); |
| IntToTimeDeltaVector(expected_compositor3, |
| std::vector<int>{300, 500, -1, -1, 410, 742, 390}); |
| base::TimeDelta expected_total3 = base::Microseconds(5112); |
| CompositorFrameReporter::EventLatencyInfo actual_predictions3 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| IntToTimeDeltaVector(actual_predictions3.dispatch_durations, |
| std::vector<int>{400, 400, 400, 500, 300, -1, -1}); |
| actual_predictions3.transition_duration = base::Microseconds(260); |
| IntToTimeDeltaVector(actual_predictions3.compositor_durations, |
| std::vector<int>{-1, 500, -1, -1, 410, 890, 420}); |
| pipeline_reporter_->CalculateEventLatencyPrediction( |
| actual_predictions3, kLatencyPredictionDeviationThreshold); |
| |
| for (int i = 0; i < kNumDispatchStages; i++) { |
| EXPECT_EQ(expected_dispatch1[i], actual_predictions1.dispatch_durations[i]); |
| EXPECT_EQ(expected_dispatch2[i], actual_predictions2.dispatch_durations[i]); |
| EXPECT_EQ(expected_dispatch3[i], actual_predictions3.dispatch_durations[i]); |
| } |
| for (int i = 0; i < kNumOfCompositorStages; i++) { |
| EXPECT_EQ(expected_compositor1[i], |
| actual_predictions1.compositor_durations[i]); |
| EXPECT_EQ(expected_compositor2[i], |
| actual_predictions2.compositor_durations[i]); |
| EXPECT_EQ(expected_compositor3[i], |
| actual_predictions3.compositor_durations[i]); |
| } |
| EXPECT_EQ(expected_transition1, actual_predictions1.transition_duration); |
| EXPECT_EQ(expected_total1, actual_predictions1.total_duration); |
| EXPECT_EQ(expected_transition2, actual_predictions2.transition_duration); |
| EXPECT_EQ(expected_total2, actual_predictions2.total_duration); |
| EXPECT_EQ(expected_transition3, actual_predictions3.transition_duration); |
| EXPECT_EQ(expected_total3, actual_predictions3.total_duration); |
| |
| pipeline_reporter_ = nullptr; |
| histogram_tester.ExpectTotalCount( |
| "EventLatency.GestureScrollUpdate.GenerationToBrowserMain", 1); |
| } |
| |
| // Tests that when a frame is presented to the user, event latency predictions |
| // are reported properly for filtered EventTypes. |
| TEST_F(CompositorFrameReporterTest, EventLatencyMultipleEventTypePredictions) { |
| base::HistogramTester histogram_tester; |
| std::vector<int> dispatch_times = { |
| /*[kGenerated, kArrivedInBrowserMain]=*/300, |
| /*[kArrivedInBrowserMain, kArrivedInRendererCompositor]=*/300, |
| /*[kArrivedInRendererCompositor, kRendererCompositorStarted]=*/300, |
| /*[kRendererCompositorStarted, kRendererCompositorFinished]=*/300, |
| /*[kRendererCompositorFinished, kRendererMainStarted]=*/300, |
| /*[kRendererMainStarted, kRendererMainFinished]=*/300}; |
| // The prediction should only be updated with the ScrollUpdateType event, |
| // other EventType metrics should be ignored. |
| std::unique_ptr<EventMetrics> event_metrics_ptrs[] = { |
| CreateEventMetrics(ui::ET_TOUCH_PRESSED), |
| CreateEventMetrics(ui::ET_TOUCH_MOVED), |
| CreateScrollUpdateEventMetricsWithDispatchTimes( |
| false, ScrollUpdateEventMetrics::ScrollUpdateType::kContinued, |
| dispatch_times), |
| CreateEventMetrics(ui::ET_TOUCH_MOVED)}; |
| // The last ET_TOUCH_MOVED event above adds 12 us to transition time. |
| const base::TimeDelta kTouchEventTransition = base::Microseconds(12); |
| EXPECT_THAT(event_metrics_ptrs, Each(NotNull())); |
| EventMetrics::List events_metrics = { |
| std::make_move_iterator(std::begin(event_metrics_ptrs)), |
| std::make_move_iterator(std::end(event_metrics_ptrs))}; |
| |
| AdvanceNowByUs(300); |
| // Total transition time is 312 us because of the extra 3 us from the |
| // ET_TOUCH_MOVED event. |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, |
| Now()); |
| |
| // For this test there are only 3 compositor substages updated which reflects |
| // a more realistic scenario. |
| |
| AdvanceNowByUs(300); // kBeginImplFrameToSendBeginMainFrame duration |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(300); // kEndActivateToSubmitCompositorFrame duration |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| |
| // kSubmitCompositorFrameToPresentationCompositorFrame duration |
| AdvanceNowByUs(300); |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now()); |
| |
| pipeline_reporter_->AddEventsMetrics(std::move(events_metrics)); |
| |
| // Test with no previous stage predictions. |
| std::vector<base::TimeDelta> expected_dispatch1(kNumDispatchStages, |
| base::Microseconds(-1)); |
| IntToTimeDeltaVector( |
| expected_dispatch1, |
| std::vector<int>{/*kScrollsBlockingTouchDispatchedToRenderer=*/-1, |
| /*kArrivedInBrowserMain=*/300, |
| /*kArrivedInRendererCompositor=*/300, |
| /*kRendererCompositorStarted=*/300, |
| /*kRendererCompositorFinished=*/300, |
| /*kRendererMainStarted=*/300, |
| /*kRenderePrMainFinished=*/300}); |
| base::TimeDelta expected_transition1 = |
| base::Microseconds(302) + kTouchEventTransition; |
| std::vector<base::TimeDelta> expected_compositor1(kNumOfCompositorStages, |
| base::Microseconds(-1)); |
| IntToTimeDeltaVector(expected_compositor1, |
| std::vector<int>{300, -1, -1, -1, -1, 300, 300}); |
| base::TimeDelta expected_total1 = |
| base::Microseconds(3002) + kTouchEventTransition; |
| CompositorFrameReporter::EventLatencyInfo actual_predictions1 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| pipeline_reporter_->CalculateEventLatencyPrediction( |
| actual_predictions1, kLatencyPredictionDeviationThreshold); |
| |
| // Test with all previous stage predictions. |
| std::vector<base::TimeDelta> expected_dispatch2(kNumDispatchStages, |
| base::Microseconds(-1)); |
| IntToTimeDeltaVector(expected_dispatch2, |
| std::vector<int>{250, 262, 262, 300, 412, 225, 450}); |
| base::TimeDelta expected_transition2 = base::Microseconds(393); |
| std::vector<base::TimeDelta> expected_compositor2(kNumOfCompositorStages, |
| base::Microseconds(-1)); |
| IntToTimeDeltaVector(expected_compositor2, |
| std::vector<int>{465, 500, 90, 720, 410, 742, 390}); |
| base::TimeDelta expected_total2 = base::Microseconds(5871); |
| CompositorFrameReporter::EventLatencyInfo actual_predictions2 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| IntToTimeDeltaVector(actual_predictions2.dispatch_durations, |
| std::vector<int>{250, 250, 250, 300, 450, 200, 500}); |
| actual_predictions2.transition_duration = base::Microseconds(420); |
| IntToTimeDeltaVector(actual_predictions2.compositor_durations, |
| std::vector<int>{520, 500, 90, 720, 410, 890, 420}); |
| pipeline_reporter_->CalculateEventLatencyPrediction( |
| actual_predictions2, kLatencyPredictionDeviationThreshold); |
| |
| for (int i = 0; i < kNumDispatchStages; i++) { |
| EXPECT_EQ(expected_dispatch1[i], actual_predictions1.dispatch_durations[i]); |
| EXPECT_EQ(expected_dispatch2[i], actual_predictions2.dispatch_durations[i]); |
| } |
| for (int i = 0; i < kNumOfCompositorStages; i++) { |
| EXPECT_EQ(expected_compositor1[i], |
| actual_predictions1.compositor_durations[i]); |
| EXPECT_EQ(expected_compositor2[i], |
| actual_predictions2.compositor_durations[i]); |
| } |
| EXPECT_EQ(expected_transition1, actual_predictions1.transition_duration); |
| EXPECT_EQ(expected_total1, actual_predictions1.total_duration); |
| EXPECT_EQ(expected_transition2, actual_predictions2.transition_duration); |
| EXPECT_EQ(expected_total2, actual_predictions2.total_duration); |
| |
| pipeline_reporter_ = nullptr; |
| histogram_tester.ExpectTotalCount( |
| "EventLatency.GestureScrollUpdate.GenerationToBrowserMain", 1); |
| } |
| |
| // Tests that when a frame is presented to the user, high latency attribution |
| // for EventLatency is reported properly for filtered EventTypes. |
| TEST_F(CompositorFrameReporterTest, EventLatencyAttributionPredictions) { |
| base::HistogramTester histogram_tester; |
| std::vector<int> dispatch_times = { |
| /*[kGenerated, kArrivedInBrowserMain]=*/300, |
| /*[kArrivedInBrowserMain, kArrivedInRendererCompositor]=*/300, |
| /*[kArrivedInRendererCompositor, kRendererCompositorStarted]=*/300, |
| /*[kRendererCompositorStarted, kRendererCompositorFinished]=*/300, |
| /*[kRendererCompositorFinished, kRendererMainStarted]=*/50000, |
| /*[kRendererMainStarted, kRendererMainFinished]=*/300}; |
| // The prediction should only be updated with the ScrollUpdateType event, |
| // other EventType metrics should be ignored. |
| std::unique_ptr<EventMetrics> event_metrics_ptrs[] = { |
| CreateScrollUpdateEventMetricsWithDispatchTimes( |
| false, ScrollUpdateEventMetrics::ScrollUpdateType::kContinued, |
| dispatch_times)}; |
| EXPECT_THAT(event_metrics_ptrs, Each(NotNull())); |
| EventMetrics::List events_metrics = { |
| std::make_move_iterator(std::begin(event_metrics_ptrs)), |
| std::make_move_iterator(std::end(event_metrics_ptrs))}; |
| |
| AdvanceNowByUs(300); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, |
| Now()); |
| |
| // For this test there are only 3 compositor substages updated which reflects |
| // a more realistic scenario. |
| |
| AdvanceNowByUs(300); // kBeginImplFrameToSendBeginMainFrame duration |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(50000); // kEndActivateToSubmitCompositorFrame duration |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| |
| // kSubmitCompositorFrameToPresentationCompositorFrame duration |
| AdvanceNowByUs(300); |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now()); |
| |
| pipeline_reporter_->AddEventsMetrics(std::move(events_metrics)); |
| |
| // Test with no high latency attribution. |
| CompositorFrameReporter::EventLatencyInfo expected_predictions1 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| IntToTimeDeltaVector(expected_predictions1.dispatch_durations, |
| std::vector<int>{-1, 300, 300, 300, 300, 50000, 300}); |
| expected_predictions1.transition_duration = base::Microseconds(300); |
| IntToTimeDeltaVector(expected_predictions1.compositor_durations, |
| std::vector<int>{300, -1, -1, -1, -1, 50000, 300}); |
| expected_predictions1.total_duration = base::Microseconds(102400); |
| |
| CompositorFrameReporter::EventLatencyInfo actual_predictions1 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| pipeline_reporter_->CalculateEventLatencyPrediction( |
| actual_predictions1, kLatencyPredictionDeviationThreshold); |
| |
| std::unique_ptr<EventMetrics>& event_metrics = |
| pipeline_reporter_->events_metrics_for_testing()[0]; |
| std::vector<std::string> attribution = event_metrics->GetHighLatencyStages(); |
| EXPECT_EQ(0u, attribution.size()); |
| event_metrics->ClearHighLatencyStagesForTesting(); |
| |
| // Test with 1 high latency stage attributed. |
| CompositorFrameReporter::EventLatencyInfo expected_predictions2 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| IntToTimeDeltaVector(expected_predictions2.dispatch_durations, |
| std::vector<int>{300, 300, 300, 300, 300, 12725, 300}); |
| expected_predictions2.transition_duration = base::Microseconds(300); |
| IntToTimeDeltaVector(expected_predictions2.compositor_durations, |
| std::vector<int>{300, -1, -1, -1, -1, 50000, 300}); |
| expected_predictions2.total_duration = base::Microseconds(65425); |
| |
| CompositorFrameReporter::EventLatencyInfo actual_predictions2 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| IntToTimeDeltaVector(actual_predictions2.dispatch_durations, |
| std::vector<int>{300, 300, 300, 300, 300, 300, 300}); |
| actual_predictions2.transition_duration = base::Microseconds(300); |
| IntToTimeDeltaVector(actual_predictions2.compositor_durations, |
| std::vector<int>{300, -1, -1, -1, -1, 50000, 300}); |
| actual_predictions2.total_duration = base::Microseconds(5200); |
| pipeline_reporter_->CalculateEventLatencyPrediction( |
| actual_predictions2, kLatencyPredictionDeviationThreshold); |
| |
| attribution = event_metrics->GetHighLatencyStages(); |
| EXPECT_EQ(1u, attribution.size()); |
| EXPECT_EQ("RendererCompositorToMain", attribution[0]); |
| event_metrics->ClearHighLatencyStagesForTesting(); |
| |
| // Test with more than 1 high latency stage attributed. |
| CompositorFrameReporter::EventLatencyInfo expected_predictions3 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| IntToTimeDeltaVector(expected_predictions3.dispatch_durations, |
| std::vector<int>{300, 300, 300, 300, 300, 12725, 300}); |
| expected_predictions3.transition_duration = base::Microseconds(300); |
| IntToTimeDeltaVector(expected_predictions3.compositor_durations, |
| std::vector<int>{300, -1, -1, -1, -1, 12725, 300}); |
| expected_predictions3.total_duration = base::Microseconds(28150); |
| |
| CompositorFrameReporter::EventLatencyInfo actual_predictions3 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| IntToTimeDeltaVector(actual_predictions3.dispatch_durations, |
| std::vector<int>{300, 300, 300, 300, 300, 300, 300}); |
| actual_predictions3.transition_duration = base::Microseconds(300); |
| IntToTimeDeltaVector(actual_predictions3.compositor_durations, |
| std::vector<int>{300, -1, -1, -1, -1, 300, 300}); |
| actual_predictions3.total_duration = base::Microseconds(2700); |
| pipeline_reporter_->CalculateEventLatencyPrediction( |
| actual_predictions3, kLatencyPredictionDeviationThreshold); |
| |
| attribution = event_metrics->GetHighLatencyStages(); |
| EXPECT_EQ(2u, attribution.size()); |
| EXPECT_EQ("RendererCompositorToMain", attribution[0]); |
| EXPECT_EQ("EndActivateToSubmitCompositorFrame", attribution[1]); |
| |
| // Check that all prediction values are accurate. |
| for (int i = 0; i < kNumDispatchStages; i++) { |
| EXPECT_EQ(expected_predictions1.dispatch_durations[i], |
| actual_predictions1.dispatch_durations[i]); |
| EXPECT_EQ(expected_predictions2.dispatch_durations[i], |
| actual_predictions2.dispatch_durations[i]); |
| EXPECT_EQ(expected_predictions3.dispatch_durations[i], |
| actual_predictions3.dispatch_durations[i]); |
| } |
| for (int i = 0; i < kNumOfCompositorStages; i++) { |
| EXPECT_EQ(expected_predictions1.compositor_durations[i], |
| actual_predictions1.compositor_durations[i]); |
| EXPECT_EQ(expected_predictions2.compositor_durations[i], |
| actual_predictions2.compositor_durations[i]); |
| EXPECT_EQ(expected_predictions3.compositor_durations[i], |
| actual_predictions3.compositor_durations[i]); |
| } |
| EXPECT_EQ(expected_predictions1.transition_duration, |
| actual_predictions1.transition_duration); |
| EXPECT_EQ(expected_predictions1.total_duration, |
| actual_predictions1.total_duration); |
| EXPECT_EQ(expected_predictions2.transition_duration, |
| actual_predictions2.transition_duration); |
| EXPECT_EQ(expected_predictions2.total_duration, |
| actual_predictions2.total_duration); |
| EXPECT_EQ(expected_predictions3.transition_duration, |
| actual_predictions3.transition_duration); |
| EXPECT_EQ(expected_predictions3.total_duration, |
| actual_predictions3.total_duration); |
| |
| pipeline_reporter_ = nullptr; |
| histogram_tester.ExpectTotalCount( |
| "EventLatency.GestureScrollUpdate.GenerationToBrowserMain", 1); |
| } |
| |
| // Tests that when a frame is presented to the user, high latency attribution |
| // for EventLatency is reported properly for filtered EventTypes. |
| TEST_F(CompositorFrameReporterTest, EventLatencyAttributionChangePredictions) { |
| base::HistogramTester histogram_tester; |
| std::vector<int> dispatch_times = { |
| /*[kGenerated, kArrivedInBrowserMain]=*/40000, |
| /*[kArrivedInBrowserMain, kArrivedInRendererCompositor]=*/150, |
| /*[kArrivedInRendererCompositor, kRendererCompositorStarted]=*/-1, |
| /*[kRendererCompositorStarted, kRendererCompositorFinished]=*/-1, |
| /*[kRendererCompositorFinished, kRendererMainStarted]=*/150, |
| /*[kRendererMainStarted, kRendererMainFinished]=*/50000}; |
| |
| // The prediction should only be updated with the ScrollUpdateType event, |
| // other EventType metrics should be ignored. |
| std::unique_ptr<EventMetrics> event_metrics_ptrs[] = { |
| CreateScrollUpdateEventMetricsWithDispatchTimes( |
| false, ScrollUpdateEventMetrics::ScrollUpdateType::kContinued, |
| dispatch_times)}; |
| EXPECT_THAT(event_metrics_ptrs, Each(NotNull())); |
| EventMetrics::List events_metrics = { |
| std::make_move_iterator(std::begin(event_metrics_ptrs)), |
| std::make_move_iterator(std::end(event_metrics_ptrs))}; |
| |
| AdvanceNowByUs(300); |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kBeginImplFrameToSendBeginMainFrame, |
| Now()); |
| |
| // For this test there are only 3 compositor substages updated which reflects |
| // a more realistic scenario. |
| |
| AdvanceNowByUs(300); // kBeginImplFrameToSendBeginMainFrame duration |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType::kEndActivateToSubmitCompositorFrame, |
| Now()); |
| |
| AdvanceNowByUs(50000); // kEndActivateToSubmitCompositorFrame duration |
| pipeline_reporter_->StartStage( |
| CompositorFrameReporter::StageType:: |
| kSubmitCompositorFrameToPresentationCompositorFrame, |
| Now()); |
| |
| // kSubmitCompositorFrameToPresentationCompositorFrame duration |
| AdvanceNowByUs(300); |
| pipeline_reporter_->TerminateFrame( |
| CompositorFrameReporter::FrameTerminationStatus::kPresentedFrame, Now()); |
| |
| pipeline_reporter_->AddEventsMetrics(std::move(events_metrics)); |
| |
| // Test 1 |
| CompositorFrameReporter::EventLatencyInfo expected_predictions1 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| IntToTimeDeltaVector(expected_predictions1.dispatch_durations, |
| std::vector<int>{-1, 10300, 262, -1, -1, 262, 42500}); |
| expected_predictions1.transition_duration = base::Microseconds(300); |
| IntToTimeDeltaVector(expected_predictions1.compositor_durations, |
| std::vector<int>{300, -1, -1, -1, -1, 15200, 300}); |
| expected_predictions1.total_duration = base::Microseconds(69424); |
| |
| CompositorFrameReporter::EventLatencyInfo actual_predictions1 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| IntToTimeDeltaVector(actual_predictions1.dispatch_durations, |
| std::vector<int>{-1, 400, 300, -1, -1, 300, 40000}); |
| actual_predictions1.transition_duration = base::Microseconds(300); |
| IntToTimeDeltaVector(actual_predictions1.compositor_durations, |
| std::vector<int>{300, -1, -1, -1, -1, 3600, 300}); |
| actual_predictions1.total_duration = base::Microseconds(45500); |
| pipeline_reporter_->CalculateEventLatencyPrediction( |
| actual_predictions1, kLatencyPredictionDeviationThreshold); |
| |
| std::unique_ptr<EventMetrics>& event_metrics = |
| pipeline_reporter_->events_metrics_for_testing()[0]; |
| std::vector<std::string> attribution = event_metrics->GetHighLatencyStages(); |
| EXPECT_EQ(2, static_cast<int>(attribution.size())); |
| EXPECT_EQ("GenerationToBrowserMain", attribution[0]); |
| EXPECT_EQ("EndActivateToSubmitCompositorFrame", attribution[1]); |
| event_metrics->ClearHighLatencyStagesForTesting(); |
| |
| // Test 2 |
| CompositorFrameReporter::EventLatencyInfo expected_predictions2 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| IntToTimeDeltaVector(expected_predictions2.dispatch_durations, |
| std::vector<int>{300, 10225, 262, -1, -1, 262, 12725}); |
| expected_predictions2.transition_duration = base::Microseconds(300); |
| |
| IntToTimeDeltaVector(expected_predictions2.compositor_durations, |
| std::vector<int>{300, -1, -1, -1, -1, 12725, 300}); |
| expected_predictions2.total_duration = base::Microseconds(37399); |
| |
| CompositorFrameReporter::EventLatencyInfo actual_predictions2 = |
| CompositorFrameReporter::EventLatencyInfo(kNumDispatchStages, |
| kNumOfCompositorStages); |
| IntToTimeDeltaVector(actual_predictions2.dispatch_durations, |
| std::vector<int>{300, 300, 300, -1, -1, 300, 300}); |
| actual_predictions2.transition_duration = base::Microseconds(300); |
| IntToTimeDeltaVector(actual_predictions2.compositor_durations, |
| std::vector<int>{300, -1, -1, -1, -1, 300, 300}); |
| actual_predictions2.total_duration = base::Microseconds(2100); |
| pipeline_reporter_->CalculateEventLatencyPrediction( |
| actual_predictions2, kLatencyPredictionDeviationThreshold); |
| |
| attribution = event_metrics->GetHighLatencyStages(); |
| EXPECT_EQ(2u, attribution.size()); |
| EXPECT_EQ("RendererMainProcessing", attribution[0]); |
| EXPECT_EQ("EndActivateToSubmitCompositorFrame", attribution[1]); |
| |
| // Check that all prediction values are accurate. |
| for (int i = 0; i < kNumDispatchStages; i++) { |
| EXPECT_EQ(expected_predictions1.dispatch_durations[i], |
| actual_predictions1.dispatch_durations[i]); |
| EXPECT_EQ(expected_predictions2.dispatch_durations[i], |
| actual_predictions2.dispatch_durations[i]); |
| } |
| for (int i = 0; i < kNumOfCompositorStages; i++) { |
| EXPECT_EQ(expected_predictions1.compositor_durations[i], |
| actual_predictions1.compositor_durations[i]); |
| EXPECT_EQ(expected_predictions2.compositor_durations[i], |
| actual_predictions2.compositor_durations[i]); |
| } |
| EXPECT_EQ(expected_predictions1.transition_duration, |
| actual_predictions1.transition_duration); |
| EXPECT_EQ(expected_predictions1.total_duration, |
| actual_predictions1.total_duration); |
| EXPECT_EQ(expected_predictions2.transition_duration, |
| actual_predictions2.transition_duration); |
| EXPECT_EQ(expected_predictions2.total_duration, |
| actual_predictions2.total_duration); |
| |
| pipeline_reporter_ = nullptr; |
| histogram_tester.ExpectTotalCount( |
| "EventLatency.GestureScrollUpdate.GenerationToBrowserMain", 1); |
| } |
| |
| } // namespace |
| } // namespace cc |