Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3980)

Unified Diff: cc/scheduler/scheduler_unittest.cc

Issue 1133673004: cc: Heuristic for Renderer latency recovery (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebaswe Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « cc/scheduler/scheduler_state_machine.cc ('k') | cc/test/scheduler_test_common.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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);
« no previous file with comments | « cc/scheduler/scheduler_state_machine.cc ('k') | cc/test/scheduler_test_common.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698