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 "testing/gtest/include/gtest/gtest.h"
12 #include <wtf/RefPtr.h>
16 using namespace WebKitTests
;
20 base::TimeDelta
interval()
22 return base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond
/ 60);
25 TEST(CCDelayBasedTimeSourceTest
, TaskPostedAndTickCalled
)
28 FakeCCTimeSourceClient client
;
29 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval(), &thread
);
30 timer
->setClient(&client
);
32 timer
->setActive(true);
33 EXPECT_TRUE(timer
->active());
34 EXPECT_TRUE(thread
.hasPendingTask());
36 timer
->setNow(timer
->now() + base::TimeDelta::FromMilliseconds(16));
37 thread
.runPendingTask();
38 EXPECT_TRUE(timer
->active());
39 EXPECT_TRUE(client
.tickCalled());
42 TEST(CCDelayBasedTimeSource
, TickNotCalledWithTaskPosted
)
45 FakeCCTimeSourceClient client
;
46 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval(), &thread
);
47 timer
->setClient(&client
);
48 timer
->setActive(true);
49 EXPECT_TRUE(thread
.hasPendingTask());
50 timer
->setActive(false);
51 thread
.runPendingTask();
52 EXPECT_FALSE(client
.tickCalled());
55 TEST(CCDelayBasedTimeSource
, StartTwiceEnqueuesOneTask
)
58 FakeCCTimeSourceClient client
;
59 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval(), &thread
);
60 timer
->setClient(&client
);
61 timer
->setActive(true);
62 EXPECT_TRUE(thread
.hasPendingTask());
64 timer
->setActive(true);
65 EXPECT_FALSE(thread
.hasPendingTask());
68 TEST(CCDelayBasedTimeSource
, StartWhenRunningDoesntTick
)
71 FakeCCTimeSourceClient client
;
72 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval(), &thread
);
73 timer
->setClient(&client
);
74 timer
->setActive(true);
75 thread
.runPendingTask();
77 timer
->setActive(true);
78 EXPECT_FALSE(thread
.hasPendingTask());
81 // At 60Hz, when the tick returns at exactly the requested next time, make sure
82 // a 16ms next delay is posted.
83 TEST(CCDelayBasedTimeSource
, NextDelaySaneWhenExactlyOnRequestedTime
)
86 FakeCCTimeSourceClient client
;
87 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval(), &thread
);
88 timer
->setClient(&client
);
89 timer
->setActive(true);
90 // Run the first task, as that activates the timer and picks up a timebase.
91 thread
.runPendingTask();
93 EXPECT_EQ(16, thread
.pendingDelayMs());
95 timer
->setNow(timer
->now() + interval());
96 thread
.runPendingTask();
98 EXPECT_EQ(16, thread
.pendingDelayMs());
101 // At 60Hz, when the tick returns at slightly after the requested next time, make sure
102 // a 16ms next delay is posted.
103 TEST(CCDelayBasedTimeSource
, NextDelaySaneWhenSlightlyAfterRequestedTime
)
106 FakeCCTimeSourceClient client
;
107 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval(), &thread
);
108 timer
->setClient(&client
);
109 timer
->setActive(true);
110 // Run the first task, as that activates the timer and picks up a timebase.
111 thread
.runPendingTask();
113 EXPECT_EQ(16, thread
.pendingDelayMs());
115 timer
->setNow(timer
->now() + interval() + base::TimeDelta::FromMicroseconds(1));
116 thread
.runPendingTask();
118 EXPECT_EQ(16, thread
.pendingDelayMs());
121 // At 60Hz, when the tick returns at exactly 2*interval after the requested next time, make sure
122 // a 16ms next delay is posted.
123 TEST(CCDelayBasedTimeSource
, NextDelaySaneWhenExactlyTwiceAfterRequestedTime
)
126 FakeCCTimeSourceClient client
;
127 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval(), &thread
);
128 timer
->setClient(&client
);
129 timer
->setActive(true);
130 // Run the first task, as that activates the timer and picks up a timebase.
131 thread
.runPendingTask();
133 EXPECT_EQ(16, thread
.pendingDelayMs());
135 timer
->setNow(timer
->now() + 2 * interval());
136 thread
.runPendingTask();
138 EXPECT_EQ(16, thread
.pendingDelayMs());
141 // At 60Hz, when the tick returns at 2*interval and a bit after the requested next time, make sure
142 // a 16ms next delay is posted.
143 TEST(CCDelayBasedTimeSource
, NextDelaySaneWhenSlightlyAfterTwiceRequestedTime
)
146 FakeCCTimeSourceClient client
;
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
->setNow(timer
->now() + 2 * interval() + base::TimeDelta::FromMicroseconds(1));
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 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval(), &thread
);
168 timer
->setClient(&client
);
169 timer
->setActive(true);
170 // Run the first task, as that activates the timer and picks up a timebase.
171 thread
.runPendingTask();
173 EXPECT_EQ(16, thread
.pendingDelayMs());
175 timer
->setNow(timer
->now() + interval() + base::TimeDelta::FromMilliseconds(8));
176 thread
.runPendingTask();
178 EXPECT_EQ(8, thread
.pendingDelayMs());
181 // If the timebase and interval are updated with a jittery source, we want to
182 // make sure we do not double tick.
183 TEST(CCDelayBasedTimeSource
, SaneHandlingOfJitteryTimebase
)
186 FakeCCTimeSourceClient client
;
187 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval(), &thread
);
188 timer
->setClient(&client
);
189 timer
->setActive(true);
190 // Run the first task, as that activates the timer and picks up a timebase.
191 thread
.runPendingTask();
193 EXPECT_EQ(16, thread
.pendingDelayMs());
195 // Jitter timebase ~1ms late
196 timer
->setNow(timer
->now() + interval());
197 timer
->setTimebaseAndInterval(timer
->now() + base::TimeDelta::FromMilliseconds(1), interval());
198 thread
.runPendingTask();
200 // Without double tick prevention, pendingDelayMs would be 1.
201 EXPECT_EQ(17, thread
.pendingDelayMs());
203 // Jitter timebase ~1ms early
204 timer
->setNow(timer
->now() + interval());
205 timer
->setTimebaseAndInterval(timer
->now() - base::TimeDelta::FromMilliseconds(1), interval());
206 thread
.runPendingTask();
208 EXPECT_EQ(15, thread
.pendingDelayMs());
211 TEST(CCDelayBasedTimeSource
, HandlesSignificantTimebaseChangesImmediately
)
214 FakeCCTimeSourceClient client
;
215 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval(), &thread
);
216 timer
->setClient(&client
);
217 timer
->setActive(true);
218 // Run the first task, as that activates the timer and picks up a timebase.
219 thread
.runPendingTask();
221 EXPECT_EQ(16, thread
.pendingDelayMs());
223 // Tick, then shift timebase by +7ms.
224 timer
->setNow(timer
->now() + interval());
225 thread
.runPendingTask();
227 EXPECT_EQ(16, thread
.pendingDelayMs());
230 thread
.runPendingTaskOnOverwrite(true);
231 base::TimeDelta jitter
= base::TimeDelta::FromMilliseconds(7) + base::TimeDelta::FromMicroseconds(1);
232 timer
->setTimebaseAndInterval(timer
->now() + jitter
, interval());
233 thread
.runPendingTaskOnOverwrite(false);
235 EXPECT_FALSE(client
.tickCalled()); // Make sure pending tasks were canceled.
236 EXPECT_EQ(7, thread
.pendingDelayMs());
238 // Tick, then shift timebase by -7ms.
239 timer
->setNow(timer
->now() + jitter
);
240 thread
.runPendingTask();
242 EXPECT_EQ(16, thread
.pendingDelayMs());
245 thread
.runPendingTaskOnOverwrite(true);
246 timer
->setTimebaseAndInterval(base::TimeTicks() + interval(), interval());
247 thread
.runPendingTaskOnOverwrite(false);
249 EXPECT_FALSE(client
.tickCalled()); // Make sure pending tasks were canceled.
250 EXPECT_EQ(16-7, thread
.pendingDelayMs());
253 TEST(CCDelayBasedTimeSource
, HanldlesSignificantIntervalChangesImmediately
)
256 FakeCCTimeSourceClient client
;
257 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval(), &thread
);
258 timer
->setClient(&client
);
259 timer
->setActive(true);
260 // Run the first task, as that activates the timer and picks up a timebase.
261 thread
.runPendingTask();
263 EXPECT_EQ(16, thread
.pendingDelayMs());
265 // Tick, then double the interval.
266 timer
->setNow(timer
->now() + interval());
267 thread
.runPendingTask();
269 EXPECT_EQ(16, thread
.pendingDelayMs());
272 thread
.runPendingTaskOnOverwrite(true);
273 timer
->setTimebaseAndInterval(base::TimeTicks() + interval(), interval() * 2);
274 thread
.runPendingTaskOnOverwrite(false);
276 EXPECT_FALSE(client
.tickCalled()); // Make sure pending tasks were canceled.
277 EXPECT_EQ(33, thread
.pendingDelayMs());
279 // Tick, then halve the interval.
280 timer
->setNow(timer
->now() + interval() * 2);
281 thread
.runPendingTask();
283 EXPECT_EQ(33, thread
.pendingDelayMs());
286 thread
.runPendingTaskOnOverwrite(true);
287 timer
->setTimebaseAndInterval(base::TimeTicks() + interval() * 3, interval());
288 thread
.runPendingTaskOnOverwrite(false);
290 EXPECT_FALSE(client
.tickCalled()); // Make sure pending tasks were canceled.
291 EXPECT_EQ(16, thread
.pendingDelayMs());
294 TEST(CCDelayBasedTimeSourceTest
, AchievesTargetRateWithNoNoise
)
296 int numIterations
= 10;
299 FakeCCTimeSourceClient client
;
300 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval(), &thread
);
301 timer
->setClient(&client
);
302 timer
->setActive(true);
304 double totalFrameTime
= 0;
305 for (int i
= 0; i
< numIterations
; ++i
) {
306 long long delayMs
= thread
.pendingDelayMs();
308 // accumulate the "delay"
309 totalFrameTime
+= delayMs
/ 1000.0;
311 // Run the callback exactly when asked
312 timer
->setNow(timer
->now() + base::TimeDelta::FromMilliseconds(delayMs
));
313 thread
.runPendingTask();
315 double averageInterval
= totalFrameTime
/ static_cast<double>(numIterations
);
316 EXPECT_NEAR(1.0 / 60.0, averageInterval
, 0.1);
319 TEST(CCDelayBasedTimeSource
, TestDeactivateWhilePending
)
322 FakeCCTimeSourceClient client
;
323 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval(), &thread
);
324 timer
->setClient(&client
);
325 timer
->setActive(true); // Should post a task.
326 timer
->setActive(false);
328 thread
.runPendingTask(); // Should run the posted task without crashing.
331 TEST(CCDelayBasedTimeSource
, TestDeactivateAndReactivateBeforeNextTickTime
)
334 FakeCCTimeSourceClient client
;
335 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval(), &thread
);
336 timer
->setClient(&client
);
338 // Should run the activate task, and pick up a new timebase.
339 timer
->setActive(true);
340 thread
.runPendingTask();
343 timer
->setActive(false);
345 // Task will be pending anyway, run it
346 thread
.runPendingTask();
348 // Start the timer again, but before the next tick time the timer previously
349 // planned on using. That same tick time should still be targeted.
350 timer
->setNow(timer
->now() + base::TimeDelta::FromMilliseconds(4));
351 timer
->setActive(true);
352 EXPECT_EQ(12, thread
.pendingDelayMs());
355 TEST(CCDelayBasedTimeSource
, TestDeactivateAndReactivateAfterNextTickTime
)
358 FakeCCTimeSourceClient client
;
359 RefPtr
<FakeCCDelayBasedTimeSource
> timer
= FakeCCDelayBasedTimeSource::create(interval(), &thread
);
360 timer
->setClient(&client
);
362 // Should run the activate task, and pick up a new timebase.
363 timer
->setActive(true);
364 thread
.runPendingTask();
367 timer
->setActive(false);
369 // Task will be pending anyway, run it
370 thread
.runPendingTask();
372 // Start the timer again, but before the next tick time the timer previously
373 // planned on using. That same tick time should still be targeted.
374 timer
->setNow(timer
->now() + base::TimeDelta::FromMilliseconds(20));
375 timer
->setActive(true);
376 EXPECT_EQ(13, thread
.pendingDelayMs());