1 // Copyright 2011 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.
7 #include "CCDelayBasedTimeSource.h"
9 #include "CCSchedulerTestCommon.h"
11 #include <gtest/gtest.h>
12 #include <wtf/RefPtr.h>
15 using namespace WebCore
;
16 using namespace WebKitTests
;
20 TEST(CCDelayBasedTimeSourceTest
, TaskPostedAndTickCalled
)
23 FakeCCTimeSourceClient client
;
24 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(1.0 / 60.0, &thread
);
25 timer
->setClient(&client
);
27 timer
->setMonotonicTimeNow(0);
28 timer
->setActive(true);
29 EXPECT_TRUE(timer
->active());
30 EXPECT_TRUE(thread
.hasPendingTask());
32 timer
->setMonotonicTimeNow(0.016);
33 thread
.runPendingTask();
34 EXPECT_TRUE(timer
->active());
35 EXPECT_TRUE(client
.tickCalled());
38 TEST(CCDelayBasedTimeSource
, TickNotCalledWithTaskPosted
)
41 FakeCCTimeSourceClient client
;
42 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(1.0 / 60.0, &thread
);
43 timer
->setClient(&client
);
44 timer
->setActive(true);
45 EXPECT_TRUE(thread
.hasPendingTask());
46 timer
->setActive(false);
47 thread
.runPendingTask();
48 EXPECT_FALSE(client
.tickCalled());
51 TEST(CCDelayBasedTimeSource
, StartTwiceEnqueuesOneTask
)
54 FakeCCTimeSourceClient client
;
55 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(1.0 / 60.0, &thread
);
56 timer
->setClient(&client
);
57 timer
->setActive(true);
58 EXPECT_TRUE(thread
.hasPendingTask());
60 timer
->setActive(true);
61 EXPECT_FALSE(thread
.hasPendingTask());
64 TEST(CCDelayBasedTimeSource
, StartWhenRunningDoesntTick
)
67 FakeCCTimeSourceClient client
;
68 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(1.0 / 60.0, &thread
);
69 timer
->setClient(&client
);
70 timer
->setActive(true);
71 thread
.runPendingTask();
73 timer
->setActive(true);
74 EXPECT_FALSE(thread
.hasPendingTask());
77 // At 60Hz, when the tick returns at exactly the requested next time, make sure
78 // a 16ms next delay is posted.
79 TEST(CCDelayBasedTimeSource
, NextDelaySaneWhenExactlyOnRequestedTime
)
82 FakeCCTimeSourceClient client
;
83 double interval
= 1.0 / 60.0;
84 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval
, &thread
);
85 timer
->setClient(&client
);
86 timer
->setActive(true);
87 // Run the first task, as that activates the timer and picks up a timebase.
88 thread
.runPendingTask();
90 EXPECT_EQ(16, thread
.pendingDelayMs());
92 timer
->setMonotonicTimeNow(interval
);
93 thread
.runPendingTask();
95 EXPECT_EQ(16, thread
.pendingDelayMs());
98 // At 60Hz, when the tick returns at slightly after the requested next time, make sure
99 // a 16ms next delay is posted.
100 TEST(CCDelayBasedTimeSource
, NextDelaySaneWhenSlightlyAfterRequestedTime
)
103 FakeCCTimeSourceClient client
;
104 double interval
= 1.0 / 60.0;
105 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval
, &thread
);
106 timer
->setClient(&client
);
107 timer
->setActive(true);
108 // Run the first task, as that activates the timer and picks up a timebase.
109 thread
.runPendingTask();
111 EXPECT_EQ(16, thread
.pendingDelayMs());
113 timer
->setMonotonicTimeNow(interval
+ 0.0000001);
114 thread
.runPendingTask();
116 EXPECT_EQ(16, thread
.pendingDelayMs());
119 // At 60Hz, when the tick returns at exactly 2*interval after the requested next time, make sure
120 // a 16ms next delay is posted.
121 TEST(CCDelayBasedTimeSource
, NextDelaySaneWhenExactlyTwiceAfterRequestedTime
)
124 FakeCCTimeSourceClient client
;
125 double interval
= 1.0 / 60.0;
126 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval
, &thread
);
127 timer
->setClient(&client
);
128 timer
->setActive(true);
129 // Run the first task, as that activates the timer and picks up a timebase.
130 thread
.runPendingTask();
132 EXPECT_EQ(16, thread
.pendingDelayMs());
134 timer
->setMonotonicTimeNow(2*interval
);
135 thread
.runPendingTask();
137 EXPECT_EQ(16, thread
.pendingDelayMs());
140 // At 60Hz, when the tick returns at 2*interval and a bit after the requested next time, make sure
141 // a 16ms next delay is posted.
142 TEST(CCDelayBasedTimeSource
, NextDelaySaneWhenSlightlyAfterTwiceRequestedTime
)
145 FakeCCTimeSourceClient client
;
146 double interval
= 1.0 / 60.0;
147 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval
, &thread
);
148 timer
->setClient(&client
);
149 timer
->setActive(true);
150 // Run the first task, as that activates the timer and picks up a timebase.
151 thread
.runPendingTask();
153 EXPECT_EQ(16, thread
.pendingDelayMs());
155 timer
->setMonotonicTimeNow(2*interval
+ 0.0000001);
156 thread
.runPendingTask();
158 EXPECT_EQ(16, thread
.pendingDelayMs());
161 // At 60Hz, when the tick returns halfway to the next frame time, make sure
162 // a correct next delay value is posted.
163 TEST(CCDelayBasedTimeSource
, NextDelaySaneWhenHalfAfterRequestedTime
)
166 FakeCCTimeSourceClient client
;
167 double interval
= 1.0 / 60.0;
168 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval
, &thread
);
169 timer
->setClient(&client
);
170 timer
->setActive(true);
171 // Run the first task, as that activates the timer and picks up a timebase.
172 thread
.runPendingTask();
174 EXPECT_EQ(16, thread
.pendingDelayMs());
176 timer
->setMonotonicTimeNow(interval
+ interval
* 0.5);
177 thread
.runPendingTask();
179 EXPECT_EQ(8, thread
.pendingDelayMs());
182 // If the timebase and interval are updated with a jittery source, we want to
183 // make sure we do not double tick.
184 TEST(CCDelayBasedTimeSource
, SaneHandlingOfJitteryTimebase
)
187 FakeCCTimeSourceClient client
;
188 double interval
= 1.0 / 60.0;
189 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval
, &thread
);
190 timer
->setClient(&client
);
191 timer
->setActive(true);
192 // Run the first task, as that activates the timer and picks up a timebase.
193 thread
.runPendingTask();
195 EXPECT_EQ(16, thread
.pendingDelayMs());
197 // Jitter timebase ~1ms late
198 timer
->setTimebaseAndInterval(interval
+ 0.001, interval
);
199 timer
->setMonotonicTimeNow(interval
);
200 thread
.runPendingTask();
202 // Without double tick prevention, pendingDelayMs would be 1.
203 EXPECT_EQ(17, thread
.pendingDelayMs());
205 // Jitter timebase ~1ms early
206 timer
->setTimebaseAndInterval(interval
* 2 - 0.001, interval
);
207 timer
->setMonotonicTimeNow(interval
* 2);
208 thread
.runPendingTask();
210 EXPECT_EQ(15, thread
.pendingDelayMs());
213 TEST(CCDelayBasedTimeSource
, HanldlesSignificantTimebaseChangesImmediately
)
216 FakeCCTimeSourceClient client
;
217 double interval
= 1.0 / 60.0;
218 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval
, &thread
);
219 timer
->setClient(&client
);
220 timer
->setActive(true);
221 // Run the first task, as that activates the timer and picks up a timebase.
222 thread
.runPendingTask();
224 EXPECT_EQ(16, thread
.pendingDelayMs());
226 // Tick, then shift timebase by +7ms.
227 timer
->setMonotonicTimeNow(interval
);
228 thread
.runPendingTask();
230 EXPECT_EQ(16, thread
.pendingDelayMs());
233 thread
.runPendingTaskOnOverwrite(true);
234 timer
->setTimebaseAndInterval(interval
+ 0.0070001, interval
);
235 thread
.runPendingTaskOnOverwrite(false);
237 EXPECT_FALSE(client
.tickCalled()); // Make sure pending tasks were canceled.
238 EXPECT_EQ(7, thread
.pendingDelayMs());
240 // Tick, then shift timebase by -7ms.
241 timer
->setMonotonicTimeNow(interval
+ 0.0070001);
242 thread
.runPendingTask();
244 EXPECT_EQ(16, thread
.pendingDelayMs());
247 thread
.runPendingTaskOnOverwrite(true);
248 timer
->setTimebaseAndInterval(interval
, interval
);
249 thread
.runPendingTaskOnOverwrite(false);
251 EXPECT_FALSE(client
.tickCalled()); // Make sure pending tasks were canceled.
252 EXPECT_EQ(16-7, thread
.pendingDelayMs());
255 TEST(CCDelayBasedTimeSource
, HanldlesSignificantIntervalChangesImmediately
)
258 FakeCCTimeSourceClient client
;
259 double interval
= 1.0 / 60.0;
260 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval
, &thread
);
261 timer
->setClient(&client
);
262 timer
->setActive(true);
263 // Run the first task, as that activates the timer and picks up a timebase.
264 thread
.runPendingTask();
266 EXPECT_EQ(16, thread
.pendingDelayMs());
268 // Tick, then double the interval.
269 timer
->setMonotonicTimeNow(interval
);
270 thread
.runPendingTask();
272 EXPECT_EQ(16, thread
.pendingDelayMs());
275 thread
.runPendingTaskOnOverwrite(true);
276 timer
->setTimebaseAndInterval(interval
, interval
* 2);
277 thread
.runPendingTaskOnOverwrite(false);
279 EXPECT_FALSE(client
.tickCalled()); // Make sure pending tasks were canceled.
280 EXPECT_EQ(33, thread
.pendingDelayMs());
282 // Tick, then halve the interval.
283 timer
->setMonotonicTimeNow(interval
* 3);
284 thread
.runPendingTask();
286 EXPECT_EQ(33, thread
.pendingDelayMs());
289 thread
.runPendingTaskOnOverwrite(true);
290 timer
->setTimebaseAndInterval(interval
* 3, interval
);
291 thread
.runPendingTaskOnOverwrite(false);
293 EXPECT_FALSE(client
.tickCalled()); // Make sure pending tasks were canceled.
294 EXPECT_EQ(16, thread
.pendingDelayMs());
297 TEST(CCDelayBasedTimeSourceTest
, AchievesTargetRateWithNoNoise
)
299 int numIterations
= 1000;
302 FakeCCTimeSourceClient client
;
303 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(1.0 / 60.0, &thread
);
304 timer
->setClient(&client
);
305 timer
->setActive(true);
307 double totalFrameTime
= 0;
308 for (int i
= 0; i
< numIterations
; ++i
) {
309 long long delayMs
= thread
.pendingDelayMs();
311 // accumulate the "delay"
312 totalFrameTime
+= delayMs
/ 1000.0;
314 // Run the callback exactly when asked
315 double now
= timer
->monotonicTimeNow() + delayMs
/ 1000.0;
316 timer
->setMonotonicTimeNow(now
);
317 thread
.runPendingTask();
319 double averageInterval
= totalFrameTime
/ static_cast<double>(numIterations
);
320 EXPECT_NEAR(1.0 / 60.0, averageInterval
, 0.1);
323 TEST(CCDelayBasedTimeSource
, TestDeactivateWhilePending
)
326 FakeCCTimeSourceClient client
;
327 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(1.0 / 60.0, &thread
);
328 timer
->setClient(&client
);
329 timer
->setActive(true); // Should post a task.
330 timer
->setActive(false);
332 thread
.runPendingTask(); // Should run the posted task without crashing.
335 TEST(CCDelayBasedTimeSource
, TestDeactivateAndReactivateBeforeNextTickTime
)
338 FakeCCTimeSourceClient client
;
339 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(1.0 / 60.0, &thread
);
340 timer
->setClient(&client
);
342 // Should run the activate task, and pick up a new timebase.
343 timer
->setActive(true);
344 timer
->setMonotonicTimeNow(0);
345 thread
.runPendingTask();
348 timer
->setActive(false);
350 // Task will be pending anyway, run it
351 thread
.runPendingTask();
353 // Start the timer again, but before the next tick time the timer previously
354 // planned on using. That same tick time should still be targeted.
355 timer
->setMonotonicTimeNow(0.004);
356 timer
->setActive(true);
357 EXPECT_EQ(12, thread
.pendingDelayMs());
360 TEST(CCDelayBasedTimeSource
, TestDeactivateAndReactivateAfterNextTickTime
)
363 FakeCCTimeSourceClient client
;
364 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(1.0 / 60.0, &thread
);
365 timer
->setClient(&client
);
367 // Should run the activate task, and pick up a new timebase.
368 timer
->setActive(true);
369 timer
->setMonotonicTimeNow(0);
370 thread
.runPendingTask();
373 timer
->setActive(false);
375 // Task will be pending anyway, run it
376 thread
.runPendingTask();
378 // Start the timer again, but before the next tick time the timer previously
379 // planned on using. That same tick time should still be targeted.
380 timer
->setMonotonicTimeNow(0.02);
381 timer
->setActive(true);
382 EXPECT_EQ(13, thread
.pendingDelayMs());