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 "components/viz/common/frame_sinks/delay_based_time_source.h"
6 
7 #include <stdint.h>
8 
9 #include "base/test/simple_test_tick_clock.h"
10 #include "base/test/test_simple_task_runner.h"
11 #include "components/viz/test/fake_delay_based_time_source.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 
14 namespace viz {
15 namespace {
16 
Interval()17 base::TimeDelta Interval() {
18   return base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond /
19                                            60);
20 }
21 
22 class DelayBasedTimeSourceTest : public ::testing::Test {
23  protected:
SetUp()24   void SetUp() override {
25     now_src_ = std::make_unique<base::SimpleTestTickClock>();
26     task_runner_ = base::MakeRefCounted<base::TestSimpleTaskRunner>();
27     delay_based_time_source_ = std::make_unique<FakeDelayBasedTimeSource>(
28         now_src_.get(), task_runner_.get());
29     delay_based_time_source_->SetClient(&client_);
30   }
31 
TearDown()32   void TearDown() override {
33     delay_based_time_source_.reset();
34     task_runner_ = nullptr;
35     now_src_.reset();
36   }
37 
SetNow(base::TimeTicks ticks)38   void SetNow(base::TimeTicks ticks) { now_src_->SetNowTicks(ticks); }
39 
task_runner()40   base::TestSimpleTaskRunner* task_runner() { return task_runner_.get(); }
41 
timer()42   FakeDelayBasedTimeSource* timer() { return delay_based_time_source_.get(); }
43 
client()44   FakeDelayBasedTimeSourceClient* client() { return &client_; }
45 
46   std::unique_ptr<base::SimpleTestTickClock> now_src_;
47   FakeDelayBasedTimeSourceClient client_;
48   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
49   std::unique_ptr<FakeDelayBasedTimeSource> delay_based_time_source_;
50 };
51 
TEST_F(DelayBasedTimeSourceTest,TaskPostedAndTickCalled)52 TEST_F(DelayBasedTimeSourceTest, TaskPostedAndTickCalled) {
53   timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
54   timer()->SetActive(true);
55   EXPECT_TRUE(timer()->Active());
56   EXPECT_TRUE(task_runner()->HasPendingTask());
57 
58   SetNow(timer()->Now() + base::TimeDelta::FromMilliseconds(16));
59   task_runner()->RunPendingTasks();
60   EXPECT_TRUE(timer()->Active());
61   EXPECT_TRUE(client()->TickCalled());
62 }
63 
TEST_F(DelayBasedTimeSourceTest,TickNotCalledWithTaskPosted)64 TEST_F(DelayBasedTimeSourceTest, TickNotCalledWithTaskPosted) {
65   timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
66   timer()->SetActive(true);
67   EXPECT_TRUE(task_runner()->HasPendingTask());
68   timer()->SetActive(false);
69   task_runner()->RunPendingTasks();
70   EXPECT_FALSE(client()->TickCalled());
71 }
72 
TEST_F(DelayBasedTimeSourceTest,StartTwiceEnqueuesOneTask)73 TEST_F(DelayBasedTimeSourceTest, StartTwiceEnqueuesOneTask) {
74   timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
75   timer()->SetActive(true);
76   EXPECT_TRUE(task_runner()->HasPendingTask());
77   task_runner()->ClearPendingTasks();
78   timer()->SetActive(true);
79   EXPECT_FALSE(task_runner()->HasPendingTask());
80 }
81 
TEST_F(DelayBasedTimeSourceTest,StartWhenRunningDoesntTick)82 TEST_F(DelayBasedTimeSourceTest, StartWhenRunningDoesntTick) {
83   timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
84   timer()->SetActive(true);
85   EXPECT_TRUE(task_runner()->HasPendingTask());
86   task_runner()->RunPendingTasks();
87   task_runner()->ClearPendingTasks();
88   timer()->SetActive(true);
89   EXPECT_FALSE(task_runner()->HasPendingTask());
90 }
91 
92 // At 60Hz, when the tick returns at exactly the requested next time, make sure
93 // a 16ms next delay is posted.
TEST_F(DelayBasedTimeSourceTest,NextDelaySaneWhenExactlyOnRequestedTime)94 TEST_F(DelayBasedTimeSourceTest, NextDelaySaneWhenExactlyOnRequestedTime) {
95   timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
96   timer()->SetActive(true);
97   // Run the first tick.
98   task_runner()->RunPendingTasks();
99 
100   EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
101 
102   SetNow(timer()->Now() + Interval());
103   task_runner()->RunPendingTasks();
104 
105   EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
106 }
107 
108 // At 60Hz, when the tick returns at slightly after the requested next time,
109 // make sure a 16ms next delay is posted.
TEST_F(DelayBasedTimeSourceTest,NextDelaySaneWhenSlightlyAfterRequestedTime)110 TEST_F(DelayBasedTimeSourceTest, NextDelaySaneWhenSlightlyAfterRequestedTime) {
111   timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
112   timer()->SetActive(true);
113   // Run the first tick.
114   task_runner()->RunPendingTasks();
115 
116   EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
117 
118   SetNow(timer()->Now() + Interval() + 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 we don't tick unnecessarily.
TEST_F(DelayBasedTimeSourceTest,NextDelaySaneWhenExactlyTwiceAfterRequestedTime)126 TEST_F(DelayBasedTimeSourceTest,
127        NextDelaySaneWhenExactlyTwiceAfterRequestedTime) {
128   timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
129   timer()->SetActive(true);
130   // Run the first tick.
131   task_runner()->RunPendingTasks();
132 
133   EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
134 
135   SetNow(timer()->Now() + 2 * Interval());
136   task_runner()->RunPendingTasks();
137 
138   EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
139 }
140 
141 // At 60Hz, when the tick returns at 2*interval and a bit after the requested
142 // next time, make sure a 16ms next delay is posted.
TEST_F(DelayBasedTimeSourceTest,NextDelaySaneWhenSlightlyAfterTwiceRequestedTime)143 TEST_F(DelayBasedTimeSourceTest,
144        NextDelaySaneWhenSlightlyAfterTwiceRequestedTime) {
145   timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
146   timer()->SetActive(true);
147   // Run the first tick.
148   task_runner()->RunPendingTasks();
149 
150   EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
151 
152   SetNow(timer()->Now() + 2 * Interval() +
153          base::TimeDelta::FromMicroseconds(1));
154   task_runner()->RunPendingTasks();
155 
156   EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
157 }
158 
159 // At 60Hz, when the tick returns halfway to the next frame time, make sure
160 // a correct next delay value is posted.
TEST_F(DelayBasedTimeSourceTest,NextDelaySaneWhenHalfAfterRequestedTime)161 TEST_F(DelayBasedTimeSourceTest, NextDelaySaneWhenHalfAfterRequestedTime) {
162   timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
163   timer()->SetActive(true);
164   // Run the first tick.
165   task_runner()->RunPendingTasks();
166 
167   EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
168 
169   SetNow(timer()->Now() + Interval() + base::TimeDelta::FromMilliseconds(8));
170   task_runner()->RunPendingTasks();
171 
172   EXPECT_EQ(8, task_runner()->NextPendingTaskDelay().InMilliseconds());
173 }
174 
TEST_F(DelayBasedTimeSourceTest,JitteryRuntimeWithFutureTimebases)175 TEST_F(DelayBasedTimeSourceTest, JitteryRuntimeWithFutureTimebases) {
176   timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
177   timer()->SetActive(true);
178 
179   // Run the first tick.
180   task_runner()->RunPendingTasks();
181   EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
182 
183   base::TimeTicks future_timebase = timer()->Now() + Interval() * 10;
184 
185   // 1ms jitter
186   base::TimeDelta jitter1 = base::TimeDelta::FromMilliseconds(1);
187 
188   // Tick with +1ms of jitter
189   future_timebase += Interval();
190   timer()->SetTimebaseAndInterval(future_timebase, Interval());
191   SetNow(timer()->Now() + Interval() + jitter1);
192   task_runner()->RunPendingTasks();
193   EXPECT_EQ(15, task_runner()->NextPendingTaskDelay().InMilliseconds());
194 
195   // Tick with 0ms of jitter
196   future_timebase += Interval();
197   timer()->SetTimebaseAndInterval(future_timebase, Interval());
198   SetNow(timer()->Now() + Interval() - jitter1);
199   task_runner()->RunPendingTasks();
200   EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
201 
202   // Tick with -1ms of jitter
203   future_timebase += Interval();
204   timer()->SetTimebaseAndInterval(future_timebase, Interval());
205   SetNow(timer()->Now() + Interval() - jitter1);
206   task_runner()->RunPendingTasks();
207   EXPECT_EQ(1, task_runner()->NextPendingTaskDelay().InMilliseconds());
208 
209   // Tick with 0ms of jitter
210   future_timebase += Interval();
211   timer()->SetTimebaseAndInterval(future_timebase, Interval());
212   SetNow(timer()->Now() + Interval() + jitter1);
213   task_runner()->RunPendingTasks();
214   EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
215 
216   // 8 ms jitter
217   base::TimeDelta jitter8 = base::TimeDelta::FromMilliseconds(8);
218 
219   // Tick with +8ms of jitter
220   future_timebase += Interval();
221   timer()->SetTimebaseAndInterval(future_timebase, Interval());
222   SetNow(timer()->Now() + Interval() + jitter8);
223   task_runner()->RunPendingTasks();
224   EXPECT_EQ(8, task_runner()->NextPendingTaskDelay().InMilliseconds());
225 
226   // Tick with 0ms of jitter
227   future_timebase += Interval();
228   timer()->SetTimebaseAndInterval(future_timebase, Interval());
229   SetNow(timer()->Now() + Interval() - jitter8);
230   task_runner()->RunPendingTasks();
231   EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
232 
233   // Tick with -8ms of jitter
234   future_timebase += Interval();
235   timer()->SetTimebaseAndInterval(future_timebase, Interval());
236   SetNow(timer()->Now() + Interval() - jitter8);
237   task_runner()->RunPendingTasks();
238   EXPECT_EQ(8, task_runner()->NextPendingTaskDelay().InMilliseconds());
239 
240   // Tick with 0ms of jitter
241   future_timebase += Interval();
242   timer()->SetTimebaseAndInterval(future_timebase, Interval());
243   SetNow(timer()->Now() + Interval() + jitter8);
244   task_runner()->RunPendingTasks();
245   EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
246 
247   // 15 ms jitter
248   base::TimeDelta jitter15 = base::TimeDelta::FromMilliseconds(15);
249 
250   // Tick with +15ms jitter
251   future_timebase += Interval();
252   timer()->SetTimebaseAndInterval(future_timebase, Interval());
253   SetNow(timer()->Now() + Interval() + jitter15);
254   task_runner()->RunPendingTasks();
255   EXPECT_EQ(1, task_runner()->NextPendingTaskDelay().InMilliseconds());
256 
257   // Tick with 0ms of jitter
258   future_timebase += Interval();
259   timer()->SetTimebaseAndInterval(future_timebase, Interval());
260   SetNow(timer()->Now() + Interval() - jitter15);
261   task_runner()->RunPendingTasks();
262   EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
263 
264   // Tick with -15ms of jitter
265   future_timebase += Interval();
266   timer()->SetTimebaseAndInterval(future_timebase, Interval());
267   SetNow(timer()->Now() + Interval() - jitter15);
268   task_runner()->RunPendingTasks();
269   EXPECT_EQ(15, task_runner()->NextPendingTaskDelay().InMilliseconds());
270 
271   // Tick with 0ms of jitter
272   future_timebase += Interval();
273   timer()->SetTimebaseAndInterval(future_timebase, Interval());
274   SetNow(timer()->Now() + Interval() + jitter15);
275   task_runner()->RunPendingTasks();
276   EXPECT_EQ(16, task_runner()->NextPendingTaskDelay().InMilliseconds());
277 }
278 
TEST_F(DelayBasedTimeSourceTest,AchievesTargetRateWithNoNoise)279 TEST_F(DelayBasedTimeSourceTest, AchievesTargetRateWithNoNoise) {
280   int num_iterations = 10;
281 
282   timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
283   timer()->SetActive(true);
284 
285   double total_frame_time = 0.0;
286   for (int i = 0; i < num_iterations; ++i) {
287     int64_t delay_ms = task_runner()->NextPendingTaskDelay().InMilliseconds();
288 
289     // accumulate the "delay"
290     total_frame_time += delay_ms / 1000.0;
291 
292     // Run the callback exactly when asked
293     SetNow(timer()->Now() + base::TimeDelta::FromMilliseconds(delay_ms));
294     task_runner()->RunPendingTasks();
295   }
296   double average_interval =
297       total_frame_time / static_cast<double>(num_iterations);
298   EXPECT_NEAR(1.0 / 60.0, average_interval, 0.1);
299 }
300 
TEST_F(DelayBasedTimeSourceTest,TestDeactivateWhilePending)301 TEST_F(DelayBasedTimeSourceTest, TestDeactivateWhilePending) {
302   timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
303   timer()->SetActive(true);  // Should post a task.
304   timer()->SetActive(false);
305   // Should run the posted task without crashing.
306   EXPECT_TRUE(task_runner()->HasPendingTask());
307   task_runner()->RunPendingTasks();
308 }
309 
TEST_F(DelayBasedTimeSourceTest,TestDeactivateAndReactivateBeforeNextTickTime)310 TEST_F(DelayBasedTimeSourceTest,
311        TestDeactivateAndReactivateBeforeNextTickTime) {
312   timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
313 
314   // Should run the activate task, and pick up a new timebase.
315   timer()->SetActive(true);
316   task_runner()->RunPendingTasks();
317 
318   // Stop the timer()
319   timer()->SetActive(false);
320 
321   // Task will be pending anyway, run it
322   task_runner()->RunPendingTasks();
323 
324   // Start the timer() again, but before the next tick time the timer()
325   // previously planned on using. That same tick time should still be targeted.
326   SetNow(timer()->Now() + base::TimeDelta::FromMilliseconds(4));
327   timer()->SetActive(true);
328   EXPECT_EQ(12, task_runner()->NextPendingTaskDelay().InMilliseconds());
329 }
330 
TEST_F(DelayBasedTimeSourceTest,TestDeactivateAndReactivateAfterNextTickTime)331 TEST_F(DelayBasedTimeSourceTest, TestDeactivateAndReactivateAfterNextTickTime) {
332   timer()->SetTimebaseAndInterval(base::TimeTicks(), Interval());
333 
334   // Should run the activate task, and pick up a new timebase.
335   timer()->SetActive(true);
336   task_runner()->RunPendingTasks();
337 
338   // Stop the timer().
339   timer()->SetActive(false);
340 
341   // Task will be pending anyway, run it.
342   task_runner()->RunPendingTasks();
343 
344   // Start the timer() again, but before the next tick time the timer()
345   // previously planned on using. That same tick time should still be targeted.
346   SetNow(timer()->Now() + base::TimeDelta::FromMilliseconds(20));
347   timer()->SetActive(true);
348   EXPECT_EQ(13, task_runner()->NextPendingTaskDelay().InMilliseconds());
349 }
350 
351 }  // namespace
352 }  // namespace viz
353