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