blob: d1ed7e3dbe21cd2fbc0466d104156df0d9dd209c [file] [log] [blame]
Kevin DuBois305bef12019-10-09 13:23:27 -07001/*
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#undef LOG_TAG
18#define LOG_TAG "LibSurfaceFlingerUnittests"
19#define LOG_NDEBUG 0
20
21#include "Scheduler/TimeKeeper.h"
22#include "Scheduler/VSyncDispatch.h"
23#include "Scheduler/VSyncTracker.h"
24
25#include <gmock/gmock.h>
26#include <gtest/gtest.h>
27#include <thread>
28
29using namespace testing;
30using namespace std::literals;
31namespace android::scheduler {
32
33class MockVSyncTracker : public VSyncTracker {
34public:
35 MockVSyncTracker(nsecs_t period) : mPeriod{period} {
36 ON_CALL(*this, nextAnticipatedVSyncTimeFrom(_))
37 .WillByDefault(Invoke(this, &MockVSyncTracker::nextVSyncTime));
38 }
39
40 MOCK_METHOD1(addVsyncTimestamp, void(nsecs_t));
41 MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
42
43 nsecs_t nextVSyncTime(nsecs_t timePoint) const {
44 if (timePoint % mPeriod == 0) {
45 return timePoint;
46 }
47 return (timePoint - (timePoint % mPeriod) + mPeriod);
48 }
49
50protected:
51 nsecs_t const mPeriod;
52};
53
54class ControllableClock : public TimeKeeper {
55public:
56 ControllableClock() {
57 ON_CALL(*this, alarmIn(_, _))
58 .WillByDefault(Invoke(this, &ControllableClock::alarmInDefaultBehavior));
59 ON_CALL(*this, now()).WillByDefault(Invoke(this, &ControllableClock::fakeTime));
60 }
61
62 MOCK_CONST_METHOD0(now, nsecs_t());
63 MOCK_METHOD2(alarmIn, void(std::function<void()> const&, nsecs_t time));
64 MOCK_METHOD0(alarmCancel, void());
65
66 void alarmInDefaultBehavior(std::function<void()> const& callback, nsecs_t time) {
67 mCallback = callback;
68 mNextCallbackTime = time + mCurrentTime;
69 }
70
71 nsecs_t fakeTime() const { return mCurrentTime; }
72
73 void advanceToNextCallback() {
74 mCurrentTime = mNextCallbackTime;
75 if (mCallback) {
76 mCallback();
77 }
78 }
79
80 void advanceBy(nsecs_t advancement) {
81 mCurrentTime += advancement;
82 if (mCurrentTime >= mNextCallbackTime && mCallback) {
83 mCallback();
84 }
85 };
86
87private:
88 std::function<void()> mCallback;
89 nsecs_t mNextCallbackTime = 0;
90 nsecs_t mCurrentTime = 0;
91};
92
93class CountingCallback {
94public:
95 CountingCallback(VSyncDispatch& dispatch)
96 : mDispatch(dispatch),
97 mToken(dispatch.registerCallback(std::bind(&CountingCallback::counter, this,
98 std::placeholders::_1),
99 "test")) {}
100 ~CountingCallback() { mDispatch.unregisterCallback(mToken); }
101
102 operator VSyncDispatch::CallbackToken() const { return mToken; }
103
104 void counter(nsecs_t time) { mCalls.push_back(time); }
105
106 VSyncDispatch& mDispatch;
107 VSyncDispatch::CallbackToken mToken;
108 std::vector<nsecs_t> mCalls;
109};
110
111class PausingCallback {
112public:
113 PausingCallback(VSyncDispatch& dispatch, std::chrono::milliseconds pauseAmount)
114 : mDispatch(dispatch),
115 mToken(dispatch.registerCallback(std::bind(&PausingCallback::pause, this,
116 std::placeholders::_1),
117 "test")),
118 mRegistered(true),
119 mPauseAmount(pauseAmount) {}
120 ~PausingCallback() { unregister(); }
121
122 operator VSyncDispatch::CallbackToken() const { return mToken; }
123
124 void pause(nsecs_t) {
125 std::unique_lock<std::mutex> lk(mMutex);
126 mPause = true;
127 mCv.notify_all();
128
129 mCv.wait_for(lk, mPauseAmount, [this] { return !mPause; });
130
131 mResourcePresent = (mResource.lock() != nullptr);
132 }
133
134 bool waitForPause() {
135 std::unique_lock<std::mutex> lk(mMutex);
136 auto waiting = mCv.wait_for(lk, 10s, [this] { return mPause; });
137 return waiting;
138 }
139
140 void stashResource(std::weak_ptr<void> const& resource) { mResource = resource; }
141
142 bool resourcePresent() { return mResourcePresent; }
143
144 void unpause() {
145 std::unique_lock<std::mutex> lk(mMutex);
146 mPause = false;
147 mCv.notify_all();
148 }
149
150 void unregister() {
151 if (mRegistered) {
152 mDispatch.unregisterCallback(mToken);
153 mRegistered = false;
154 }
155 }
156
157 VSyncDispatch& mDispatch;
158 VSyncDispatch::CallbackToken mToken;
159 bool mRegistered = true;
160
161 std::mutex mMutex;
162 std::condition_variable mCv;
163 bool mPause = false;
164 std::weak_ptr<void> mResource;
165 bool mResourcePresent = false;
166 std::chrono::milliseconds const mPauseAmount;
167};
168
169class VSyncDispatchTest : public testing::Test {
170protected:
171 std::unique_ptr<TimeKeeper> createTimeKeeper() {
172 class TimeKeeperWrapper : public TimeKeeper {
173 public:
174 TimeKeeperWrapper(TimeKeeper& control) : mControllableClock(control) {}
175 void alarmIn(std::function<void()> const& callback, nsecs_t time) final {
176 mControllableClock.alarmIn(callback, time);
177 }
178 void alarmCancel() final { mControllableClock.alarmCancel(); }
179 nsecs_t now() const final { return mControllableClock.now(); }
180
181 private:
182 TimeKeeper& mControllableClock;
183 };
184 return std::make_unique<TimeKeeperWrapper>(mMockClock);
185 }
186
187 ~VSyncDispatchTest() {
188 // destructor of dispatch will cancelAlarm(). Ignore final cancel in common test.
189 Mock::VerifyAndClearExpectations(&mMockClock);
190 }
191
192 void advanceToNextCallback() { mMockClock.advanceToNextCallback(); }
193
194 NiceMock<ControllableClock> mMockClock;
195 static nsecs_t constexpr mDispatchGroupThreshold = 5;
196 nsecs_t const mPeriod = 1000;
197 NiceMock<MockVSyncTracker> mStubTracker{mPeriod};
198 VSyncDispatch mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold};
199};
200
201TEST_F(VSyncDispatchTest, unregistersSetAlarmOnDestruction) {
202 EXPECT_CALL(mMockClock, alarmIn(_, 900));
203 EXPECT_CALL(mMockClock, alarmCancel());
204 {
205 VSyncDispatch mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold};
206 CountingCallback cb(mDispatch);
207 EXPECT_EQ(mDispatch.schedule(cb, 100, 1000), ScheduleResult::Scheduled);
208 }
209}
210
211TEST_F(VSyncDispatchTest, basicAlarmSettingFuture) {
212 auto intended = mPeriod - 230;
213 EXPECT_CALL(mMockClock, alarmIn(_, 900));
214
215 CountingCallback cb(mDispatch);
216 EXPECT_EQ(mDispatch.schedule(cb, 100, intended), ScheduleResult::Scheduled);
217 advanceToNextCallback();
218
219 ASSERT_THAT(cb.mCalls.size(), Eq(1));
220 EXPECT_THAT(cb.mCalls[0], Eq(mPeriod));
221}
222
223TEST_F(VSyncDispatchTest, basicAlarmSettingFutureWithAdjustmentToTrueVsync) {
224 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000)).WillOnce(Return(1150));
225 EXPECT_CALL(mMockClock, alarmIn(_, 1050));
226
227 CountingCallback cb(mDispatch);
228 mDispatch.schedule(cb, 100, mPeriod);
229 advanceToNextCallback();
230
231 ASSERT_THAT(cb.mCalls.size(), Eq(1));
232 EXPECT_THAT(cb.mCalls[0], Eq(1150));
233}
234
235TEST_F(VSyncDispatchTest, basicAlarmSettingAdjustmentPast) {
236 auto const now = 234;
237 mMockClock.advanceBy(234);
238 auto const workDuration = 10 * mPeriod;
239 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(now + workDuration))
240 .WillOnce(Return(mPeriod * 11));
241 EXPECT_CALL(mMockClock, alarmIn(_, mPeriod - now));
242
243 CountingCallback cb(mDispatch);
244 EXPECT_EQ(mDispatch.schedule(cb, workDuration, mPeriod), ScheduleResult::Scheduled);
245}
246
247TEST_F(VSyncDispatchTest, basicAlarmCancel) {
248 EXPECT_CALL(mMockClock, alarmIn(_, 900));
249 EXPECT_CALL(mMockClock, alarmCancel());
250
251 CountingCallback cb(mDispatch);
252 EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
253 EXPECT_EQ(mDispatch.cancel(cb), CancelResult::Cancelled);
254}
255
256TEST_F(VSyncDispatchTest, basicAlarmCancelTooLate) {
257 EXPECT_CALL(mMockClock, alarmIn(_, 900));
258 EXPECT_CALL(mMockClock, alarmCancel());
259
260 CountingCallback cb(mDispatch);
261 EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
262 mMockClock.advanceBy(950);
263 EXPECT_EQ(mDispatch.cancel(cb), CancelResult::TooLate);
264}
265
266TEST_F(VSyncDispatchTest, basicAlarmCancelTooLateWhenRunning) {
267 EXPECT_CALL(mMockClock, alarmIn(_, 900));
268 EXPECT_CALL(mMockClock, alarmCancel());
269
270 PausingCallback cb(mDispatch, std::chrono::duration_cast<std::chrono::milliseconds>(1s));
271 EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
272
273 std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
274 EXPECT_TRUE(cb.waitForPause());
275 EXPECT_EQ(mDispatch.cancel(cb), CancelResult::TooLate);
276 cb.unpause();
277 pausingThread.join();
278}
279
280TEST_F(VSyncDispatchTest, unregisterSynchronizes) {
281 EXPECT_CALL(mMockClock, alarmIn(_, 900));
282 EXPECT_CALL(mMockClock, alarmCancel());
283
284 auto resource = std::make_shared<int>(110);
285
286 PausingCallback cb(mDispatch, 50ms);
287 cb.stashResource(resource);
288 EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
289
290 std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
291 EXPECT_TRUE(cb.waitForPause());
292
293 cb.unregister();
294 resource.reset();
295
296 cb.unpause();
297 pausingThread.join();
298
299 EXPECT_TRUE(cb.resourcePresent());
300}
301
302TEST_F(VSyncDispatchTest, basicTwoAlarmSetting) {
303 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
304 .Times(4)
305 .WillOnce(Return(1055))
306 .WillOnce(Return(1063))
307 .WillOnce(Return(1063))
308 .WillOnce(Return(1075));
309
310 Sequence seq;
311 EXPECT_CALL(mMockClock, alarmIn(_, 955)).InSequence(seq);
312 EXPECT_CALL(mMockClock, alarmIn(_, 813)).InSequence(seq);
313 EXPECT_CALL(mMockClock, alarmIn(_, 162)).InSequence(seq);
314
315 CountingCallback cb0(mDispatch);
316 CountingCallback cb1(mDispatch);
317
318 mDispatch.schedule(cb0, 100, mPeriod);
319 mDispatch.schedule(cb1, 250, mPeriod);
320
321 advanceToNextCallback();
322 advanceToNextCallback();
323
324 ASSERT_THAT(cb0.mCalls.size(), Eq(1));
325 EXPECT_THAT(cb0.mCalls[0], Eq(1075));
326 ASSERT_THAT(cb1.mCalls.size(), Eq(1));
327 EXPECT_THAT(cb1.mCalls[0], Eq(1063));
328}
329
330TEST_F(VSyncDispatchTest, rearmsFaroutTimeoutWhenCancellingCloseOne) {
331 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
332 .Times(4)
333 .WillOnce(Return(10000))
334 .WillOnce(Return(1000))
335 .WillOnce(Return(10000))
336 .WillOnce(Return(10000));
337
338 Sequence seq;
339 EXPECT_CALL(mMockClock, alarmIn(_, 9900)).InSequence(seq);
340 EXPECT_CALL(mMockClock, alarmIn(_, 750)).InSequence(seq);
341 EXPECT_CALL(mMockClock, alarmIn(_, 9900)).InSequence(seq);
342
343 CountingCallback cb0(mDispatch);
344 CountingCallback cb1(mDispatch);
345
346 mDispatch.schedule(cb0, 100, mPeriod * 10);
347 mDispatch.schedule(cb1, 250, mPeriod);
348 mDispatch.cancel(cb1);
349}
350
351TEST_F(VSyncDispatchTest, noUnnecessaryRearmsWhenRescheduling) {
352 Sequence seq;
353 EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
354 EXPECT_CALL(mMockClock, alarmIn(_, 100)).InSequence(seq);
355
356 CountingCallback cb0(mDispatch);
357 CountingCallback cb1(mDispatch);
358
359 mDispatch.schedule(cb0, 400, 1000);
360 mDispatch.schedule(cb1, 200, 1000);
361 mDispatch.schedule(cb1, 300, 1000);
362 advanceToNextCallback();
363}
364
365TEST_F(VSyncDispatchTest, necessaryRearmsWhenModifying) {
366 Sequence seq;
367 EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
368 EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
369 EXPECT_CALL(mMockClock, alarmIn(_, 100)).InSequence(seq);
370
371 CountingCallback cb0(mDispatch);
372 CountingCallback cb1(mDispatch);
373
374 mDispatch.schedule(cb0, 400, 1000);
375 mDispatch.schedule(cb1, 200, 1000);
376 mDispatch.schedule(cb1, 500, 1000);
377 advanceToNextCallback();
378}
379
380TEST_F(VSyncDispatchTest, modifyIntoGroup) {
381 Sequence seq;
382 EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
383 EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
384 EXPECT_CALL(mMockClock, alarmIn(_, 990)).InSequence(seq);
385 EXPECT_CALL(mMockClock, alarmIn(_, 10)).InSequence(seq);
386
387 auto offset = 400;
388 auto closeOffset = offset + mDispatchGroupThreshold - 1;
389 auto notCloseOffset = offset + 2 * mDispatchGroupThreshold;
390
391 CountingCallback cb0(mDispatch);
392 CountingCallback cb1(mDispatch);
393
394 mDispatch.schedule(cb0, 400, 1000);
395 mDispatch.schedule(cb1, 200, 1000);
396 mDispatch.schedule(cb1, closeOffset, 1000);
397
398 advanceToNextCallback();
399 ASSERT_THAT(cb0.mCalls.size(), Eq(1));
400 EXPECT_THAT(cb0.mCalls[0], Eq(mPeriod));
401 ASSERT_THAT(cb1.mCalls.size(), Eq(1));
402 EXPECT_THAT(cb1.mCalls[0], Eq(mPeriod));
403
404 mDispatch.schedule(cb0, 400, 2000);
405 mDispatch.schedule(cb1, notCloseOffset, 2000);
406 advanceToNextCallback();
407 ASSERT_THAT(cb1.mCalls.size(), Eq(2));
408 EXPECT_THAT(cb1.mCalls[1], Eq(2000));
409
410 advanceToNextCallback();
411 ASSERT_THAT(cb0.mCalls.size(), Eq(2));
412 EXPECT_THAT(cb0.mCalls[1], Eq(2000));
413}
414
415TEST_F(VSyncDispatchTest, rearmsWhenEndingAndDoesntCancel) {
416 EXPECT_CALL(mMockClock, alarmIn(_, 900));
417 EXPECT_CALL(mMockClock, alarmIn(_, 800));
418 EXPECT_CALL(mMockClock, alarmIn(_, 100));
419 EXPECT_CALL(mMockClock, alarmCancel());
420
421 CountingCallback cb0(mDispatch);
422 CountingCallback cb1(mDispatch);
423
424 mDispatch.schedule(cb0, 100, 1000);
425 mDispatch.schedule(cb1, 200, 1000);
426 advanceToNextCallback();
427 EXPECT_EQ(mDispatch.cancel(cb0), CancelResult::Cancelled);
428}
429
430TEST_F(VSyncDispatchTest, setAlarmCallsAtCorrectTimeWithChangingVsync) {
431 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
432 .Times(3)
433 .WillOnce(Return(950))
434 .WillOnce(Return(1975))
435 .WillOnce(Return(2950));
436
437 CountingCallback cb(mDispatch);
438 mDispatch.schedule(cb, 100, 920);
439
440 mMockClock.advanceBy(850);
441 EXPECT_THAT(cb.mCalls.size(), Eq(1));
442
443 mDispatch.schedule(cb, 100, 1900);
444 mMockClock.advanceBy(900);
445 EXPECT_THAT(cb.mCalls.size(), Eq(1));
446 mMockClock.advanceBy(125);
447 EXPECT_THAT(cb.mCalls.size(), Eq(2));
448
449 mDispatch.schedule(cb, 100, 2900);
450 mMockClock.advanceBy(975);
451 EXPECT_THAT(cb.mCalls.size(), Eq(3));
452}
453
454TEST_F(VSyncDispatchTest, callbackReentrancy) {
455 Sequence seq;
456 EXPECT_CALL(mMockClock, alarmIn(_, 900)).InSequence(seq);
457 EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
458
459 VSyncDispatch::CallbackToken tmp;
460 tmp = mDispatch.registerCallback([&](auto) { mDispatch.schedule(tmp, 100, 2000); }, "o.o");
461
462 mDispatch.schedule(tmp, 100, 1000);
463 advanceToNextCallback();
464}
465
466TEST_F(VSyncDispatchTest, callbackReentrantWithPastWakeup) {
467 VSyncDispatch::CallbackToken tmp;
468 tmp = mDispatch.registerCallback(
469 [&](auto) {
470 EXPECT_EQ(mDispatch.schedule(tmp, 400, 1000), ScheduleResult::CannotSchedule);
471 },
472 "oo");
473
474 mDispatch.schedule(tmp, 999, 1000);
475 advanceToNextCallback();
476}
477
478TEST_F(VSyncDispatchTest, modificationsAroundVsyncTime) {
479 Sequence seq;
480 EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
481 EXPECT_CALL(mMockClock, alarmIn(_, 200)).InSequence(seq);
482 EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
483 EXPECT_CALL(mMockClock, alarmIn(_, 150)).InSequence(seq);
484
485 CountingCallback cb(mDispatch);
486 mDispatch.schedule(cb, 0, 1000);
487
488 mMockClock.advanceBy(750);
489 mDispatch.schedule(cb, 50, 1000);
490
491 advanceToNextCallback();
492 mDispatch.schedule(cb, 50, 2000);
493
494 mMockClock.advanceBy(800);
495 mDispatch.schedule(cb, 100, 2000);
496}
497
498TEST_F(VSyncDispatchTest, lateModifications) {
499 Sequence seq;
500 EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
501 EXPECT_CALL(mMockClock, alarmIn(_, 400)).InSequence(seq);
502 EXPECT_CALL(mMockClock, alarmIn(_, 350)).InSequence(seq);
503 EXPECT_CALL(mMockClock, alarmIn(_, 950)).InSequence(seq);
504
505 CountingCallback cb0(mDispatch);
506 CountingCallback cb1(mDispatch);
507
508 mDispatch.schedule(cb0, 500, 1000);
509 mDispatch.schedule(cb1, 100, 1000);
510
511 advanceToNextCallback();
512 mDispatch.schedule(cb0, 200, 2000);
513 mDispatch.schedule(cb1, 150, 1000);
514
515 advanceToNextCallback();
516 advanceToNextCallback();
517}
518
519TEST_F(VSyncDispatchTest, doesntCancelPriorValidTimerForFutureMod) {
520 Sequence seq;
521 EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
522
523 CountingCallback cb0(mDispatch);
524 CountingCallback cb1(mDispatch);
525 mDispatch.schedule(cb0, 500, 1000);
526 mDispatch.schedule(cb1, 500, 20000);
527}
528
529TEST_F(VSyncDispatchTest, setsTimerAfterCancellation) {
530 Sequence seq;
531 EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
532 EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
533 EXPECT_CALL(mMockClock, alarmIn(_, 900)).InSequence(seq);
534
535 CountingCallback cb0(mDispatch);
536 mDispatch.schedule(cb0, 500, 1000);
537 mDispatch.cancel(cb0);
538 mDispatch.schedule(cb0, 100, 1000);
539}
540
541TEST_F(VSyncDispatchTest, makingUpIdsError) {
542 VSyncDispatch::CallbackToken token(100);
543 EXPECT_THAT(mDispatch.schedule(token, 100, 1000), Eq(ScheduleResult::Error));
544 EXPECT_THAT(mDispatch.cancel(token), Eq(CancelResult::Error));
545}
546
547TEST_F(VSyncDispatchTest, distinguishesScheduleAndReschedule) {
548 CountingCallback cb0(mDispatch);
549 EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
550 EXPECT_EQ(mDispatch.schedule(cb0, 100, 1000), ScheduleResult::ReScheduled);
551}
552
553TEST_F(VSyncDispatchTest, helperMove) {
554 EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1);
555 EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
556
557 VSyncCallbackRegistration cb(
558 mDispatch, [](auto) {}, "");
559 VSyncCallbackRegistration cb1(std::move(cb));
560 cb.schedule(100, 1000);
561 cb.cancel();
562
563 cb1.schedule(500, 1000);
564 cb1.cancel();
565}
566
567TEST_F(VSyncDispatchTest, helperMoveAssign) {
568 EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1);
569 EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
570
571 VSyncCallbackRegistration cb(
572 mDispatch, [](auto) {}, "");
573 VSyncCallbackRegistration cb1(
574 mDispatch, [](auto) {}, "");
575 cb1 = std::move(cb);
576 cb.schedule(100, 1000);
577 cb.cancel();
578
579 cb1.schedule(500, 1000);
580 cb1.cancel();
581}
582
583class VSyncDispatchEntryTest : public testing::Test {
584protected:
585 nsecs_t const mPeriod = 1000;
586 NiceMock<MockVSyncTracker> mStubTracker{mPeriod};
587};
588
589TEST_F(VSyncDispatchEntryTest, stateAfterInitialization) {
590 std::string name("basicname");
591 impl::VSyncDispatchEntry entry(name, [](auto) {});
592 EXPECT_THAT(entry.name(), Eq(name));
593 EXPECT_FALSE(entry.lastExecutedVsyncTarget());
594 EXPECT_FALSE(entry.wakeupTime());
595}
596
597TEST_F(VSyncDispatchEntryTest, stateScheduling) {
598 impl::VSyncDispatchEntry entry("test", [](auto) {});
599
600 EXPECT_FALSE(entry.wakeupTime());
601 auto const wakeup = entry.schedule(100, 500, mStubTracker, 0);
602 auto const queried = entry.wakeupTime();
603 ASSERT_TRUE(queried);
604 EXPECT_THAT(*queried, Eq(wakeup));
605 EXPECT_THAT(*queried, Eq(900));
606
607 entry.disarm();
608 EXPECT_FALSE(entry.wakeupTime());
609}
610
611TEST_F(VSyncDispatchEntryTest, stateSchedulingReallyLongWakeupLatency) {
612 auto const duration = 500;
613 auto const now = 8750;
614
615 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(now + duration))
616 .Times(1)
617 .WillOnce(Return(10000));
618 impl::VSyncDispatchEntry entry("test", [](auto) {});
619
620 EXPECT_FALSE(entry.wakeupTime());
621 auto const wakeup = entry.schedule(500, 994, mStubTracker, now);
622 auto const queried = entry.wakeupTime();
623 ASSERT_TRUE(queried);
624 EXPECT_THAT(*queried, Eq(wakeup));
625 EXPECT_THAT(*queried, Eq(9500));
626}
627
628TEST_F(VSyncDispatchEntryTest, runCallback) {
629 auto callCount = 0;
630 auto calledTime = 0;
631 impl::VSyncDispatchEntry entry("test", [&](auto time) {
632 callCount++;
633 calledTime = time;
634 });
635
636 auto const wakeup = entry.schedule(100, 500, mStubTracker, 0);
637 EXPECT_THAT(wakeup, Eq(900));
638
639 entry.callback(entry.executing());
640
641 EXPECT_THAT(callCount, Eq(1));
642 EXPECT_THAT(calledTime, Eq(mPeriod));
643 EXPECT_FALSE(entry.wakeupTime());
644 auto lastCalledTarget = entry.lastExecutedVsyncTarget();
645 ASSERT_TRUE(lastCalledTarget);
646 EXPECT_THAT(*lastCalledTarget, Eq(mPeriod));
647}
648
649TEST_F(VSyncDispatchEntryTest, updateCallback) {
650 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
651 .Times(2)
652 .WillOnce(Return(1000))
653 .WillOnce(Return(1020));
654
655 impl::VSyncDispatchEntry entry("test", [](auto) {});
656
657 EXPECT_FALSE(entry.wakeupTime());
658 entry.update(mStubTracker, 0);
659 EXPECT_FALSE(entry.wakeupTime());
660
661 auto const wakeup = entry.schedule(100, 500, mStubTracker, 0);
662 EXPECT_THAT(wakeup, Eq(900));
663
664 entry.update(mStubTracker, 0);
665 auto const queried = entry.wakeupTime();
666 ASSERT_TRUE(queried);
667 EXPECT_THAT(*queried, Eq(920));
668}
669
670TEST_F(VSyncDispatchEntryTest, skipsUpdateIfJustScheduled) {
671 impl::VSyncDispatchEntry entry("test", [](auto) {});
672 auto const wakeup = entry.schedule(100, 500, mStubTracker, 0);
673 entry.update(mStubTracker, 0);
674
675 auto const queried = entry.wakeupTime();
676 ASSERT_TRUE(queried);
677 EXPECT_THAT(*queried, Eq(wakeup));
678}
679
680} // namespace android::scheduler