1 /*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 // TODO(b/129481165): remove the #pragma below and fix conversion issues
18 #pragma clang diagnostic push
19 #pragma clang diagnostic ignored "-Wconversion"
20 #pragma clang diagnostic ignored "-Wextra"
21
22 #undef LOG_TAG
23 #define LOG_TAG "LibSurfaceFlingerUnittests"
24 #define LOG_NDEBUG 0
25
26 #include "Scheduler/TimeKeeper.h"
27 #include "Scheduler/VSyncDispatchTimerQueue.h"
28 #include "Scheduler/VSyncTracker.h"
29
30 #include <gmock/gmock.h>
31 #include <gtest/gtest.h>
32 #include <thread>
33
34 using namespace testing;
35 using namespace std::literals;
36 namespace android::scheduler {
37
38 class MockVSyncTracker : public VSyncTracker {
39 public:
MockVSyncTracker(nsecs_t period)40 MockVSyncTracker(nsecs_t period) : mPeriod{period} {
41 ON_CALL(*this, nextAnticipatedVSyncTimeFrom(_))
42 .WillByDefault(Invoke(this, &MockVSyncTracker::nextVSyncTime));
43 ON_CALL(*this, addVsyncTimestamp(_)).WillByDefault(Return(true));
44 }
45
46 MOCK_METHOD1(addVsyncTimestamp, bool(nsecs_t));
47 MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
48 MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
49 MOCK_METHOD1(setPeriod, void(nsecs_t));
50 MOCK_METHOD0(resetModel, void());
51 MOCK_CONST_METHOD0(needsMoreSamples, bool());
52 MOCK_CONST_METHOD2(isVSyncInPhase, bool(nsecs_t, Fps));
53 MOCK_CONST_METHOD1(dump, void(std::string&));
54
nextVSyncTime(nsecs_t timePoint) const55 nsecs_t nextVSyncTime(nsecs_t timePoint) const {
56 if (timePoint % mPeriod == 0) {
57 return timePoint;
58 }
59 return (timePoint - (timePoint % mPeriod) + mPeriod);
60 }
61
62 protected:
63 nsecs_t const mPeriod;
64 };
65
66 class ControllableClock : public TimeKeeper {
67 public:
ControllableClock()68 ControllableClock() {
69 ON_CALL(*this, alarmAt(_, _))
70 .WillByDefault(Invoke(this, &ControllableClock::alarmAtDefaultBehavior));
71 ON_CALL(*this, now()).WillByDefault(Invoke(this, &ControllableClock::fakeTime));
72 }
73
74 MOCK_CONST_METHOD0(now, nsecs_t());
75 MOCK_METHOD2(alarmAt, void(std::function<void()> const&, nsecs_t time));
76 MOCK_METHOD0(alarmCancel, void());
77 MOCK_CONST_METHOD1(dump, void(std::string&));
78
alarmAtDefaultBehavior(std::function<void ()> const & callback,nsecs_t time)79 void alarmAtDefaultBehavior(std::function<void()> const& callback, nsecs_t time) {
80 mCallback = callback;
81 mNextCallbackTime = time;
82 }
83
fakeTime() const84 nsecs_t fakeTime() const { return mCurrentTime; }
85
advanceToNextCallback()86 void advanceToNextCallback() {
87 mCurrentTime = mNextCallbackTime;
88 if (mCallback) {
89 mCallback();
90 }
91 }
92
advanceBy(nsecs_t advancement)93 void advanceBy(nsecs_t advancement) {
94 mCurrentTime += advancement;
95 if (mCurrentTime >= (mNextCallbackTime + mLag) && mCallback) {
96 mCallback();
97 }
98 };
99
setLag(nsecs_t lag)100 void setLag(nsecs_t lag) { mLag = lag; }
101
102 private:
103 std::function<void()> mCallback;
104 nsecs_t mNextCallbackTime = 0;
105 nsecs_t mCurrentTime = 0;
106 nsecs_t mLag = 0;
107 };
108
109 class CountingCallback {
110 public:
CountingCallback(VSyncDispatch & dispatch)111 CountingCallback(VSyncDispatch& dispatch)
112 : mDispatch(dispatch),
113 mToken(dispatch.registerCallback(std::bind(&CountingCallback::counter, this,
114 std::placeholders::_1, std::placeholders::_2,
115 std::placeholders::_3),
116 "test")) {}
~CountingCallback()117 ~CountingCallback() { mDispatch.unregisterCallback(mToken); }
118
119 operator VSyncDispatch::CallbackToken() const { return mToken; }
120
counter(nsecs_t time,nsecs_t wakeup_time,nsecs_t readyTime)121 void counter(nsecs_t time, nsecs_t wakeup_time, nsecs_t readyTime) {
122 mCalls.push_back(time);
123 mWakeupTime.push_back(wakeup_time);
124 mReadyTime.push_back(readyTime);
125 }
126
127 VSyncDispatch& mDispatch;
128 VSyncDispatch::CallbackToken mToken;
129 std::vector<nsecs_t> mCalls;
130 std::vector<nsecs_t> mWakeupTime;
131 std::vector<nsecs_t> mReadyTime;
132 };
133
134 class PausingCallback {
135 public:
PausingCallback(VSyncDispatch & dispatch,std::chrono::milliseconds pauseAmount)136 PausingCallback(VSyncDispatch& dispatch, std::chrono::milliseconds pauseAmount)
137 : mDispatch(dispatch),
138 mToken(dispatch.registerCallback(std::bind(&PausingCallback::pause, this,
139 std::placeholders::_1,
140 std::placeholders::_2),
141 "test")),
142 mRegistered(true),
143 mPauseAmount(pauseAmount) {}
~PausingCallback()144 ~PausingCallback() { unregister(); }
145
146 operator VSyncDispatch::CallbackToken() const { return mToken; }
147
pause(nsecs_t,nsecs_t)148 void pause(nsecs_t, nsecs_t) {
149 std::unique_lock lock(mMutex);
150 mPause = true;
151 mCv.notify_all();
152
153 mCv.wait_for(lock, mPauseAmount, [this] { return !mPause; });
154
155 mResourcePresent = (mResource.lock() != nullptr);
156 }
157
waitForPause()158 bool waitForPause() {
159 std::unique_lock lock(mMutex);
160 auto waiting = mCv.wait_for(lock, 10s, [this] { return mPause; });
161 return waiting;
162 }
163
stashResource(std::weak_ptr<void> const & resource)164 void stashResource(std::weak_ptr<void> const& resource) { mResource = resource; }
165
resourcePresent()166 bool resourcePresent() { return mResourcePresent; }
167
unpause()168 void unpause() {
169 std::unique_lock lock(mMutex);
170 mPause = false;
171 mCv.notify_all();
172 }
173
unregister()174 void unregister() {
175 if (mRegistered) {
176 mDispatch.unregisterCallback(mToken);
177 mRegistered = false;
178 }
179 }
180
181 VSyncDispatch& mDispatch;
182 VSyncDispatch::CallbackToken mToken;
183 bool mRegistered = true;
184
185 std::mutex mMutex;
186 std::condition_variable mCv;
187 bool mPause = false;
188 std::weak_ptr<void> mResource;
189 bool mResourcePresent = false;
190 std::chrono::milliseconds const mPauseAmount;
191 };
192
193 class VSyncDispatchTimerQueueTest : public testing::Test {
194 protected:
createTimeKeeper()195 std::unique_ptr<TimeKeeper> createTimeKeeper() {
196 class TimeKeeperWrapper : public TimeKeeper {
197 public:
198 TimeKeeperWrapper(TimeKeeper& control) : mControllableClock(control) {}
199 void alarmAt(std::function<void()> const& callback, nsecs_t time) final {
200 mControllableClock.alarmAt(callback, time);
201 }
202 void alarmCancel() final { mControllableClock.alarmCancel(); }
203 nsecs_t now() const final { return mControllableClock.now(); }
204 void dump(std::string&) const final {}
205
206 private:
207 TimeKeeper& mControllableClock;
208 };
209 return std::make_unique<TimeKeeperWrapper>(mMockClock);
210 }
211
~VSyncDispatchTimerQueueTest()212 ~VSyncDispatchTimerQueueTest() {
213 // destructor of dispatch will cancelAlarm(). Ignore final cancel in common test.
214 Mock::VerifyAndClearExpectations(&mMockClock);
215 }
216
advanceToNextCallback()217 void advanceToNextCallback() { mMockClock.advanceToNextCallback(); }
218
219 NiceMock<ControllableClock> mMockClock;
220 static nsecs_t constexpr mDispatchGroupThreshold = 5;
221 nsecs_t const mPeriod = 1000;
222 nsecs_t const mVsyncMoveThreshold = 300;
223 NiceMock<MockVSyncTracker> mStubTracker{mPeriod};
224 VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold,
225 mVsyncMoveThreshold};
226 };
227
TEST_F(VSyncDispatchTimerQueueTest,unregistersSetAlarmOnDestruction)228 TEST_F(VSyncDispatchTimerQueueTest, unregistersSetAlarmOnDestruction) {
229 EXPECT_CALL(mMockClock, alarmAt(_, 900));
230 EXPECT_CALL(mMockClock, alarmCancel());
231 {
232 VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold,
233 mVsyncMoveThreshold};
234 CountingCallback cb(mDispatch);
235 const auto result = mDispatch.schedule(cb,
236 {.workDuration = 100,
237 .readyDuration = 0,
238 .earliestVsync = 1000});
239 EXPECT_TRUE(result.has_value());
240 EXPECT_EQ(900, *result);
241 }
242 }
243
TEST_F(VSyncDispatchTimerQueueTest,basicAlarmSettingFuture)244 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFuture) {
245 auto intended = mPeriod - 230;
246 EXPECT_CALL(mMockClock, alarmAt(_, 900));
247
248 CountingCallback cb(mDispatch);
249 const auto result = mDispatch.schedule(cb,
250 {.workDuration = 100,
251 .readyDuration = 0,
252 .earliestVsync = intended});
253 EXPECT_TRUE(result.has_value());
254 EXPECT_EQ(900, *result);
255
256 advanceToNextCallback();
257
258 ASSERT_THAT(cb.mCalls.size(), Eq(1));
259 EXPECT_THAT(cb.mCalls[0], Eq(mPeriod));
260 }
261
TEST_F(VSyncDispatchTimerQueueTest,basicAlarmSettingFutureWithAdjustmentToTrueVsync)262 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFutureWithAdjustmentToTrueVsync) {
263 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000)).WillOnce(Return(1150));
264 EXPECT_CALL(mMockClock, alarmAt(_, 1050));
265
266 CountingCallback cb(mDispatch);
267 mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod});
268 advanceToNextCallback();
269
270 ASSERT_THAT(cb.mCalls.size(), Eq(1));
271 EXPECT_THAT(cb.mCalls[0], Eq(1150));
272 }
273
TEST_F(VSyncDispatchTimerQueueTest,basicAlarmSettingAdjustmentPast)274 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingAdjustmentPast) {
275 auto const now = 234;
276 mMockClock.advanceBy(234);
277 auto const workDuration = 10 * mPeriod;
278 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(now + workDuration))
279 .WillOnce(Return(mPeriod * 11));
280 EXPECT_CALL(mMockClock, alarmAt(_, mPeriod));
281
282 CountingCallback cb(mDispatch);
283 const auto result = mDispatch.schedule(cb,
284 {.workDuration = workDuration,
285 .readyDuration = 0,
286 .earliestVsync = mPeriod});
287 EXPECT_TRUE(result.has_value());
288 EXPECT_EQ(mPeriod, *result);
289 }
290
TEST_F(VSyncDispatchTimerQueueTest,basicAlarmCancel)291 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancel) {
292 EXPECT_CALL(mMockClock, alarmAt(_, 900));
293 EXPECT_CALL(mMockClock, alarmCancel());
294
295 CountingCallback cb(mDispatch);
296 const auto result =
297 mDispatch.schedule(cb,
298 {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod});
299 EXPECT_TRUE(result.has_value());
300 EXPECT_EQ(mPeriod - 100, *result);
301 EXPECT_EQ(mDispatch.cancel(cb), CancelResult::Cancelled);
302 }
303
TEST_F(VSyncDispatchTimerQueueTest,basicAlarmCancelTooLate)304 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLate) {
305 EXPECT_CALL(mMockClock, alarmAt(_, 900));
306 EXPECT_CALL(mMockClock, alarmCancel());
307
308 CountingCallback cb(mDispatch);
309 const auto result =
310 mDispatch.schedule(cb,
311 {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod});
312 EXPECT_TRUE(result.has_value());
313 EXPECT_EQ(mPeriod - 100, *result);
314 mMockClock.advanceBy(950);
315 EXPECT_EQ(mDispatch.cancel(cb), CancelResult::TooLate);
316 }
317
TEST_F(VSyncDispatchTimerQueueTest,basicAlarmCancelTooLateWhenRunning)318 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLateWhenRunning) {
319 EXPECT_CALL(mMockClock, alarmAt(_, 900));
320 EXPECT_CALL(mMockClock, alarmCancel());
321
322 PausingCallback cb(mDispatch, std::chrono::duration_cast<std::chrono::milliseconds>(1s));
323 const auto result =
324 mDispatch.schedule(cb,
325 {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod});
326 EXPECT_TRUE(result.has_value());
327 EXPECT_EQ(mPeriod - 100, *result);
328
329 std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
330 EXPECT_TRUE(cb.waitForPause());
331 EXPECT_EQ(mDispatch.cancel(cb), CancelResult::TooLate);
332 cb.unpause();
333 pausingThread.join();
334 }
335
TEST_F(VSyncDispatchTimerQueueTest,unregisterSynchronizes)336 TEST_F(VSyncDispatchTimerQueueTest, unregisterSynchronizes) {
337 EXPECT_CALL(mMockClock, alarmAt(_, 900));
338 EXPECT_CALL(mMockClock, alarmCancel());
339
340 auto resource = std::make_shared<int>(110);
341
342 PausingCallback cb(mDispatch, 50ms);
343 cb.stashResource(resource);
344 const auto result =
345 mDispatch.schedule(cb,
346 {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod});
347 EXPECT_TRUE(result.has_value());
348 EXPECT_EQ(mPeriod - 100, *result);
349
350 std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
351 EXPECT_TRUE(cb.waitForPause());
352
353 cb.unregister();
354 resource.reset();
355
356 cb.unpause();
357 pausingThread.join();
358
359 EXPECT_TRUE(cb.resourcePresent());
360 }
361
TEST_F(VSyncDispatchTimerQueueTest,basicTwoAlarmSetting)362 TEST_F(VSyncDispatchTimerQueueTest, basicTwoAlarmSetting) {
363 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
364 .Times(4)
365 .WillOnce(Return(1055))
366 .WillOnce(Return(1063))
367 .WillOnce(Return(1063))
368 .WillOnce(Return(1075));
369
370 Sequence seq;
371 EXPECT_CALL(mMockClock, alarmAt(_, 955)).InSequence(seq);
372 EXPECT_CALL(mMockClock, alarmAt(_, 813)).InSequence(seq);
373 EXPECT_CALL(mMockClock, alarmAt(_, 975)).InSequence(seq);
374
375 CountingCallback cb0(mDispatch);
376 CountingCallback cb1(mDispatch);
377
378 mDispatch.schedule(cb0, {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod});
379 mDispatch.schedule(cb1, {.workDuration = 250, .readyDuration = 0, .earliestVsync = mPeriod});
380
381 advanceToNextCallback();
382 advanceToNextCallback();
383
384 ASSERT_THAT(cb0.mCalls.size(), Eq(1));
385 EXPECT_THAT(cb0.mCalls[0], Eq(1075));
386 ASSERT_THAT(cb1.mCalls.size(), Eq(1));
387 EXPECT_THAT(cb1.mCalls[0], Eq(1063));
388 }
389
TEST_F(VSyncDispatchTimerQueueTest,rearmsFaroutTimeoutWhenCancellingCloseOne)390 TEST_F(VSyncDispatchTimerQueueTest, rearmsFaroutTimeoutWhenCancellingCloseOne) {
391 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
392 .Times(4)
393 .WillOnce(Return(10000))
394 .WillOnce(Return(1000))
395 .WillOnce(Return(10000))
396 .WillOnce(Return(10000));
397
398 Sequence seq;
399 EXPECT_CALL(mMockClock, alarmAt(_, 9900)).InSequence(seq);
400 EXPECT_CALL(mMockClock, alarmAt(_, 750)).InSequence(seq);
401 EXPECT_CALL(mMockClock, alarmAt(_, 9900)).InSequence(seq);
402
403 CountingCallback cb0(mDispatch);
404 CountingCallback cb1(mDispatch);
405
406 mDispatch.schedule(cb0,
407 {.workDuration = 100, .readyDuration = 0, .earliestVsync = mPeriod * 10});
408 mDispatch.schedule(cb1, {.workDuration = 250, .readyDuration = 0, .earliestVsync = mPeriod});
409 mDispatch.cancel(cb1);
410 }
411
TEST_F(VSyncDispatchTimerQueueTest,noUnnecessaryRearmsWhenRescheduling)412 TEST_F(VSyncDispatchTimerQueueTest, noUnnecessaryRearmsWhenRescheduling) {
413 Sequence seq;
414 EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
415 EXPECT_CALL(mMockClock, alarmAt(_, 700)).InSequence(seq);
416
417 CountingCallback cb0(mDispatch);
418 CountingCallback cb1(mDispatch);
419
420 mDispatch.schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
421 mDispatch.schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000});
422 mDispatch.schedule(cb1, {.workDuration = 300, .readyDuration = 0, .earliestVsync = 1000});
423 advanceToNextCallback();
424 }
425
TEST_F(VSyncDispatchTimerQueueTest,necessaryRearmsWhenModifying)426 TEST_F(VSyncDispatchTimerQueueTest, necessaryRearmsWhenModifying) {
427 Sequence seq;
428 EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
429 EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
430 EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
431
432 CountingCallback cb0(mDispatch);
433 CountingCallback cb1(mDispatch);
434
435 mDispatch.schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
436 mDispatch.schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000});
437 mDispatch.schedule(cb1, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
438 advanceToNextCallback();
439 }
440
TEST_F(VSyncDispatchTimerQueueTest,modifyIntoGroup)441 TEST_F(VSyncDispatchTimerQueueTest, modifyIntoGroup) {
442 Sequence seq;
443 EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
444 EXPECT_CALL(mMockClock, alarmAt(_, 1600)).InSequence(seq);
445 EXPECT_CALL(mMockClock, alarmAt(_, 1590)).InSequence(seq);
446 EXPECT_CALL(mMockClock, alarmAt(_, 1600)).InSequence(seq);
447
448 auto offset = 400;
449 auto closeOffset = offset + mDispatchGroupThreshold - 1;
450 auto notCloseOffset = offset + 2 * mDispatchGroupThreshold;
451
452 CountingCallback cb0(mDispatch);
453 CountingCallback cb1(mDispatch);
454
455 mDispatch.schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
456 mDispatch.schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000});
457 mDispatch.schedule(cb1,
458 {.workDuration = closeOffset, .readyDuration = 0, .earliestVsync = 1000});
459
460 advanceToNextCallback();
461 ASSERT_THAT(cb0.mCalls.size(), Eq(1));
462 EXPECT_THAT(cb0.mCalls[0], Eq(mPeriod));
463 ASSERT_THAT(cb1.mCalls.size(), Eq(1));
464 EXPECT_THAT(cb1.mCalls[0], Eq(mPeriod));
465
466 mDispatch.schedule(cb0, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 2000});
467 mDispatch.schedule(cb1,
468 {.workDuration = notCloseOffset, .readyDuration = 0, .earliestVsync = 2000});
469 advanceToNextCallback();
470 ASSERT_THAT(cb1.mCalls.size(), Eq(2));
471 EXPECT_THAT(cb1.mCalls[1], Eq(2000));
472
473 advanceToNextCallback();
474 ASSERT_THAT(cb0.mCalls.size(), Eq(2));
475 EXPECT_THAT(cb0.mCalls[1], Eq(2000));
476 }
477
TEST_F(VSyncDispatchTimerQueueTest,rearmsWhenEndingAndDoesntCancel)478 TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenEndingAndDoesntCancel) {
479 Sequence seq;
480 EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
481 EXPECT_CALL(mMockClock, alarmAt(_, 800)).InSequence(seq);
482 EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
483 EXPECT_CALL(mMockClock, alarmCancel());
484
485 CountingCallback cb0(mDispatch);
486 CountingCallback cb1(mDispatch);
487
488 mDispatch.schedule(cb0, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
489 mDispatch.schedule(cb1, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 1000});
490 advanceToNextCallback();
491 EXPECT_EQ(mDispatch.cancel(cb0), CancelResult::Cancelled);
492 }
493
TEST_F(VSyncDispatchTimerQueueTest,setAlarmCallsAtCorrectTimeWithChangingVsync)494 TEST_F(VSyncDispatchTimerQueueTest, setAlarmCallsAtCorrectTimeWithChangingVsync) {
495 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
496 .Times(3)
497 .WillOnce(Return(950))
498 .WillOnce(Return(1975))
499 .WillOnce(Return(2950));
500
501 CountingCallback cb(mDispatch);
502 mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 920});
503
504 mMockClock.advanceBy(850);
505 EXPECT_THAT(cb.mCalls.size(), Eq(1));
506
507 mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1900});
508 mMockClock.advanceBy(900);
509 EXPECT_THAT(cb.mCalls.size(), Eq(1));
510 mMockClock.advanceBy(125);
511 EXPECT_THAT(cb.mCalls.size(), Eq(2));
512
513 mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2900});
514 mMockClock.advanceBy(975);
515 EXPECT_THAT(cb.mCalls.size(), Eq(3));
516 }
517
TEST_F(VSyncDispatchTimerQueueTest,callbackReentrancy)518 TEST_F(VSyncDispatchTimerQueueTest, callbackReentrancy) {
519 Sequence seq;
520 EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
521 EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
522
523 VSyncDispatch::CallbackToken tmp;
524 tmp = mDispatch.registerCallback(
525 [&](auto, auto, auto) {
526 mDispatch.schedule(tmp,
527 {.workDuration = 100,
528 .readyDuration = 0,
529 .earliestVsync = 2000});
530 },
531 "o.o");
532
533 mDispatch.schedule(tmp, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
534 advanceToNextCallback();
535 }
536
TEST_F(VSyncDispatchTimerQueueTest,callbackReentrantWithPastWakeup)537 TEST_F(VSyncDispatchTimerQueueTest, callbackReentrantWithPastWakeup) {
538 VSyncDispatch::CallbackToken tmp;
539 std::optional<nsecs_t> lastTarget;
540 tmp = mDispatch.registerCallback(
541 [&](auto timestamp, auto, auto) {
542 auto result =
543 mDispatch.schedule(tmp,
544 {.workDuration = 400,
545 .readyDuration = 0,
546 .earliestVsync = timestamp - mVsyncMoveThreshold});
547 EXPECT_TRUE(result.has_value());
548 EXPECT_EQ(mPeriod + timestamp - 400, *result);
549 result = mDispatch.schedule(tmp,
550 {.workDuration = 400,
551 .readyDuration = 0,
552 .earliestVsync = timestamp});
553 EXPECT_TRUE(result.has_value());
554 EXPECT_EQ(mPeriod + timestamp - 400, *result);
555 result = mDispatch.schedule(tmp,
556 {.workDuration = 400,
557 .readyDuration = 0,
558 .earliestVsync = timestamp + mVsyncMoveThreshold});
559 EXPECT_TRUE(result.has_value());
560 EXPECT_EQ(mPeriod + timestamp - 400, *result);
561 lastTarget = timestamp;
562 },
563 "oo");
564
565 mDispatch.schedule(tmp, {.workDuration = 999, .readyDuration = 0, .earliestVsync = 1000});
566 advanceToNextCallback();
567 EXPECT_THAT(lastTarget, Eq(1000));
568
569 advanceToNextCallback();
570 EXPECT_THAT(lastTarget, Eq(2000));
571 }
572
TEST_F(VSyncDispatchTimerQueueTest,modificationsAroundVsyncTime)573 TEST_F(VSyncDispatchTimerQueueTest, modificationsAroundVsyncTime) {
574 Sequence seq;
575 EXPECT_CALL(mMockClock, alarmAt(_, 1000)).InSequence(seq);
576 EXPECT_CALL(mMockClock, alarmAt(_, 950)).InSequence(seq);
577 EXPECT_CALL(mMockClock, alarmAt(_, 1950)).InSequence(seq);
578 EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
579
580 CountingCallback cb(mDispatch);
581 mDispatch.schedule(cb, {.workDuration = 0, .readyDuration = 0, .earliestVsync = 1000});
582
583 mMockClock.advanceBy(750);
584 mDispatch.schedule(cb, {.workDuration = 50, .readyDuration = 0, .earliestVsync = 1000});
585
586 advanceToNextCallback();
587 mDispatch.schedule(cb, {.workDuration = 50, .readyDuration = 0, .earliestVsync = 2000});
588
589 mMockClock.advanceBy(800);
590 mDispatch.schedule(cb, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000});
591 }
592
TEST_F(VSyncDispatchTimerQueueTest,lateModifications)593 TEST_F(VSyncDispatchTimerQueueTest, lateModifications) {
594 Sequence seq;
595 EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
596 EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
597 EXPECT_CALL(mMockClock, alarmAt(_, 850)).InSequence(seq);
598 EXPECT_CALL(mMockClock, alarmAt(_, 1800)).InSequence(seq);
599
600 CountingCallback cb0(mDispatch);
601 CountingCallback cb1(mDispatch);
602
603 mDispatch.schedule(cb0, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
604 mDispatch.schedule(cb1, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
605
606 advanceToNextCallback();
607 mDispatch.schedule(cb0, {.workDuration = 200, .readyDuration = 0, .earliestVsync = 2000});
608 mDispatch.schedule(cb1, {.workDuration = 150, .readyDuration = 0, .earliestVsync = 1000});
609
610 advanceToNextCallback();
611 advanceToNextCallback();
612 }
613
TEST_F(VSyncDispatchTimerQueueTest,doesntCancelPriorValidTimerForFutureMod)614 TEST_F(VSyncDispatchTimerQueueTest, doesntCancelPriorValidTimerForFutureMod) {
615 Sequence seq;
616 EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
617
618 CountingCallback cb0(mDispatch);
619 CountingCallback cb1(mDispatch);
620 mDispatch.schedule(cb0, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
621 mDispatch.schedule(cb1, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 20000});
622 }
623
TEST_F(VSyncDispatchTimerQueueTest,setsTimerAfterCancellation)624 TEST_F(VSyncDispatchTimerQueueTest, setsTimerAfterCancellation) {
625 Sequence seq;
626 EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
627 EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
628 EXPECT_CALL(mMockClock, alarmAt(_, 900)).InSequence(seq);
629
630 CountingCallback cb0(mDispatch);
631 mDispatch.schedule(cb0, {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
632 mDispatch.cancel(cb0);
633 mDispatch.schedule(cb0, {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
634 }
635
TEST_F(VSyncDispatchTimerQueueTest,makingUpIdsError)636 TEST_F(VSyncDispatchTimerQueueTest, makingUpIdsError) {
637 VSyncDispatch::CallbackToken token(100);
638 EXPECT_FALSE(mDispatch
639 .schedule(token,
640 {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000})
641 .has_value());
642 EXPECT_THAT(mDispatch.cancel(token), Eq(CancelResult::Error));
643 }
644
TEST_F(VSyncDispatchTimerQueueTest,canMoveCallbackBackwardsInTime)645 TEST_F(VSyncDispatchTimerQueueTest, canMoveCallbackBackwardsInTime) {
646 CountingCallback cb0(mDispatch);
647 auto result =
648 mDispatch.schedule(cb0,
649 {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
650 EXPECT_TRUE(result.has_value());
651 EXPECT_EQ(500, *result);
652 result = mDispatch.schedule(cb0,
653 {.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
654 EXPECT_TRUE(result.has_value());
655 EXPECT_EQ(900, *result);
656 }
657
658 // b/1450138150
TEST_F(VSyncDispatchTimerQueueTest,doesNotMoveCallbackBackwardsAndSkipAScheduledTargetVSync)659 TEST_F(VSyncDispatchTimerQueueTest, doesNotMoveCallbackBackwardsAndSkipAScheduledTargetVSync) {
660 EXPECT_CALL(mMockClock, alarmAt(_, 500));
661 CountingCallback cb(mDispatch);
662 auto result =
663 mDispatch.schedule(cb,
664 {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
665 EXPECT_TRUE(result.has_value());
666 EXPECT_EQ(500, *result);
667 mMockClock.advanceBy(400);
668
669 result = mDispatch.schedule(cb,
670 {.workDuration = 800, .readyDuration = 0, .earliestVsync = 1000});
671 EXPECT_TRUE(result.has_value());
672 EXPECT_EQ(1200, *result);
673 advanceToNextCallback();
674 ASSERT_THAT(cb.mCalls.size(), Eq(1));
675 }
676
TEST_F(VSyncDispatchTimerQueueTest,targetOffsetMovingBackALittleCanStillSchedule)677 TEST_F(VSyncDispatchTimerQueueTest, targetOffsetMovingBackALittleCanStillSchedule) {
678 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
679 .Times(2)
680 .WillOnce(Return(1000))
681 .WillOnce(Return(1002));
682 CountingCallback cb(mDispatch);
683 auto result =
684 mDispatch.schedule(cb,
685 {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
686 EXPECT_TRUE(result.has_value());
687 EXPECT_EQ(500, *result);
688 mMockClock.advanceBy(400);
689 result = mDispatch.schedule(cb,
690 {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
691 EXPECT_TRUE(result.has_value());
692 EXPECT_EQ(602, *result);
693 }
694
TEST_F(VSyncDispatchTimerQueueTest,canScheduleNegativeOffsetAgainstDifferentPeriods)695 TEST_F(VSyncDispatchTimerQueueTest, canScheduleNegativeOffsetAgainstDifferentPeriods) {
696 CountingCallback cb0(mDispatch);
697 auto result =
698 mDispatch.schedule(cb0,
699 {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
700 EXPECT_TRUE(result.has_value());
701 EXPECT_EQ(500, *result);
702 advanceToNextCallback();
703 result = mDispatch.schedule(cb0,
704 {.workDuration = 1100, .readyDuration = 0, .earliestVsync = 2000});
705 EXPECT_TRUE(result.has_value());
706 EXPECT_EQ(900, *result);
707 }
708
TEST_F(VSyncDispatchTimerQueueTest,canScheduleLargeNegativeOffset)709 TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) {
710 Sequence seq;
711 EXPECT_CALL(mMockClock, alarmAt(_, 500)).InSequence(seq);
712 EXPECT_CALL(mMockClock, alarmAt(_, 1100)).InSequence(seq);
713 CountingCallback cb0(mDispatch);
714 auto result =
715 mDispatch.schedule(cb0,
716 {.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
717 EXPECT_TRUE(result.has_value());
718 EXPECT_EQ(500, *result);
719 advanceToNextCallback();
720 result = mDispatch.schedule(cb0,
721 {.workDuration = 1900, .readyDuration = 0, .earliestVsync = 2000});
722 EXPECT_TRUE(result.has_value());
723 EXPECT_EQ(1100, *result);
724 }
725
TEST_F(VSyncDispatchTimerQueueTest,scheduleUpdatesDoesNotAffectSchedulingState)726 TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesNotAffectSchedulingState) {
727 EXPECT_CALL(mMockClock, alarmAt(_, 600));
728
729 CountingCallback cb(mDispatch);
730 auto result =
731 mDispatch.schedule(cb,
732 {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
733 EXPECT_TRUE(result.has_value());
734 EXPECT_EQ(600, *result);
735
736 result = mDispatch.schedule(cb,
737 {.workDuration = 1400, .readyDuration = 0, .earliestVsync = 1000});
738 EXPECT_TRUE(result.has_value());
739 EXPECT_EQ(600, *result);
740
741 advanceToNextCallback();
742 }
743
TEST_F(VSyncDispatchTimerQueueTest,helperMove)744 TEST_F(VSyncDispatchTimerQueueTest, helperMove) {
745 EXPECT_CALL(mMockClock, alarmAt(_, 500)).Times(1);
746 EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
747
748 VSyncCallbackRegistration cb(
749 mDispatch, [](auto, auto, auto) {}, "");
750 VSyncCallbackRegistration cb1(std::move(cb));
751 cb.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
752 cb.cancel();
753
754 cb1.schedule({.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
755 cb1.cancel();
756 }
757
TEST_F(VSyncDispatchTimerQueueTest,helperMoveAssign)758 TEST_F(VSyncDispatchTimerQueueTest, helperMoveAssign) {
759 EXPECT_CALL(mMockClock, alarmAt(_, 500)).Times(1);
760 EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
761
762 VSyncCallbackRegistration cb(
763 mDispatch, [](auto, auto, auto) {}, "");
764 VSyncCallbackRegistration cb1(
765 mDispatch, [](auto, auto, auto) {}, "");
766 cb1 = std::move(cb);
767 cb.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 1000});
768 cb.cancel();
769
770 cb1.schedule({.workDuration = 500, .readyDuration = 0, .earliestVsync = 1000});
771 cb1.cancel();
772 }
773
774 // b/154303580
TEST_F(VSyncDispatchTimerQueueTest,skipsSchedulingIfTimerReschedulingIsImminent)775 TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminent) {
776 Sequence seq;
777 EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
778 EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
779 CountingCallback cb1(mDispatch);
780 CountingCallback cb2(mDispatch);
781
782 auto result =
783 mDispatch.schedule(cb1,
784 {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
785 EXPECT_TRUE(result.has_value());
786 EXPECT_EQ(600, *result);
787
788 mMockClock.setLag(100);
789 mMockClock.advanceBy(620);
790
791 result = mDispatch.schedule(cb2,
792 {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000});
793 EXPECT_TRUE(result.has_value());
794 EXPECT_EQ(1900, *result);
795 mMockClock.advanceBy(80);
796
797 EXPECT_THAT(cb1.mCalls.size(), Eq(1));
798 EXPECT_THAT(cb2.mCalls.size(), Eq(0));
799 }
800
801 // b/154303580.
802 // If the same callback tries to reschedule itself after it's too late, timer opts to apply the
803 // update later, as opposed to blocking the calling thread.
TEST_F(VSyncDispatchTimerQueueTest,skipsSchedulingIfTimerReschedulingIsImminentSameCallback)804 TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminentSameCallback) {
805 Sequence seq;
806 EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
807 EXPECT_CALL(mMockClock, alarmAt(_, 1630)).InSequence(seq);
808 CountingCallback cb(mDispatch);
809
810 auto result =
811 mDispatch.schedule(cb,
812 {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
813 EXPECT_TRUE(result.has_value());
814 EXPECT_EQ(600, *result);
815
816 mMockClock.setLag(100);
817 mMockClock.advanceBy(620);
818
819 result = mDispatch.schedule(cb,
820 {.workDuration = 370, .readyDuration = 0, .earliestVsync = 2000});
821 EXPECT_TRUE(result.has_value());
822 EXPECT_EQ(1630, *result);
823 mMockClock.advanceBy(80);
824
825 EXPECT_THAT(cb.mCalls.size(), Eq(1));
826 }
827
828 // b/154303580.
TEST_F(VSyncDispatchTimerQueueTest,skipsRearmingWhenNotNextScheduled)829 TEST_F(VSyncDispatchTimerQueueTest, skipsRearmingWhenNotNextScheduled) {
830 Sequence seq;
831 EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
832 EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
833 CountingCallback cb1(mDispatch);
834 CountingCallback cb2(mDispatch);
835
836 auto result =
837 mDispatch.schedule(cb1,
838 {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
839 EXPECT_TRUE(result.has_value());
840 EXPECT_EQ(600, *result);
841 result = mDispatch.schedule(cb2,
842 {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000});
843 EXPECT_TRUE(result.has_value());
844 EXPECT_EQ(1900, *result);
845
846 mMockClock.setLag(100);
847 mMockClock.advanceBy(620);
848
849 EXPECT_EQ(mDispatch.cancel(cb2), CancelResult::Cancelled);
850
851 mMockClock.advanceBy(80);
852
853 EXPECT_THAT(cb1.mCalls.size(), Eq(1));
854 EXPECT_THAT(cb2.mCalls.size(), Eq(0));
855 }
856
TEST_F(VSyncDispatchTimerQueueTest,rearmsWhenCancelledAndIsNextScheduled)857 TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenCancelledAndIsNextScheduled) {
858 Sequence seq;
859 EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
860 EXPECT_CALL(mMockClock, alarmAt(_, 1900)).InSequence(seq);
861 EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
862 CountingCallback cb1(mDispatch);
863 CountingCallback cb2(mDispatch);
864
865 auto result =
866 mDispatch.schedule(cb1,
867 {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
868 EXPECT_TRUE(result.has_value());
869 EXPECT_EQ(600, *result);
870 result = mDispatch.schedule(cb2,
871 {.workDuration = 100, .readyDuration = 0, .earliestVsync = 2000});
872 EXPECT_TRUE(result.has_value());
873 EXPECT_EQ(1900, *result);
874
875 mMockClock.setLag(100);
876 mMockClock.advanceBy(620);
877
878 EXPECT_EQ(mDispatch.cancel(cb1), CancelResult::Cancelled);
879
880 EXPECT_THAT(cb1.mCalls.size(), Eq(0));
881 EXPECT_THAT(cb2.mCalls.size(), Eq(0));
882 mMockClock.advanceToNextCallback();
883
884 EXPECT_THAT(cb1.mCalls.size(), Eq(0));
885 EXPECT_THAT(cb2.mCalls.size(), Eq(1));
886 }
887
TEST_F(VSyncDispatchTimerQueueTest,laggedTimerGroupsCallbacksWithinLag)888 TEST_F(VSyncDispatchTimerQueueTest, laggedTimerGroupsCallbacksWithinLag) {
889 CountingCallback cb1(mDispatch);
890 CountingCallback cb2(mDispatch);
891
892 Sequence seq;
893 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
894 .InSequence(seq)
895 .WillOnce(Return(1000));
896 EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
897 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
898 .InSequence(seq)
899 .WillOnce(Return(1000));
900
901 auto result =
902 mDispatch.schedule(cb1,
903 {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
904 EXPECT_TRUE(result.has_value());
905 EXPECT_EQ(600, *result);
906 result = mDispatch.schedule(cb2,
907 {.workDuration = 390, .readyDuration = 0, .earliestVsync = 1000});
908 EXPECT_TRUE(result.has_value());
909 EXPECT_EQ(610, *result);
910
911 mMockClock.setLag(100);
912 mMockClock.advanceBy(700);
913
914 ASSERT_THAT(cb1.mWakeupTime.size(), Eq(1));
915 EXPECT_THAT(cb1.mWakeupTime[0], Eq(600));
916 ASSERT_THAT(cb1.mReadyTime.size(), Eq(1));
917 EXPECT_THAT(cb1.mReadyTime[0], Eq(1000));
918 ASSERT_THAT(cb2.mWakeupTime.size(), Eq(1));
919 EXPECT_THAT(cb2.mWakeupTime[0], Eq(610));
920 ASSERT_THAT(cb2.mReadyTime.size(), Eq(1));
921 EXPECT_THAT(cb2.mReadyTime[0], Eq(1000));
922 }
923
TEST_F(VSyncDispatchTimerQueueTest,basicAlarmSettingFutureWithReadyDuration)924 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFutureWithReadyDuration) {
925 auto intended = mPeriod - 230;
926 EXPECT_CALL(mMockClock, alarmAt(_, 900));
927
928 CountingCallback cb(mDispatch);
929 const auto result = mDispatch.schedule(cb,
930 {.workDuration = 70,
931 .readyDuration = 30,
932 .earliestVsync = intended});
933 EXPECT_TRUE(result.has_value());
934 EXPECT_EQ(900, *result);
935 advanceToNextCallback();
936
937 ASSERT_THAT(cb.mCalls.size(), Eq(1));
938 EXPECT_THAT(cb.mCalls[0], Eq(mPeriod));
939 ASSERT_THAT(cb.mWakeupTime.size(), Eq(1));
940 EXPECT_THAT(cb.mWakeupTime[0], 900);
941 ASSERT_THAT(cb.mReadyTime.size(), Eq(1));
942 EXPECT_THAT(cb.mReadyTime[0], 970);
943 }
944
TEST_F(VSyncDispatchTimerQueueTest,updatesVsyncTimeForCloseWakeupTime)945 TEST_F(VSyncDispatchTimerQueueTest, updatesVsyncTimeForCloseWakeupTime) {
946 Sequence seq;
947 EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
948
949 CountingCallback cb(mDispatch);
950
951 mDispatch.schedule(cb, {.workDuration = 400, .readyDuration = 0, .earliestVsync = 1000});
952 mDispatch.schedule(cb, {.workDuration = 1400, .readyDuration = 0, .earliestVsync = 1000});
953
954 advanceToNextCallback();
955
956 advanceToNextCallback();
957
958 ASSERT_THAT(cb.mCalls.size(), Eq(1));
959 EXPECT_THAT(cb.mCalls[0], Eq(2000));
960 ASSERT_THAT(cb.mWakeupTime.size(), Eq(1));
961 EXPECT_THAT(cb.mWakeupTime[0], Eq(600));
962 ASSERT_THAT(cb.mReadyTime.size(), Eq(1));
963 EXPECT_THAT(cb.mReadyTime[0], Eq(2000));
964 }
965
966 class VSyncDispatchTimerQueueEntryTest : public testing::Test {
967 protected:
968 nsecs_t const mPeriod = 1000;
969 nsecs_t const mVsyncMoveThreshold = 200;
970 NiceMock<MockVSyncTracker> mStubTracker{mPeriod};
971 };
972
TEST_F(VSyncDispatchTimerQueueEntryTest,stateAfterInitialization)973 TEST_F(VSyncDispatchTimerQueueEntryTest, stateAfterInitialization) {
974 std::string name("basicname");
975 VSyncDispatchTimerQueueEntry entry(
976 name, [](auto, auto, auto) {}, mVsyncMoveThreshold);
977 EXPECT_THAT(entry.name(), Eq(name));
978 EXPECT_FALSE(entry.lastExecutedVsyncTarget());
979 EXPECT_FALSE(entry.wakeupTime());
980 }
981
TEST_F(VSyncDispatchTimerQueueEntryTest,stateScheduling)982 TEST_F(VSyncDispatchTimerQueueEntryTest, stateScheduling) {
983 VSyncDispatchTimerQueueEntry entry(
984 "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
985
986 EXPECT_FALSE(entry.wakeupTime());
987 EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
988 mStubTracker, 0)
989 .has_value());
990 auto const wakeup = entry.wakeupTime();
991 ASSERT_TRUE(wakeup);
992 EXPECT_THAT(*wakeup, Eq(900));
993
994 entry.disarm();
995 EXPECT_FALSE(entry.wakeupTime());
996 }
997
TEST_F(VSyncDispatchTimerQueueEntryTest,stateSchedulingReallyLongWakeupLatency)998 TEST_F(VSyncDispatchTimerQueueEntryTest, stateSchedulingReallyLongWakeupLatency) {
999 auto const duration = 500;
1000 auto const now = 8750;
1001
1002 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(now + duration))
1003 .Times(1)
1004 .WillOnce(Return(10000));
1005 VSyncDispatchTimerQueueEntry entry(
1006 "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
1007
1008 EXPECT_FALSE(entry.wakeupTime());
1009 EXPECT_TRUE(entry.schedule({.workDuration = 500, .readyDuration = 0, .earliestVsync = 994},
1010 mStubTracker, now)
1011 .has_value());
1012 auto const wakeup = entry.wakeupTime();
1013 ASSERT_TRUE(wakeup);
1014 EXPECT_THAT(*wakeup, Eq(9500));
1015 }
1016
TEST_F(VSyncDispatchTimerQueueEntryTest,runCallback)1017 TEST_F(VSyncDispatchTimerQueueEntryTest, runCallback) {
1018 auto callCount = 0;
1019 auto vsyncCalledTime = 0;
1020 auto wakeupCalledTime = 0;
1021 auto readyCalledTime = 0;
1022 VSyncDispatchTimerQueueEntry entry(
1023 "test",
1024 [&](auto vsyncTime, auto wakeupTime, auto readyTime) {
1025 callCount++;
1026 vsyncCalledTime = vsyncTime;
1027 wakeupCalledTime = wakeupTime;
1028 readyCalledTime = readyTime;
1029 },
1030 mVsyncMoveThreshold);
1031
1032 EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
1033 mStubTracker, 0)
1034 .has_value());
1035 auto const wakeup = entry.wakeupTime();
1036 ASSERT_TRUE(wakeup);
1037 EXPECT_THAT(*wakeup, Eq(900));
1038
1039 auto const ready = entry.readyTime();
1040 ASSERT_TRUE(ready);
1041 EXPECT_THAT(*ready, Eq(1000));
1042
1043 entry.callback(entry.executing(), *wakeup, *ready);
1044
1045 EXPECT_THAT(callCount, Eq(1));
1046 EXPECT_THAT(vsyncCalledTime, Eq(mPeriod));
1047 EXPECT_THAT(wakeupCalledTime, Eq(*wakeup));
1048 EXPECT_FALSE(entry.wakeupTime());
1049 auto lastCalledTarget = entry.lastExecutedVsyncTarget();
1050 ASSERT_TRUE(lastCalledTarget);
1051 EXPECT_THAT(*lastCalledTarget, Eq(mPeriod));
1052 }
1053
TEST_F(VSyncDispatchTimerQueueEntryTest,updateCallback)1054 TEST_F(VSyncDispatchTimerQueueEntryTest, updateCallback) {
1055 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
1056 .Times(2)
1057 .WillOnce(Return(1000))
1058 .WillOnce(Return(1020));
1059
1060 VSyncDispatchTimerQueueEntry entry(
1061 "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
1062
1063 EXPECT_FALSE(entry.wakeupTime());
1064 entry.update(mStubTracker, 0);
1065 EXPECT_FALSE(entry.wakeupTime());
1066
1067 EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
1068 mStubTracker, 0)
1069 .has_value());
1070 auto wakeup = entry.wakeupTime();
1071 ASSERT_TRUE(wakeup);
1072 EXPECT_THAT(wakeup, Eq(900));
1073
1074 entry.update(mStubTracker, 0);
1075 wakeup = entry.wakeupTime();
1076 ASSERT_TRUE(wakeup);
1077 EXPECT_THAT(*wakeup, Eq(920));
1078 }
1079
TEST_F(VSyncDispatchTimerQueueEntryTest,skipsUpdateIfJustScheduled)1080 TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) {
1081 VSyncDispatchTimerQueueEntry entry(
1082 "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
1083 EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
1084 mStubTracker, 0)
1085 .has_value());
1086 entry.update(mStubTracker, 0);
1087
1088 auto const wakeup = entry.wakeupTime();
1089 ASSERT_TRUE(wakeup);
1090 EXPECT_THAT(*wakeup, Eq(wakeup));
1091 }
1092
TEST_F(VSyncDispatchTimerQueueEntryTest,willSnapToNextTargettableVSync)1093 TEST_F(VSyncDispatchTimerQueueEntryTest, willSnapToNextTargettableVSync) {
1094 VSyncDispatchTimerQueueEntry entry(
1095 "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
1096 EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
1097 mStubTracker, 0)
1098 .has_value());
1099 entry.executing(); // 1000 is executing
1100 // had 1000 not been executing, this could have been scheduled for time 800.
1101 EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 500},
1102 mStubTracker, 0)
1103 .has_value());
1104 EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
1105 EXPECT_THAT(*entry.readyTime(), Eq(2000));
1106
1107 EXPECT_TRUE(entry.schedule({.workDuration = 50, .readyDuration = 0, .earliestVsync = 500},
1108 mStubTracker, 0)
1109 .has_value());
1110 EXPECT_THAT(*entry.wakeupTime(), Eq(1950));
1111 EXPECT_THAT(*entry.readyTime(), Eq(2000));
1112
1113 EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 1001},
1114 mStubTracker, 0)
1115 .has_value());
1116 EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
1117 EXPECT_THAT(*entry.readyTime(), Eq(2000));
1118 }
1119
TEST_F(VSyncDispatchTimerQueueEntryTest,willRequestNextEstimateWhenSnappingToNextTargettableVSync)1120 TEST_F(VSyncDispatchTimerQueueEntryTest,
1121 willRequestNextEstimateWhenSnappingToNextTargettableVSync) {
1122 VSyncDispatchTimerQueueEntry entry(
1123 "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
1124
1125 Sequence seq;
1126 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500))
1127 .InSequence(seq)
1128 .WillOnce(Return(1000));
1129 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500))
1130 .InSequence(seq)
1131 .WillOnce(Return(1000));
1132 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000 + mVsyncMoveThreshold))
1133 .InSequence(seq)
1134 .WillOnce(Return(2000));
1135
1136 EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
1137 mStubTracker, 0)
1138 .has_value());
1139
1140 entry.executing(); // 1000 is executing
1141
1142 EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 500},
1143 mStubTracker, 0)
1144 .has_value());
1145 }
1146
TEST_F(VSyncDispatchTimerQueueEntryTest,reportsScheduledIfStillTime)1147 TEST_F(VSyncDispatchTimerQueueEntryTest, reportsScheduledIfStillTime) {
1148 VSyncDispatchTimerQueueEntry entry(
1149 "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
1150 EXPECT_TRUE(entry.schedule({.workDuration = 100, .readyDuration = 0, .earliestVsync = 500},
1151 mStubTracker, 0)
1152 .has_value());
1153 EXPECT_TRUE(entry.schedule({.workDuration = 200, .readyDuration = 0, .earliestVsync = 500},
1154 mStubTracker, 0)
1155 .has_value());
1156 EXPECT_TRUE(entry.schedule({.workDuration = 50, .readyDuration = 0, .earliestVsync = 500},
1157 mStubTracker, 0)
1158 .has_value());
1159 EXPECT_TRUE(entry.schedule({.workDuration = 1200, .readyDuration = 0, .earliestVsync = 500},
1160 mStubTracker, 0)
1161 .has_value());
1162 }
1163
TEST_F(VSyncDispatchTimerQueueEntryTest,storesPendingUpdatesUntilUpdate)1164 TEST_F(VSyncDispatchTimerQueueEntryTest, storesPendingUpdatesUntilUpdate) {
1165 static constexpr auto effectualOffset = 200;
1166 VSyncDispatchTimerQueueEntry entry(
1167 "test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
1168 EXPECT_FALSE(entry.hasPendingWorkloadUpdate());
1169 entry.addPendingWorkloadUpdate({.workDuration = 100, .readyDuration = 0, .earliestVsync = 400});
1170 entry.addPendingWorkloadUpdate(
1171 {.workDuration = effectualOffset, .readyDuration = 0, .earliestVsync = 400});
1172 EXPECT_TRUE(entry.hasPendingWorkloadUpdate());
1173 entry.update(mStubTracker, 0);
1174 EXPECT_FALSE(entry.hasPendingWorkloadUpdate());
1175 EXPECT_THAT(*entry.wakeupTime(), Eq(mPeriod - effectualOffset));
1176 }
1177
TEST_F(VSyncDispatchTimerQueueEntryTest,runCallbackWithReadyDuration)1178 TEST_F(VSyncDispatchTimerQueueEntryTest, runCallbackWithReadyDuration) {
1179 auto callCount = 0;
1180 auto vsyncCalledTime = 0;
1181 auto wakeupCalledTime = 0;
1182 auto readyCalledTime = 0;
1183 VSyncDispatchTimerQueueEntry entry(
1184 "test",
1185 [&](auto vsyncTime, auto wakeupTime, auto readyTime) {
1186 callCount++;
1187 vsyncCalledTime = vsyncTime;
1188 wakeupCalledTime = wakeupTime;
1189 readyCalledTime = readyTime;
1190 },
1191 mVsyncMoveThreshold);
1192
1193 EXPECT_TRUE(entry.schedule({.workDuration = 70, .readyDuration = 30, .earliestVsync = 500},
1194 mStubTracker, 0)
1195 .has_value());
1196 auto const wakeup = entry.wakeupTime();
1197 ASSERT_TRUE(wakeup);
1198 EXPECT_THAT(*wakeup, Eq(900));
1199
1200 auto const ready = entry.readyTime();
1201 ASSERT_TRUE(ready);
1202 EXPECT_THAT(*ready, Eq(970));
1203
1204 entry.callback(entry.executing(), *wakeup, *ready);
1205
1206 EXPECT_THAT(callCount, Eq(1));
1207 EXPECT_THAT(vsyncCalledTime, Eq(mPeriod));
1208 EXPECT_THAT(wakeupCalledTime, Eq(*wakeup));
1209 EXPECT_FALSE(entry.wakeupTime());
1210 auto lastCalledTarget = entry.lastExecutedVsyncTarget();
1211 ASSERT_TRUE(lastCalledTarget);
1212 EXPECT_THAT(*lastCalledTarget, Eq(mPeriod));
1213 }
1214
1215 } // namespace android::scheduler
1216
1217 // TODO(b/129481165): remove the #pragma below and fix conversion issues
1218 #pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
1219