Home | History | Annotate | Download | only in scheduler
      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