1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/renderer/scheduler/renderer_scheduler_impl.h"
7 #include "base/callback.h"
8 #include "cc/output/begin_frame_args.h"
9 #include "cc/test/ordered_simple_task_runner.h"
10 #include "testing/gmock/include/gmock/gmock.h"
11 #include "testing/gtest/include/gtest/gtest.h"
15 class RendererSchedulerImplForTest : public RendererSchedulerImpl {
17 RendererSchedulerImplForTest(
18 scoped_refptr<cc::OrderedSimpleTaskRunner> task_runner,
19 scoped_refptr<cc::TestNowSource> clock)
20 : RendererSchedulerImpl(task_runner), clock_(clock) {}
21 ~RendererSchedulerImplForTest() override {}
24 base::TimeTicks Now() const override { return clock_->Now(); }
27 scoped_refptr<cc::TestNowSource> clock_;
30 class RendererSchedulerImplTest : public testing::Test {
32 RendererSchedulerImplTest()
33 : clock_(cc::TestNowSource::Create(5000)),
34 mock_task_runner_(new cc::OrderedSimpleTaskRunner(clock_, false)),
35 scheduler_(new RendererSchedulerImplForTest(mock_task_runner_, clock_)),
36 default_task_runner_(scheduler_->DefaultTaskRunner()),
37 compositor_task_runner_(scheduler_->CompositorTaskRunner()),
38 idle_task_runner_(scheduler_->IdleTaskRunner()) {}
39 ~RendererSchedulerImplTest() override {}
41 void RunUntilIdle() { mock_task_runner_->RunUntilIdle(); }
43 void EnableIdleTasks() {
44 scheduler_->WillBeginFrame(
45 cc::BeginFrameArgs::Create(clock_->Now(), base::TimeTicks(),
46 base::TimeDelta::FromMilliseconds(1000)));
47 scheduler_->DidCommitFrameToCompositor();
51 scoped_refptr<cc::TestNowSource> clock_;
52 scoped_refptr<cc::OrderedSimpleTaskRunner> mock_task_runner_;
54 scoped_ptr<RendererSchedulerImpl> scheduler_;
55 scoped_refptr<base::SingleThreadTaskRunner> default_task_runner_;
56 scoped_refptr<base::SingleThreadTaskRunner> compositor_task_runner_;
57 scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner_;
59 DISALLOW_COPY_AND_ASSIGN(RendererSchedulerImplTest);
65 void OrderedTestTask(int value, int* result) {
66 *result = (*result << 4) | value;
69 void UnorderedTestTask(int value, int* result) {
73 void AppendToVectorTestTask(std::vector<std::string>* vector,
75 vector->push_back(value);
78 void AppendToVectorIdleTestTask(std::vector<std::string>* vector,
80 base::TimeTicks deadline) {
81 AppendToVectorTestTask(vector, value);
84 void AppendToVectorReentrantTask(
85 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
86 std::vector<int>* vector,
88 int max_reentrant_count) {
89 vector->push_back((*reentrant_count)++);
90 if (*reentrant_count < max_reentrant_count) {
91 task_runner->PostTask(
92 FROM_HERE, base::Bind(AppendToVectorReentrantTask, task_runner, vector,
93 reentrant_count, max_reentrant_count));
97 void IdleTestTask(bool* task_run,
98 base::TimeTicks* deadline_out,
99 base::TimeTicks deadline) {
100 EXPECT_FALSE(*task_run);
101 *deadline_out = deadline;
105 void RepostingIdleTestTask(
106 scoped_refptr<SingleThreadIdleTaskRunner> idle_task_runner,
108 base::TimeTicks deadline) {
109 if (*run_count == 0) {
110 idle_task_runner->PostIdleTask(
112 base::Bind(&RepostingIdleTestTask, idle_task_runner, run_count));
117 void UpdateClockToDeadlineIdleTestTask(
118 scoped_refptr<cc::TestNowSource> clock,
119 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
121 base::TimeTicks deadline) {
122 clock->SetNow(deadline);
123 // Due to the way in which OrderedSimpleTestRunner orders tasks and the fact
124 // that we updated the time within a task, the delayed pending task to call
125 // EndIdlePeriod will not happen until after a TaskQueueManager DoWork, so
126 // post a normal task here to ensure it runs before the next idle task.
127 task_runner->PostTask(FROM_HERE, base::Bind(NullTask));
131 void PostingYieldingTestTask(
132 RendererSchedulerImpl* scheduler,
133 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
135 bool* should_yield_before,
136 bool* should_yield_after) {
137 *should_yield_before = scheduler->ShouldYieldForHighPriorityWork();
138 task_runner->PostTask(FROM_HERE, base::Bind(NullTask));
139 if (simulate_input) {
140 scheduler->DidReceiveInputEventOnCompositorThread();
142 *should_yield_after = scheduler->ShouldYieldForHighPriorityWork();
145 TEST_F(RendererSchedulerImplTest, TestPostDefaultTask) {
147 default_task_runner_->PostTask(FROM_HERE,
148 base::Bind(OrderedTestTask, 1, &result));
149 default_task_runner_->PostTask(FROM_HERE,
150 base::Bind(OrderedTestTask, 2, &result));
151 default_task_runner_->PostTask(FROM_HERE,
152 base::Bind(OrderedTestTask, 3, &result));
153 default_task_runner_->PostTask(FROM_HERE,
154 base::Bind(OrderedTestTask, 4, &result));
156 EXPECT_EQ(0x1234, result);
159 TEST_F(RendererSchedulerImplTest, TestPostDefaultAndCompositor) {
161 default_task_runner_->PostTask(FROM_HERE,
162 base::Bind(&UnorderedTestTask, 1, &result));
163 compositor_task_runner_->PostTask(FROM_HERE,
164 base::Bind(&UnorderedTestTask, 2, &result));
166 EXPECT_EQ(3, result);
169 TEST_F(RendererSchedulerImplTest, TestRentrantTask) {
171 std::vector<int> order;
172 default_task_runner_->PostTask(
173 FROM_HERE, base::Bind(AppendToVectorReentrantTask, default_task_runner_,
177 EXPECT_THAT(order, testing::ElementsAre(0, 1, 2, 3, 4));
180 TEST_F(RendererSchedulerImplTest, TestPostIdleTask) {
181 bool task_run = false;
182 base::TimeTicks expected_deadline =
183 clock_->Now() + base::TimeDelta::FromMilliseconds(2300);
184 base::TimeTicks deadline_in_task;
186 clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(100));
187 idle_task_runner_->PostIdleTask(
188 FROM_HERE, base::Bind(&IdleTestTask, &task_run, &deadline_in_task));
191 EXPECT_FALSE(task_run); // Shouldn't run yet as no WillBeginFrame.
193 scheduler_->WillBeginFrame(
194 cc::BeginFrameArgs::Create(clock_->Now(), base::TimeTicks(),
195 base::TimeDelta::FromMilliseconds(1000)));
197 EXPECT_FALSE(task_run); // Shouldn't run as no DidCommitFrameToCompositor.
199 clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(1200));
200 scheduler_->DidCommitFrameToCompositor();
202 EXPECT_FALSE(task_run); // We missed the deadline.
204 scheduler_->WillBeginFrame(
205 cc::BeginFrameArgs::Create(clock_->Now(), base::TimeTicks(),
206 base::TimeDelta::FromMilliseconds(1000)));
207 clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(800));
208 scheduler_->DidCommitFrameToCompositor();
210 EXPECT_TRUE(task_run);
211 EXPECT_EQ(expected_deadline, deadline_in_task);
214 TEST_F(RendererSchedulerImplTest, TestRepostingIdleTask) {
217 idle_task_runner_->PostIdleTask(
219 base::Bind(&RepostingIdleTestTask, idle_task_runner_, &run_count));
222 EXPECT_EQ(1, run_count);
224 // Reposted tasks shouldn't run until next idle period.
226 EXPECT_EQ(1, run_count);
230 EXPECT_EQ(2, run_count);
233 TEST_F(RendererSchedulerImplTest, TestIdleTaskExceedsDeadline) {
234 mock_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
237 // Post two UpdateClockToDeadlineIdleTestTask tasks.
238 idle_task_runner_->PostIdleTask(
239 FROM_HERE, base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_,
240 default_task_runner_, &run_count));
241 idle_task_runner_->PostIdleTask(
242 FROM_HERE, base::Bind(&UpdateClockToDeadlineIdleTestTask, clock_,
243 default_task_runner_, &run_count));
247 // Only the first idle task should execute since it's used up the deadline.
248 EXPECT_EQ(1, run_count);
252 // Second task should be run on the next idle period.
253 EXPECT_EQ(2, run_count);
256 TEST_F(RendererSchedulerImplTest, TestDefaultPolicy) {
257 std::vector<std::string> order;
259 idle_task_runner_->PostIdleTask(
261 base::Bind(&AppendToVectorIdleTestTask, &order, std::string("I1")));
262 default_task_runner_->PostTask(
264 base::Bind(&AppendToVectorTestTask, &order, std::string("D1")));
265 compositor_task_runner_->PostTask(
267 base::Bind(&AppendToVectorTestTask, &order, std::string("C1")));
268 default_task_runner_->PostTask(
270 base::Bind(&AppendToVectorTestTask, &order, std::string("D2")));
271 compositor_task_runner_->PostTask(
273 base::Bind(&AppendToVectorTestTask, &order, std::string("C2")));
277 EXPECT_THAT(order, testing::ElementsAre(std::string("D1"), std::string("C1"),
278 std::string("D2"), std::string("C2"),
282 TEST_F(RendererSchedulerImplTest, TestCompositorPolicy) {
283 std::vector<std::string> order;
285 idle_task_runner_->PostIdleTask(
287 base::Bind(&AppendToVectorIdleTestTask, &order, std::string("I1")));
288 default_task_runner_->PostTask(
290 base::Bind(&AppendToVectorTestTask, &order, std::string("D1")));
291 compositor_task_runner_->PostTask(
293 base::Bind(&AppendToVectorTestTask, &order, std::string("C1")));
294 default_task_runner_->PostTask(
296 base::Bind(&AppendToVectorTestTask, &order, std::string("D2")));
297 compositor_task_runner_->PostTask(
299 base::Bind(&AppendToVectorTestTask, &order, std::string("C2")));
301 scheduler_->DidReceiveInputEventOnCompositorThread();
304 EXPECT_THAT(order, testing::ElementsAre(std::string("C1"), std::string("C2"),
305 std::string("D1"), std::string("D2"),
309 TEST_F(RendererSchedulerImplTest,
310 TestCompositorPolicyDoesNotStarveDefaultTasks) {
311 std::vector<std::string> order;
313 default_task_runner_->PostTask(
315 base::Bind(&AppendToVectorTestTask, &order, std::string("D1")));
316 compositor_task_runner_->PostTask(
318 base::Bind(&AppendToVectorTestTask, &order, std::string("C1")));
319 for (int i = 0; i < 20; i++) {
320 compositor_task_runner_->PostTask(FROM_HERE, base::Bind(&NullTask));
322 compositor_task_runner_->PostTask(
324 base::Bind(&AppendToVectorTestTask, &order, std::string("C2")));
326 scheduler_->DidReceiveInputEventOnCompositorThread();
328 // Ensure that the default D1 task gets to run at some point before the final
329 // C2 compositor task.
330 EXPECT_THAT(order, testing::ElementsAre(std::string("C1"), std::string("D1"),
334 TEST_F(RendererSchedulerImplTest, TestCompositorPolicyEnds) {
335 std::vector<std::string> order;
337 default_task_runner_->PostTask(
339 base::Bind(&AppendToVectorTestTask, &order, std::string("D1")));
340 compositor_task_runner_->PostTask(
342 base::Bind(&AppendToVectorTestTask, &order, std::string("C1")));
343 default_task_runner_->PostTask(
345 base::Bind(&AppendToVectorTestTask, &order, std::string("D2")));
346 compositor_task_runner_->PostTask(
348 base::Bind(&AppendToVectorTestTask, &order, std::string("C2")));
350 scheduler_->DidReceiveInputEventOnCompositorThread();
353 testing::ElementsAre(std::string("C1"), std::string("C2"),
354 std::string("D1"), std::string("D2")));
357 clock_->AdvanceNow(base::TimeDelta::FromMilliseconds(1000));
359 default_task_runner_->PostTask(
361 base::Bind(&AppendToVectorTestTask, &order, std::string("D1")));
362 compositor_task_runner_->PostTask(
364 base::Bind(&AppendToVectorTestTask, &order, std::string("C1")));
365 default_task_runner_->PostTask(
367 base::Bind(&AppendToVectorTestTask, &order, std::string("D2")));
368 compositor_task_runner_->PostTask(
370 base::Bind(&AppendToVectorTestTask, &order, std::string("C2")));
372 // Compositor policy mode should have ended now that the clock has advanced.
375 testing::ElementsAre(std::string("D1"), std::string("C1"),
376 std::string("D2"), std::string("C2")));
379 TEST_F(RendererSchedulerImplTest, TestShouldYield) {
380 bool should_yield_before = false;
381 bool should_yield_after = false;
383 default_task_runner_->PostTask(
384 FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(),
385 default_task_runner_, false, &should_yield_before,
386 &should_yield_after));
388 // Posting to default runner shouldn't cause yielding.
389 EXPECT_FALSE(should_yield_before);
390 EXPECT_FALSE(should_yield_after);
392 default_task_runner_->PostTask(
393 FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(),
394 compositor_task_runner_, false,
395 &should_yield_before, &should_yield_after));
397 // Posting while not in compositor priority shouldn't cause yielding.
398 EXPECT_FALSE(should_yield_before);
399 EXPECT_FALSE(should_yield_after);
401 default_task_runner_->PostTask(
402 FROM_HERE, base::Bind(&PostingYieldingTestTask, scheduler_.get(),
403 compositor_task_runner_, true, &should_yield_before,
404 &should_yield_after));
406 // We should be able to switch to compositor priority mid-task.
407 EXPECT_FALSE(should_yield_before);
408 EXPECT_TRUE(should_yield_after);
411 } // namespace content