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.
6 #include "platform/scheduler/Scheduler.h"
8 #include "platform/TestingPlatformSupport.h"
9 #include "platform/TraceLocation.h"
10 #include "public/platform/Platform.h"
11 #include "public/platform/WebThread.h"
13 #include <gmock/gmock.h>
14 #include <gtest/gtest.h>
18 using blink::Scheduler;
22 class SchedulerForTest : public blink::Scheduler {
24 static void initializeOnMainThread()
26 s_sharedScheduler = new SchedulerForTest();
29 using Scheduler::Normal;
30 using Scheduler::CompositorPriority;
31 using Scheduler::enterSchedulerPolicy;
34 class TestMainThread : public blink::WebThread {
36 // blink::WebThread implementation.
37 virtual void postTask(Task* task) OVERRIDE
39 m_pendingTasks.append(adoptPtr(task));
42 virtual void postDelayedTask(Task* task, long long delayMs) OVERRIDE
47 virtual bool isCurrentThread() const OVERRIDE
52 virtual blink::PlatformThreadId threadId() const OVERRIDE
58 virtual void enterRunLoop() OVERRIDE
63 virtual void exitRunLoop() OVERRIDE
68 void runPendingTasks()
70 while (!m_pendingTasks.isEmpty())
71 m_pendingTasks.takeFirst()->run();
74 size_t numPendingMainThreadTasks() const
76 return m_pendingTasks.size();
80 WTF::Deque<OwnPtr<Task> > m_pendingTasks;
83 class SchedulerTestingPlatformSupport : blink::TestingPlatformSupport {
85 SchedulerTestingPlatformSupport()
86 : TestingPlatformSupport(TestingPlatformSupport::Config())
87 , m_sharedTimerFunction(nullptr)
88 , m_sharedTimerRunning(false)
89 , m_sharedTimerFireInterval(0)
90 , m_monotonicallyIncreasingTime(0)
94 // blink::Platform implementation.
95 virtual blink::WebThread* currentThread() OVERRIDE
100 virtual void setSharedTimerFiredFunction(SharedTimerFunction timerFunction) OVERRIDE
102 m_sharedTimerFunction = timerFunction;
105 virtual double monotonicallyIncreasingTime() OVERRIDE
107 return m_monotonicallyIncreasingTime;
110 virtual void setSharedTimerFireInterval(double)
112 m_sharedTimerFireInterval = 0;
113 m_sharedTimerRunning = true;
116 virtual void stopSharedTimer()
118 m_sharedTimerRunning = false;
121 void runPendingTasks()
123 m_mainThread.runPendingTasks();
126 bool sharedTimerRunning() const
128 return m_sharedTimerRunning;
131 double sharedTimerFireInterval() const
133 return m_sharedTimerFireInterval;
136 void triggerSharedTimer()
138 m_sharedTimerFunction();
141 size_t numPendingMainThreadTasks() const
143 return m_mainThread.numPendingMainThreadTasks();
146 void setMonotonicTimeForTest(double time)
148 m_monotonicallyIncreasingTime = time;
152 TestMainThread m_mainThread;
153 SharedTimerFunction m_sharedTimerFunction;
154 bool m_sharedTimerRunning;
155 double m_sharedTimerFireInterval;
156 double m_monotonicallyIncreasingTime;
159 class SchedulerTest : public testing::Test {
162 : m_reentrantCount(0)
165 SchedulerForTest::initializeOnMainThread();
166 m_scheduler = static_cast<SchedulerForTest*>(Scheduler::shared());
171 Scheduler::shutdown();
174 virtual void SetUp() OVERRIDE
176 m_scheduler->enterSchedulerPolicy(SchedulerForTest::Normal);
179 virtual void TearDown() OVERRIDE
181 // If the Scheduler hasn't been shut down then explicitly flush the tasks.
182 if (Scheduler::shared())
186 void runPendingTasks()
188 m_platformSupport.runPendingTasks();
191 void appendToVector(std::string value)
193 m_order.push_back(value);
196 void appendToVectorReentrantTask()
198 m_reentrantOrder.push_back(m_reentrantCount++);
200 if (m_reentrantCount > m_maxRecursion)
202 Scheduler::shared()->postTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVectorReentrantTask, this));
205 void appendToVectorReentrantInputTask()
207 m_reentrantOrder.push_back(m_reentrantCount++);
209 if (m_reentrantCount > m_maxRecursion)
211 m_scheduler->postInputTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVectorReentrantInputTask, this));
214 void appendToVectorReentrantCompositorTask()
216 m_reentrantOrder.push_back(m_reentrantCount++);
218 if (m_reentrantCount > m_maxRecursion)
220 m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVectorReentrantCompositorTask, this));
224 SchedulerTestingPlatformSupport m_platformSupport;
225 SchedulerForTest* m_scheduler;
226 std::vector<std::string> m_order;
227 std::vector<int> m_reentrantOrder;
228 int m_reentrantCount;
232 void orderedTestTask(int value, int* result)
234 *result = (*result << 4) | value;
237 void unorderedTestTask(int value, int* result)
242 void idleTestTask(int value, int* result, double allottedTime)
247 TEST_F(SchedulerTest, TestPostTask)
250 m_scheduler->postTask(FROM_HERE, WTF::bind(&orderedTestTask, 1, &result));
251 m_scheduler->postTask(FROM_HERE, WTF::bind(&orderedTestTask, 2, &result));
252 m_scheduler->postTask(FROM_HERE, WTF::bind(&orderedTestTask, 3, &result));
253 m_scheduler->postTask(FROM_HERE, WTF::bind(&orderedTestTask, 4, &result));
255 EXPECT_EQ(0x1234, result);
258 TEST_F(SchedulerTest, TestPostMixedTaskTypes)
261 m_scheduler->postTask(FROM_HERE, WTF::bind(&unorderedTestTask, 1, &result));
262 m_scheduler->postInputTask(FROM_HERE, WTF::bind(&unorderedTestTask, 2, &result));
263 m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&unorderedTestTask, 4, &result));
264 m_scheduler->postTask(FROM_HERE, WTF::bind(&unorderedTestTask, 8, &result));
265 m_scheduler->postIpcTask(FROM_HERE, WTF::bind(&unorderedTestTask, 16, &result));
267 EXPECT_EQ(31, result);
270 int s_sharedTimerTickCount;
271 void sharedTimerFunction()
273 s_sharedTimerTickCount++;
276 TEST_F(SchedulerTest, TestSharedTimer)
278 s_sharedTimerTickCount = 0;
279 m_scheduler->setSharedTimerFiredFunction(&sharedTimerFunction);
280 EXPECT_FALSE(m_platformSupport.sharedTimerRunning());
281 m_scheduler->setSharedTimerFireInterval(0);
282 EXPECT_TRUE(m_platformSupport.sharedTimerRunning());
284 m_platformSupport.triggerSharedTimer();
285 EXPECT_EQ(1, s_sharedTimerTickCount);
287 m_scheduler->stopSharedTimer();
288 EXPECT_FALSE(m_platformSupport.sharedTimerRunning());
290 m_scheduler->setSharedTimerFiredFunction(nullptr);
291 EXPECT_FALSE(m_platformSupport.sharedTimerRunning());
294 TEST_F(SchedulerTest, TestIdleTask)
296 // TODO: Check task allottedTime when implemented in the scheduler.
298 m_scheduler->postIdleTask(FROM_HERE, WTF::bind<double>(&idleTestTask, 1, &result));
299 m_scheduler->postIdleTask(FROM_HERE, WTF::bind<double>(&idleTestTask, 1, &result));
300 m_scheduler->postIdleTask(FROM_HERE, WTF::bind<double>(&idleTestTask, 1, &result));
301 m_scheduler->postIdleTask(FROM_HERE, WTF::bind<double>(&idleTestTask, 1, &result));
303 EXPECT_EQ(4, result);
306 TEST_F(SchedulerTest, TestTaskPrioritization_normalPolicy)
308 m_scheduler->postTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("L1")));
309 m_scheduler->postTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("L2")));
310 m_scheduler->postInputTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("I1")));
311 m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("C1")));
312 m_scheduler->postInputTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("I2")));
313 m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("C2")));
314 m_scheduler->postIpcTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("IPC")));
317 EXPECT_THAT(m_order, testing::ElementsAre(
318 std::string("L1"), std::string("L2"), std::string("I1"), std::string("C1"), std::string("I2"), std::string("C2"),
319 std::string("IPC")));
322 TEST_F(SchedulerTest, TestTaskPrioritization_compositorPriorityPolicy)
324 m_scheduler->enterSchedulerPolicy(SchedulerForTest::CompositorPriority);
325 m_scheduler->postTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("L1")));
326 m_scheduler->postTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("L2")));
327 m_scheduler->postInputTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("I1")));
328 m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("C1")));
329 m_scheduler->postInputTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("I2")));
330 m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("C2")));
331 m_scheduler->postIpcTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVector, this, std::string("IPC")));
334 EXPECT_THAT(m_order, testing::ElementsAre(
335 std::string("I1"), std::string("C1"), std::string("I2"), std::string("C2"), std::string("L1"), std::string("L2"),
336 std::string("IPC")));
339 TEST_F(SchedulerTest, TestRentrantTask)
341 m_scheduler->postTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVectorReentrantTask, this));
344 EXPECT_THAT(m_reentrantOrder, testing::ElementsAre(0, 1, 2, 3, 4));
348 TEST_F(SchedulerTest, TestRentrantInputTaskDuringShutdown)
350 m_scheduler->postInputTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVectorReentrantInputTask, this));
351 Scheduler::shutdown();
353 EXPECT_THAT(m_reentrantOrder, testing::ElementsAre(0, 1, 2, 3, 4));
356 TEST_F(SchedulerTest, TestRentrantCompositorTaskDuringShutdown)
358 m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVectorReentrantCompositorTask, this));
359 Scheduler::shutdown();
361 EXPECT_THAT(m_reentrantOrder, testing::ElementsAre(0, 1, 2, 3, 4));
364 bool s_shouldContinue;
365 void reentrantInputTask(Scheduler* scheduler)
367 if (s_shouldContinue)
368 scheduler->postInputTask(FROM_HERE, WTF::bind(&reentrantInputTask, scheduler));
371 void reentrantCompositorTask(Scheduler* scheduler)
373 if (s_shouldContinue)
374 scheduler->postCompositorTask(FROM_HERE, WTF::bind(&reentrantCompositorTask, scheduler));
377 void stopReentrantTask()
379 s_shouldContinue = false;
382 TEST_F(SchedulerTest, TestRentrantInputTaskDoesNotStarveOutLowPriorityTask)
384 s_shouldContinue = true;
385 m_scheduler->postInputTask(FROM_HERE, WTF::bind(&reentrantInputTask, m_scheduler));
386 m_scheduler->postTask(FROM_HERE, WTF::bind(&stopReentrantTask));
388 // If starvation occurs then this will never exit.
392 TEST_F(SchedulerTest, TestRentrantCompositorTaskDoesNotStarveOutLowPriorityTask)
394 s_shouldContinue = true;
395 m_scheduler->postInputTask(FROM_HERE, WTF::bind(&reentrantCompositorTask, m_scheduler));
396 m_scheduler->postTask(FROM_HERE, WTF::bind(&stopReentrantTask));
398 // If starvation occurs then this will never exit.
402 int s_dummyTaskCount;
408 TEST_F(SchedulerTest, TestMultipleCallsToPostInputOrCompositorTaskResultsInOnlyOneMainThreadTask)
410 EXPECT_EQ(0U, m_platformSupport.numPendingMainThreadTasks());
412 for (int i = 0; i < 10; i++) {
413 m_scheduler->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
414 m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
417 EXPECT_EQ(1U, m_platformSupport.numPendingMainThreadTasks());
420 TEST_F(SchedulerTest, TestMainThreadTaskLifeCycle)
422 EXPECT_EQ(0U, m_platformSupport.numPendingMainThreadTasks());
424 m_scheduler->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
425 EXPECT_EQ(1U, m_platformSupport.numPendingMainThreadTasks());
428 EXPECT_EQ(0U, m_platformSupport.numPendingMainThreadTasks());
430 m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
431 EXPECT_EQ(1U, m_platformSupport.numPendingMainThreadTasks());
434 EXPECT_EQ(0U, m_platformSupport.numPendingMainThreadTasks());
437 void postDummyInputTask()
439 Scheduler::shared()->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
442 TEST_F(SchedulerTest, HighPriorityTasksOnlyDontRunBecauseOfSharedTimerFiring_InNormalMode)
444 s_dummyTaskCount = 0;
445 m_scheduler->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
446 // Trigger the posting of an input task during execution of the shared timer function.
447 m_scheduler->setSharedTimerFiredFunction(&postDummyInputTask);
448 m_scheduler->setSharedTimerFireInterval(0);
449 m_platformSupport.triggerSharedTimer();
451 EXPECT_EQ(0, s_dummyTaskCount);
454 m_scheduler->stopSharedTimer();
455 m_scheduler->setSharedTimerFiredFunction(nullptr);
458 TEST_F(SchedulerTest, HighPriorityTasksOnlyRunOncePerSharedTimerFiring_InLowSchedulerPolicy)
460 s_dummyTaskCount = 0;
461 m_scheduler->enterSchedulerPolicy(SchedulerForTest::CompositorPriority);
462 m_scheduler->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
463 // Trigger the posting of an input task during execution of the shared timer function.
464 m_scheduler->setSharedTimerFiredFunction(&postDummyInputTask);
465 m_scheduler->setSharedTimerFireInterval(0);
466 m_platformSupport.triggerSharedTimer();
468 EXPECT_EQ(1, s_dummyTaskCount);
471 m_scheduler->stopSharedTimer();
472 m_scheduler->setSharedTimerFiredFunction(nullptr);
475 TEST_F(SchedulerTest, TestInputEventDoesNotTriggerShouldYield_InNormalMode)
477 m_scheduler->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
479 EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
482 TEST_F(SchedulerTest, TestDidReceiveInputEventDoesNotTriggerShouldYield)
484 m_scheduler->didReceiveInputEvent();
486 EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
489 TEST_F(SchedulerTest, TestCompositorTaskDoesNotTriggerShouldYield_InNormalMode)
491 m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
493 EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
496 TEST_F(SchedulerTest, TestIpcTaskDoesNotTriggerShouldYield_InNormalMode)
498 m_scheduler->postIpcTask(FROM_HERE, WTF::bind(&dummyTask));
500 EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
503 TEST_F(SchedulerTest, TestCompositorTaskDoesTriggerShouldYieldAfterDidReceiveInputEvent)
505 m_scheduler->didReceiveInputEvent();
507 ASSERT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
508 m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
510 EXPECT_TRUE(m_scheduler->shouldYieldForHighPriorityWork());
513 TEST_F(SchedulerTest, TestInputTaskDoesTriggerShouldYield_InCompositorPriorityMode)
515 m_scheduler->enterSchedulerPolicy(SchedulerForTest::CompositorPriority);
516 m_scheduler->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
518 EXPECT_TRUE(m_scheduler->shouldYieldForHighPriorityWork());
522 TEST_F(SchedulerTest, TestCompositorTaskDoesTriggerShouldYield_InCompositorPriorityMode)
524 m_scheduler->enterSchedulerPolicy(SchedulerForTest::CompositorPriority);
525 m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
527 EXPECT_TRUE(m_scheduler->shouldYieldForHighPriorityWork());
530 TEST_F(SchedulerTest, TestIpcTaskDoesNotTriggerShouldYield_InCompositorPriorityMode)
532 m_scheduler->enterSchedulerPolicy(SchedulerForTest::CompositorPriority);
533 m_scheduler->postIpcTask(FROM_HERE, WTF::bind(&dummyTask));
535 EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
538 TEST_F(SchedulerTest, testDidReceiveInputEvent_DoesntTriggerLowLatencyModeForLong)
540 m_platformSupport.setMonotonicTimeForTest(1000.0);
542 // Note the latency mode gets reset by executeHighPriorityTasks, so we need a dummy task here
543 // to make sure runPendingTasks triggers executeHighPriorityTasks.
544 m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
545 m_scheduler->didReceiveInputEvent();
546 m_platformSupport.setMonotonicTimeForTest(1000.5);
549 ASSERT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
550 m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
552 EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());