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

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: rebase; really simplify heuristic Created 5 years, 7 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
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));

Powered by Google App Engine
This is Rietveld 408576698