| Index: cc/scheduler/scheduler_unittest.cc
|
| diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
|
| index 2f878fdcdbfa9a22a3d101934c3200fb3c30b96d..388b4db8178d95419419c5902fbf13a190f2ef43 100644
|
| --- a/cc/scheduler/scheduler_unittest.cc
|
| +++ b/cc/scheduler/scheduler_unittest.cc
|
| @@ -150,12 +150,17 @@ class FakeSchedulerClient : public SchedulerClient {
|
| if (log_anticipated_draw_time_change_)
|
| PushAction("DidAnticipatedDrawTimeChange");
|
| }
|
| - base::TimeDelta DrawDurationEstimate() override { return base::TimeDelta(); }
|
| +
|
| + // Use really long estimations by default so we don't inadvertently
|
| + // test latency recovery logic unless a test explicitly wants to.
|
| + base::TimeDelta DrawDurationEstimate() override {
|
| + return base::TimeDelta::FromHours(1);
|
| + }
|
| base::TimeDelta BeginMainFrameToCommitDurationEstimate() override {
|
| - return base::TimeDelta();
|
| + return base::TimeDelta::FromHours(1);
|
| }
|
| base::TimeDelta CommitToActivateDurationEstimate() override {
|
| - return base::TimeDelta();
|
| + return base::TimeDelta::FromHours(1);
|
| }
|
|
|
| void SendBeginFramesToChildren(const BeginFrameArgs& args) override {
|
| @@ -203,9 +208,9 @@ class FakeSchedulerClient : public SchedulerClient {
|
| TestScheduler* scheduler_;
|
| };
|
|
|
| -class SchedulerClientWithFixedEstimates : public FakeSchedulerClient {
|
| +class SchedulerClientWithCustomEstimates : public FakeSchedulerClient {
|
| public:
|
| - SchedulerClientWithFixedEstimates(
|
| + SchedulerClientWithCustomEstimates(
|
| base::TimeDelta draw_duration,
|
| base::TimeDelta begin_main_frame_to_commit_duration,
|
| base::TimeDelta commit_to_activate_duration)
|
| @@ -222,7 +227,7 @@ class SchedulerClientWithFixedEstimates : public FakeSchedulerClient {
|
| return commit_to_activate_duration_;
|
| }
|
|
|
| - private:
|
| + public:
|
| base::TimeDelta draw_duration_;
|
| base::TimeDelta begin_main_frame_to_commit_duration_;
|
| base::TimeDelta commit_to_activate_duration_;
|
| @@ -418,6 +423,11 @@ class SchedulerTest : public testing::Test {
|
| int64 commit_to_activate_estimate_in_ms,
|
| bool impl_latency_takes_priority,
|
| bool should_send_begin_main_frame);
|
| + void ImplFrameInHighLatencyMode(
|
| + int64 begin_main_frame_to_commit_estimate_in_ms,
|
| + int64 commit_to_activate_estimate_in_ms,
|
| + bool swap_ack_before_deadline,
|
| + bool should_begin_impl_frame_in_high_latency);
|
| void BeginFramesNotFromClient(bool use_external_begin_frame_source,
|
| bool throttle_frame_production);
|
| void BeginFramesNotFromClient_SwapThrottled(
|
| @@ -484,8 +494,8 @@ TEST_F(SchedulerTest, SendBeginFramesToChildrenWithoutCommit) {
|
|
|
| TEST_F(SchedulerTest, SendBeginFramesToChildrenDeadlineNotAdjusted) {
|
| // Set up client with specified estimates.
|
| - SchedulerClientWithFixedEstimates* client =
|
| - new SchedulerClientWithFixedEstimates(
|
| + SchedulerClientWithCustomEstimates* client =
|
| + new SchedulerClientWithCustomEstimates(
|
| base::TimeDelta::FromMilliseconds(1),
|
| base::TimeDelta::FromMilliseconds(2),
|
| base::TimeDelta::FromMilliseconds(4));
|
| @@ -1316,8 +1326,8 @@ void SchedulerTest::MainFrameInHighLatencyMode(
|
| bool impl_latency_takes_priority,
|
| bool should_send_begin_main_frame) {
|
| // Set up client with specified estimates (draw duration is set to 1).
|
| - SchedulerClientWithFixedEstimates* client =
|
| - new SchedulerClientWithFixedEstimates(
|
| + SchedulerClientWithCustomEstimates* client =
|
| + new SchedulerClientWithCustomEstimates(
|
| base::TimeDelta::FromMilliseconds(1),
|
| base::TimeDelta::FromMilliseconds(
|
| begin_main_frame_to_commit_estimate_in_ms),
|
| @@ -1378,11 +1388,239 @@ TEST_F(SchedulerTest, NotSkipMainFrameInPreferImplLatencyMode) {
|
| EXPECT_SCOPED(MainFrameInHighLatencyMode(1, 1, true, true));
|
| }
|
|
|
| +void SchedulerTest::ImplFrameInHighLatencyMode(
|
| + int64 begin_main_frame_to_commit_estimate_in_ms,
|
| + int64 commit_to_activate_estimate_in_ms,
|
| + bool swap_ack_before_deadline,
|
| + bool should_begin_impl_frame_in_high_latency) {
|
| + // Set up client with specified estimates (draw duration is set to 1).
|
| + SchedulerClientWithCustomEstimates* client =
|
| + new SchedulerClientWithCustomEstimates(
|
| + base::TimeDelta::FromMilliseconds(1),
|
| + base::TimeDelta::FromMilliseconds(
|
| + begin_main_frame_to_commit_estimate_in_ms),
|
| + base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms));
|
| +
|
| + scheduler_settings_.use_external_begin_frame_source = true;
|
| + SetUpScheduler(make_scoped_ptr(client).Pass(), true);
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| +
|
| + // 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_->SetNeedsRedraw();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + EXPECT_SCOPED(AdvanceFrame());
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + task_runner().RunPendingTasks(); // Run posted deadline.
|
| + EXPECT_TRUE(client->HasAction("ScheduledActionDrawAndSwapIfPossible"));
|
| +
|
| + // Not calling scheduler_->DidSwapBuffersComplete() until after next frame
|
| + // puts impl thread in high latency mode.
|
| + client->Reset();
|
| + scheduler_->SetNeedsRedraw();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + EXPECT_SCOPED(AdvanceFrame());
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + if (swap_ack_before_deadline) {
|
| + scheduler_->DidSwapBuffersComplete();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_TRUE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + task_runner().RunPendingTasks(); // Run posted deadline.
|
| + EXPECT_TRUE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + } else {
|
| + task_runner().RunPendingTasks(); // Run posted deadline.
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_TRUE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + scheduler_->DidSwapBuffersComplete();
|
| + EXPECT_TRUE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + }
|
| +
|
| + // Now that we are in a high latency mode, test if we recover or not.
|
| + client->Reset();
|
| + scheduler_->SetNeedsRedraw();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_TRUE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + SendNextBeginFrame();
|
| + EXPECT_EQ(should_begin_impl_frame_in_high_latency,
|
| + client->HasAction("WillBeginImplFrame"));
|
| +
|
| + // Verify that we make forward progress even when we aren't expecting
|
| + // another swap ack.
|
| + if (!swap_ack_before_deadline) {
|
| + client->Reset();
|
| + SendNextBeginFrame();
|
| + EXPECT_TRUE(client->HasAction("WillBeginImplFrame"));
|
| + }
|
| +}
|
| +
|
| +TEST_F(SchedulerTest,
|
| + SkipImplFrameIfHighLatencyAndCanDrawBeforeDeadline_SwapAckThenDeadline) {
|
| + // Set up client so that estimates indicate that we can commit and activate
|
| + // before the deadline (~8ms by default).
|
| + EXPECT_SCOPED(ImplFrameInHighLatencyMode(1, 1, true, false));
|
| +}
|
| +
|
| +TEST_F(SchedulerTest,
|
| + SkipImplFrameIfHighLatencyAndCanDrawBeforeDeadline_DeadlineThenSwapAck) {
|
| + // Set up client so that estimates indicate that we can commit and activate
|
| + // before the deadline (~8ms by default).
|
| + EXPECT_SCOPED(ImplFrameInHighLatencyMode(1, 1, false, false));
|
| +}
|
| +
|
| +TEST_F(SchedulerTest, NotSkipImplFrameIfHighLatencyAndCanCommitTooLong) {
|
| + // Set up client so that estimates indicate that the commit cannot finish
|
| + // before the deadline (~8ms by default).
|
| + EXPECT_SCOPED(ImplFrameInHighLatencyMode(10, 1, true, true));
|
| +}
|
| +
|
| +TEST_F(SchedulerTest, NotSkipImplFrameIfHighLatencyAndCanActivateTooLong) {
|
| + // Set up client so that estimates indicate that the activate cannot finish
|
| + // before the deadline (~8ms by default).
|
| + EXPECT_SCOPED(ImplFrameInHighLatencyMode(1, 10, true, true));
|
| +}
|
| +
|
| +TEST_F(SchedulerTest, MainAndImplFrameInHighLatencyMode) {
|
| + // Set up client with custom estimates.
|
| + // This test starts off with expensive estimates to prevent latency recovery
|
| + // initially, the lowers the estimates to enable it once both the main
|
| + // and impl threads are in a high latency mode.
|
| + auto fast_duration = base::TimeDelta::FromMilliseconds(1);
|
| + auto slow_duration = base::TimeDelta::FromMilliseconds(10);
|
| + SchedulerClientWithCustomEstimates* client =
|
| + new SchedulerClientWithCustomEstimates(slow_duration, slow_duration,
|
| + slow_duration);
|
| +
|
| + scheduler_settings_.use_external_begin_frame_source = true;
|
| + SetUpScheduler(make_scoped_ptr(client).Pass(), true);
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| +
|
| + // 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_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + EXPECT_SCOPED(AdvanceFrame());
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + task_runner().RunPendingTasks(); // Run posted deadline.
|
| + EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + scheduler_->NotifyBeginMainFrameStarted();
|
| + scheduler_->NotifyReadyToCommit();
|
| + EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + EXPECT_TRUE(client->HasAction("WillBeginImplFrame"));
|
| + EXPECT_TRUE(client->HasAction("ScheduledActionSendBeginMainFrame"));
|
| +
|
| + // Draw and swap for first commit, start second commit.
|
| + client->Reset();
|
| + scheduler_->SetNeedsCommit();
|
| + EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + EXPECT_SCOPED(AdvanceFrame());
|
| + EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + task_runner().RunPendingTasks(); // Run posted deadline.
|
| + scheduler_->NotifyBeginMainFrameStarted();
|
| + scheduler_->NotifyReadyToCommit();
|
| + EXPECT_TRUE(client->HasAction("WillBeginImplFrame"));
|
| + EXPECT_TRUE(client->HasAction("ScheduledActionSendBeginMainFrame"));
|
| + EXPECT_TRUE(client->HasAction("ScheduledActionDrawAndSwapIfPossible"));
|
| +
|
| + // Don't call scheduler_->DidSwapBuffersComplete() until after next frame
|
| + // to make ImplThreadIsLikelyInHighLatencyMode true.
|
| + client->Reset();
|
| + scheduler_->SetNeedsCommit();
|
| + EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + EXPECT_SCOPED(AdvanceFrame());
|
| + EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + task_runner().RunPendingTasks(); // Run posted deadline.
|
| + scheduler_->DidSwapBuffersComplete();
|
| + EXPECT_TRUE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + EXPECT_TRUE(client->HasAction("WillBeginImplFrame"));
|
| + // Note: BeginMainFrame and BeginImplFrame are skipped here because
|
| + // of backpressure, not because of latency recovery.
|
| + EXPECT_FALSE(client->HasAction("ScheduledActionSendBeginMainFrame"));
|
| + EXPECT_FALSE(client->HasAction("ScheduledActionDrawAndSwapIfPossible"));
|
| +
|
| + // Lower estimates so that the scheduler will attempt latency recovery.
|
| + client->begin_main_frame_to_commit_duration_ = fast_duration;
|
| + client->commit_to_activate_duration_ = fast_duration;
|
| + client->draw_duration_ = 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();
|
| + EXPECT_TRUE(scheduler_->NeedsCommit()); // Previous commit still outstanding.
|
| + EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_TRUE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + SendNextBeginFrame();
|
| + task_runner().RunPendingTasks(); // Run posted deadline.
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_TRUE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + EXPECT_TRUE(client->HasAction("WillBeginImplFrame"));
|
| + EXPECT_FALSE(client->HasAction("ScheduledActionSendBeginMainFrame"));
|
| + EXPECT_TRUE(client->HasAction("ScheduledActionDrawAndSwapIfPossible"));
|
| +
|
| + // Verify we skip the BeginImplFrame second.
|
| + client->Reset();
|
| + EXPECT_TRUE(scheduler_->NeedsCommit()); // Previous commit still outstanding.
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_TRUE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + SendNextBeginFrame();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_TRUE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + scheduler_->DidSwapBuffersComplete();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + EXPECT_FALSE(client->HasAction("WillBeginImplFrame"));
|
| + EXPECT_FALSE(client->HasAction("ScheduledActionSendBeginMainFrame"));
|
| + EXPECT_FALSE(client->HasAction("ScheduledActionDrawAndSwapIfPossible"));
|
| +
|
| + // Then verify we operate in a low latency mode.
|
| + client->Reset();
|
| + EXPECT_TRUE(scheduler_->NeedsCommit()); // Previous commit still outstanding.
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + SendNextBeginFrame();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + scheduler_->NotifyBeginMainFrameStarted();
|
| + scheduler_->NotifyReadyToCommit();
|
| + task_runner().RunPendingTasks(); // Run posted deadline.
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + scheduler_->DidSwapBuffersComplete();
|
| + EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode());
|
| + EXPECT_FALSE(scheduler_->ImplThreadIsLikelyInHighLatencyMode());
|
| + EXPECT_TRUE(client->HasAction("WillBeginImplFrame"));
|
| + EXPECT_TRUE(client->HasAction("ScheduledActionSendBeginMainFrame"));
|
| + EXPECT_TRUE(client->HasAction("ScheduledActionDrawAndSwapIfPossible"));
|
| +}
|
| +
|
| TEST_F(SchedulerTest, PollForCommitCompletion) {
|
| // 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.
|
| - SchedulerClientWithFixedEstimates* client =
|
| - new SchedulerClientWithFixedEstimates(
|
| + SchedulerClientWithCustomEstimates* client =
|
| + new SchedulerClientWithCustomEstimates(
|
| base::TimeDelta::FromMilliseconds(1),
|
| base::TimeDelta::FromMilliseconds(32),
|
| base::TimeDelta::FromMilliseconds(32));
|
|
|