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 "base/test/test_simple_task_runner.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
) {
21 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
22 new base::TestSimpleTaskRunner
;
23 FakeTimeSourceClient client
;
24 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
25 FakeDelayBasedTimeSource::Create(Interval(), task_runner
.get());
26 timer
->SetClient(&client
);
28 timer
->SetActive(true);
29 EXPECT_TRUE(timer
->Active());
30 EXPECT_TRUE(task_runner
->HasPendingTask());
32 timer
->SetNow(timer
->Now() + base::TimeDelta::FromMilliseconds(16));
33 task_runner
->RunPendingTasks();
34 EXPECT_TRUE(timer
->Active());
35 EXPECT_TRUE(client
.TickCalled());
38 TEST(DelayBasedTimeSource
, TickNotCalledWithTaskPosted
) {
39 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
40 new base::TestSimpleTaskRunner
;
41 FakeTimeSourceClient client
;
42 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
43 FakeDelayBasedTimeSource::Create(Interval(), task_runner
.get());
44 timer
->SetClient(&client
);
45 timer
->SetActive(true);
46 EXPECT_TRUE(task_runner
->HasPendingTask());
47 timer
->SetActive(false);
48 task_runner
->RunPendingTasks();
49 EXPECT_FALSE(client
.TickCalled());
52 TEST(DelayBasedTimeSource
, StartTwiceEnqueuesOneTask
) {
53 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
54 new base::TestSimpleTaskRunner
;
55 FakeTimeSourceClient client
;
56 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
57 FakeDelayBasedTimeSource::Create(Interval(), task_runner
.get());
58 timer
->SetClient(&client
);
59 timer
->SetActive(true);
60 EXPECT_TRUE(task_runner
->HasPendingTask());
61 task_runner
->ClearPendingTasks();
62 timer
->SetActive(true);
63 EXPECT_FALSE(task_runner
->HasPendingTask());
66 TEST(DelayBasedTimeSource
, StartWhenRunningDoesntTick
) {
67 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
68 new base::TestSimpleTaskRunner
;
69 FakeTimeSourceClient client
;
70 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
71 FakeDelayBasedTimeSource::Create(Interval(), task_runner
.get());
72 timer
->SetClient(&client
);
73 timer
->SetActive(true);
74 EXPECT_TRUE(task_runner
->HasPendingTask());
75 task_runner
->RunPendingTasks();
76 task_runner
->ClearPendingTasks();
77 timer
->SetActive(true);
78 EXPECT_FALSE(task_runner
->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(DelayBasedTimeSource
, NextDelaySaneWhenExactlyOnRequestedTime
) {
84 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
85 new base::TestSimpleTaskRunner
;
86 FakeTimeSourceClient client
;
87 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
88 FakeDelayBasedTimeSource::Create(Interval(), task_runner
.get());
89 timer
->SetClient(&client
);
90 timer
->SetActive(true);
91 // Run the first task, as that activates the timer and picks up a timebase.
92 task_runner
->RunPendingTasks();
94 EXPECT_EQ(16, task_runner
->NextPendingTaskDelay().InMilliseconds());
96 timer
->SetNow(timer
->Now() + Interval());
97 task_runner
->RunPendingTasks();
99 EXPECT_EQ(16, task_runner
->NextPendingTaskDelay().InMilliseconds());
102 // At 60Hz, when the tick returns at slightly after the requested next time,
103 // make sure a 16ms next delay is posted.
104 TEST(DelayBasedTimeSource
, NextDelaySaneWhenSlightlyAfterRequestedTime
) {
105 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
106 new base::TestSimpleTaskRunner
;
107 FakeTimeSourceClient client
;
108 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
109 FakeDelayBasedTimeSource::Create(Interval(), task_runner
.get());
110 timer
->SetClient(&client
);
111 timer
->SetActive(true);
112 // Run the first task, as that activates the timer and picks up a timebase.
113 task_runner
->RunPendingTasks();
115 EXPECT_EQ(16, task_runner
->NextPendingTaskDelay().InMilliseconds());
117 timer
->SetNow(timer
->Now() + Interval() +
118 base::TimeDelta::FromMicroseconds(1));
119 task_runner
->RunPendingTasks();
121 EXPECT_EQ(16, task_runner
->NextPendingTaskDelay().InMilliseconds());
124 // At 60Hz, when the tick returns at exactly 2*interval after the requested next
125 // time, make sure a 16ms next delay is posted.
126 TEST(DelayBasedTimeSource
, NextDelaySaneWhenExactlyTwiceAfterRequestedTime
) {
127 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
128 new base::TestSimpleTaskRunner
;
129 FakeTimeSourceClient client
;
130 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
131 FakeDelayBasedTimeSource::Create(Interval(), task_runner
.get());
132 timer
->SetClient(&client
);
133 timer
->SetActive(true);
134 // Run the first task, as that activates the timer and picks up a timebase.
135 task_runner
->RunPendingTasks();
137 EXPECT_EQ(16, task_runner
->NextPendingTaskDelay().InMilliseconds());
139 timer
->SetNow(timer
->Now() + 2 * Interval());
140 task_runner
->RunPendingTasks();
142 EXPECT_EQ(16, task_runner
->NextPendingTaskDelay().InMilliseconds());
145 // At 60Hz, when the tick returns at 2*interval and a bit after the requested
146 // next time, make sure a 16ms next delay is posted.
147 TEST(DelayBasedTimeSource
, NextDelaySaneWhenSlightlyAfterTwiceRequestedTime
) {
148 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
149 new base::TestSimpleTaskRunner
;
150 FakeTimeSourceClient client
;
151 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
152 FakeDelayBasedTimeSource::Create(Interval(), task_runner
.get());
153 timer
->SetClient(&client
);
154 timer
->SetActive(true);
155 // Run the first task, as that activates the timer and picks up a timebase.
156 task_runner
->RunPendingTasks();
158 EXPECT_EQ(16, task_runner
->NextPendingTaskDelay().InMilliseconds());
160 timer
->SetNow(timer
->Now() + 2 * Interval() +
161 base::TimeDelta::FromMicroseconds(1));
162 task_runner
->RunPendingTasks();
164 EXPECT_EQ(16, task_runner
->NextPendingTaskDelay().InMilliseconds());
167 // At 60Hz, when the tick returns halfway to the next frame time, make sure
168 // a correct next delay value is posted.
169 TEST(DelayBasedTimeSource
, NextDelaySaneWhenHalfAfterRequestedTime
) {
170 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
171 new base::TestSimpleTaskRunner
;
172 FakeTimeSourceClient client
;
173 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
174 FakeDelayBasedTimeSource::Create(Interval(), task_runner
.get());
175 timer
->SetClient(&client
);
176 timer
->SetActive(true);
177 // Run the first task, as that activates the timer and picks up a timebase.
178 task_runner
->RunPendingTasks();
180 EXPECT_EQ(16, task_runner
->NextPendingTaskDelay().InMilliseconds());
182 timer
->SetNow(timer
->Now() + Interval() +
183 base::TimeDelta::FromMilliseconds(8));
184 task_runner
->RunPendingTasks();
186 EXPECT_EQ(8, task_runner
->NextPendingTaskDelay().InMilliseconds());
189 // If the timebase and interval are updated with a jittery source, we want to
190 // make sure we do not double tick.
191 TEST(DelayBasedTimeSource
, SaneHandlingOfJitteryTimebase
) {
192 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
193 new base::TestSimpleTaskRunner
;
194 FakeTimeSourceClient client
;
195 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
196 FakeDelayBasedTimeSource::Create(Interval(), task_runner
.get());
197 timer
->SetClient(&client
);
198 timer
->SetActive(true);
199 // Run the first task, as that activates the timer and picks up a timebase.
200 task_runner
->RunPendingTasks();
202 EXPECT_EQ(16, task_runner
->NextPendingTaskDelay().InMilliseconds());
204 // Jitter timebase ~1ms late
205 timer
->SetNow(timer
->Now() + Interval());
206 timer
->SetTimebaseAndInterval(
207 timer
->Now() + base::TimeDelta::FromMilliseconds(1), Interval());
208 task_runner
->RunPendingTasks();
210 // Without double tick prevention, NextPendingTaskDelay would be 1.
211 EXPECT_EQ(17, task_runner
->NextPendingTaskDelay().InMilliseconds());
213 // Jitter timebase ~1ms early
214 timer
->SetNow(timer
->Now() + Interval());
215 timer
->SetTimebaseAndInterval(
216 timer
->Now() - base::TimeDelta::FromMilliseconds(1), Interval());
217 task_runner
->RunPendingTasks();
219 EXPECT_EQ(15, task_runner
->NextPendingTaskDelay().InMilliseconds());
222 TEST(DelayBasedTimeSource
, HandlesSignificantTimebaseChangesImmediately
) {
223 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
224 new base::TestSimpleTaskRunner
;
225 FakeTimeSourceClient client
;
226 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
227 FakeDelayBasedTimeSource::Create(Interval(), task_runner
.get());
228 timer
->SetClient(&client
);
229 timer
->SetActive(true);
230 // Run the first task, as that activates the timer and picks up a timebase.
231 task_runner
->RunPendingTasks();
233 EXPECT_EQ(16, task_runner
->NextPendingTaskDelay().InMilliseconds());
235 // Tick, then shift timebase by +7ms.
236 timer
->SetNow(timer
->Now() + Interval());
237 task_runner
->RunPendingTasks();
239 EXPECT_EQ(16, task_runner
->NextPendingTaskDelay().InMilliseconds());
242 task_runner
->ClearPendingTasks();
243 task_runner
->RunPendingTasks();
244 base::TimeDelta jitter
= base::TimeDelta::FromMilliseconds(7) +
245 base::TimeDelta::FromMicroseconds(1);
246 timer
->SetTimebaseAndInterval(timer
->Now() + jitter
, Interval());
248 EXPECT_FALSE(client
.TickCalled()); // Make sure pending tasks were canceled.
249 EXPECT_EQ(7, task_runner
->NextPendingTaskDelay().InMilliseconds());
251 // Tick, then shift timebase by -7ms.
252 timer
->SetNow(timer
->Now() + jitter
);
253 task_runner
->RunPendingTasks();
255 EXPECT_EQ(16, task_runner
->NextPendingTaskDelay().InMilliseconds());
258 task_runner
->ClearPendingTasks();
259 task_runner
->RunPendingTasks();
260 timer
->SetTimebaseAndInterval(base::TimeTicks() + Interval(), Interval());
262 EXPECT_FALSE(client
.TickCalled()); // Make sure pending tasks were canceled.
263 EXPECT_EQ(16 - 7, task_runner
->NextPendingTaskDelay().InMilliseconds());
266 TEST(DelayBasedTimeSource
, HanldlesSignificantIntervalChangesImmediately
) {
267 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
268 new base::TestSimpleTaskRunner
;
269 FakeTimeSourceClient client
;
270 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
271 FakeDelayBasedTimeSource::Create(Interval(), task_runner
.get());
272 timer
->SetClient(&client
);
273 timer
->SetActive(true);
274 // Run the first task, as that activates the timer and picks up a timebase.
275 task_runner
->RunPendingTasks();
277 EXPECT_EQ(16, task_runner
->NextPendingTaskDelay().InMilliseconds());
279 // Tick, then double the interval.
280 timer
->SetNow(timer
->Now() + Interval());
281 task_runner
->RunPendingTasks();
283 EXPECT_EQ(16, task_runner
->NextPendingTaskDelay().InMilliseconds());
286 task_runner
->ClearPendingTasks();
287 task_runner
->RunPendingTasks();
288 timer
->SetTimebaseAndInterval(base::TimeTicks() + Interval(), Interval() * 2);
290 EXPECT_FALSE(client
.TickCalled()); // Make sure pending tasks were canceled.
291 EXPECT_EQ(33, task_runner
->NextPendingTaskDelay().InMilliseconds());
293 // Tick, then halve the interval.
294 timer
->SetNow(timer
->Now() + Interval() * 2);
295 task_runner
->RunPendingTasks();
297 EXPECT_EQ(33, task_runner
->NextPendingTaskDelay().InMilliseconds());
300 task_runner
->ClearPendingTasks();
301 task_runner
->RunPendingTasks();
302 timer
->SetTimebaseAndInterval(base::TimeTicks() + Interval() * 3, Interval());
304 EXPECT_FALSE(client
.TickCalled()); // Make sure pending tasks were canceled.
305 EXPECT_EQ(16, task_runner
->NextPendingTaskDelay().InMilliseconds());
308 TEST(DelayBasedTimeSourceTest
, AchievesTargetRateWithNoNoise
) {
309 int num_iterations
= 10;
311 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
312 new base::TestSimpleTaskRunner
;
313 FakeTimeSourceClient client
;
314 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
315 FakeDelayBasedTimeSource::Create(Interval(), task_runner
.get());
316 timer
->SetClient(&client
);
317 timer
->SetActive(true);
319 double total_frame_time
= 0.0;
320 for (int i
= 0; i
< num_iterations
; ++i
) {
321 int64 delay_ms
= task_runner
->NextPendingTaskDelay().InMilliseconds();
323 // accumulate the "delay"
324 total_frame_time
+= delay_ms
/ 1000.0;
326 // Run the callback exactly when asked
327 timer
->SetNow(timer
->Now() + base::TimeDelta::FromMilliseconds(delay_ms
));
328 task_runner
->RunPendingTasks();
330 double average_interval
=
331 total_frame_time
/ static_cast<double>(num_iterations
);
332 EXPECT_NEAR(1.0 / 60.0, average_interval
, 0.1);
335 TEST(DelayBasedTimeSource
, TestDeactivateWhilePending
) {
336 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
337 new base::TestSimpleTaskRunner
;
338 FakeTimeSourceClient client
;
339 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
340 FakeDelayBasedTimeSource::Create(Interval(), task_runner
.get());
341 timer
->SetClient(&client
);
342 timer
->SetActive(true); // Should post a task.
343 timer
->SetActive(false);
345 // Should run the posted task without crashing.
346 EXPECT_TRUE(task_runner
->HasPendingTask());
347 task_runner
->RunPendingTasks();
350 TEST(DelayBasedTimeSource
, TestDeactivateAndReactivateBeforeNextTickTime
) {
351 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
352 new base::TestSimpleTaskRunner
;
353 FakeTimeSourceClient client
;
354 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
355 FakeDelayBasedTimeSource::Create(Interval(), task_runner
.get());
356 timer
->SetClient(&client
);
358 // Should run the activate task, and pick up a new timebase.
359 timer
->SetActive(true);
360 task_runner
->RunPendingTasks();
363 timer
->SetActive(false);
365 // Task will be pending anyway, run it
366 task_runner
->RunPendingTasks();
368 // Start the timer again, but before the next tick time the timer previously
369 // planned on using. That same tick time should still be targeted.
370 timer
->SetNow(timer
->Now() + base::TimeDelta::FromMilliseconds(4));
371 timer
->SetActive(true);
372 EXPECT_EQ(12, task_runner
->NextPendingTaskDelay().InMilliseconds());
375 TEST(DelayBasedTimeSource
, TestDeactivateAndReactivateAfterNextTickTime
) {
376 scoped_refptr
<base::TestSimpleTaskRunner
> task_runner
=
377 new base::TestSimpleTaskRunner
;
378 FakeTimeSourceClient client
;
379 scoped_refptr
<FakeDelayBasedTimeSource
> timer
=
380 FakeDelayBasedTimeSource::Create(Interval(), task_runner
.get());
381 timer
->SetClient(&client
);
383 // Should run the activate task, and pick up a new timebase.
384 timer
->SetActive(true);
385 task_runner
->RunPendingTasks();
388 timer
->SetActive(false);
390 // Task will be pending anyway, run it.
391 task_runner
->RunPendingTasks();
393 // Start the timer again, but before the next tick time the timer previously
394 // planned on using. That same tick time should still be targeted.
395 timer
->SetNow(timer
->Now() + base::TimeDelta::FromMilliseconds(20));
396 timer
->SetActive(true);
397 EXPECT_EQ(13, task_runner
->NextPendingTaskDelay().InMilliseconds());