Fix Win8 metro startup crash from window switcher button
[chromium-blink-merge.git] / cc / scheduler / delay_based_time_source_unittest.cc
blobc3681950c3b78bcc9f056392a464dba9b9df3435
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"
12 namespace cc {
13 namespace {
15 base::TimeDelta Interval() {
16 return base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond /
17 60);
20 TEST(DelayBasedTimeSourceTest, TaskPostedAndTickCalled) {
21 FakeThread thread;
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) {
38 FakeThread thread;
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) {
51 FakeThread thread;
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());
58 thread.Reset();
59 timer->SetActive(true);
60 EXPECT_FALSE(thread.HasPendingTask());
63 TEST(DelayBasedTimeSource, StartWhenRunningDoesntTick) {
64 FakeThread thread;
65 FakeTimeSourceClient client;
66 scoped_refptr<FakeDelayBasedTimeSource> timer =
67 FakeDelayBasedTimeSource::Create(Interval(), &thread);
68 timer->SetClient(&client);
69 timer->SetActive(true);
70 thread.RunPendingTask();
71 thread.Reset();
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) {
79 FakeThread thread;
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) {
99 FakeThread thread;
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) {
120 FakeThread thread;
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) {
140 FakeThread thread;
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) {
161 FakeThread thread;
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) {
182 FakeThread thread;
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) {
212 FakeThread thread;
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());
229 client.Reset();
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());
245 client.Reset();
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) {
255 FakeThread thread;
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());
272 client.Reset();
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());
286 client.Reset();
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;
298 FakeThread thread;
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) {
322 FakeThread thread;
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);
329 timer = NULL;
330 thread.RunPendingTask(); // Should run the posted task without crashing.
333 TEST(DelayBasedTimeSource, TestDeactivateAndReactivateBeforeNextTickTime) {
334 FakeThread thread;
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();
344 // Stop the timer
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) {
358 FakeThread thread;
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();
368 // Stop the timer.
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());
381 } // namespace
382 } // namespace cc