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 "cc/scheduler/delay_based_time_source.h" 6 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" 11 12 namespace cc { 13 namespace { 14 15 base::TimeDelta Interval() { 16 return base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond / 17 60); 18 } 19 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); 27 28 timer->SetActive(true); 29 EXPECT_TRUE(timer->Active()); 30 EXPECT_TRUE(task_runner->HasPendingTask()); 31 32 timer->SetNow(timer->Now() + base::TimeDelta::FromMilliseconds(16)); 33 task_runner->RunPendingTasks(); 34 EXPECT_TRUE(timer->Active()); 35 EXPECT_TRUE(client.TickCalled()); 36 } 37 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()); 50 } 51 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()); 64 } 65 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()); 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(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(); 93 94 EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds()); 95 96 timer->SetNow(timer->Now() + Interval()); 97 task_runner->RunPendingTasks(); 98 99 EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds()); 100 } 101 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(); 114 115 EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds()); 116 117 timer->SetNow(timer->Now() + Interval() + 118 base::TimeDelta::FromMicroseconds(1)); 119 task_runner->RunPendingTasks(); 120 121 EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds()); 122 } 123 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(); 136 137 EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds()); 138 139 timer->SetNow(timer->Now() + 2 * Interval()); 140 task_runner->RunPendingTasks(); 141 142 EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds()); 143 } 144 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(); 157 158 EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds()); 159 160 timer->SetNow(timer->Now() + 2 * Interval() + 161 base::TimeDelta::FromMicroseconds(1)); 162 task_runner->RunPendingTasks(); 163 164 EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds()); 165 } 166 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(); 179 180 EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds()); 181 182 timer->SetNow(timer->Now() + Interval() + 183 base::TimeDelta::FromMilliseconds(8)); 184 task_runner->RunPendingTasks(); 185 186 EXPECT_EQ(8, task_runner->NextPendingTaskDelay().InMilliseconds()); 187 } 188 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(); 201 202 EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds()); 203 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(); 209 210 // Without double tick prevention, NextPendingTaskDelay would be 1. 211 EXPECT_EQ(17, task_runner->NextPendingTaskDelay().InMilliseconds()); 212 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(); 218 219 EXPECT_EQ(15, task_runner->NextPendingTaskDelay().InMilliseconds()); 220 } 221 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(); 232 233 EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds()); 234 235 // Tick, then shift timebase by +7ms. 236 timer->SetNow(timer->Now() + Interval()); 237 task_runner->RunPendingTasks(); 238 239 EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds()); 240 241 client.Reset(); 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()); 247 248 EXPECT_FALSE(client.TickCalled()); // Make sure pending tasks were canceled. 249 EXPECT_EQ(7, task_runner->NextPendingTaskDelay().InMilliseconds()); 250 251 // Tick, then shift timebase by -7ms. 252 timer->SetNow(timer->Now() + jitter); 253 task_runner->RunPendingTasks(); 254 255 EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds()); 256 257 client.Reset(); 258 task_runner->ClearPendingTasks(); 259 task_runner->RunPendingTasks(); 260 timer->SetTimebaseAndInterval(base::TimeTicks() + Interval(), Interval()); 261 262 EXPECT_FALSE(client.TickCalled()); // Make sure pending tasks were canceled. 263 EXPECT_EQ(16 - 7, task_runner->NextPendingTaskDelay().InMilliseconds()); 264 } 265 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(); 276 277 EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds()); 278 279 // Tick, then double the interval. 280 timer->SetNow(timer->Now() + Interval()); 281 task_runner->RunPendingTasks(); 282 283 EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds()); 284 285 client.Reset(); 286 task_runner->ClearPendingTasks(); 287 task_runner->RunPendingTasks(); 288 timer->SetTimebaseAndInterval(base::TimeTicks() + Interval(), Interval() * 2); 289 290 EXPECT_FALSE(client.TickCalled()); // Make sure pending tasks were canceled. 291 EXPECT_EQ(33, task_runner->NextPendingTaskDelay().InMilliseconds()); 292 293 // Tick, then halve the interval. 294 timer->SetNow(timer->Now() + Interval() * 2); 295 task_runner->RunPendingTasks(); 296 297 EXPECT_EQ(33, task_runner->NextPendingTaskDelay().InMilliseconds()); 298 299 client.Reset(); 300 task_runner->ClearPendingTasks(); 301 task_runner->RunPendingTasks(); 302 timer->SetTimebaseAndInterval(base::TimeTicks() + Interval() * 3, Interval()); 303 304 EXPECT_FALSE(client.TickCalled()); // Make sure pending tasks were canceled. 305 EXPECT_EQ(16, task_runner->NextPendingTaskDelay().InMilliseconds()); 306 } 307 308 TEST(DelayBasedTimeSourceTest, AchievesTargetRateWithNoNoise) { 309 int num_iterations = 10; 310 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); 318 319 double total_frame_time = 0.0; 320 for (int i = 0; i < num_iterations; ++i) { 321 int64 delay_ms = task_runner->NextPendingTaskDelay().InMilliseconds(); 322 323 // accumulate the "delay" 324 total_frame_time += delay_ms / 1000.0; 325 326 // Run the callback exactly when asked 327 timer->SetNow(timer->Now() + base::TimeDelta::FromMilliseconds(delay_ms)); 328 task_runner->RunPendingTasks(); 329 } 330 double average_interval = 331 total_frame_time / static_cast<double>(num_iterations); 332 EXPECT_NEAR(1.0 / 60.0, average_interval, 0.1); 333 } 334 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); 344 timer = NULL; 345 // Should run the posted task without crashing. 346 EXPECT_TRUE(task_runner->HasPendingTask()); 347 task_runner->RunPendingTasks(); 348 } 349 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); 357 358 // Should run the activate task, and pick up a new timebase. 359 timer->SetActive(true); 360 task_runner->RunPendingTasks(); 361 362 // Stop the timer 363 timer->SetActive(false); 364 365 // Task will be pending anyway, run it 366 task_runner->RunPendingTasks(); 367 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()); 373 } 374 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); 382 383 // Should run the activate task, and pick up a new timebase. 384 timer->SetActive(true); 385 task_runner->RunPendingTasks(); 386 387 // Stop the timer. 388 timer->SetActive(false); 389 390 // Task will be pending anyway, run it. 391 task_runner->RunPendingTasks(); 392 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()); 398 } 399 400 } // namespace 401 } // namespace cc 402