Index: cc/scheduler/scheduler_unittest.cc |
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc |
index f8a9d3fc68c2e657e4ee3bbd02a18f9cb07df092..e6d9d8a2db6bf8b35ef6cb9702b1b001318a4c2b 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); |
sunnyps
2015/05/22 21:15:05
nit: base::TimeDelta::Max()
brianderson
2015/05/23 00:53:57
Tried this and ended up with test failures - I thi
|
+ } |
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: |
sunnyps
2015/05/22 21:15:05
Why public?
brianderson
2015/05/23 00:53:56
One of the tests changes the settings dynamically
|
base::TimeDelta draw_duration_; |
base::TimeDelta begin_main_frame_to_commit_duration_; |
base::TimeDelta commit_to_activate_duration_; |
@@ -420,6 +425,12 @@ class SchedulerTest : public testing::Test { |
int64 commit_to_activate_estimate_in_ms, |
bool impl_latency_takes_priority, |
bool should_send_begin_main_frame); |
+ void SwapIsHighLatency(int64 draw_estimate_in_ms, |
+ int64 begin_main_frame_to_commit_estimate_in_ms, |
+ int64 commit_to_activate_estimate_in_ms, |
+ bool has_impl_side_updates, |
+ bool swap_ack_before_deadline, |
+ bool should_draw_and_swap_in_high_latency); |
void BeginFramesNotFromClient(bool use_external_begin_frame_source, |
bool throttle_frame_production); |
void BeginFramesNotFromClient_SwapThrottled( |
@@ -486,8 +497,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)); |
@@ -1318,8 +1329,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), |
@@ -1357,29 +1368,255 @@ void SchedulerTest::MainFrameInHighLatencyMode( |
TEST_F(SchedulerTest, |
SkipMainFrameIfHighLatencyAndCanCommitAndActivateBeforeDeadline) { |
// Set up client so that estimates indicate that we can commit and activate |
- // before the deadline (~8ms by default). |
+ // before the deadline (~11ms by default). |
EXPECT_SCOPED(MainFrameInHighLatencyMode(1, 1, false, false)); |
} |
TEST_F(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanCommitTooLong) { |
// Set up client so that estimates indicate that the commit cannot finish |
- // before the deadline (~8ms by default). |
+ // before the deadline (~11ms by default). |
EXPECT_SCOPED(MainFrameInHighLatencyMode(10, 1, false, true)); |
} |
TEST_F(SchedulerTest, NotSkipMainFrameIfHighLatencyAndCanActivateTooLong) { |
// Set up client so that estimates indicate that the activate cannot finish |
- // before the deadline (~8ms by default). |
+ // before the deadline (~11ms by default). |
EXPECT_SCOPED(MainFrameInHighLatencyMode(1, 10, false, true)); |
} |
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 |
+ // before the deadline (~11ms by default), but also enable impl latency takes |
// priority mode. |
EXPECT_SCOPED(MainFrameInHighLatencyMode(1, 1, true, true)); |
} |
+void SchedulerTest::SwapIsHighLatency( |
sunnyps
2015/05/22 21:15:05
nit: ImplFrameInHighLatencyMode or similar? feel f
|
+ int64 draw_estimate_in_ms, |
+ int64 begin_main_frame_to_commit_estimate_in_ms, |
+ int64 commit_to_activate_estimate_in_ms, |
+ bool has_impl_side_updates, |
+ bool swap_ack_before_deadline, |
+ bool should_draw_and_swap_in_high_latency) { |
+ // Set up client with specified estimates. |
+ SchedulerClientWithCustomEstimates* client = |
+ new SchedulerClientWithCustomEstimates( |
+ base::TimeDelta::FromMilliseconds(draw_estimate_in_ms), |
+ 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); |
sunnyps
2015/05/22 21:15:05
No need to call Pass() here.
brianderson
2015/06/30 22:03:52
NA in latest patch set.
|
+ |
+ // To get into a high latency state, this test disables automatic swap acks. |
+ scheduler_->SetMaxSwapsPending(1); |
+ client_->SetAutomaticSwapAck(false); |
sunnyps
2015/05/22 21:15:05
Use either client_ or client consistently. I would
brianderson
2015/06/30 22:03:53
NA in latest patch set.
|
+ |
sunnyps
2015/05/22 21:15:05
Please make these changes to the MainFrameInHighLa
brianderson
2015/06/30 22:03:53
Also NA now.
Looked into using client_ in all sch
|
+ // Draw and swap for first BeginFrame |
+ client->Reset(); |
+ scheduler_->SetNeedsCommit(); |
+ if (has_impl_side_updates) |
+ scheduler_->SetNeedsRedraw(); |
+ EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); |
+ EXPECT_SCOPED(AdvanceFrame()); |
+ scheduler_->NotifyBeginMainFrameStarted(); |
+ scheduler_->NotifyReadyToCommit(); |
+ EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); |
+ task_runner().RunPendingTasks(); // Run posted deadline. |
sunnyps
2015/05/22 21:15:05
nit: RunTasksWhile(deadline)
brianderson
2015/06/30 22:03:53
Done.
|
+ EXPECT_TRUE(client->HasAction("ScheduledActionDrawAndSwapIfPossible")); |
sunnyps
2015/05/22 21:15:06
nit: consider using EXPECT_ACTION
|
+ |
+ // Not calling scheduler_->DidSwapBuffersComplete() until after next frame |
+ // puts impl thread in high latency mode. |
+ client->Reset(); |
+ scheduler_->SetNeedsCommit(); |
+ if (has_impl_side_updates) |
+ scheduler_->SetNeedsRedraw(); |
+ EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); |
sunnyps
2015/05/22 21:15:06
Use SendNextBeginFrame in both cases. Use differen
brianderson
2015/06/30 22:03:52
Done.
|
+ if (should_draw_and_swap_in_high_latency) { |
+ AdvanceFrame(); |
+ } else { |
+ // Don't use AdvanceFrame since we expect the the Scheduler to |
+ // skip the BeginImplFrame. |
+ SendNextBeginFrame(); |
+ EXPECT_FALSE(client->HasAction("WillBeginImplFrame")); |
+ EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending()); |
+ } |
+ EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); |
+ |
+ if (should_draw_and_swap_in_high_latency) { |
+ DCHECK(swap_ack_before_deadline); |
+ scheduler_->DidSwapBuffersComplete(); |
+ scheduler_->NotifyBeginMainFrameStarted(); |
+ scheduler_->NotifyReadyToCommit(); |
+ task_runner().RunPendingTasks(); // Run posted deadline. |
+ } else if (swap_ack_before_deadline) { |
+ scheduler_->DidSwapBuffersComplete(); |
+ task_runner().RunPendingTasks(); // Run posted deadline. |
+ } else { |
+ task_runner().RunPendingTasks(); // Run posted deadline. |
+ scheduler_->DidSwapBuffersComplete(); |
+ } |
+ |
+ // Verify that we recovered immediately if we were supposed to. |
+ EXPECT_EQ(should_draw_and_swap_in_high_latency, |
sunnyps
2015/05/22 21:15:05
Is this meant to be an implication or equality? If
brianderson
2015/06/30 22:03:52
Meant to test equality. Will update comment.
|
+ client->HasAction("ScheduledActionDrawAndSwapIfPossible")); |
+ if (should_draw_and_swap_in_high_latency) |
sunnyps
2015/05/22 21:15:05
nit: Consider combining this and the above expect
brianderson
2015/06/30 22:03:53
Done.
|
+ scheduler_->DidSwapBuffersComplete(); |
+ |
+ // Verify that we: |
+ // 1) Don't skip two frames in a row. |
+ // 2) Continue normal operation if we didn't skip a frame. |
+ // 3) Make forward progress even when we aren't expecting another swap ack. |
+ client->Reset(); |
+ EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); |
sunnyps
2015/05/22 21:15:06
There are a bunch of expectations about MainThread
brianderson
2015/05/23 00:53:56
I was able to check expectations in previous patch
|
+ scheduler_->SetNeedsCommit(); |
+ if (has_impl_side_updates) |
+ scheduler_->SetNeedsRedraw(); |
+ EXPECT_SCOPED(AdvanceFrame()); |
+ scheduler_->NotifyBeginMainFrameStarted(); |
+ scheduler_->NotifyReadyToCommit(); |
+ task_runner().RunPendingTasks(); // Run posted deadline. |
+ EXPECT_TRUE(client->HasAction("ScheduledActionDrawAndSwapIfPossible")); |
+} |
+ |
+TEST_F(SchedulerTest, |
+ SkipSwapIfHighLatencyAndCanDrawBeforeDeadline_SwapAckThenDeadline) { |
+ // Set up client so that estimates indicate that we can commit and activate |
+ // before the deadline (~11ms by default). |
+ EXPECT_SCOPED(SwapIsHighLatency(1, 1, 1, true, true, false)); |
+} |
+ |
+TEST_F(SchedulerTest, |
+ SkipSwapIfHighLatencyAndCanDrawBeforeDeadline_DeadlineThenSwapAck) { |
+ // Set up client so that estimates indicate that we can commit and activate |
+ // before the deadline (~11ms by default). |
+ EXPECT_SCOPED(SwapIsHighLatency(1, 1, 1, true, false, false)); |
+} |
+ |
+TEST_F(SchedulerTest, NotSkipSwapIfHighLatencyAndCanDrawTooLong) { |
+ // Set up client so that estimates indicate that the commit cannot finish |
sunnyps
2015/05/22 21:15:05
the draw cannot finish before the deadline.
brianderson
2015/06/30 22:03:53
Done.
|
+ // before the deadline (~11ms by default). |
+ EXPECT_SCOPED(SwapIsHighLatency(20, 1, 1, true, true, true)); |
+} |
+ |
+TEST_F(SchedulerTest, NotSkipSwapIfHighLatencyAndCanActivateTooLong) { |
+ // Set up client so that estimates indicate that the activate cannot finish |
sunnyps
2015/05/22 21:15:05
commit and activation cannot finish before the dea
brianderson
2015/06/30 22:03:52
Done.
|
+ // before the deadline (~11ms by default). |
+ EXPECT_SCOPED(SwapIsHighLatency(1, 8, 8, false, true, true)); |
+} |
+ |
+TEST_F(SchedulerTest, MainAndSwapInHighLatencyMode) { |
+ // 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); |
sunnyps
2015/05/22 21:15:05
nit: base::TimeDelta instead of auto.
brianderson
2015/06/30 22:03:52
Done.
|
+ 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); |
+ |
+ // 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. |
sunnyps
2015/05/22 21:15:06
nit: RunTasksWhile(deadline) instead of RunPending
brianderson
2015/06/30 22:03:52
Done.
|
+ EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode()); |
+ scheduler_->NotifyBeginMainFrameStarted(); |
+ scheduler_->NotifyReadyToCommit(); |
+ EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode()); |
+ EXPECT_TRUE(client->HasAction("WillBeginImplFrame")); |
sunnyps
2015/05/22 21:15:05
nit: EXPECT_ACTION
|
+ EXPECT_TRUE(client->HasAction("ScheduledActionSendBeginMainFrame")); |
+ |
+ // 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. |
+ 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 put the impl thread in a high latency mode. |
+ client->Reset(); |
+ scheduler_->SetNeedsCommit(); |
+ EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode()); |
+ EXPECT_SCOPED(AdvanceFrame()); |
+ EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode()); |
+ task_runner().RunPendingTasks(); // Run posted deadline. |
+ scheduler_->DidSwapBuffersComplete(); |
+ EXPECT_TRUE(client->HasAction("WillBeginImplFrame")); |
+ // Note: BeginMainFrame and BeginImplFrame are skipped here because |
sunnyps
2015/05/22 21:15:05
You mean Draw and not BeginImplFrame right?
brianderson
2015/06/30 22:03:52
Fixed.
|
+ // 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; |
sunnyps
2015/05/22 21:15:05
nit: Use setters instead of accessing member vars
brianderson
2015/06/30 22:03:53
Done.
|
+ 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. |
sunnyps
2015/05/22 21:15:05
NeedsCommit doesn't mean that previous commit is o
brianderson
2015/06/30 22:03:53
Updated the comment.
|
+ EXPECT_TRUE(scheduler_->MainThreadIsInHighLatencyMode()); |
+ SendNextBeginFrame(); |
+ task_runner().RunPendingTasks(); // Run posted deadline. |
+ EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); |
+ EXPECT_TRUE(client->HasAction("WillBeginImplFrame")); |
+ EXPECT_FALSE(client->HasAction("ScheduledActionSendBeginMainFrame")); |
+ EXPECT_TRUE(client->HasAction("ScheduledActionDrawAndSwapIfPossible")); |
+ |
+ // Verify we skip the DrawAndSwap second. |
+ client->Reset(); |
+ EXPECT_TRUE(scheduler_->NeedsCommit()); // Previous commit still outstanding. |
+ EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); |
+ SendNextBeginFrame(); |
+ task_runner().RunPendingTasks(); // Run posted deadline. |
+ EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); |
+ scheduler_->DidSwapBuffersComplete(); |
+ EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); |
+ 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()); |
+ SendNextBeginFrame(); |
+ EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); |
+ scheduler_->NotifyBeginMainFrameStarted(); |
+ scheduler_->NotifyReadyToCommit(); |
+ task_runner().RunPendingTasks(); // Run posted deadline. |
+ EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); |
+ scheduler_->DidSwapBuffersComplete(); |
+ EXPECT_FALSE(scheduler_->MainThreadIsInHighLatencyMode()); |
+ EXPECT_TRUE(client->HasAction("WillBeginImplFrame")); |
+ EXPECT_TRUE(client->HasAction("ScheduledActionSendBeginMainFrame")); |
+ EXPECT_TRUE(client->HasAction("ScheduledActionDrawAndSwapIfPossible")); |
+} |
+ |
TEST_F(SchedulerTest, |
Deadlock_NotifyReadyToCommitMakesProgressWhileSwapTrottled) { |
// NPAPI plugins on Windows block the Browser UI thread on the Renderer main |
@@ -1390,8 +1627,8 @@ TEST_F(SchedulerTest, |
// 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)); |
@@ -1456,8 +1693,8 @@ TEST_F( |
// 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)); |
@@ -1534,8 +1771,8 @@ TEST_F(SchedulerTest, |
// 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)); |
@@ -1621,8 +1858,8 @@ TEST_F( |
// 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)); |