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

Unified Diff: content/renderer/scheduler/renderer_scheduler_impl_unittest.cc

Issue 664963002: content: Add RendererScheduler. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update comments Created 6 years, 1 month 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: content/renderer/scheduler/renderer_scheduler_impl_unittest.cc
diff --git a/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc b/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..701a222c71ed724c974382bfff62e9509a68bfe9
--- /dev/null
+++ b/content/renderer/scheduler/renderer_scheduler_impl_unittest.cc
@@ -0,0 +1,411 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/renderer/scheduler/renderer_scheduler_impl.h"
+
+#include "base/callback.h"
+#include "cc/output/begin_frame_args.h"
+#include "cc/test/ordered_simple_task_runner.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace content {
+
+class RendererSchedulerImplForTest : public RendererSchedulerImpl {
+ public:
+ RendererSchedulerImplForTest(
+ scoped_refptr<cc::OrderedSimpleTaskRunner> task_runner,
+ scoped_refptr<cc::TestNowSource> clock)
+ : RendererSchedulerImpl(task_runner), clock_(clock) {}
+ ~RendererSchedulerImplForTest() override {}
+
+ protected:
+ base::TimeTicks Now() const override { return clock_->Now(); }
+
+ private:
+ scoped_refptr<cc::TestNowSource> clock_;
+};
+
+class RendererSchedulerImplTest : public testing::Test {
+ public:
+ RendererSchedulerImplTest()
+ : clock_(cc::TestNowSource::Create(5000)),
+ mock_task_runner_(new cc::OrderedSimpleTaskRunner(clock_, false)),
+ scheduler_(new RendererSchedulerImplForTest(mock_task_runner_, clock_)),
+ default_task_runner_(scheduler_->DefaultTaskRunner()),
+ compositor_task_runner_(scheduler_->CompositorTaskRunner()),
+ idle_task_runner_(scheduler_->IdleTaskRunner()) {}
+ ~RendererSchedulerImplTest() override {}
+
+ void RunUntilIdle() { mock_task_runner_->RunUntilIdle(); }
+
+ void EnableIdleTasks() {
+ scheduler_->WillBeginFrame(
+ cc::BeginFrameArgs::Create(clock_->Now(), base::TimeTicks(),
+ base::TimeDelta::FromMilliseconds(1000)));
+ scheduler_->DidCommitFrameToCompositor();
+ }
+
+ protected:
+ scoped_refptr<cc::TestNowSource> clock_;
+ scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
+
+ scoped_ptr<RendererSchedulerImpl> scheduler_;
+ scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
+ scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
+
+ DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImplTest);
+};
+
+void NullTask() {
+}
+
+void OrderedTestTask(int value, int* result) {
+ *result = (*result << 4) | value;
+}
+
+void UnorderedTestTask(int value, int* result) {
+ *result += value;
+}
+
+void AppendToVectorTestTask(std::vector<std::string>* vector,
+ std::string value) {
+ vector->push_back(value);
+}
+
+void AppendToVectorIdleTestTask(std::vector<std::string>* vector,
+ std::string value,
+ base::TimeTicks deadline) {
+ AppendToVectorTestTask(vector, value);
+}
+
+void AppendToVectorReentrantTask(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ std::vector<int>* vector,
+ int* reentrant_count,
+ int max_reentrant_count) {
+ vector->push_back((*reentrant_count)++);
+ if (*reentrant_count < max_reentrant_count) {
+ task_runner->PostTask(
+ FROM_HERE, base::Bind(AppendToVectorReentrantTask, task_runner, vector,
+ reentrant_count, max_reentrant_count));
+ }
+}
+
+void IdleTestTask(bool* task_run,
+ base::TimeTicks* deadline_out,
+ base::TimeTicks deadline) {
+ EXPECT_FALSE(*task_run);
+ *deadline_out = deadline;
+ *task_run = true;
+}
+
+void RepostingIdleTestTask(
+ scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner,
+ int* run_count,
+ base::TimeTicks deadline) {
+ if (*run_count == 0) {
+ idle_task_runner->PostIdleTask(
+ FROM_HERE,
+ base::Bind(&RepostingIdleTestTask, idle_task_runner, run_count));
+ }
+ (*run_count)++;
+}
+
+void UpdateClockToDeadlineIdleTestTask(
+ scoped_refptr<cc::TestNowSource> clock,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ int* run_count,
+ base::TimeTicks deadline) {
+ clock->SetNow(deadline);
+ // Due to the way in which OrderedSimpleTestRunner orders tasks and the fact
+ // that we updated the time within a task, the delayed pending task to call
+ // EndIdlePeriod will not happen until after a TaskQueueManager DoWork, so
+ // post a normal task here to ensure it runs before the next idle task.
+ task_runner->PostTask(FROM_HERE, base::Bind(NullTask));
+ (*run_count)++;
+}
+
+void PostingYieldingTestTask(
+ RendererSchedulerImpl* scheduler,
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ bool simulate_input,
+ bool* should_yield_before,
+ bool* should_yield_after) {
+ *should_yield_before = scheduler->ShouldYieldForHighPriorityWork();
+ task_runner->PostTask(FROM_HERE, base::Bind(NullTask));
+ if (simulate_input) {
+ scheduler->DidReceiveInputEventOnCompositorThread();
+ }
+ *should_yield_after = scheduler->ShouldYieldForHighPriorityWork();
+}
+
+TEST_F(RendererSchedulerImplTest, TestPostDefaultTask) {
+ int result = 0;
+ default_task_runner_->PostTask(FROM_HERE,
+ base::Bind(OrderedTestTask, 1, &result));
+ default_task_runner_->PostTask(FROM_HERE,
+ base::Bind(OrderedTestTask, 2, &result));
+ default_task_runner_->PostTask(FROM_HERE,
+ base::Bind(OrderedTestTask, 3, &result));
+ default_task_runner_->PostTask(FROM_HERE,
+ base::Bind(OrderedTestTask, 4, &result));
+ RunUntilIdle();
+ EXPECT_EQ(0x1234, result);
+}
+
+TEST_F(RendererSchedulerImplTest, TestPostDefaultAndCompositor) {
+ int result = 0;
+ default_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&UnorderedTestTask, 1, &result));
+ compositor_task_runner_->PostTask(FROM_HERE,
+ base::Bind(&UnorderedTestTask, 2, &result));
+ RunUntilIdle();
+ EXPECT_EQ(3, result);
+}
+
+TEST_F(RendererSchedulerImplTest, TestRentrantTask) {
+ int count = 0;
+ std::vector<int> order;
+ default_task_runner_->PostTask(
+ FROM_HERE, base::Bind(AppendToVectorReentrantTask, default_task_runner_,
+ &order, &count, 5));
+ RunUntilIdle();
+
+ EXPECT_THAT(order, testing::ElementsAre(0, 1, 2, 3, 4));
+}
+
+TEST_F(RendererSchedulerImplTest, TestPostIdleTask) {
+ bool task_run = false;
+ base::TimeTicks expected_deadline =
+ clock_->Now() + base::TimeDelta::FromMilliseconds(2300);
+ base::TimeTicks deadline_in_task;
+
+ clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(100));
+ idle_task_runner_->PostIdleTask(
+ FROM_HERE, base::Bind(&IdleTestTask, &task_run, &deadline_in_task));
+
+ RunUntilIdle();
+ EXPECT_FALSE(task_run); // Shouldn't run yet as no WillBeginFrame.
+
+ scheduler_->WillBeginFrame(
+ cc::BeginFrameArgs::Create(clock_->Now(), base::TimeTicks(),
+ base::TimeDelta::FromMilliseconds(1000)));
+ RunUntilIdle();
+ EXPECT_FALSE(task_run); // Shouldn't run as no DidCommitFrameToCompositor.
+
+ clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(1200));
+ scheduler_->DidCommitFrameToCompositor();
+ RunUntilIdle();
+ EXPECT_FALSE(task_run); // We missed the deadline.
+
+ scheduler_->WillBeginFrame(
+ cc::BeginFrameArgs::Create(clock_->Now(), base::TimeTicks(),
+ base::TimeDelta::FromMilliseconds(1000)));
+ clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(800));
+ scheduler_->DidCommitFrameToCompositor();
+ RunUntilIdle();
+ EXPECT_TRUE(task_run);
+ EXPECT_EQ(expected_deadline, deadline_in_task);
+}
+
+TEST_F(RendererSchedulerImplTest, TestRepostingIdleTask) {
+ int run_count = 0;
+
+ idle_task_runner_->PostIdleTask(
+ FROM_HERE,
+ base::Bind(&RepostingIdleTestTask, idle_task_runner_, &run_count));
+ EnableIdleTasks();
+ RunUntilIdle();
+ EXPECT_EQ(1, run_count);
+
+ // Reposted tasks shouldn't run until next idle period.
+ RunUntilIdle();
+ EXPECT_EQ(1, run_count);
+
+ EnableIdleTasks();
+ RunUntilIdle();
+ EXPECT_EQ(2, run_count);
+}
+
+TEST_F(RendererSchedulerImplTest, TestIdleTaskExceedsDeadline) {
+ mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
+ int run_count = 0;
+
+ // Post two UpdateClockToDeadlineIdleTestTask tasks.
+ idle_task_runner_->PostIdleTask(
+ FROM_HERE, base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_,
+ default_task_runner_, &run_count));
+ idle_task_runner_->PostIdleTask(
+ FROM_HERE, base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_,
+ default_task_runner_, &run_count));
+
+ EnableIdleTasks();
+ RunUntilIdle();
+ // Only the first idle task should execute since it's used up the deadline.
+ EXPECT_EQ(1, run_count);
+
+ EnableIdleTasks();
+ RunUntilIdle();
+ // Second task should be run on the next idle period.
+ EXPECT_EQ(2, run_count);
+}
+
+TEST_F(RendererSchedulerImplTest, TestDefaultPolicy) {
+ std::vector<std::string> order;
+
+ idle_task_runner_->PostIdleTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorIdleTestTask, &order, std::string("I1")));
+ default_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("D1")));
+ compositor_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("C1")));
+ default_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("D2")));
+ compositor_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("C2")));
+
+ EnableIdleTasks();
+ RunUntilIdle();
+ EXPECT_THAT(order, testing::ElementsAre(std::string("D1"), std::string("C1"),
+ std::string("D2"), std::string("C2"),
+ std::string("I1")));
+}
+
+TEST_F(RendererSchedulerImplTest, TestCompositorPolicy) {
+ std::vector<std::string> order;
+
+ idle_task_runner_->PostIdleTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorIdleTestTask, &order, std::string("I1")));
+ default_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("D1")));
+ compositor_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("C1")));
+ default_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("D2")));
+ compositor_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("C2")));
+
+ scheduler_->DidReceiveInputEventOnCompositorThread();
+ EnableIdleTasks();
+ RunUntilIdle();
+ EXPECT_THAT(order, testing::ElementsAre(std::string("C1"), std::string("C2"),
+ std::string("D1"), std::string("D2"),
+ std::string("I1")));
+}
+
+TEST_F(RendererSchedulerImplTest,
+ TestCompositorPolicyDoesNotStarveDefaultTasks) {
+ std::vector<std::string> order;
+
+ default_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("D1")));
+ compositor_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("C1")));
+ for (int i = 0; i < 20; i++) {
+ compositor_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask));
+ }
+ compositor_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("C2")));
+
+ scheduler_->DidReceiveInputEventOnCompositorThread();
+ RunUntilIdle();
+ // Ensure that the default D1 task gets to run at some point before the final
+ // C2 compositor task.
+ EXPECT_THAT(order, testing::ElementsAre(std::string("C1"), std::string("D1"),
+ std::string("C2")));
+}
+
+TEST_F(RendererSchedulerImplTest, TestCompositorPolicyEnds) {
+ std::vector<std::string> order;
+
+ default_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("D1")));
+ compositor_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("C1")));
+ default_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("D2")));
+ compositor_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("C2")));
+
+ scheduler_->DidReceiveInputEventOnCompositorThread();
+ RunUntilIdle();
+ EXPECT_THAT(order,
+ testing::ElementsAre(std::string("C1"), std::string("C2"),
+ std::string("D1"), std::string("D2")));
+
+ order.clear();
+ clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(1000));
+
+ default_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("D1")));
+ compositor_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("C1")));
+ default_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("D2")));
+ compositor_task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&AppendToVectorTestTask, &order, std::string("C2")));
+
+ // Compositor policy mode should have ended now that the clock has advanced.
+ RunUntilIdle();
+ EXPECT_THAT(order,
+ testing::ElementsAre(std::string("D1"), std::string("C1"),
+ std::string("D2"), std::string("C2")));
+}
+
+TEST_F(RendererSchedulerImplTest, TestShouldYield) {
+ bool should_yield_before = false;
+ bool should_yield_after = false;
+
+ default_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(),
+ default_task_runner_, false, &should_yield_before,
+ &should_yield_after));
+ RunUntilIdle();
+ // Posting to default runner shouldn't cause yielding.
+ EXPECT_FALSE(should_yield_before);
+ EXPECT_FALSE(should_yield_after);
+
+ default_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(),
+ compositor_task_runner_, false,
+ &should_yield_before, &should_yield_after));
+ RunUntilIdle();
+ // Posting while not in compositor priority shouldn't cause yielding.
+ EXPECT_FALSE(should_yield_before);
+ EXPECT_FALSE(should_yield_after);
+
+ default_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(),
+ compositor_task_runner_, true, &should_yield_before,
+ &should_yield_after));
+ RunUntilIdle();
+ // We should be able to switch to compositor priority mid-task.
+ EXPECT_FALSE(should_yield_before);
+ EXPECT_TRUE(should_yield_after);
+}
+
+} // namespace content
« no previous file with comments | « content/renderer/scheduler/renderer_scheduler_impl.cc ('k') | content/renderer/scheduler/single_thread_idle_task_runner.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698