OLD | NEW |
1 // Copyright 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/scheduler/delay_based_time_source.h" | 5 #include "cc/scheduler/delay_based_time_source.h" |
6 | 6 |
7 #include "cc/base/thread.h" | 7 #include "cc/base/thread.h" |
8 #include "cc/test/scheduler_test_common.h" | 8 #include "cc/test/scheduler_test_common.h" |
9 #include "testing/gtest/include/gtest/gtest.h" | 9 #include "testing/gtest/include/gtest/gtest.h" |
10 | 10 |
11 namespace cc { | 11 namespace cc { |
12 namespace { | 12 namespace { |
13 | 13 |
14 base::TimeDelta interval() | 14 base::TimeDelta Interval() { |
15 { | 15 return base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond / |
16 return base::TimeDelta::FromMicroseconds(base::Time::kMicrosecondsPerSecond
/ 60); | 16 60); |
17 } | 17 } |
18 | 18 |
19 TEST(DelayBasedTimeSourceTest, TaskPostedAndTickCalled) | 19 TEST(DelayBasedTimeSourceTest, TaskPostedAndTickCalled) { |
20 { | 20 FakeThread thread; |
21 FakeThread thread; | 21 FakeTimeSourceClient client; |
22 FakeTimeSourceClient client; | 22 scoped_refptr<FakeDelayBasedTimeSource> timer = |
23 scoped_refptr<FakeDelayBasedTimeSource> timer = FakeDelayBasedTimeSource::cr
eate(interval(), &thread); | 23 FakeDelayBasedTimeSource::create(Interval(), &thread); |
24 timer->setClient(&client); | 24 timer->SetClient(&client); |
25 | 25 |
26 timer->setActive(true); | 26 timer->SetActive(true); |
27 EXPECT_TRUE(timer->active()); | 27 EXPECT_TRUE(timer->Active()); |
28 EXPECT_TRUE(thread.hasPendingTask()); | 28 EXPECT_TRUE(thread.hasPendingTask()); |
29 | 29 |
30 timer->setNow(timer->now() + base::TimeDelta::FromMilliseconds(16)); | 30 timer->setNow(timer->Now() + base::TimeDelta::FromMilliseconds(16)); |
31 thread.runPendingTask(); | 31 thread.runPendingTask(); |
32 EXPECT_TRUE(timer->active()); | 32 EXPECT_TRUE(timer->Active()); |
33 EXPECT_TRUE(client.tickCalled()); | 33 EXPECT_TRUE(client.tickCalled()); |
34 } | 34 } |
35 | 35 |
36 TEST(DelayBasedTimeSource, TickNotCalledWithTaskPosted) | 36 TEST(DelayBasedTimeSource, TickNotCalledWithTaskPosted) { |
37 { | 37 FakeThread thread; |
38 FakeThread thread; | 38 FakeTimeSourceClient client; |
39 FakeTimeSourceClient client; | 39 scoped_refptr<FakeDelayBasedTimeSource> timer = |
40 scoped_refptr<FakeDelayBasedTimeSource> timer = FakeDelayBasedTimeSource::cr
eate(interval(), &thread); | 40 FakeDelayBasedTimeSource::create(Interval(), &thread); |
41 timer->setClient(&client); | 41 timer->SetClient(&client); |
42 timer->setActive(true); | 42 timer->SetActive(true); |
43 EXPECT_TRUE(thread.hasPendingTask()); | 43 EXPECT_TRUE(thread.hasPendingTask()); |
44 timer->setActive(false); | 44 timer->SetActive(false); |
45 thread.runPendingTask(); | 45 thread.runPendingTask(); |
46 EXPECT_FALSE(client.tickCalled()); | 46 EXPECT_FALSE(client.tickCalled()); |
47 } | 47 } |
48 | 48 |
49 TEST(DelayBasedTimeSource, StartTwiceEnqueuesOneTask) | 49 TEST(DelayBasedTimeSource, StartTwiceEnqueuesOneTask) { |
50 { | 50 FakeThread thread; |
51 FakeThread thread; | 51 FakeTimeSourceClient client; |
52 FakeTimeSourceClient client; | 52 scoped_refptr<FakeDelayBasedTimeSource> timer = |
53 scoped_refptr<FakeDelayBasedTimeSource> timer = FakeDelayBasedTimeSource::cr
eate(interval(), &thread); | 53 FakeDelayBasedTimeSource::create(Interval(), &thread); |
54 timer->setClient(&client); | 54 timer->SetClient(&client); |
55 timer->setActive(true); | 55 timer->SetActive(true); |
56 EXPECT_TRUE(thread.hasPendingTask()); | 56 EXPECT_TRUE(thread.hasPendingTask()); |
57 thread.reset(); | 57 thread.reset(); |
58 timer->setActive(true); | 58 timer->SetActive(true); |
59 EXPECT_FALSE(thread.hasPendingTask()); | 59 EXPECT_FALSE(thread.hasPendingTask()); |
60 } | 60 } |
61 | 61 |
62 TEST(DelayBasedTimeSource, StartWhenRunningDoesntTick) | 62 TEST(DelayBasedTimeSource, StartWhenRunningDoesntTick) { |
63 { | 63 FakeThread thread; |
64 FakeThread thread; | 64 FakeTimeSourceClient client; |
65 FakeTimeSourceClient client; | 65 scoped_refptr<FakeDelayBasedTimeSource> timer = |
66 scoped_refptr<FakeDelayBasedTimeSource> timer = FakeDelayBasedTimeSource::cr
eate(interval(), &thread); | 66 FakeDelayBasedTimeSource::create(Interval(), &thread); |
67 timer->setClient(&client); | 67 timer->SetClient(&client); |
68 timer->setActive(true); | 68 timer->SetActive(true); |
69 thread.runPendingTask(); | 69 thread.runPendingTask(); |
70 thread.reset(); | 70 thread.reset(); |
71 timer->setActive(true); | 71 timer->SetActive(true); |
72 EXPECT_FALSE(thread.hasPendingTask()); | 72 EXPECT_FALSE(thread.hasPendingTask()); |
73 } | 73 } |
74 | 74 |
75 // At 60Hz, when the tick returns at exactly the requested next time, make sure | 75 // At 60Hz, when the tick returns at exactly the requested next time, make sure |
76 // a 16ms next delay is posted. | 76 // a 16ms next delay is posted. |
77 TEST(DelayBasedTimeSource, NextDelaySaneWhenExactlyOnRequestedTime) | 77 TEST(DelayBasedTimeSource, NextDelaySaneWhenExactlyOnRequestedTime) { |
78 { | 78 FakeThread thread; |
79 FakeThread thread; | 79 FakeTimeSourceClient client; |
80 FakeTimeSourceClient client; | 80 scoped_refptr<FakeDelayBasedTimeSource> timer = |
81 scoped_refptr<FakeDelayBasedTimeSource> timer = FakeDelayBasedTimeSource::cr
eate(interval(), &thread); | 81 FakeDelayBasedTimeSource::create(Interval(), &thread); |
82 timer->setClient(&client); | 82 timer->SetClient(&client); |
83 timer->setActive(true); | 83 timer->SetActive(true); |
84 // Run the first task, as that activates the timer and picks up a timebase. | 84 // Run the first task, as that activates the timer and picks up a timebase. |
85 thread.runPendingTask(); | 85 thread.runPendingTask(); |
86 | 86 |
87 EXPECT_EQ(16, thread.pendingDelayMs()); | 87 EXPECT_EQ(16, thread.pendingDelayMs()); |
88 | 88 |
89 timer->setNow(timer->now() + interval()); | 89 timer->setNow(timer->Now() + Interval()); |
90 thread.runPendingTask(); | 90 thread.runPendingTask(); |
91 | 91 |
92 EXPECT_EQ(16, thread.pendingDelayMs()); | 92 EXPECT_EQ(16, thread.pendingDelayMs()); |
93 } | 93 } |
94 | 94 |
95 // At 60Hz, when the tick returns at slightly after the requested next time, mak
e sure | 95 // At 60Hz, when the tick returns at slightly after the requested next time, |
96 // a 16ms next delay is posted. | 96 // make sure a 16ms next delay is posted. |
97 TEST(DelayBasedTimeSource, NextDelaySaneWhenSlightlyAfterRequestedTime) | 97 TEST(DelayBasedTimeSource, NextDelaySaneWhenSlightlyAfterRequestedTime) { |
98 { | 98 FakeThread thread; |
99 FakeThread thread; | 99 FakeTimeSourceClient client; |
100 FakeTimeSourceClient client; | 100 scoped_refptr<FakeDelayBasedTimeSource> timer = |
101 scoped_refptr<FakeDelayBasedTimeSource> timer = FakeDelayBasedTimeSource::cr
eate(interval(), &thread); | 101 FakeDelayBasedTimeSource::create(Interval(), &thread); |
102 timer->setClient(&client); | 102 timer->SetClient(&client); |
103 timer->setActive(true); | 103 timer->SetActive(true); |
104 // Run the first task, as that activates the timer and picks up a timebase. | 104 // Run the first task, as that activates the timer and picks up a timebase. |
105 thread.runPendingTask(); | 105 thread.runPendingTask(); |
106 | 106 |
107 EXPECT_EQ(16, thread.pendingDelayMs()); | 107 EXPECT_EQ(16, thread.pendingDelayMs()); |
108 | 108 |
109 timer->setNow(timer->now() + interval() + base::TimeDelta::FromMicroseconds(
1)); | 109 timer->setNow(timer->Now() + Interval() + |
110 thread.runPendingTask(); | 110 base::TimeDelta::FromMicroseconds(1)); |
111 | 111 thread.runPendingTask(); |
112 EXPECT_EQ(16, thread.pendingDelayMs()); | 112 |
113 } | 113 EXPECT_EQ(16, thread.pendingDelayMs()); |
114 | 114 } |
115 // At 60Hz, when the tick returns at exactly 2*interval after the requested next
time, make sure | 115 |
116 // a 16ms next delay is posted. | 116 // At 60Hz, when the tick returns at exactly 2*interval after the requested next |
117 TEST(DelayBasedTimeSource, NextDelaySaneWhenExactlyTwiceAfterRequestedTime) | 117 // time, make sure a 16ms next delay is posted. |
118 { | 118 TEST(DelayBasedTimeSource, NextDelaySaneWhenExactlyTwiceAfterRequestedTime) { |
119 FakeThread thread; | 119 FakeThread thread; |
120 FakeTimeSourceClient client; | 120 FakeTimeSourceClient client; |
121 scoped_refptr<FakeDelayBasedTimeSource> timer = FakeDelayBasedTimeSource::cr
eate(interval(), &thread); | 121 scoped_refptr<FakeDelayBasedTimeSource> timer = |
122 timer->setClient(&client); | 122 FakeDelayBasedTimeSource::create(Interval(), &thread); |
123 timer->setActive(true); | 123 timer->SetClient(&client); |
124 // Run the first task, as that activates the timer and picks up a timebase. | 124 timer->SetActive(true); |
125 thread.runPendingTask(); | 125 // Run the first task, as that activates the timer and picks up a timebase. |
126 | 126 thread.runPendingTask(); |
127 EXPECT_EQ(16, thread.pendingDelayMs()); | 127 |
128 | 128 EXPECT_EQ(16, thread.pendingDelayMs()); |
129 timer->setNow(timer->now() + 2 * interval()); | 129 |
130 thread.runPendingTask(); | 130 timer->setNow(timer->Now() + 2 * Interval()); |
131 | 131 thread.runPendingTask(); |
132 EXPECT_EQ(16, thread.pendingDelayMs()); | 132 |
133 } | 133 EXPECT_EQ(16, thread.pendingDelayMs()); |
134 | 134 } |
135 // At 60Hz, when the tick returns at 2*interval and a bit after the requested ne
xt time, make sure | 135 |
136 // a 16ms next delay is posted. | 136 // At 60Hz, when the tick returns at 2*interval and a bit after the requested |
137 TEST(DelayBasedTimeSource, NextDelaySaneWhenSlightlyAfterTwiceRequestedTime) | 137 // next time, make sure a 16ms next delay is posted. |
138 { | 138 TEST(DelayBasedTimeSource, NextDelaySaneWhenSlightlyAfterTwiceRequestedTime) { |
139 FakeThread thread; | 139 FakeThread thread; |
140 FakeTimeSourceClient client; | 140 FakeTimeSourceClient client; |
141 scoped_refptr<FakeDelayBasedTimeSource> timer = FakeDelayBasedTimeSource::cr
eate(interval(), &thread); | 141 scoped_refptr<FakeDelayBasedTimeSource> timer = |
142 timer->setClient(&client); | 142 FakeDelayBasedTimeSource::create(Interval(), &thread); |
143 timer->setActive(true); | 143 timer->SetClient(&client); |
144 // Run the first task, as that activates the timer and picks up a timebase. | 144 timer->SetActive(true); |
145 thread.runPendingTask(); | 145 // Run the first task, as that activates the timer and picks up a timebase. |
146 | 146 thread.runPendingTask(); |
147 EXPECT_EQ(16, thread.pendingDelayMs()); | 147 |
148 | 148 EXPECT_EQ(16, thread.pendingDelayMs()); |
149 timer->setNow(timer->now() + 2 * interval() + base::TimeDelta::FromMicroseco
nds(1)); | 149 |
150 thread.runPendingTask(); | 150 timer->setNow(timer->Now() + 2 * Interval() + |
151 | 151 base::TimeDelta::FromMicroseconds(1)); |
152 EXPECT_EQ(16, thread.pendingDelayMs()); | 152 thread.runPendingTask(); |
| 153 |
| 154 EXPECT_EQ(16, thread.pendingDelayMs()); |
153 } | 155 } |
154 | 156 |
155 // At 60Hz, when the tick returns halfway to the next frame time, make sure | 157 // At 60Hz, when the tick returns halfway to the next frame time, make sure |
156 // a correct next delay value is posted. | 158 // a correct next delay value is posted. |
157 TEST(DelayBasedTimeSource, NextDelaySaneWhenHalfAfterRequestedTime) | 159 TEST(DelayBasedTimeSource, NextDelaySaneWhenHalfAfterRequestedTime) { |
158 { | 160 FakeThread thread; |
159 FakeThread thread; | 161 FakeTimeSourceClient client; |
160 FakeTimeSourceClient client; | 162 scoped_refptr<FakeDelayBasedTimeSource> timer = |
161 scoped_refptr<FakeDelayBasedTimeSource> timer = FakeDelayBasedTimeSource::cr
eate(interval(), &thread); | 163 FakeDelayBasedTimeSource::create(Interval(), &thread); |
162 timer->setClient(&client); | 164 timer->SetClient(&client); |
163 timer->setActive(true); | 165 timer->SetActive(true); |
164 // Run the first task, as that activates the timer and picks up a timebase. | 166 // Run the first task, as that activates the timer and picks up a timebase. |
165 thread.runPendingTask(); | 167 thread.runPendingTask(); |
166 | 168 |
167 EXPECT_EQ(16, thread.pendingDelayMs()); | 169 EXPECT_EQ(16, thread.pendingDelayMs()); |
168 | 170 |
169 timer->setNow(timer->now() + interval() + base::TimeDelta::FromMilliseconds(
8)); | 171 timer->setNow(timer->Now() + Interval() + |
170 thread.runPendingTask(); | 172 base::TimeDelta::FromMilliseconds(8)); |
171 | 173 thread.runPendingTask(); |
172 EXPECT_EQ(8, thread.pendingDelayMs()); | 174 |
| 175 EXPECT_EQ(8, thread.pendingDelayMs()); |
173 } | 176 } |
174 | 177 |
175 // If the timebase and interval are updated with a jittery source, we want to | 178 // If the timebase and interval are updated with a jittery source, we want to |
176 // make sure we do not double tick. | 179 // make sure we do not double tick. |
177 TEST(DelayBasedTimeSource, SaneHandlingOfJitteryTimebase) | 180 TEST(DelayBasedTimeSource, SaneHandlingOfJitteryTimebase) { |
178 { | 181 FakeThread thread; |
179 FakeThread thread; | 182 FakeTimeSourceClient client; |
180 FakeTimeSourceClient client; | 183 scoped_refptr<FakeDelayBasedTimeSource> timer = |
181 scoped_refptr<FakeDelayBasedTimeSource> timer = FakeDelayBasedTimeSource::cr
eate(interval(), &thread); | 184 FakeDelayBasedTimeSource::create(Interval(), &thread); |
182 timer->setClient(&client); | 185 timer->SetClient(&client); |
183 timer->setActive(true); | 186 timer->SetActive(true); |
184 // Run the first task, as that activates the timer and picks up a timebase. | 187 // Run the first task, as that activates the timer and picks up a timebase. |
| 188 thread.runPendingTask(); |
| 189 |
| 190 EXPECT_EQ(16, thread.pendingDelayMs()); |
| 191 |
| 192 // Jitter timebase ~1ms late |
| 193 timer->setNow(timer->Now() + Interval()); |
| 194 timer->SetTimebaseAndInterval( |
| 195 timer->Now() + base::TimeDelta::FromMilliseconds(1), Interval()); |
| 196 thread.runPendingTask(); |
| 197 |
| 198 // Without double tick prevention, pendingDelayMs would be 1. |
| 199 EXPECT_EQ(17, thread.pendingDelayMs()); |
| 200 |
| 201 // Jitter timebase ~1ms early |
| 202 timer->setNow(timer->Now() + Interval()); |
| 203 timer->SetTimebaseAndInterval( |
| 204 timer->Now() - base::TimeDelta::FromMilliseconds(1), Interval()); |
| 205 thread.runPendingTask(); |
| 206 |
| 207 EXPECT_EQ(15, thread.pendingDelayMs()); |
| 208 } |
| 209 |
| 210 TEST(DelayBasedTimeSource, HandlesSignificantTimebaseChangesImmediately) { |
| 211 FakeThread thread; |
| 212 FakeTimeSourceClient client; |
| 213 scoped_refptr<FakeDelayBasedTimeSource> timer = |
| 214 FakeDelayBasedTimeSource::create(Interval(), &thread); |
| 215 timer->SetClient(&client); |
| 216 timer->SetActive(true); |
| 217 // Run the first task, as that activates the timer and picks up a timebase. |
| 218 thread.runPendingTask(); |
| 219 |
| 220 EXPECT_EQ(16, thread.pendingDelayMs()); |
| 221 |
| 222 // Tick, then shift timebase by +7ms. |
| 223 timer->setNow(timer->Now() + Interval()); |
| 224 thread.runPendingTask(); |
| 225 |
| 226 EXPECT_EQ(16, thread.pendingDelayMs()); |
| 227 |
| 228 client.reset(); |
| 229 thread.runPendingTaskOnOverwrite(true); |
| 230 base::TimeDelta jitter = base::TimeDelta::FromMilliseconds(7) + |
| 231 base::TimeDelta::FromMicroseconds(1); |
| 232 timer->SetTimebaseAndInterval(timer->Now() + jitter, Interval()); |
| 233 thread.runPendingTaskOnOverwrite(false); |
| 234 |
| 235 EXPECT_FALSE(client.tickCalled()); // Make sure pending tasks were canceled. |
| 236 EXPECT_EQ(7, thread.pendingDelayMs()); |
| 237 |
| 238 // Tick, then shift timebase by -7ms. |
| 239 timer->setNow(timer->Now() + jitter); |
| 240 thread.runPendingTask(); |
| 241 |
| 242 EXPECT_EQ(16, thread.pendingDelayMs()); |
| 243 |
| 244 client.reset(); |
| 245 thread.runPendingTaskOnOverwrite(true); |
| 246 timer->SetTimebaseAndInterval(base::TimeTicks() + Interval(), Interval()); |
| 247 thread.runPendingTaskOnOverwrite(false); |
| 248 |
| 249 EXPECT_FALSE(client.tickCalled()); // Make sure pending tasks were canceled. |
| 250 EXPECT_EQ(16 - 7, thread.pendingDelayMs()); |
| 251 } |
| 252 |
| 253 TEST(DelayBasedTimeSource, HanldlesSignificantIntervalChangesImmediately) { |
| 254 FakeThread thread; |
| 255 FakeTimeSourceClient client; |
| 256 scoped_refptr<FakeDelayBasedTimeSource> timer = |
| 257 FakeDelayBasedTimeSource::create(Interval(), &thread); |
| 258 timer->SetClient(&client); |
| 259 timer->SetActive(true); |
| 260 // Run the first task, as that activates the timer and picks up a timebase. |
| 261 thread.runPendingTask(); |
| 262 |
| 263 EXPECT_EQ(16, thread.pendingDelayMs()); |
| 264 |
| 265 // Tick, then double the interval. |
| 266 timer->setNow(timer->Now() + Interval()); |
| 267 thread.runPendingTask(); |
| 268 |
| 269 EXPECT_EQ(16, thread.pendingDelayMs()); |
| 270 |
| 271 client.reset(); |
| 272 thread.runPendingTaskOnOverwrite(true); |
| 273 timer->SetTimebaseAndInterval(base::TimeTicks() + Interval(), Interval() * 2); |
| 274 thread.runPendingTaskOnOverwrite(false); |
| 275 |
| 276 EXPECT_FALSE(client.tickCalled()); // Make sure pending tasks were canceled. |
| 277 EXPECT_EQ(33, thread.pendingDelayMs()); |
| 278 |
| 279 // Tick, then halve the interval. |
| 280 timer->setNow(timer->Now() + Interval() * 2); |
| 281 thread.runPendingTask(); |
| 282 |
| 283 EXPECT_EQ(33, thread.pendingDelayMs()); |
| 284 |
| 285 client.reset(); |
| 286 thread.runPendingTaskOnOverwrite(true); |
| 287 timer->SetTimebaseAndInterval(base::TimeTicks() + Interval() * 3, Interval()); |
| 288 thread.runPendingTaskOnOverwrite(false); |
| 289 |
| 290 EXPECT_FALSE(client.tickCalled()); // Make sure pending tasks were canceled. |
| 291 EXPECT_EQ(16, thread.pendingDelayMs()); |
| 292 } |
| 293 |
| 294 TEST(DelayBasedTimeSourceTest, AchievesTargetRateWithNoNoise) { |
| 295 int num_iterations = 10; |
| 296 |
| 297 FakeThread thread; |
| 298 FakeTimeSourceClient client; |
| 299 scoped_refptr<FakeDelayBasedTimeSource> timer = |
| 300 FakeDelayBasedTimeSource::create(Interval(), &thread); |
| 301 timer->SetClient(&client); |
| 302 timer->SetActive(true); |
| 303 |
| 304 double total_frame_time = 0.0; |
| 305 for (int i = 0; i < num_iterations; ++i) { |
| 306 long long delay_ms = thread.pendingDelayMs(); |
| 307 |
| 308 // accumulate the "delay" |
| 309 total_frame_time += delay_ms / 1000.0; |
| 310 |
| 311 // Run the callback exactly when asked |
| 312 timer->setNow(timer->Now() + base::TimeDelta::FromMilliseconds(delay_ms)); |
185 thread.runPendingTask(); | 313 thread.runPendingTask(); |
186 | 314 } |
187 EXPECT_EQ(16, thread.pendingDelayMs()); | 315 double average_interval = |
188 | 316 total_frame_time / static_cast<double>(num_iterations); |
189 // Jitter timebase ~1ms late | 317 EXPECT_NEAR(1.0 / 60.0, average_interval, 0.1); |
190 timer->setNow(timer->now() + interval()); | 318 } |
191 timer->setTimebaseAndInterval(timer->now() + base::TimeDelta::FromMillisecon
ds(1), interval()); | 319 |
192 thread.runPendingTask(); | 320 TEST(DelayBasedTimeSource, TestDeactivateWhilePending) { |
193 | 321 FakeThread thread; |
194 // Without double tick prevention, pendingDelayMs would be 1. | 322 FakeTimeSourceClient client; |
195 EXPECT_EQ(17, thread.pendingDelayMs()); | 323 scoped_refptr<FakeDelayBasedTimeSource> timer = |
196 | 324 FakeDelayBasedTimeSource::create(Interval(), &thread); |
197 // Jitter timebase ~1ms early | 325 timer->SetClient(&client); |
198 timer->setNow(timer->now() + interval()); | 326 timer->SetActive(true); // Should post a task. |
199 timer->setTimebaseAndInterval(timer->now() - base::TimeDelta::FromMillisecon
ds(1), interval()); | 327 timer->SetActive(false); |
200 thread.runPendingTask(); | 328 timer = NULL; |
201 | 329 thread.runPendingTask(); // Should run the posted task without crashing. |
202 EXPECT_EQ(15, thread.pendingDelayMs()); | 330 } |
203 } | 331 |
204 | 332 TEST(DelayBasedTimeSource, TestDeactivateAndReactivateBeforeNextTickTime) { |
205 TEST(DelayBasedTimeSource, HandlesSignificantTimebaseChangesImmediately) | 333 FakeThread thread; |
206 { | 334 FakeTimeSourceClient client; |
207 FakeThread thread; | 335 scoped_refptr<FakeDelayBasedTimeSource> timer = |
208 FakeTimeSourceClient client; | 336 FakeDelayBasedTimeSource::create(Interval(), &thread); |
209 scoped_refptr<FakeDelayBasedTimeSource> timer = FakeDelayBasedTimeSource::cr
eate(interval(), &thread); | 337 timer->SetClient(&client); |
210 timer->setClient(&client); | 338 |
211 timer->setActive(true); | 339 // Should run the activate task, and pick up a new timebase. |
212 // Run the first task, as that activates the timer and picks up a timebase. | 340 timer->SetActive(true); |
213 thread.runPendingTask(); | 341 thread.runPendingTask(); |
214 | 342 |
215 EXPECT_EQ(16, thread.pendingDelayMs()); | 343 // Stop the timer |
216 | 344 timer->SetActive(false); |
217 // Tick, then shift timebase by +7ms. | 345 |
218 timer->setNow(timer->now() + interval()); | 346 // Task will be pending anyway, run it |
219 thread.runPendingTask(); | 347 thread.runPendingTask(); |
220 | 348 |
221 EXPECT_EQ(16, thread.pendingDelayMs()); | 349 // Start the timer again, but before the next tick time the timer previously |
222 | 350 // planned on using. That same tick time should still be targeted. |
223 client.reset(); | 351 timer->setNow(timer->Now() + base::TimeDelta::FromMilliseconds(4)); |
224 thread.runPendingTaskOnOverwrite(true); | 352 timer->SetActive(true); |
225 base::TimeDelta jitter = base::TimeDelta::FromMilliseconds(7) + base::TimeDe
lta::FromMicroseconds(1); | 353 EXPECT_EQ(12, thread.pendingDelayMs()); |
226 timer->setTimebaseAndInterval(timer->now() + jitter, interval()); | 354 } |
227 thread.runPendingTaskOnOverwrite(false); | 355 |
228 | 356 TEST(DelayBasedTimeSource, TestDeactivateAndReactivateAfterNextTickTime) { |
229 EXPECT_FALSE(client.tickCalled()); // Make sure pending tasks were canceled. | 357 FakeThread thread; |
230 EXPECT_EQ(7, thread.pendingDelayMs()); | 358 FakeTimeSourceClient client; |
231 | 359 scoped_refptr<FakeDelayBasedTimeSource> timer = |
232 // Tick, then shift timebase by -7ms. | 360 FakeDelayBasedTimeSource::create(Interval(), &thread); |
233 timer->setNow(timer->now() + jitter); | 361 timer->SetClient(&client); |
234 thread.runPendingTask(); | 362 |
235 | 363 // Should run the activate task, and pick up a new timebase. |
236 EXPECT_EQ(16, thread.pendingDelayMs()); | 364 timer->SetActive(true); |
237 | 365 thread.runPendingTask(); |
238 client.reset(); | 366 |
239 thread.runPendingTaskOnOverwrite(true); | 367 // Stop the timer. |
240 timer->setTimebaseAndInterval(base::TimeTicks() + interval(), interval()); | 368 timer->SetActive(false); |
241 thread.runPendingTaskOnOverwrite(false); | 369 |
242 | 370 // Task will be pending anyway, run it. |
243 EXPECT_FALSE(client.tickCalled()); // Make sure pending tasks were canceled. | 371 thread.runPendingTask(); |
244 EXPECT_EQ(16-7, thread.pendingDelayMs()); | 372 |
245 } | 373 // Start the timer again, but before the next tick time the timer previously |
246 | 374 // planned on using. That same tick time should still be targeted. |
247 TEST(DelayBasedTimeSource, HanldlesSignificantIntervalChangesImmediately) | 375 timer->setNow(timer->Now() + base::TimeDelta::FromMilliseconds(20)); |
248 { | 376 timer->SetActive(true); |
249 FakeThread thread; | 377 EXPECT_EQ(13, thread.pendingDelayMs()); |
250 FakeTimeSourceClient client; | |
251 scoped_refptr<FakeDelayBasedTimeSource> timer = FakeDelayBasedTimeSource::cr
eate(interval(), &thread); | |
252 timer->setClient(&client); | |
253 timer->setActive(true); | |
254 // Run the first task, as that activates the timer and picks up a timebase. | |
255 thread.runPendingTask(); | |
256 | |
257 EXPECT_EQ(16, thread.pendingDelayMs()); | |
258 | |
259 // Tick, then double the interval. | |
260 timer->setNow(timer->now() + interval()); | |
261 thread.runPendingTask(); | |
262 | |
263 EXPECT_EQ(16, thread.pendingDelayMs()); | |
264 | |
265 client.reset(); | |
266 thread.runPendingTaskOnOverwrite(true); | |
267 timer->setTimebaseAndInterval(base::TimeTicks() + interval(), interval() * 2
); | |
268 thread.runPendingTaskOnOverwrite(false); | |
269 | |
270 EXPECT_FALSE(client.tickCalled()); // Make sure pending tasks were canceled. | |
271 EXPECT_EQ(33, thread.pendingDelayMs()); | |
272 | |
273 // Tick, then halve the interval. | |
274 timer->setNow(timer->now() + interval() * 2); | |
275 thread.runPendingTask(); | |
276 | |
277 EXPECT_EQ(33, thread.pendingDelayMs()); | |
278 | |
279 client.reset(); | |
280 thread.runPendingTaskOnOverwrite(true); | |
281 timer->setTimebaseAndInterval(base::TimeTicks() + interval() * 3, interval()
); | |
282 thread.runPendingTaskOnOverwrite(false); | |
283 | |
284 EXPECT_FALSE(client.tickCalled()); // Make sure pending tasks were canceled. | |
285 EXPECT_EQ(16, thread.pendingDelayMs()); | |
286 } | |
287 | |
288 TEST(DelayBasedTimeSourceTest, AchievesTargetRateWithNoNoise) | |
289 { | |
290 int numIterations = 10; | |
291 | |
292 FakeThread thread; | |
293 FakeTimeSourceClient client; | |
294 scoped_refptr<FakeDelayBasedTimeSource> timer = FakeDelayBasedTimeSource::cr
eate(interval(), &thread); | |
295 timer->setClient(&client); | |
296 timer->setActive(true); | |
297 | |
298 double totalFrameTime = 0; | |
299 for (int i = 0; i < numIterations; ++i) { | |
300 long long delayMs = thread.pendingDelayMs(); | |
301 | |
302 // accumulate the "delay" | |
303 totalFrameTime += delayMs / 1000.0; | |
304 | |
305 // Run the callback exactly when asked | |
306 timer->setNow(timer->now() + base::TimeDelta::FromMilliseconds(delayMs))
; | |
307 thread.runPendingTask(); | |
308 } | |
309 double averageInterval = totalFrameTime / static_cast<double>(numIterations)
; | |
310 EXPECT_NEAR(1.0 / 60.0, averageInterval, 0.1); | |
311 } | |
312 | |
313 TEST(DelayBasedTimeSource, TestDeactivateWhilePending) | |
314 { | |
315 FakeThread thread; | |
316 FakeTimeSourceClient client; | |
317 scoped_refptr<FakeDelayBasedTimeSource> timer = FakeDelayBasedTimeSource::cr
eate(interval(), &thread); | |
318 timer->setClient(&client); | |
319 timer->setActive(true); // Should post a task. | |
320 timer->setActive(false); | |
321 timer = NULL; | |
322 thread.runPendingTask(); // Should run the posted task without crashing. | |
323 } | |
324 | |
325 TEST(DelayBasedTimeSource, TestDeactivateAndReactivateBeforeNextTickTime) | |
326 { | |
327 FakeThread thread; | |
328 FakeTimeSourceClient client; | |
329 scoped_refptr<FakeDelayBasedTimeSource> timer = FakeDelayBasedTimeSource::cr
eate(interval(), &thread); | |
330 timer->setClient(&client); | |
331 | |
332 // Should run the activate task, and pick up a new timebase. | |
333 timer->setActive(true); | |
334 thread.runPendingTask(); | |
335 | |
336 // Stop the timer | |
337 timer->setActive(false); | |
338 | |
339 // Task will be pending anyway, run it | |
340 thread.runPendingTask(); | |
341 | |
342 // Start the timer again, but before the next tick time the timer previously | |
343 // planned on using. That same tick time should still be targeted. | |
344 timer->setNow(timer->now() + base::TimeDelta::FromMilliseconds(4)); | |
345 timer->setActive(true); | |
346 EXPECT_EQ(12, thread.pendingDelayMs()); | |
347 } | |
348 | |
349 TEST(DelayBasedTimeSource, TestDeactivateAndReactivateAfterNextTickTime) | |
350 { | |
351 FakeThread thread; | |
352 FakeTimeSourceClient client; | |
353 scoped_refptr<FakeDelayBasedTimeSource> timer = FakeDelayBasedTimeSource::cr
eate(interval(), &thread); | |
354 timer->setClient(&client); | |
355 | |
356 // Should run the activate task, and pick up a new timebase. | |
357 timer->setActive(true); | |
358 thread.runPendingTask(); | |
359 | |
360 // Stop the timer | |
361 timer->setActive(false); | |
362 | |
363 // Task will be pending anyway, run it | |
364 thread.runPendingTask(); | |
365 | |
366 // Start the timer again, but before the next tick time the timer previously | |
367 // planned on using. That same tick time should still be targeted. | |
368 timer->setNow(timer->now() + base::TimeDelta::FromMilliseconds(20)); | |
369 timer->setActive(true); | |
370 EXPECT_EQ(13, thread.pendingDelayMs()); | |
371 } | 378 } |
372 | 379 |
373 } // namespace | 380 } // namespace |
374 } // namespace cc | 381 } // namespace cc |
OLD | NEW |