OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "config.h" | |
6 | |
7 #include "CCDelayBasedTimeSource.h" | |
8 | |
9 #include "CCSchedulerTestCommon.h" | |
10 #include "CCThread.h" | |
11 #include "testing/gtest/include/gtest/gtest.h" | |
12 #include <wtf/RefPtr.h> | |
13 | |
14 using namespace cc; | |
15 using namespace WTF; | |
16 using namespace WebKitTests; | |
17 | |
18 namespace { | |
19 | |
20 base::TimeDelta interval() | |
21 { | |
22 return base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond
/ 60); | |
23 } | |
24 | |
25 TEST(CCDelayBasedTimeSourceTest, TaskPostedAndTickCalled) | |
26 { | |
27 FakeCCThread thread; | |
28 FakeCCTimeSourceClient client; | |
29 RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::creat
e(interval(), &thread); | |
30 timer->setClient(&client); | |
31 | |
32 timer->setActive(true); | |
33 EXPECT_TRUE(timer->active()); | |
34 EXPECT_TRUE(thread.hasPendingTask()); | |
35 | |
36 timer->setNow(timer->now() + base::TimeDelta::FromMilliseconds(16)); | |
37 thread.runPendingTask(); | |
38 EXPECT_TRUE(timer->active()); | |
39 EXPECT_TRUE(client.tickCalled()); | |
40 } | |
41 | |
42 TEST(CCDelayBasedTimeSource, TickNotCalledWithTaskPosted) | |
43 { | |
44 FakeCCThread thread; | |
45 FakeCCTimeSourceClient client; | |
46 RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::creat
e(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()); | |
53 } | |
54 | |
55 TEST(CCDelayBasedTimeSource, StartTwiceEnqueuesOneTask) | |
56 { | |
57 FakeCCThread thread; | |
58 FakeCCTimeSourceClient client; | |
59 RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::creat
e(interval(), &thread); | |
60 timer->setClient(&client); | |
61 timer->setActive(true); | |
62 EXPECT_TRUE(thread.hasPendingTask()); | |
63 thread.reset(); | |
64 timer->setActive(true); | |
65 EXPECT_FALSE(thread.hasPendingTask()); | |
66 } | |
67 | |
68 TEST(CCDelayBasedTimeSource, StartWhenRunningDoesntTick) | |
69 { | |
70 FakeCCThread thread; | |
71 FakeCCTimeSourceClient client; | |
72 RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::creat
e(interval(), &thread); | |
73 timer->setClient(&client); | |
74 timer->setActive(true); | |
75 thread.runPendingTask(); | |
76 thread.reset(); | |
77 timer->setActive(true); | |
78 EXPECT_FALSE(thread.hasPendingTask()); | |
79 } | |
80 | |
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) | |
84 { | |
85 FakeCCThread thread; | |
86 FakeCCTimeSourceClient client; | |
87 RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::creat
e(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(); | |
92 | |
93 EXPECT_EQ(16, thread.pendingDelayMs()); | |
94 | |
95 timer->setNow(timer->now() + interval()); | |
96 thread.runPendingTask(); | |
97 | |
98 EXPECT_EQ(16, thread.pendingDelayMs()); | |
99 } | |
100 | |
101 // At 60Hz, when the tick returns at slightly after the requested next time, mak
e sure | |
102 // a 16ms next delay is posted. | |
103 TEST(CCDelayBasedTimeSource, NextDelaySaneWhenSlightlyAfterRequestedTime) | |
104 { | |
105 FakeCCThread thread; | |
106 FakeCCTimeSourceClient client; | |
107 RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::creat
e(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(); | |
112 | |
113 EXPECT_EQ(16, thread.pendingDelayMs()); | |
114 | |
115 timer->setNow(timer->now() + interval() + base::TimeDelta::FromMicroseconds(
1)); | |
116 thread.runPendingTask(); | |
117 | |
118 EXPECT_EQ(16, thread.pendingDelayMs()); | |
119 } | |
120 | |
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) | |
124 { | |
125 FakeCCThread thread; | |
126 FakeCCTimeSourceClient client; | |
127 RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::creat
e(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(); | |
132 | |
133 EXPECT_EQ(16, thread.pendingDelayMs()); | |
134 | |
135 timer->setNow(timer->now() + 2 * interval()); | |
136 thread.runPendingTask(); | |
137 | |
138 EXPECT_EQ(16, thread.pendingDelayMs()); | |
139 } | |
140 | |
141 // At 60Hz, when the tick returns at 2*interval and a bit after the requested ne
xt time, make sure | |
142 // a 16ms next delay is posted. | |
143 TEST(CCDelayBasedTimeSource, NextDelaySaneWhenSlightlyAfterTwiceRequestedTime) | |
144 { | |
145 FakeCCThread thread; | |
146 FakeCCTimeSourceClient client; | |
147 RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::creat
e(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(); | |
152 | |
153 EXPECT_EQ(16, thread.pendingDelayMs()); | |
154 | |
155 timer->setNow(timer->now() + 2 * interval() + base::TimeDelta::FromMicroseco
nds(1)); | |
156 thread.runPendingTask(); | |
157 | |
158 EXPECT_EQ(16, thread.pendingDelayMs()); | |
159 } | |
160 | |
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) | |
164 { | |
165 FakeCCThread thread; | |
166 FakeCCTimeSourceClient client; | |
167 RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::creat
e(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(); | |
172 | |
173 EXPECT_EQ(16, thread.pendingDelayMs()); | |
174 | |
175 timer->setNow(timer->now() + interval() + base::TimeDelta::FromMilliseconds(
8)); | |
176 thread.runPendingTask(); | |
177 | |
178 EXPECT_EQ(8, thread.pendingDelayMs()); | |
179 } | |
180 | |
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) | |
184 { | |
185 FakeCCThread thread; | |
186 FakeCCTimeSourceClient client; | |
187 RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::creat
e(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(); | |
192 | |
193 EXPECT_EQ(16, thread.pendingDelayMs()); | |
194 | |
195 // Jitter timebase ~1ms late | |
196 timer->setNow(timer->now() + interval()); | |
197 timer->setTimebaseAndInterval(timer->now() + base::TimeDelta::FromMillisecon
ds(1), interval()); | |
198 thread.runPendingTask(); | |
199 | |
200 // Without double tick prevention, pendingDelayMs would be 1. | |
201 EXPECT_EQ(17, thread.pendingDelayMs()); | |
202 | |
203 // Jitter timebase ~1ms early | |
204 timer->setNow(timer->now() + interval()); | |
205 timer->setTimebaseAndInterval(timer->now() - base::TimeDelta::FromMillisecon
ds(1), interval()); | |
206 thread.runPendingTask(); | |
207 | |
208 EXPECT_EQ(15, thread.pendingDelayMs()); | |
209 } | |
210 | |
211 TEST(CCDelayBasedTimeSource, HandlesSignificantTimebaseChangesImmediately) | |
212 { | |
213 FakeCCThread thread; | |
214 FakeCCTimeSourceClient client; | |
215 RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::creat
e(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(); | |
220 | |
221 EXPECT_EQ(16, thread.pendingDelayMs()); | |
222 | |
223 // Tick, then shift timebase by +7ms. | |
224 timer->setNow(timer->now() + interval()); | |
225 thread.runPendingTask(); | |
226 | |
227 EXPECT_EQ(16, thread.pendingDelayMs()); | |
228 | |
229 client.reset(); | |
230 thread.runPendingTaskOnOverwrite(true); | |
231 base::TimeDelta jitter = base::TimeDelta::FromMilliseconds(7) + base::TimeDe
lta::FromMicroseconds(1); | |
232 timer->setTimebaseAndInterval(timer->now() + jitter, interval()); | |
233 thread.runPendingTaskOnOverwrite(false); | |
234 | |
235 EXPECT_FALSE(client.tickCalled()); // Make sure pending tasks were canceled. | |
236 EXPECT_EQ(7, thread.pendingDelayMs()); | |
237 | |
238 // Tick, then shift timebase by -7ms. | |
239 timer->setNow(timer->now() + jitter); | |
240 thread.runPendingTask(); | |
241 | |
242 EXPECT_EQ(16, thread.pendingDelayMs()); | |
243 | |
244 client.reset(); | |
245 thread.runPendingTaskOnOverwrite(true); | |
246 timer->setTimebaseAndInterval(base::TimeTicks() + interval(), interval()); | |
247 thread.runPendingTaskOnOverwrite(false); | |
248 | |
249 EXPECT_FALSE(client.tickCalled()); // Make sure pending tasks were canceled. | |
250 EXPECT_EQ(16-7, thread.pendingDelayMs()); | |
251 } | |
252 | |
253 TEST(CCDelayBasedTimeSource, HanldlesSignificantIntervalChangesImmediately) | |
254 { | |
255 FakeCCThread thread; | |
256 FakeCCTimeSourceClient client; | |
257 RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::creat
e(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(); | |
262 | |
263 EXPECT_EQ(16, thread.pendingDelayMs()); | |
264 | |
265 // Tick, then double the interval. | |
266 timer->setNow(timer->now() + interval()); | |
267 thread.runPendingTask(); | |
268 | |
269 EXPECT_EQ(16, thread.pendingDelayMs()); | |
270 | |
271 client.reset(); | |
272 thread.runPendingTaskOnOverwrite(true); | |
273 timer->setTimebaseAndInterval(base::TimeTicks() + interval(), interval() * 2
); | |
274 thread.runPendingTaskOnOverwrite(false); | |
275 | |
276 EXPECT_FALSE(client.tickCalled()); // Make sure pending tasks were canceled. | |
277 EXPECT_EQ(33, thread.pendingDelayMs()); | |
278 | |
279 // Tick, then halve the interval. | |
280 timer->setNow(timer->now() + interval() * 2); | |
281 thread.runPendingTask(); | |
282 | |
283 EXPECT_EQ(33, thread.pendingDelayMs()); | |
284 | |
285 client.reset(); | |
286 thread.runPendingTaskOnOverwrite(true); | |
287 timer->setTimebaseAndInterval(base::TimeTicks() + interval() * 3, interval()
); | |
288 thread.runPendingTaskOnOverwrite(false); | |
289 | |
290 EXPECT_FALSE(client.tickCalled()); // Make sure pending tasks were canceled. | |
291 EXPECT_EQ(16, thread.pendingDelayMs()); | |
292 } | |
293 | |
294 TEST(CCDelayBasedTimeSourceTest, AchievesTargetRateWithNoNoise) | |
295 { | |
296 int numIterations = 10; | |
297 | |
298 FakeCCThread thread; | |
299 FakeCCTimeSourceClient client; | |
300 RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::creat
e(interval(), &thread); | |
301 timer->setClient(&client); | |
302 timer->setActive(true); | |
303 | |
304 double totalFrameTime = 0; | |
305 for (int i = 0; i < numIterations; ++i) { | |
306 long long delayMs = thread.pendingDelayMs(); | |
307 | |
308 // accumulate the "delay" | |
309 totalFrameTime += delayMs / 1000.0; | |
310 | |
311 // Run the callback exactly when asked | |
312 timer->setNow(timer->now() + base::TimeDelta::FromMilliseconds(delayMs))
; | |
313 thread.runPendingTask(); | |
314 } | |
315 double averageInterval = totalFrameTime / static_cast<double>(numIterations)
; | |
316 EXPECT_NEAR(1.0 / 60.0, averageInterval, 0.1); | |
317 } | |
318 | |
319 TEST(CCDelayBasedTimeSource, TestDeactivateWhilePending) | |
320 { | |
321 FakeCCThread thread; | |
322 FakeCCTimeSourceClient client; | |
323 RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::creat
e(interval(), &thread); | |
324 timer->setClient(&client); | |
325 timer->setActive(true); // Should post a task. | |
326 timer->setActive(false); | |
327 timer.clear(); | |
328 thread.runPendingTask(); // Should run the posted task without crashing. | |
329 } | |
330 | |
331 TEST(CCDelayBasedTimeSource, TestDeactivateAndReactivateBeforeNextTickTime) | |
332 { | |
333 FakeCCThread thread; | |
334 FakeCCTimeSourceClient client; | |
335 RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::creat
e(interval(), &thread); | |
336 timer->setClient(&client); | |
337 | |
338 // Should run the activate task, and pick up a new timebase. | |
339 timer->setActive(true); | |
340 thread.runPendingTask(); | |
341 | |
342 // Stop the timer | |
343 timer->setActive(false); | |
344 | |
345 // Task will be pending anyway, run it | |
346 thread.runPendingTask(); | |
347 | |
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()); | |
353 } | |
354 | |
355 TEST(CCDelayBasedTimeSource, TestDeactivateAndReactivateAfterNextTickTime) | |
356 { | |
357 FakeCCThread thread; | |
358 FakeCCTimeSourceClient client; | |
359 RefPtr<FakeCCDelayBasedTimeSource> timer = FakeCCDelayBasedTimeSource::creat
e(interval(), &thread); | |
360 timer->setClient(&client); | |
361 | |
362 // Should run the activate task, and pick up a new timebase. | |
363 timer->setActive(true); | |
364 thread.runPendingTask(); | |
365 | |
366 // Stop the timer | |
367 timer->setActive(false); | |
368 | |
369 // Task will be pending anyway, run it | |
370 thread.runPendingTask(); | |
371 | |
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()); | |
377 } | |
378 | |
379 } | |
OLD | NEW |