Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / scheduler / SchedulerTest.cpp
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.
4
5 #include "config.h"
6 #include "platform/scheduler/Scheduler.h"
7
8 #include "platform/TestingPlatformSupport.h"
9 #include "platform/TraceLocation.h"
10 #include "public/platform/Platform.h"
11 #include "public/platform/WebThread.h"
12
13 #include <gmock/gmock.h>
14 #include <gtest/gtest.h>
15 #include <string>
16 #include <vector>
17
18 using blink::Scheduler;
19
20 namespace {
21
22 class SchedulerForTest : public blink::Scheduler {
23 public:
24     static void initializeOnMainThread()
25     {
26         s_sharedScheduler = new SchedulerForTest();
27     }
28
29     using Scheduler::Normal;
30     using Scheduler::CompositorPriority;
31     using Scheduler::enterSchedulerPolicy;
32 };
33
34 class TestMainThread : public blink::WebThread {
35 public:
36     // blink::WebThread implementation.
37     virtual void postTask(Task* task) OVERRIDE
38     {
39         m_pendingTasks.append(adoptPtr(task));
40     }
41
42     virtual void postDelayedTask(Task* task, long long delayMs) OVERRIDE
43     {
44         ASSERT_NOT_REACHED();
45     }
46
47     virtual bool isCurrentThread() const OVERRIDE
48     {
49         return true;
50     }
51
52     virtual blink::PlatformThreadId threadId() const OVERRIDE
53     {
54         ASSERT_NOT_REACHED();
55         return 0;
56     }
57
58     virtual void enterRunLoop() OVERRIDE
59     {
60         ASSERT_NOT_REACHED();
61     }
62
63     virtual void exitRunLoop() OVERRIDE
64     {
65         ASSERT_NOT_REACHED();
66     }
67
68     void runPendingTasks()
69     {
70         while (!m_pendingTasks.isEmpty())
71             m_pendingTasks.takeFirst()->run();
72     }
73
74     size_t numPendingMainThreadTasks() const
75     {
76         return m_pendingTasks.size();
77     }
78
79 private:
80     WTF::Deque<OwnPtr<Task> > m_pendingTasks;
81 };
82
83 class SchedulerTestingPlatformSupport : blink::TestingPlatformSupport {
84 public:
85     SchedulerTestingPlatformSupport()
86         : TestingPlatformSupport(TestingPlatformSupport::Config())
87         , m_sharedTimerFunction(nullptr)
88         , m_sharedTimerRunning(false)
89         , m_sharedTimerFireInterval(0)
90         , m_monotonicallyIncreasingTime(0)
91     {
92     }
93
94     // blink::Platform implementation.
95     virtual blink::WebThread* currentThread() OVERRIDE
96     {
97         return &m_mainThread;
98     }
99
100     virtual void setSharedTimerFiredFunction(SharedTimerFunction timerFunction) OVERRIDE
101     {
102         m_sharedTimerFunction = timerFunction;
103     }
104
105     virtual double monotonicallyIncreasingTime() OVERRIDE
106     {
107         return m_monotonicallyIncreasingTime;
108     }
109
110     virtual void setSharedTimerFireInterval(double)
111     {
112         m_sharedTimerFireInterval = 0;
113         m_sharedTimerRunning = true;
114     }
115
116     virtual void stopSharedTimer()
117     {
118         m_sharedTimerRunning = false;
119     }
120
121     void runPendingTasks()
122     {
123         m_mainThread.runPendingTasks();
124     }
125
126     bool sharedTimerRunning() const
127     {
128         return m_sharedTimerRunning;
129     }
130
131     double sharedTimerFireInterval() const
132     {
133         return m_sharedTimerFireInterval;
134     }
135
136     void triggerSharedTimer()
137     {
138         m_sharedTimerFunction();
139     }
140
141     size_t numPendingMainThreadTasks() const
142     {
143         return m_mainThread.numPendingMainThreadTasks();
144     }
145
146     void setMonotonicTimeForTest(double time)
147     {
148         m_monotonicallyIncreasingTime = time;
149     }
150
151 private:
152     TestMainThread m_mainThread;
153     SharedTimerFunction m_sharedTimerFunction;
154     bool m_sharedTimerRunning;
155     double m_sharedTimerFireInterval;
156     double m_monotonicallyIncreasingTime;
157 };
158
159 class SchedulerTest : public testing::Test {
160 public:
161     SchedulerTest()
162         : m_reentrantCount(0)
163         , m_maxRecursion(4)
164     {
165         SchedulerForTest::initializeOnMainThread();
166         m_scheduler = static_cast<SchedulerForTest*>(Scheduler::shared());
167     }
168
169     ~SchedulerTest()
170     {
171         Scheduler::shutdown();
172     }
173
174     virtual void SetUp() OVERRIDE
175     {
176         m_scheduler->enterSchedulerPolicy(SchedulerForTest::Normal);
177     }
178
179     virtual void TearDown() OVERRIDE
180     {
181         // If the Scheduler hasn't been shut down then explicitly flush the tasks.
182         if (Scheduler::shared())
183             runPendingTasks();
184     }
185
186     void runPendingTasks()
187     {
188         m_platformSupport.runPendingTasks();
189     }
190
191     void appendToVector(std::string value)
192     {
193         m_order.push_back(value);
194     }
195
196     void appendToVectorReentrantTask()
197     {
198         m_reentrantOrder.push_back(m_reentrantCount++);
199
200         if (m_reentrantCount > m_maxRecursion)
201             return;
202         Scheduler::shared()->postTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVectorReentrantTask, this));
203     }
204
205     void appendToVectorReentrantInputTask()
206     {
207         m_reentrantOrder.push_back(m_reentrantCount++);
208
209         if (m_reentrantCount > m_maxRecursion)
210             return;
211         m_scheduler->postInputTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVectorReentrantInputTask, this));
212     }
213
214     void appendToVectorReentrantCompositorTask()
215     {
216         m_reentrantOrder.push_back(m_reentrantCount++);
217
218         if (m_reentrantCount > m_maxRecursion)
219             return;
220         m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVectorReentrantCompositorTask, this));
221     }
222
223 protected:
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;
229     int m_maxRecursion;
230 };
231
232 void orderedTestTask(int value, int* result)
233 {
234     *result = (*result << 4) | value;
235 }
236
237 void unorderedTestTask(int value, int* result)
238 {
239     *result += value;
240 }
241
242 void idleTestTask(int value, int* result, double allottedTime)
243 {
244     *result += value;
245 }
246
247 TEST_F(SchedulerTest, TestPostTask)
248 {
249     int result = 0;
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));
254     runPendingTasks();
255     EXPECT_EQ(0x1234, result);
256 }
257
258 TEST_F(SchedulerTest, TestPostMixedTaskTypes)
259 {
260     int result = 0;
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));
266     runPendingTasks();
267     EXPECT_EQ(31, result);
268 }
269
270 int s_sharedTimerTickCount;
271 void sharedTimerFunction()
272 {
273     s_sharedTimerTickCount++;
274 }
275
276 TEST_F(SchedulerTest, TestSharedTimer)
277 {
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());
283
284     m_platformSupport.triggerSharedTimer();
285     EXPECT_EQ(1, s_sharedTimerTickCount);
286
287     m_scheduler->stopSharedTimer();
288     EXPECT_FALSE(m_platformSupport.sharedTimerRunning());
289
290     m_scheduler->setSharedTimerFiredFunction(nullptr);
291     EXPECT_FALSE(m_platformSupport.sharedTimerRunning());
292 }
293
294 TEST_F(SchedulerTest, TestIdleTask)
295 {
296     // TODO: Check task allottedTime when implemented in the scheduler.
297     int result = 0;
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));
302     runPendingTasks();
303     EXPECT_EQ(4, result);
304 }
305
306 TEST_F(SchedulerTest, TestTaskPrioritization_normalPolicy)
307 {
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")));
315
316     runPendingTasks();
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")));
320 }
321
322 TEST_F(SchedulerTest, TestTaskPrioritization_compositorPriorityPolicy)
323 {
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")));
332
333     runPendingTasks();
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")));
337 }
338
339 TEST_F(SchedulerTest, TestRentrantTask)
340 {
341     m_scheduler->postTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVectorReentrantTask, this));
342     runPendingTasks();
343
344     EXPECT_THAT(m_reentrantOrder, testing::ElementsAre(0, 1, 2, 3, 4));
345 }
346
347
348 TEST_F(SchedulerTest, TestRentrantInputTaskDuringShutdown)
349 {
350     m_scheduler->postInputTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVectorReentrantInputTask, this));
351     Scheduler::shutdown();
352
353     EXPECT_THAT(m_reentrantOrder, testing::ElementsAre(0, 1, 2, 3, 4));
354 }
355
356 TEST_F(SchedulerTest, TestRentrantCompositorTaskDuringShutdown)
357 {
358     m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&SchedulerTest::appendToVectorReentrantCompositorTask, this));
359     Scheduler::shutdown();
360
361     EXPECT_THAT(m_reentrantOrder, testing::ElementsAre(0, 1, 2, 3, 4));
362 }
363
364 bool s_shouldContinue;
365 void reentrantInputTask(Scheduler* scheduler)
366 {
367     if (s_shouldContinue)
368         scheduler->postInputTask(FROM_HERE, WTF::bind(&reentrantInputTask, scheduler));
369 }
370
371 void reentrantCompositorTask(Scheduler* scheduler)
372 {
373     if (s_shouldContinue)
374         scheduler->postCompositorTask(FROM_HERE, WTF::bind(&reentrantCompositorTask, scheduler));
375 }
376
377 void stopReentrantTask()
378 {
379     s_shouldContinue = false;
380 }
381
382 TEST_F(SchedulerTest, TestRentrantInputTaskDoesNotStarveOutLowPriorityTask)
383 {
384     s_shouldContinue = true;
385     m_scheduler->postInputTask(FROM_HERE, WTF::bind(&reentrantInputTask, m_scheduler));
386     m_scheduler->postTask(FROM_HERE, WTF::bind(&stopReentrantTask));
387
388     // If starvation occurs then this will never exit.
389     runPendingTasks();
390 }
391
392 TEST_F(SchedulerTest, TestRentrantCompositorTaskDoesNotStarveOutLowPriorityTask)
393 {
394     s_shouldContinue = true;
395     m_scheduler->postInputTask(FROM_HERE, WTF::bind(&reentrantCompositorTask, m_scheduler));
396     m_scheduler->postTask(FROM_HERE, WTF::bind(&stopReentrantTask));
397
398     // If starvation occurs then this will never exit.
399     runPendingTasks();
400 }
401
402 int s_dummyTaskCount;
403 void dummyTask()
404 {
405     s_dummyTaskCount++;
406 }
407
408 TEST_F(SchedulerTest, TestMultipleCallsToPostInputOrCompositorTaskResultsInOnlyOneMainThreadTask)
409 {
410     EXPECT_EQ(0U, m_platformSupport.numPendingMainThreadTasks());
411
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));
415     }
416
417     EXPECT_EQ(1U, m_platformSupport.numPendingMainThreadTasks());
418 }
419
420 TEST_F(SchedulerTest, TestMainThreadTaskLifeCycle)
421 {
422     EXPECT_EQ(0U, m_platformSupport.numPendingMainThreadTasks());
423
424     m_scheduler->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
425     EXPECT_EQ(1U, m_platformSupport.numPendingMainThreadTasks());
426
427     runPendingTasks();
428     EXPECT_EQ(0U, m_platformSupport.numPendingMainThreadTasks());
429
430     m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
431     EXPECT_EQ(1U, m_platformSupport.numPendingMainThreadTasks());
432
433     runPendingTasks();
434     EXPECT_EQ(0U, m_platformSupport.numPendingMainThreadTasks());
435 }
436
437 void postDummyInputTask()
438 {
439     Scheduler::shared()->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
440 }
441
442 TEST_F(SchedulerTest, HighPriorityTasksOnlyDontRunBecauseOfSharedTimerFiring_InNormalMode)
443 {
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();
450
451     EXPECT_EQ(0, s_dummyTaskCount);
452
453     // Clean up.
454     m_scheduler->stopSharedTimer();
455     m_scheduler->setSharedTimerFiredFunction(nullptr);
456 }
457
458 TEST_F(SchedulerTest, HighPriorityTasksOnlyRunOncePerSharedTimerFiring_InLowSchedulerPolicy)
459 {
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();
467
468     EXPECT_EQ(1, s_dummyTaskCount);
469
470     // Clean up.
471     m_scheduler->stopSharedTimer();
472     m_scheduler->setSharedTimerFiredFunction(nullptr);
473 }
474
475 TEST_F(SchedulerTest, TestInputEventDoesNotTriggerShouldYield_InNormalMode)
476 {
477     m_scheduler->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
478
479     EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
480 }
481
482 TEST_F(SchedulerTest, TestDidReceiveInputEventDoesNotTriggerShouldYield)
483 {
484     m_scheduler->didReceiveInputEvent();
485
486     EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
487 }
488
489 TEST_F(SchedulerTest, TestCompositorTaskDoesNotTriggerShouldYield_InNormalMode)
490 {
491     m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
492
493     EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
494 }
495
496 TEST_F(SchedulerTest, TestIpcTaskDoesNotTriggerShouldYield_InNormalMode)
497 {
498     m_scheduler->postIpcTask(FROM_HERE, WTF::bind(&dummyTask));
499
500     EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
501 }
502
503 TEST_F(SchedulerTest, TestCompositorTaskDoesTriggerShouldYieldAfterDidReceiveInputEvent)
504 {
505     m_scheduler->didReceiveInputEvent();
506
507     ASSERT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
508     m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
509
510     EXPECT_TRUE(m_scheduler->shouldYieldForHighPriorityWork());
511 }
512
513 TEST_F(SchedulerTest, TestInputTaskDoesTriggerShouldYield_InCompositorPriorityMode)
514 {
515     m_scheduler->enterSchedulerPolicy(SchedulerForTest::CompositorPriority);
516     m_scheduler->postInputTask(FROM_HERE, WTF::bind(&dummyTask));
517
518     EXPECT_TRUE(m_scheduler->shouldYieldForHighPriorityWork());
519 }
520
521
522 TEST_F(SchedulerTest, TestCompositorTaskDoesTriggerShouldYield_InCompositorPriorityMode)
523 {
524     m_scheduler->enterSchedulerPolicy(SchedulerForTest::CompositorPriority);
525     m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
526
527     EXPECT_TRUE(m_scheduler->shouldYieldForHighPriorityWork());
528 }
529
530 TEST_F(SchedulerTest, TestIpcTaskDoesNotTriggerShouldYield_InCompositorPriorityMode)
531 {
532     m_scheduler->enterSchedulerPolicy(SchedulerForTest::CompositorPriority);
533     m_scheduler->postIpcTask(FROM_HERE, WTF::bind(&dummyTask));
534
535     EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
536 }
537
538 TEST_F(SchedulerTest, testDidReceiveInputEvent_DoesntTriggerLowLatencyModeForLong)
539 {
540     m_platformSupport.setMonotonicTimeForTest(1000.0);
541
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);
547     runPendingTasks();
548
549     ASSERT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
550     m_scheduler->postCompositorTask(FROM_HERE, WTF::bind(&dummyTask));
551
552     EXPECT_FALSE(m_scheduler->shouldYieldForHighPriorityWork());
553 }
554
555 } // namespace