| Index: cc/scheduler/scheduler_unittest.cc
|
| diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
|
| index 1c377483ef62a570cce89273649a5ebf7cc60fa5..77e1f2796f00939032c0a9b4a1ecdf60c2295753 100644
|
| --- a/cc/scheduler/scheduler_unittest.cc
|
| +++ b/cc/scheduler/scheduler_unittest.cc
|
| @@ -246,6 +246,12 @@ class SchedulerTest : public testing::Test {
|
| fake_compositor_timing_history.Pass());
|
| DCHECK(scheduler_);
|
| client_->set_scheduler(scheduler_.get());
|
| +
|
| + // Use large estimates by default to avoid latency recovery
|
| + // in most tests.
|
| + base::TimeDelta slow_duration = base::TimeDelta::FromSeconds(1);
|
| + fake_compositor_timing_history_->SetAllEstimatesTo(slow_duration);
|
| +
|
| return scheduler_.get();
|
| }
|
|
|
| @@ -384,11 +390,9 @@ class SchedulerTest : public testing::Test {
|
| return fake_external_begin_frame_source_.get();
|
| }
|
|
|
| - void MainFrameInHighLatencyMode(
|
| - int64 begin_main_frame_to_commit_estimate_in_ms,
|
| - int64 commit_to_activate_estimate_in_ms,
|
| - bool impl_latency_takes_priority,
|
| - bool should_send_begin_main_frame);
|
| + void CheckMainFrameSkippedAfterLateCommit(bool expect_send_begin_main_frame);
|
| + void ImplFrameSkippedAfterLateSwapAck(bool swap_ack_before_deadline);
|
| + void ImplFrameIsNotSkippedAfterLateSwapAck();
|
| void BeginFramesNotFromClient(bool use_external_begin_frame_source,
|
| bool throttle_frame_production);
|
| void BeginFramesNotFromClient_SwapThrottled(
|
| @@ -1323,73 +1327,538 @@ TEST_F(SchedulerTest, WaitForReadyToDrawCancelledWhenLostOutputSurface) {
|
| EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
|
| }
|
|
|
| -void SchedulerTest::MainFrameInHighLatencyMode(
|
| - int64 begin_main_frame_to_commit_estimate_in_ms,
|
| - int64 commit_to_activate_estimate_in_ms,
|
| - bool impl_latency_takes_priority,
|
| - bool should_send_begin_main_frame) {
|
| +void SchedulerTest::CheckMainFrameSkippedAfterLateCommit(
|
| + bool expect_send_begin_main_frame) {
|
| + // Impl thread hits deadline before commit finishes.
|
| + scheduler_->SetNeedsCommit();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_SCOPED(AdvanceFrame());
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
|
| + EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + scheduler_->NotifyBeginMainFrameStarted();
|
| + scheduler_->NotifyReadyToCommit();
|
| + scheduler_->NotifyReadyToActivate();
|
| + EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 5);
|
| + EXPECT_ACTION("WillBeginImplFrame", client_, 1, 5);
|
| + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 5);
|
| + EXPECT_ACTION("ScheduledActionCommit", client_, 3, 5);
|
| + EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 4, 5);
|
| + EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| +
|
| + client_->Reset();
|
| + scheduler_->SetNeedsCommit();
|
| + EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_SCOPED(AdvanceFrame());
|
| + EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
|
| + EXPECT_EQ(expect_send_begin_main_frame,
|
| + scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_EQ(expect_send_begin_main_frame,
|
| + client_->HasAction("ScheduledActionSendBeginMainFrame"));
|
| +}
|
| +
|
| +TEST_F(SchedulerTest, MainFrameSkippedAfterLateCommit) {
|
| + scheduler_settings_.use_external_begin_frame_source = true;
|
| + SetUpScheduler(true);
|
| +
|
| + auto fast_duration = base::TimeDelta::FromMilliseconds(1);
|
| + fake_compositor_timing_history_->SetAllEstimatesTo(fast_duration);
|
| +
|
| + bool expect_send_begin_main_frame = false;
|
| + EXPECT_SCOPED(
|
| + CheckMainFrameSkippedAfterLateCommit(expect_send_begin_main_frame));
|
| +}
|
| +
|
| +TEST_F(SchedulerTest,
|
| + MainFrameNotSkippedAfterLateCommitInPreferImplLatencyMode) {
|
| scheduler_settings_.use_external_begin_frame_source = true;
|
| SetUpScheduler(true);
|
| + scheduler_->SetImplLatencyTakesPriority(true);
|
| +
|
| + auto fast_duration = base::TimeDelta::FromMilliseconds(1);
|
| + fake_compositor_timing_history_->SetAllEstimatesTo(fast_duration);
|
|
|
| + bool expect_send_begin_main_frame = true;
|
| + EXPECT_SCOPED(
|
| + CheckMainFrameSkippedAfterLateCommit(expect_send_begin_main_frame));
|
| +}
|
| +
|
| +TEST_F(SchedulerTest,
|
| + MainFrameNotSkippedAfterLateCommit_CommitEstimateTooLong) {
|
| + scheduler_settings_.use_external_begin_frame_source = true;
|
| + SetUpScheduler(true);
|
| + auto fast_duration = base::TimeDelta::FromMilliseconds(1);
|
| + fake_compositor_timing_history_->SetAllEstimatesTo(fast_duration);
|
| + auto slow_duration = base::TimeDelta::FromSeconds(1);
|
| fake_compositor_timing_history_->SetBeginMainFrameToCommitDurationEstimate(
|
| - base::TimeDelta::FromMilliseconds(
|
| - begin_main_frame_to_commit_estimate_in_ms));
|
| + slow_duration);
|
| +
|
| + bool expect_send_begin_main_frame = true;
|
| + EXPECT_SCOPED(
|
| + CheckMainFrameSkippedAfterLateCommit(expect_send_begin_main_frame));
|
| +}
|
| +
|
| +TEST_F(SchedulerTest,
|
| + MainFrameNotSkippedAfterLateCommit_ReadyToActivateEstimateTooLong) {
|
| + scheduler_settings_.use_external_begin_frame_source = true;
|
| + SetUpScheduler(true);
|
| + auto fast_duration = base::TimeDelta::FromMilliseconds(1);
|
| + fake_compositor_timing_history_->SetAllEstimatesTo(fast_duration);
|
| + auto slow_duration = base::TimeDelta::FromSeconds(1);
|
| fake_compositor_timing_history_->SetCommitToReadyToActivateDurationEstimate(
|
| - base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms));
|
| - fake_compositor_timing_history_->SetDrawDurationEstimate(
|
| - base::TimeDelta::FromMilliseconds(1));
|
| + slow_duration);
|
|
|
| - scheduler_->SetImplLatencyTakesPriority(impl_latency_takes_priority);
|
| + bool expect_send_begin_main_frame = true;
|
| + EXPECT_SCOPED(
|
| + CheckMainFrameSkippedAfterLateCommit(expect_send_begin_main_frame));
|
| +}
|
|
|
| - // Impl thread hits deadline before commit finishes.
|
| +TEST_F(SchedulerTest,
|
| + MainFrameNotSkippedAfterLateCommit_ActivateEstimateTooLong) {
|
| + scheduler_settings_.use_external_begin_frame_source = true;
|
| + SetUpScheduler(true);
|
| + auto fast_duration = base::TimeDelta::FromMilliseconds(1);
|
| + fake_compositor_timing_history_->SetAllEstimatesTo(fast_duration);
|
| + auto slow_duration = base::TimeDelta::FromSeconds(1);
|
| + fake_compositor_timing_history_->SetActivateDurationEstimate(slow_duration);
|
| +
|
| + bool expect_send_begin_main_frame = true;
|
| + EXPECT_SCOPED(
|
| + CheckMainFrameSkippedAfterLateCommit(expect_send_begin_main_frame));
|
| +}
|
| +
|
| +TEST_F(SchedulerTest, MainFrameNotSkippedAfterLateCommit_DrawEstimateTooLong) {
|
| + scheduler_settings_.use_external_begin_frame_source = true;
|
| + SetUpScheduler(true);
|
| + auto fast_duration = base::TimeDelta::FromMilliseconds(1);
|
| + fake_compositor_timing_history_->SetAllEstimatesTo(fast_duration);
|
| + auto slow_duration = base::TimeDelta::FromSeconds(1);
|
| + fake_compositor_timing_history_->SetDrawDurationEstimate(slow_duration);
|
| +
|
| + bool expect_send_begin_main_frame = true;
|
| + EXPECT_SCOPED(
|
| + CheckMainFrameSkippedAfterLateCommit(expect_send_begin_main_frame));
|
| +}
|
| +
|
| +void SchedulerTest::ImplFrameSkippedAfterLateSwapAck(
|
| + bool swap_ack_before_deadline) {
|
| + // To get into a high latency state, this test disables automatic swap acks.
|
| + scheduler_->SetMaxSwapsPending(1);
|
| + client_->SetAutomaticSwapAck(false);
|
| +
|
| + // Draw and swap for first BeginFrame
|
| + client_->Reset();
|
| + scheduler_->SetNeedsCommit();
|
| + scheduler_->SetNeedsRedraw();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + SendNextBeginFrame();
|
| + EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 4);
|
| + EXPECT_ACTION("WillBeginImplFrame", client_, 1, 4);
|
| + EXPECT_ACTION("ScheduledActionAnimate", client_, 2, 4);
|
| + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 3, 4);
|
| +
|
| + client_->Reset();
|
| + scheduler_->NotifyBeginMainFrameStarted();
|
| + scheduler_->NotifyReadyToCommit();
|
| + scheduler_->NotifyReadyToActivate();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
|
| + EXPECT_ACTION("ScheduledActionCommit", client_, 0, 4);
|
| + EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 1, 4);
|
| + EXPECT_ACTION("ScheduledActionAnimate", client_, 2, 4);
|
| + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 3, 4);
|
| +
|
| + // Verify we skip every other frame if the swap ack consistently
|
| + // comes back late.
|
| + for (int i = 0; i < 10; i++) {
|
| + // Not calling scheduler_->DidSwapBuffersComplete() until after next
|
| + // BeginImplFrame puts the impl thread in high latency mode.
|
| + client_->Reset();
|
| + scheduler_->SetNeedsCommit();
|
| + scheduler_->SetNeedsRedraw();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + SendNextBeginFrame();
|
| + // Verify that we skip the BeginImplFrame
|
| + EXPECT_NO_ACTION(client_);
|
| + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| +
|
| + // Verify that we do not perform any actions after we are no longer
|
| + // swap throttled.
|
| + client_->Reset();
|
| + if (swap_ack_before_deadline) {
|
| + // It shouldn't matter if the swap ack comes back before the deadline...
|
| + scheduler_->DidSwapBuffersComplete();
|
| + task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
|
| + } else {
|
| + // ... or after the deadline.
|
| + task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
|
| + scheduler_->DidSwapBuffersComplete();
|
| + }
|
| + EXPECT_NO_ACTION(client_);
|
| +
|
| + // Verify that we start the next BeginImplFrame and continue normally
|
| + // after having just skipped a BeginImplFrame.
|
| + client_->Reset();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + SendNextBeginFrame();
|
| + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
|
| + EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3);
|
| + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 3);
|
| +
|
| + client_->Reset();
|
| + scheduler_->NotifyBeginMainFrameStarted();
|
| + scheduler_->NotifyReadyToCommit();
|
| + scheduler_->NotifyReadyToActivate();
|
| + task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
|
| + EXPECT_ACTION("ScheduledActionCommit", client_, 0, 4);
|
| + EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 1, 4);
|
| + EXPECT_ACTION("ScheduledActionAnimate", client_, 2, 4);
|
| + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 3, 4);
|
| + }
|
| +}
|
| +
|
| +TEST_F(SchedulerTest,
|
| + ImplFrameSkippedAfterLateSwapAck_FastEstimates_SwapAckThenDeadline) {
|
| + scheduler_settings_.use_external_begin_frame_source = true;
|
| + SetUpScheduler(true);
|
| +
|
| + auto fast_duration = base::TimeDelta::FromMilliseconds(1);
|
| + fake_compositor_timing_history_->SetAllEstimatesTo(fast_duration);
|
| +
|
| + bool swap_ack_before_deadline = true;
|
| + EXPECT_SCOPED(ImplFrameSkippedAfterLateSwapAck(swap_ack_before_deadline));
|
| +}
|
| +
|
| +TEST_F(SchedulerTest,
|
| + ImplFrameSkippedAfterLateSwapAck_FastEstimates_DeadlineThenSwapAck) {
|
| + scheduler_settings_.use_external_begin_frame_source = true;
|
| + SetUpScheduler(true);
|
| +
|
| + auto fast_duration = base::TimeDelta::FromMilliseconds(1);
|
| + fake_compositor_timing_history_->SetAllEstimatesTo(fast_duration);
|
| +
|
| + bool swap_ack_before_deadline = false;
|
| + EXPECT_SCOPED(ImplFrameSkippedAfterLateSwapAck(swap_ack_before_deadline));
|
| +}
|
| +
|
| +TEST_F(SchedulerTest,
|
| + ImplFrameSkippedAfterLateSwapAck_ImplLatencyTakesPriority) {
|
| + scheduler_settings_.use_external_begin_frame_source = true;
|
| + SetUpScheduler(true);
|
| +
|
| + // Even if every estimate related to the main thread is slow, we should
|
| + // still expect to recover impl thread latency if the draw is fast and we
|
| + // are in impl latency takes priority.
|
| + scheduler_->SetImplLatencyTakesPriority(true);
|
| + auto slow_duration = base::TimeDelta::FromSeconds(1);
|
| + fake_compositor_timing_history_->SetAllEstimatesTo(slow_duration);
|
| + auto fast_duration = base::TimeDelta::FromMilliseconds(1);
|
| + fake_compositor_timing_history_->SetDrawDurationEstimate(fast_duration);
|
| +
|
| + bool swap_ack_before_deadline = false;
|
| + EXPECT_SCOPED(ImplFrameSkippedAfterLateSwapAck(swap_ack_before_deadline));
|
| +}
|
| +
|
| +TEST_F(SchedulerTest,
|
| + ImplFrameSkippedAfterLateSwapAck_OnlyImplSideUpdatesExpected) {
|
| + // This tests that we recover impl thread latency when there are no commits.
|
| + scheduler_settings_.use_external_begin_frame_source = true;
|
| + SetUpScheduler(true);
|
| +
|
| + // To get into a high latency state, this test disables automatic swap acks.
|
| + scheduler_->SetMaxSwapsPending(1);
|
| + client_->SetAutomaticSwapAck(false);
|
| +
|
| + // Even if every estimate related to the main thread is slow, we should
|
| + // still expect to recover impl thread latency if there are no commits from
|
| + // the main thread.
|
| + auto slow_duration = base::TimeDelta::FromSeconds(1);
|
| + fake_compositor_timing_history_->SetAllEstimatesTo(slow_duration);
|
| + auto fast_duration = base::TimeDelta::FromMilliseconds(1);
|
| + fake_compositor_timing_history_->SetDrawDurationEstimate(fast_duration);
|
| +
|
| + // Draw and swap for first BeginFrame
|
| + client_->Reset();
|
| + scheduler_->SetNeedsRedraw();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + SendNextBeginFrame();
|
| + EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 3);
|
| + EXPECT_ACTION("WillBeginImplFrame", client_, 1, 3);
|
| + EXPECT_ACTION("ScheduledActionAnimate", client_, 2, 3);
|
| +
|
| + client_->Reset();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
|
| + EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_);
|
| +
|
| + // Verify we skip every other frame if the swap ack consistently
|
| + // comes back late.
|
| + for (int i = 0; i < 10; i++) {
|
| + // Not calling scheduler_->DidSwapBuffersComplete() until after next
|
| + // BeginImplFrame puts the impl thread in high latency mode.
|
| + client_->Reset();
|
| + scheduler_->SetNeedsRedraw();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + SendNextBeginFrame();
|
| + // Verify that we skip the BeginImplFrame
|
| + EXPECT_NO_ACTION(client_);
|
| + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| +
|
| + // Verify that we do not perform any actions after we are no longer
|
| + // swap throttled.
|
| + client_->Reset();
|
| + scheduler_->DidSwapBuffersComplete();
|
| + EXPECT_NO_ACTION(client_);
|
| +
|
| + // Verify that we start the next BeginImplFrame and continue normally
|
| + // after having just skipped a BeginImplFrame.
|
| + client_->Reset();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + SendNextBeginFrame();
|
| + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
|
| + EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
|
| +
|
| + client_->Reset();
|
| + // Deadline should be immediate.
|
| + EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
|
| + task_runner().RunUntilTime(now_src_->NowTicks());
|
| + EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
|
| + EXPECT_SINGLE_ACTION("ScheduledActionDrawAndSwapIfPossible", client_);
|
| + }
|
| +}
|
| +
|
| +void SchedulerTest::ImplFrameIsNotSkippedAfterLateSwapAck() {
|
| + // To get into a high latency state, this test disables automatic swap acks.
|
| + scheduler_->SetMaxSwapsPending(1);
|
| + client_->SetAutomaticSwapAck(false);
|
| +
|
| + // Draw and swap for first BeginFrame
|
| + client_->Reset();
|
| + scheduler_->SetNeedsCommit();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + SendNextBeginFrame();
|
| + EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 3);
|
| + EXPECT_ACTION("WillBeginImplFrame", client_, 1, 3);
|
| + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 3);
|
| +
|
| + client_->Reset();
|
| + scheduler_->NotifyBeginMainFrameStarted();
|
| + scheduler_->NotifyReadyToCommit();
|
| + scheduler_->NotifyReadyToActivate();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
|
| + EXPECT_ACTION("ScheduledActionCommit", client_, 0, 4);
|
| + EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 1, 4);
|
| + EXPECT_ACTION("ScheduledActionAnimate", client_, 2, 4);
|
| + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 3, 4);
|
| +
|
| + // Verify impl thread consistently operates in high latency mode
|
| + // without skipping any frames.
|
| + for (int i = 0; i < 10; i++) {
|
| + // Not calling scheduler_->DidSwapBuffersComplete() until after next frame
|
| + // puts the impl thread in high latency mode.
|
| + client_->Reset();
|
| + scheduler_->SetNeedsCommit();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + SendNextBeginFrame();
|
| + EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
|
| + EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| +
|
| + client_->Reset();
|
| + scheduler_->DidSwapBuffersComplete();
|
| + scheduler_->NotifyBeginMainFrameStarted();
|
| + scheduler_->NotifyReadyToCommit();
|
| + scheduler_->NotifyReadyToActivate();
|
| + task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
|
| +
|
| + // Verify that we don't skip the actions of the BeginImplFrame
|
| + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 0, 5);
|
| + EXPECT_ACTION("ScheduledActionCommit", client_, 1, 5);
|
| + EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 2, 5);
|
| + EXPECT_ACTION("ScheduledActionAnimate", client_, 3, 5);
|
| + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 4, 5);
|
| + }
|
| +}
|
| +
|
| +TEST_F(SchedulerTest,
|
| + ImplFrameIsNotSkippedAfterLateSwapAck_CommitEstimateTooLong) {
|
| + scheduler_settings_.use_external_begin_frame_source = true;
|
| + SetUpScheduler(true);
|
| + auto fast_duration = base::TimeDelta::FromMilliseconds(1);
|
| + fake_compositor_timing_history_->SetAllEstimatesTo(fast_duration);
|
| + auto slow_duration = base::TimeDelta::FromSeconds(1);
|
| + fake_compositor_timing_history_->SetBeginMainFrameToCommitDurationEstimate(
|
| + slow_duration);
|
| + EXPECT_SCOPED(ImplFrameIsNotSkippedAfterLateSwapAck());
|
| +}
|
| +
|
| +TEST_F(SchedulerTest,
|
| + ImplFrameIsNotSkippedAfterLateSwapAck_ReadyToActivateEstimateTooLong) {
|
| + scheduler_settings_.use_external_begin_frame_source = true;
|
| + SetUpScheduler(true);
|
| + auto fast_duration = base::TimeDelta::FromMilliseconds(1);
|
| + fake_compositor_timing_history_->SetAllEstimatesTo(fast_duration);
|
| + auto slow_duration = base::TimeDelta::FromSeconds(1);
|
| + fake_compositor_timing_history_->SetCommitToReadyToActivateDurationEstimate(
|
| + slow_duration);
|
| + EXPECT_SCOPED(ImplFrameIsNotSkippedAfterLateSwapAck());
|
| +}
|
| +
|
| +TEST_F(SchedulerTest,
|
| + ImplFrameIsNotSkippedAfterLateSwapAck_ActivateEstimateTooLong) {
|
| + scheduler_settings_.use_external_begin_frame_source = true;
|
| + SetUpScheduler(true);
|
| + auto fast_duration = base::TimeDelta::FromMilliseconds(1);
|
| + fake_compositor_timing_history_->SetAllEstimatesTo(fast_duration);
|
| + auto slow_duration = base::TimeDelta::FromSeconds(1);
|
| + fake_compositor_timing_history_->SetActivateDurationEstimate(slow_duration);
|
| + EXPECT_SCOPED(ImplFrameIsNotSkippedAfterLateSwapAck());
|
| +}
|
| +
|
| +TEST_F(SchedulerTest,
|
| + ImplFrameIsNotSkippedAfterLateSwapAck_DrawEstimateTooLong) {
|
| + scheduler_settings_.use_external_begin_frame_source = true;
|
| + SetUpScheduler(true);
|
| + auto fast_duration = base::TimeDelta::FromMilliseconds(1);
|
| + fake_compositor_timing_history_->SetAllEstimatesTo(fast_duration);
|
| + auto slow_duration = base::TimeDelta::FromSeconds(1);
|
| + fake_compositor_timing_history_->SetDrawDurationEstimate(slow_duration);
|
| + EXPECT_SCOPED(ImplFrameIsNotSkippedAfterLateSwapAck());
|
| +}
|
| +
|
| +TEST_F(SchedulerTest,
|
| + MainFrameThenImplFrameSkippedAfterLateCommitAndLateSwapAck) {
|
| + // Set up client with custom estimates.
|
| + // This test starts off with expensive estimates to prevent latency recovery
|
| + // initially, then lowers the estimates to enable it once both the main
|
| + // and impl threads are in a high latency mode.
|
| + scheduler_settings_.use_external_begin_frame_source = true;
|
| + SetUpScheduler(true);
|
| +
|
| + auto slow_duration = base::TimeDelta::FromSeconds(1);
|
| + fake_compositor_timing_history_->SetAllEstimatesTo(slow_duration);
|
| +
|
| + // To get into a high latency state, this test disables automatic swap acks.
|
| + scheduler_->SetMaxSwapsPending(1);
|
| + client_->SetAutomaticSwapAck(false);
|
| +
|
| + // Impl thread hits deadline before commit finishes to make
|
| + // MainThreadIsInHighLatencyMode true
|
| + client_->Reset();
|
| scheduler_->SetNeedsCommit();
|
| EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| EXPECT_SCOPED(AdvanceFrame());
|
| EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| - task_runner().RunPendingTasks(); // Run posted deadline.
|
| + task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
|
| EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| scheduler_->NotifyBeginMainFrameStarted();
|
| scheduler_->NotifyReadyToCommit();
|
| scheduler_->NotifyReadyToActivate();
|
| EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| - EXPECT_TRUE(client_->HasAction("ScheduledActionSendBeginMainFrame"));
|
|
|
| + EXPECT_ACTION("SetNeedsBeginFrames(true)", client_, 0, 5);
|
| + EXPECT_ACTION("WillBeginImplFrame", client_, 1, 5);
|
| + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 5);
|
| + EXPECT_ACTION("ScheduledActionCommit", client_, 3, 5);
|
| + EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 4, 5);
|
| +
|
| + // Draw and swap for first commit, start second commit.
|
| client_->Reset();
|
| scheduler_->SetNeedsCommit();
|
| EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| EXPECT_SCOPED(AdvanceFrame());
|
| EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| - task_runner().RunPendingTasks(); // Run posted deadline.
|
| - EXPECT_EQ(scheduler_->MainThreadIsInHighLatencyMode(),
|
| - should_send_begin_main_frame);
|
| - EXPECT_EQ(client_->HasAction("ScheduledActionSendBeginMainFrame"),
|
| - should_send_begin_main_frame);
|
| -}
|
| + task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
|
| + scheduler_->NotifyBeginMainFrameStarted();
|
| + scheduler_->NotifyReadyToCommit();
|
| + scheduler_->NotifyReadyToActivate();
|
|
|
| -TEST_F(SchedulerTest,
|
| - SkipMainFrameIfHighLatencyAndCanCommitAndActivateBeforeDeadline) {
|
| - // Set up client so that estimates indicate that we can commit and activate
|
| - // before the deadline (~8ms by default).
|
| - EXPECT_SCOPED(MainFrameInHighLatencyMode(1, 1, false, false));
|
| -}
|
| + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 6);
|
| + EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 6);
|
| + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 2, 6);
|
| + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 3, 6);
|
| + EXPECT_ACTION("ScheduledActionCommit", client_, 4, 6);
|
| + EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 5, 6);
|
|
|
| -TEST_F(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanCommitTooLong) {
|
| - // Set up client so that estimates indicate that the commit cannot finish
|
| - // before the deadline (~8ms by default).
|
| - EXPECT_SCOPED(MainFrameInHighLatencyMode(10, 1, false, true));
|
| -}
|
| + // Don't call scheduler_->DidSwapBuffersComplete() until after next frame
|
| + // to put the impl thread in a high latency mode.
|
| + client_->Reset();
|
| + scheduler_->SetNeedsCommit();
|
| + EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_TRUE(scheduler_->SwapThrottled());
|
| + EXPECT_SCOPED(AdvanceFrame());
|
| + EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
|
|
|
| -TEST_F(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanActivateTooLong) {
|
| - // Set up client so that estimates indicate that the activate cannot finish
|
| - // before the deadline (~8ms by default).
|
| - EXPECT_SCOPED(MainFrameInHighLatencyMode(1, 10, false, true));
|
| -}
|
| + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
|
| + EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 2);
|
| + // Note: BeginMainFrame and swap are skipped here because of
|
| + // swap ack backpressure, not because of latency recovery.
|
| + EXPECT_FALSE(client_->HasAction("ScheduledActionSendBeginMainFrame"));
|
| + EXPECT_FALSE(client_->HasAction("ScheduledActionDrawAndSwapIfPossible"));
|
| + EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| +
|
| + // Lower estimates so that the scheduler will attempt latency recovery.
|
| + auto fast_duration = base::TimeDelta::FromMilliseconds(1);
|
| + fake_compositor_timing_history_->SetAllEstimatesTo(fast_duration);
|
| +
|
| + // Now that both threads are in a high latency mode, make sure we
|
| + // skip the BeginMainFrame, then the BeginImplFrame, but not both
|
| + // at the same time.
|
| +
|
| + // Verify we skip BeginMainFrame first.
|
| + client_->Reset();
|
| + // Previous commit request is still outstanding.
|
| + EXPECT_TRUE(scheduler_->NeedsCommit());
|
| + EXPECT_TRUE(scheduler_->SwapThrottled());
|
| + SendNextBeginFrame();
|
| + EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + scheduler_->DidSwapBuffersComplete();
|
| + task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
|
| +
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 3);
|
| + EXPECT_ACTION("ScheduledActionAnimate", client_, 1, 3);
|
| + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 2, 3);
|
| +
|
| + // Verify we skip the BeginImplFrame second.
|
| + client_->Reset();
|
| + // Previous commit request is still outstanding.
|
| + EXPECT_TRUE(scheduler_->NeedsCommit());
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + SendNextBeginFrame();
|
| + task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + scheduler_->DidSwapBuffersComplete();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| +
|
| + EXPECT_NO_ACTION(client_);
|
| +
|
| + // Then verify we operate in a low latency mode.
|
| + client_->Reset();
|
| + // Previous commit request is still outstanding.
|
| + EXPECT_TRUE(scheduler_->NeedsCommit());
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + SendNextBeginFrame();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + scheduler_->NotifyBeginMainFrameStarted();
|
| + scheduler_->NotifyReadyToCommit();
|
| + scheduler_->NotifyReadyToActivate();
|
| + task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + scheduler_->DidSwapBuffersComplete();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
|
|
| -TEST_F(SchedulerTest, NotSkipMainFrameInPreferImplLatencyMode) {
|
| - // Set up client so that estimates indicate that we can commit and activate
|
| - // before the deadline (~8ms by default), but also enable impl latency takes
|
| - // priority mode.
|
| - EXPECT_SCOPED(MainFrameInHighLatencyMode(1, 1, true, true));
|
| + EXPECT_ACTION("WillBeginImplFrame", client_, 0, 6);
|
| + EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 6);
|
| + EXPECT_ACTION("ScheduledActionCommit", client_, 2, 6);
|
| + EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 3, 6);
|
| + EXPECT_ACTION("ScheduledActionAnimate", client_, 4, 6);
|
| + EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 5, 6);
|
| }
|
|
|
| TEST_F(
|
| @@ -1398,19 +1867,10 @@ TEST_F(
|
| // NPAPI plugins on Windows block the Browser UI thread on the Renderer main
|
| // thread. This prevents the scheduler from receiving any pending swap acks.
|
|
|
| - // Since we are simulating a long commit, set up a client with draw duration
|
| - // estimates that prevent skipping main frames to get to low latency mode.
|
| scheduler_settings_.use_external_begin_frame_source = true;
|
| scheduler_settings_.main_frame_while_swap_throttled_enabled = true;
|
| SetUpScheduler(true);
|
|
|
| - fake_compositor_timing_history_->SetBeginMainFrameToCommitDurationEstimate(
|
| - base::TimeDelta::FromMilliseconds(32));
|
| - fake_compositor_timing_history_->SetCommitToReadyToActivateDurationEstimate(
|
| - base::TimeDelta::FromMilliseconds(32));
|
| - fake_compositor_timing_history_->SetDrawDurationEstimate(
|
| - base::TimeDelta::FromMilliseconds(1));
|
| -
|
| // Disables automatic swap acks so this test can force swap ack throttling
|
| // to simulate a blocked Browser ui thread.
|
| scheduler_->SetMaxSwapsPending(1);
|
| @@ -1477,20 +1937,11 @@ TEST_F(SchedulerTest,
|
| // swap trottled and we have a pending tree and active tree that
|
| // still needs to be drawn for the first time.
|
|
|
| - // Since we are simulating a long commit, set up a client with draw duration
|
| - // estimates that prevent skipping main frames to get to low latency mode.
|
| scheduler_settings_.use_external_begin_frame_source = true;
|
| scheduler_settings_.main_frame_while_swap_throttled_enabled = true;
|
| scheduler_settings_.main_frame_before_activation_enabled = true;
|
| SetUpScheduler(true);
|
|
|
| - fake_compositor_timing_history_->SetBeginMainFrameToCommitDurationEstimate(
|
| - base::TimeDelta::FromMilliseconds(32));
|
| - fake_compositor_timing_history_->SetCommitToReadyToActivateDurationEstimate(
|
| - base::TimeDelta::FromMilliseconds(32));
|
| - fake_compositor_timing_history_->SetDrawDurationEstimate(
|
| - base::TimeDelta::FromMilliseconds(1));
|
| -
|
| // Disables automatic swap acks so this test can force swap ack throttling
|
| // to simulate a blocked Browser ui thread.
|
| scheduler_->SetMaxSwapsPending(1);
|
| @@ -1572,13 +2023,6 @@ TEST_F(
|
| scheduler_settings_.main_frame_before_activation_enabled = true;
|
| SetUpScheduler(true);
|
|
|
| - fake_compositor_timing_history_->SetBeginMainFrameToCommitDurationEstimate(
|
| - base::TimeDelta::FromMilliseconds(32));
|
| - fake_compositor_timing_history_->SetCommitToReadyToActivateDurationEstimate(
|
| - base::TimeDelta::FromMilliseconds(32));
|
| - fake_compositor_timing_history_->SetDrawDurationEstimate(
|
| - base::TimeDelta::FromMilliseconds(1));
|
| -
|
| // Disables automatic swap acks so this test can force swap ack throttling
|
| // to simulate a blocked Browser ui thread.
|
| scheduler_->SetMaxSwapsPending(1);
|
|
|