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.
5 #include "cc/scheduler/delay_based_time_source.h"
7 #include "base/basictypes.h"
8 #include "cc/base/thread.h"
9 #include "cc/test/scheduler_test_common.h"
10 #include "testing/gtest/include/gtest/gtest.h"
15 base::TimeDelta
Interval() {
16 return base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond
/
20 TEST(DelayBasedTimeSourceTest
, TaskPostedAndTickCalled
) {
22 FakeTimeSourceClient client
;
23 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
24 FakeDelayBasedTimeSource::Create(Interval(), &thread
);
25 timer
->SetClient(&client
);
27 timer
->SetActive(true);
28 EXPECT_TRUE(timer
->Active());
29 EXPECT_TRUE(thread
.HasPendingTask());
31 timer
->SetNow(timer
->Now() + base::TimeDelta::FromMilliseconds(16));
32 thread
.RunPendingTask();
33 EXPECT_TRUE(timer
->Active());
34 EXPECT_TRUE(client
.TickCalled());
37 TEST(DelayBasedTimeSource
, TickNotCalledWithTaskPosted
) {
39 FakeTimeSourceClient client
;
40 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
41 FakeDelayBasedTimeSource::Create(Interval(), &thread
);
42 timer
->SetClient(&client
);
43 timer
->SetActive(true);
44 EXPECT_TRUE(thread
.HasPendingTask());
45 timer
->SetActive(false);
46 thread
.RunPendingTask();
47 EXPECT_FALSE(client
.TickCalled());
50 TEST(DelayBasedTimeSource
, StartTwiceEnqueuesOneTask
) {
52 FakeTimeSourceClient client
;
53 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
54 FakeDelayBasedTimeSource::Create(Interval(), &thread
);
55 timer
->SetClient(&client
);
56 timer
->SetActive(true);
57 EXPECT_TRUE(thread
.HasPendingTask());
59 timer
->SetActive(true);
60 EXPECT_FALSE(thread
.HasPendingTask());
63 TEST(DelayBasedTimeSource
, StartWhenRunningDoesntTick
) {
65 FakeTimeSourceClient client
;
66 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
67 FakeDelayBasedTimeSource::Create(Interval(), &thread
);
68 timer
->SetClient(&client
);
69 timer
->SetActive(true);
70 thread
.RunPendingTask();
72 timer
->SetActive(true);
73 EXPECT_FALSE(thread
.HasPendingTask());
76 // At 60Hz, when the tick returns at exactly the requested next time, make sure
77 // a 16ms next delay is posted.
78 TEST(DelayBasedTimeSource
, NextDelaySaneWhenExactlyOnRequestedTime
) {
80 FakeTimeSourceClient client
;
81 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
82 FakeDelayBasedTimeSource::Create(Interval(), &thread
);
83 timer
->SetClient(&client
);
84 timer
->SetActive(true);
85 // Run the first task, as that activates the timer and picks up a timebase.
86 thread
.RunPendingTask();
88 EXPECT_EQ(16, thread
.PendingDelayMs());
90 timer
->SetNow(timer
->Now() + Interval());
91 thread
.RunPendingTask();
93 EXPECT_EQ(16, thread
.PendingDelayMs());
96 // At 60Hz, when the tick returns at slightly after the requested next time,
97 // make sure a 16ms next delay is posted.
98 TEST(DelayBasedTimeSource
, NextDelaySaneWhenSlightlyAfterRequestedTime
) {
100 FakeTimeSourceClient client
;
101 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
102 FakeDelayBasedTimeSource::Create(Interval(), &thread
);
103 timer
->SetClient(&client
);
104 timer
->SetActive(true);
105 // Run the first task, as that activates the timer and picks up a timebase.
106 thread
.RunPendingTask();
108 EXPECT_EQ(16, thread
.PendingDelayMs());
110 timer
->SetNow(timer
->Now() + Interval() +
111 base::TimeDelta::FromMicroseconds(1));
112 thread
.RunPendingTask();
114 EXPECT_EQ(16, thread
.PendingDelayMs());
117 // At 60Hz, when the tick returns at exactly 2*interval after the requested next
118 // time, make sure a 16ms next delay is posted.
119 TEST(DelayBasedTimeSource
, NextDelaySaneWhenExactlyTwiceAfterRequestedTime
) {
121 FakeTimeSourceClient client
;
122 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
123 FakeDelayBasedTimeSource::Create(Interval(), &thread
);
124 timer
->SetClient(&client
);
125 timer
->SetActive(true);
126 // Run the first task, as that activates the timer and picks up a timebase.
127 thread
.RunPendingTask();
129 EXPECT_EQ(16, thread
.PendingDelayMs());
131 timer
->SetNow(timer
->Now() + 2 * Interval());
132 thread
.RunPendingTask();
134 EXPECT_EQ(16, thread
.PendingDelayMs());
137 // At 60Hz, when the tick returns at 2*interval and a bit after the requested
138 // next time, make sure a 16ms next delay is posted.
139 TEST(DelayBasedTimeSource
, NextDelaySaneWhenSlightlyAfterTwiceRequestedTime
) {
141 FakeTimeSourceClient client
;
142 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
143 FakeDelayBasedTimeSource::Create(Interval(), &thread
);
144 timer
->SetClient(&client
);
145 timer
->SetActive(true);
146 // Run the first task, as that activates the timer and picks up a timebase.
147 thread
.RunPendingTask();
149 EXPECT_EQ(16, thread
.PendingDelayMs());
151 timer
->SetNow(timer
->Now() + 2 * Interval() +
152 base::TimeDelta::FromMicroseconds(1));
153 thread
.RunPendingTask();
155 EXPECT_EQ(16, thread
.PendingDelayMs());
158 // At 60Hz, when the tick returns halfway to the next frame time, make sure
159 // a correct next delay value is posted.
160 TEST(DelayBasedTimeSource
, NextDelaySaneWhenHalfAfterRequestedTime
) {
162 FakeTimeSourceClient client
;
163 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
164 FakeDelayBasedTimeSource::Create(Interval(), &thread
);
165 timer
->SetClient(&client
);
166 timer
->SetActive(true);
167 // Run the first task, as that activates the timer and picks up a timebase.
168 thread
.RunPendingTask();
170 EXPECT_EQ(16, thread
.PendingDelayMs());
172 timer
->SetNow(timer
->Now() + Interval() +
173 base::TimeDelta::FromMilliseconds(8));
174 thread
.RunPendingTask();
176 EXPECT_EQ(8, thread
.PendingDelayMs());
179 // If the timebase and interval are updated with a jittery source, we want to
180 // make sure we do not double tick.
181 TEST(DelayBasedTimeSource
, SaneHandlingOfJitteryTimebase
) {
183 FakeTimeSourceClient client
;
184 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
185 FakeDelayBasedTimeSource::Create(Interval(), &thread
);
186 timer
->SetClient(&client
);
187 timer
->SetActive(true);
188 // Run the first task, as that activates the timer and picks up a timebase.
189 thread
.RunPendingTask();
191 EXPECT_EQ(16, thread
.PendingDelayMs());
193 // Jitter timebase ~1ms late
194 timer
->SetNow(timer
->Now() + Interval());
195 timer
->SetTimebaseAndInterval(
196 timer
->Now() + base::TimeDelta::FromMilliseconds(1), Interval());
197 thread
.RunPendingTask();
199 // Without double tick prevention, PendingDelayMs would be 1.
200 EXPECT_EQ(17, thread
.PendingDelayMs());
202 // Jitter timebase ~1ms early
203 timer
->SetNow(timer
->Now() + Interval());
204 timer
->SetTimebaseAndInterval(
205 timer
->Now() - base::TimeDelta::FromMilliseconds(1), Interval());
206 thread
.RunPendingTask();
208 EXPECT_EQ(15, thread
.PendingDelayMs());
211 TEST(DelayBasedTimeSource
, HandlesSignificantTimebaseChangesImmediately
) {
213 FakeTimeSourceClient client
;
214 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
215 FakeDelayBasedTimeSource::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) +
232 base::TimeDelta::FromMicroseconds(1);
233 timer
->SetTimebaseAndInterval(timer
->Now() + jitter
, Interval());
234 thread
.RunPendingTaskOnOverwrite(false);
236 EXPECT_FALSE(client
.TickCalled()); // Make sure pending tasks were canceled.
237 EXPECT_EQ(7, thread
.PendingDelayMs());
239 // Tick, then shift timebase by -7ms.
240 timer
->SetNow(timer
->Now() + jitter
);
241 thread
.RunPendingTask();
243 EXPECT_EQ(16, thread
.PendingDelayMs());
246 thread
.RunPendingTaskOnOverwrite(true);
247 timer
->SetTimebaseAndInterval(base::TimeTicks() + Interval(), Interval());
248 thread
.RunPendingTaskOnOverwrite(false);
250 EXPECT_FALSE(client
.TickCalled()); // Make sure pending tasks were canceled.
251 EXPECT_EQ(16 - 7, thread
.PendingDelayMs());
254 TEST(DelayBasedTimeSource
, HanldlesSignificantIntervalChangesImmediately
) {
256 FakeTimeSourceClient client
;
257 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
258 FakeDelayBasedTimeSource::Create(Interval(), &thread
);
259 timer
->SetClient(&client
);
260 timer
->SetActive(true);
261 // Run the first task, as that activates the timer and picks up a timebase.
262 thread
.RunPendingTask();
264 EXPECT_EQ(16, thread
.PendingDelayMs());
266 // Tick, then double the interval.
267 timer
->SetNow(timer
->Now() + Interval());
268 thread
.RunPendingTask();
270 EXPECT_EQ(16, thread
.PendingDelayMs());
273 thread
.RunPendingTaskOnOverwrite(true);
274 timer
->SetTimebaseAndInterval(base::TimeTicks() + Interval(), Interval() * 2);
275 thread
.RunPendingTaskOnOverwrite(false);
277 EXPECT_FALSE(client
.TickCalled()); // Make sure pending tasks were canceled.
278 EXPECT_EQ(33, thread
.PendingDelayMs());
280 // Tick, then halve the interval.
281 timer
->SetNow(timer
->Now() + Interval() * 2);
282 thread
.RunPendingTask();
284 EXPECT_EQ(33, thread
.PendingDelayMs());
287 thread
.RunPendingTaskOnOverwrite(true);
288 timer
->SetTimebaseAndInterval(base::TimeTicks() + Interval() * 3, Interval());
289 thread
.RunPendingTaskOnOverwrite(false);
291 EXPECT_FALSE(client
.TickCalled()); // Make sure pending tasks were canceled.
292 EXPECT_EQ(16, thread
.PendingDelayMs());
295 TEST(DelayBasedTimeSourceTest
, AchievesTargetRateWithNoNoise
) {
296 int num_iterations
= 10;
299 FakeTimeSourceClient client
;
300 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
301 FakeDelayBasedTimeSource::Create(Interval(), &thread
);
302 timer
->SetClient(&client
);
303 timer
->SetActive(true);
305 double total_frame_time
= 0.0;
306 for (int i
= 0; i
< num_iterations
; ++i
) {
307 int64 delay_ms
= thread
.PendingDelayMs();
309 // accumulate the "delay"
310 total_frame_time
+= delay_ms
/ 1000.0;
312 // Run the callback exactly when asked
313 timer
->SetNow(timer
->Now() + base::TimeDelta::FromMilliseconds(delay_ms
));
314 thread
.RunPendingTask();
316 double average_interval
=
317 total_frame_time
/ static_cast<double>(num_iterations
);
318 EXPECT_NEAR(1.0 / 60.0, average_interval
, 0.1);
321 TEST(DelayBasedTimeSource
, TestDeactivateWhilePending
) {
323 FakeTimeSourceClient client
;
324 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
325 FakeDelayBasedTimeSource::Create(Interval(), &thread
);
326 timer
->SetClient(&client
);
327 timer
->SetActive(true); // Should post a task.
328 timer
->SetActive(false);
330 thread
.RunPendingTask(); // Should run the posted task without crashing.
333 TEST(DelayBasedTimeSource
, TestDeactivateAndReactivateBeforeNextTickTime
) {
335 FakeTimeSourceClient client
;
336 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
337 FakeDelayBasedTimeSource::Create(Interval(), &thread
);
338 timer
->SetClient(&client
);
340 // Should run the activate task, and pick up a new timebase.
341 timer
->SetActive(true);
342 thread
.RunPendingTask();
345 timer
->SetActive(false);
347 // Task will be pending anyway, run it
348 thread
.RunPendingTask();
350 // Start the timer again, but before the next tick time the timer previously
351 // planned on using. That same tick time should still be targeted.
352 timer
->SetNow(timer
->Now() + base::TimeDelta::FromMilliseconds(4));
353 timer
->SetActive(true);
354 EXPECT_EQ(12, thread
.PendingDelayMs());
357 TEST(DelayBasedTimeSource
, TestDeactivateAndReactivateAfterNextTickTime
) {
359 FakeTimeSourceClient client
;
360 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
361 FakeDelayBasedTimeSource::Create(Interval(), &thread
);
362 timer
->SetClient(&client
);
364 // Should run the activate task, and pick up a new timebase.
365 timer
->SetActive(true);
366 thread
.RunPendingTask();
369 timer
->SetActive(false);
371 // Task will be pending anyway, run it.
372 thread
.RunPendingTask();
374 // Start the timer again, but before the next tick time the timer previously
375 // planned on using. That same tick time should still be targeted.
376 timer
->SetNow(timer
->Now() + base::TimeDelta::FromMilliseconds(20));
377 timer
->SetActive(true);
378 EXPECT_EQ(13, thread
.PendingDelayMs());