blob: 70c92254b29de80c183b5e2498136d98d7643081 [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
Ady Abrahamb0dbdaa2020-01-06 16:19:42 -080017// TODO(b/129481165): remove the #pragma below and fix conversion issues
18#pragma clang diagnostic push
19#pragma clang diagnostic ignored "-Wconversion"
20
Kevin DuBois305bef12019-10-09 13:23:27 -070021#undef LOG_TAG
22#define LOG_TAG "LibSurfaceFlingerUnittests"
23#define LOG_NDEBUG 0
24
25#include "Scheduler/TimeKeeper.h"
Kevin DuBoise4f27a82019-11-12 11:41:41 -080026#include "Scheduler/VSyncDispatchTimerQueue.h"
Kevin DuBois305bef12019-10-09 13:23:27 -070027#include "Scheduler/VSyncTracker.h"
28
29#include <gmock/gmock.h>
30#include <gtest/gtest.h>
31#include <thread>
32
33using namespace testing;
34using namespace std::literals;
35namespace android::scheduler {
36
37class MockVSyncTracker : public VSyncTracker {
38public:
39 MockVSyncTracker(nsecs_t period) : mPeriod{period} {
40 ON_CALL(*this, nextAnticipatedVSyncTimeFrom(_))
41 .WillByDefault(Invoke(this, &MockVSyncTracker::nextVSyncTime));
42 }
43
44 MOCK_METHOD1(addVsyncTimestamp, void(nsecs_t));
45 MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
Kevin DuBois2fd3cea2019-11-14 08:52:45 -080046 MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
Kevin DuBoisee2ad9f2019-11-21 11:10:57 -080047 MOCK_METHOD1(setPeriod, void(nsecs_t));
Kevin DuBoisc3e9e8e2020-01-07 09:06:52 -080048 MOCK_METHOD0(resetModel, void());
Kevin DuBois305bef12019-10-09 13:23:27 -070049
50 nsecs_t nextVSyncTime(nsecs_t timePoint) const {
51 if (timePoint % mPeriod == 0) {
52 return timePoint;
53 }
54 return (timePoint - (timePoint % mPeriod) + mPeriod);
55 }
56
57protected:
58 nsecs_t const mPeriod;
59};
60
61class ControllableClock : public TimeKeeper {
62public:
63 ControllableClock() {
64 ON_CALL(*this, alarmIn(_, _))
65 .WillByDefault(Invoke(this, &ControllableClock::alarmInDefaultBehavior));
66 ON_CALL(*this, now()).WillByDefault(Invoke(this, &ControllableClock::fakeTime));
67 }
68
69 MOCK_CONST_METHOD0(now, nsecs_t());
70 MOCK_METHOD2(alarmIn, void(std::function<void()> const&, nsecs_t time));
71 MOCK_METHOD0(alarmCancel, void());
72
73 void alarmInDefaultBehavior(std::function<void()> const& callback, nsecs_t time) {
74 mCallback = callback;
75 mNextCallbackTime = time + mCurrentTime;
76 }
77
78 nsecs_t fakeTime() const { return mCurrentTime; }
79
80 void advanceToNextCallback() {
81 mCurrentTime = mNextCallbackTime;
82 if (mCallback) {
83 mCallback();
84 }
85 }
86
87 void advanceBy(nsecs_t advancement) {
88 mCurrentTime += advancement;
89 if (mCurrentTime >= mNextCallbackTime && mCallback) {
90 mCallback();
91 }
92 };
93
94private:
95 std::function<void()> mCallback;
96 nsecs_t mNextCallbackTime = 0;
97 nsecs_t mCurrentTime = 0;
98};
99
100class CountingCallback {
101public:
102 CountingCallback(VSyncDispatch& dispatch)
103 : mDispatch(dispatch),
104 mToken(dispatch.registerCallback(std::bind(&CountingCallback::counter, this,
Kevin DuBois2968afc2020-01-14 09:48:50 -0800105 std::placeholders::_1,
106 std::placeholders::_2),
Kevin DuBois305bef12019-10-09 13:23:27 -0700107 "test")) {}
108 ~CountingCallback() { mDispatch.unregisterCallback(mToken); }
109
110 operator VSyncDispatch::CallbackToken() const { return mToken; }
111
Kevin DuBois2968afc2020-01-14 09:48:50 -0800112 void counter(nsecs_t time, nsecs_t) { mCalls.push_back(time); }
Kevin DuBois305bef12019-10-09 13:23:27 -0700113
114 VSyncDispatch& mDispatch;
115 VSyncDispatch::CallbackToken mToken;
116 std::vector<nsecs_t> mCalls;
117};
118
119class PausingCallback {
120public:
121 PausingCallback(VSyncDispatch& dispatch, std::chrono::milliseconds pauseAmount)
122 : mDispatch(dispatch),
123 mToken(dispatch.registerCallback(std::bind(&PausingCallback::pause, this,
Kevin DuBois2968afc2020-01-14 09:48:50 -0800124 std::placeholders::_1,
125 std::placeholders::_2),
Kevin DuBois305bef12019-10-09 13:23:27 -0700126 "test")),
127 mRegistered(true),
128 mPauseAmount(pauseAmount) {}
129 ~PausingCallback() { unregister(); }
130
131 operator VSyncDispatch::CallbackToken() const { return mToken; }
132
Kevin DuBois2968afc2020-01-14 09:48:50 -0800133 void pause(nsecs_t, nsecs_t) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700134 std::unique_lock<std::mutex> lk(mMutex);
135 mPause = true;
136 mCv.notify_all();
137
138 mCv.wait_for(lk, mPauseAmount, [this] { return !mPause; });
139
140 mResourcePresent = (mResource.lock() != nullptr);
141 }
142
143 bool waitForPause() {
144 std::unique_lock<std::mutex> lk(mMutex);
145 auto waiting = mCv.wait_for(lk, 10s, [this] { return mPause; });
146 return waiting;
147 }
148
149 void stashResource(std::weak_ptr<void> const& resource) { mResource = resource; }
150
151 bool resourcePresent() { return mResourcePresent; }
152
153 void unpause() {
154 std::unique_lock<std::mutex> lk(mMutex);
155 mPause = false;
156 mCv.notify_all();
157 }
158
159 void unregister() {
160 if (mRegistered) {
161 mDispatch.unregisterCallback(mToken);
162 mRegistered = false;
163 }
164 }
165
166 VSyncDispatch& mDispatch;
167 VSyncDispatch::CallbackToken mToken;
168 bool mRegistered = true;
169
170 std::mutex mMutex;
171 std::condition_variable mCv;
172 bool mPause = false;
173 std::weak_ptr<void> mResource;
174 bool mResourcePresent = false;
175 std::chrono::milliseconds const mPauseAmount;
176};
177
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800178class VSyncDispatchTimerQueueTest : public testing::Test {
Kevin DuBois305bef12019-10-09 13:23:27 -0700179protected:
180 std::unique_ptr<TimeKeeper> createTimeKeeper() {
181 class TimeKeeperWrapper : public TimeKeeper {
182 public:
183 TimeKeeperWrapper(TimeKeeper& control) : mControllableClock(control) {}
184 void alarmIn(std::function<void()> const& callback, nsecs_t time) final {
185 mControllableClock.alarmIn(callback, time);
186 }
187 void alarmCancel() final { mControllableClock.alarmCancel(); }
188 nsecs_t now() const final { return mControllableClock.now(); }
189
190 private:
191 TimeKeeper& mControllableClock;
192 };
193 return std::make_unique<TimeKeeperWrapper>(mMockClock);
194 }
195
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800196 ~VSyncDispatchTimerQueueTest() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700197 // destructor of dispatch will cancelAlarm(). Ignore final cancel in common test.
198 Mock::VerifyAndClearExpectations(&mMockClock);
199 }
200
201 void advanceToNextCallback() { mMockClock.advanceToNextCallback(); }
202
203 NiceMock<ControllableClock> mMockClock;
204 static nsecs_t constexpr mDispatchGroupThreshold = 5;
205 nsecs_t const mPeriod = 1000;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800206 nsecs_t const mVsyncMoveThreshold = 300;
Kevin DuBois305bef12019-10-09 13:23:27 -0700207 NiceMock<MockVSyncTracker> mStubTracker{mPeriod};
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800208 VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold,
209 mVsyncMoveThreshold};
Kevin DuBois305bef12019-10-09 13:23:27 -0700210};
211
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800212TEST_F(VSyncDispatchTimerQueueTest, unregistersSetAlarmOnDestruction) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700213 EXPECT_CALL(mMockClock, alarmIn(_, 900));
214 EXPECT_CALL(mMockClock, alarmCancel());
215 {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800216 VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold,
217 mVsyncMoveThreshold};
Kevin DuBois305bef12019-10-09 13:23:27 -0700218 CountingCallback cb(mDispatch);
219 EXPECT_EQ(mDispatch.schedule(cb, 100, 1000), ScheduleResult::Scheduled);
220 }
221}
222
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800223TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFuture) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700224 auto intended = mPeriod - 230;
225 EXPECT_CALL(mMockClock, alarmIn(_, 900));
226
227 CountingCallback cb(mDispatch);
228 EXPECT_EQ(mDispatch.schedule(cb, 100, intended), ScheduleResult::Scheduled);
229 advanceToNextCallback();
230
231 ASSERT_THAT(cb.mCalls.size(), Eq(1));
232 EXPECT_THAT(cb.mCalls[0], Eq(mPeriod));
233}
234
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800235TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFutureWithAdjustmentToTrueVsync) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700236 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000)).WillOnce(Return(1150));
237 EXPECT_CALL(mMockClock, alarmIn(_, 1050));
238
239 CountingCallback cb(mDispatch);
240 mDispatch.schedule(cb, 100, mPeriod);
241 advanceToNextCallback();
242
243 ASSERT_THAT(cb.mCalls.size(), Eq(1));
244 EXPECT_THAT(cb.mCalls[0], Eq(1150));
245}
246
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800247TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingAdjustmentPast) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700248 auto const now = 234;
249 mMockClock.advanceBy(234);
250 auto const workDuration = 10 * mPeriod;
251 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(now + workDuration))
252 .WillOnce(Return(mPeriod * 11));
253 EXPECT_CALL(mMockClock, alarmIn(_, mPeriod - now));
254
255 CountingCallback cb(mDispatch);
256 EXPECT_EQ(mDispatch.schedule(cb, workDuration, mPeriod), ScheduleResult::Scheduled);
257}
258
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800259TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancel) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700260 EXPECT_CALL(mMockClock, alarmIn(_, 900));
261 EXPECT_CALL(mMockClock, alarmCancel());
262
263 CountingCallback cb(mDispatch);
264 EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
265 EXPECT_EQ(mDispatch.cancel(cb), CancelResult::Cancelled);
266}
267
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800268TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLate) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700269 EXPECT_CALL(mMockClock, alarmIn(_, 900));
270 EXPECT_CALL(mMockClock, alarmCancel());
271
272 CountingCallback cb(mDispatch);
273 EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
274 mMockClock.advanceBy(950);
275 EXPECT_EQ(mDispatch.cancel(cb), CancelResult::TooLate);
276}
277
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800278TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLateWhenRunning) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700279 EXPECT_CALL(mMockClock, alarmIn(_, 900));
280 EXPECT_CALL(mMockClock, alarmCancel());
281
282 PausingCallback cb(mDispatch, std::chrono::duration_cast<std::chrono::milliseconds>(1s));
283 EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
284
285 std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
286 EXPECT_TRUE(cb.waitForPause());
287 EXPECT_EQ(mDispatch.cancel(cb), CancelResult::TooLate);
288 cb.unpause();
289 pausingThread.join();
290}
291
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800292TEST_F(VSyncDispatchTimerQueueTest, unregisterSynchronizes) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700293 EXPECT_CALL(mMockClock, alarmIn(_, 900));
294 EXPECT_CALL(mMockClock, alarmCancel());
295
296 auto resource = std::make_shared<int>(110);
297
298 PausingCallback cb(mDispatch, 50ms);
299 cb.stashResource(resource);
300 EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
301
302 std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
303 EXPECT_TRUE(cb.waitForPause());
304
305 cb.unregister();
306 resource.reset();
307
308 cb.unpause();
309 pausingThread.join();
310
311 EXPECT_TRUE(cb.resourcePresent());
312}
313
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800314TEST_F(VSyncDispatchTimerQueueTest, basicTwoAlarmSetting) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700315 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
316 .Times(4)
317 .WillOnce(Return(1055))
318 .WillOnce(Return(1063))
319 .WillOnce(Return(1063))
320 .WillOnce(Return(1075));
321
322 Sequence seq;
323 EXPECT_CALL(mMockClock, alarmIn(_, 955)).InSequence(seq);
324 EXPECT_CALL(mMockClock, alarmIn(_, 813)).InSequence(seq);
325 EXPECT_CALL(mMockClock, alarmIn(_, 162)).InSequence(seq);
326
327 CountingCallback cb0(mDispatch);
328 CountingCallback cb1(mDispatch);
329
330 mDispatch.schedule(cb0, 100, mPeriod);
331 mDispatch.schedule(cb1, 250, mPeriod);
332
333 advanceToNextCallback();
334 advanceToNextCallback();
335
336 ASSERT_THAT(cb0.mCalls.size(), Eq(1));
337 EXPECT_THAT(cb0.mCalls[0], Eq(1075));
338 ASSERT_THAT(cb1.mCalls.size(), Eq(1));
339 EXPECT_THAT(cb1.mCalls[0], Eq(1063));
340}
341
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800342TEST_F(VSyncDispatchTimerQueueTest, rearmsFaroutTimeoutWhenCancellingCloseOne) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700343 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
344 .Times(4)
345 .WillOnce(Return(10000))
346 .WillOnce(Return(1000))
347 .WillOnce(Return(10000))
348 .WillOnce(Return(10000));
349
350 Sequence seq;
351 EXPECT_CALL(mMockClock, alarmIn(_, 9900)).InSequence(seq);
352 EXPECT_CALL(mMockClock, alarmIn(_, 750)).InSequence(seq);
353 EXPECT_CALL(mMockClock, alarmIn(_, 9900)).InSequence(seq);
354
355 CountingCallback cb0(mDispatch);
356 CountingCallback cb1(mDispatch);
357
358 mDispatch.schedule(cb0, 100, mPeriod * 10);
359 mDispatch.schedule(cb1, 250, mPeriod);
360 mDispatch.cancel(cb1);
361}
362
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800363TEST_F(VSyncDispatchTimerQueueTest, noUnnecessaryRearmsWhenRescheduling) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700364 Sequence seq;
365 EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
366 EXPECT_CALL(mMockClock, alarmIn(_, 100)).InSequence(seq);
367
368 CountingCallback cb0(mDispatch);
369 CountingCallback cb1(mDispatch);
370
371 mDispatch.schedule(cb0, 400, 1000);
372 mDispatch.schedule(cb1, 200, 1000);
373 mDispatch.schedule(cb1, 300, 1000);
374 advanceToNextCallback();
375}
376
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800377TEST_F(VSyncDispatchTimerQueueTest, necessaryRearmsWhenModifying) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700378 Sequence seq;
379 EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
380 EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
381 EXPECT_CALL(mMockClock, alarmIn(_, 100)).InSequence(seq);
382
383 CountingCallback cb0(mDispatch);
384 CountingCallback cb1(mDispatch);
385
386 mDispatch.schedule(cb0, 400, 1000);
387 mDispatch.schedule(cb1, 200, 1000);
388 mDispatch.schedule(cb1, 500, 1000);
389 advanceToNextCallback();
390}
391
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800392TEST_F(VSyncDispatchTimerQueueTest, modifyIntoGroup) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700393 Sequence seq;
394 EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
395 EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
396 EXPECT_CALL(mMockClock, alarmIn(_, 990)).InSequence(seq);
397 EXPECT_CALL(mMockClock, alarmIn(_, 10)).InSequence(seq);
398
399 auto offset = 400;
400 auto closeOffset = offset + mDispatchGroupThreshold - 1;
401 auto notCloseOffset = offset + 2 * mDispatchGroupThreshold;
402
403 CountingCallback cb0(mDispatch);
404 CountingCallback cb1(mDispatch);
405
406 mDispatch.schedule(cb0, 400, 1000);
407 mDispatch.schedule(cb1, 200, 1000);
408 mDispatch.schedule(cb1, closeOffset, 1000);
409
410 advanceToNextCallback();
411 ASSERT_THAT(cb0.mCalls.size(), Eq(1));
412 EXPECT_THAT(cb0.mCalls[0], Eq(mPeriod));
413 ASSERT_THAT(cb1.mCalls.size(), Eq(1));
414 EXPECT_THAT(cb1.mCalls[0], Eq(mPeriod));
415
416 mDispatch.schedule(cb0, 400, 2000);
417 mDispatch.schedule(cb1, notCloseOffset, 2000);
418 advanceToNextCallback();
419 ASSERT_THAT(cb1.mCalls.size(), Eq(2));
420 EXPECT_THAT(cb1.mCalls[1], Eq(2000));
421
422 advanceToNextCallback();
423 ASSERT_THAT(cb0.mCalls.size(), Eq(2));
424 EXPECT_THAT(cb0.mCalls[1], Eq(2000));
425}
426
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800427TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenEndingAndDoesntCancel) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700428 EXPECT_CALL(mMockClock, alarmIn(_, 900));
429 EXPECT_CALL(mMockClock, alarmIn(_, 800));
430 EXPECT_CALL(mMockClock, alarmIn(_, 100));
431 EXPECT_CALL(mMockClock, alarmCancel());
432
433 CountingCallback cb0(mDispatch);
434 CountingCallback cb1(mDispatch);
435
436 mDispatch.schedule(cb0, 100, 1000);
437 mDispatch.schedule(cb1, 200, 1000);
438 advanceToNextCallback();
439 EXPECT_EQ(mDispatch.cancel(cb0), CancelResult::Cancelled);
440}
441
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800442TEST_F(VSyncDispatchTimerQueueTest, setAlarmCallsAtCorrectTimeWithChangingVsync) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700443 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
444 .Times(3)
445 .WillOnce(Return(950))
446 .WillOnce(Return(1975))
447 .WillOnce(Return(2950));
448
449 CountingCallback cb(mDispatch);
450 mDispatch.schedule(cb, 100, 920);
451
452 mMockClock.advanceBy(850);
453 EXPECT_THAT(cb.mCalls.size(), Eq(1));
454
455 mDispatch.schedule(cb, 100, 1900);
456 mMockClock.advanceBy(900);
457 EXPECT_THAT(cb.mCalls.size(), Eq(1));
458 mMockClock.advanceBy(125);
459 EXPECT_THAT(cb.mCalls.size(), Eq(2));
460
461 mDispatch.schedule(cb, 100, 2900);
462 mMockClock.advanceBy(975);
463 EXPECT_THAT(cb.mCalls.size(), Eq(3));
464}
465
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800466TEST_F(VSyncDispatchTimerQueueTest, callbackReentrancy) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700467 Sequence seq;
468 EXPECT_CALL(mMockClock, alarmIn(_, 900)).InSequence(seq);
469 EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
470
471 VSyncDispatch::CallbackToken tmp;
Kevin DuBois2968afc2020-01-14 09:48:50 -0800472 tmp = mDispatch.registerCallback([&](auto, auto) { mDispatch.schedule(tmp, 100, 2000); },
473 "o.o");
Kevin DuBois305bef12019-10-09 13:23:27 -0700474
475 mDispatch.schedule(tmp, 100, 1000);
476 advanceToNextCallback();
477}
478
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800479TEST_F(VSyncDispatchTimerQueueTest, callbackReentrantWithPastWakeup) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700480 VSyncDispatch::CallbackToken tmp;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800481 std::optional<nsecs_t> lastTarget;
Kevin DuBois305bef12019-10-09 13:23:27 -0700482 tmp = mDispatch.registerCallback(
Kevin DuBois2968afc2020-01-14 09:48:50 -0800483 [&](auto timestamp, auto) {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800484 EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp - mVsyncMoveThreshold),
485 ScheduleResult::Scheduled);
486 EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp), ScheduleResult::Scheduled);
487 EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp + mVsyncMoveThreshold),
488 ScheduleResult::Scheduled);
489 lastTarget = timestamp;
Kevin DuBois305bef12019-10-09 13:23:27 -0700490 },
491 "oo");
492
493 mDispatch.schedule(tmp, 999, 1000);
494 advanceToNextCallback();
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800495 EXPECT_THAT(lastTarget, Eq(1000));
496
497 advanceToNextCallback();
498 EXPECT_THAT(lastTarget, Eq(2000));
Kevin DuBois305bef12019-10-09 13:23:27 -0700499}
500
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800501TEST_F(VSyncDispatchTimerQueueTest, modificationsAroundVsyncTime) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700502 Sequence seq;
503 EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
504 EXPECT_CALL(mMockClock, alarmIn(_, 200)).InSequence(seq);
505 EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
506 EXPECT_CALL(mMockClock, alarmIn(_, 150)).InSequence(seq);
507
508 CountingCallback cb(mDispatch);
509 mDispatch.schedule(cb, 0, 1000);
510
511 mMockClock.advanceBy(750);
512 mDispatch.schedule(cb, 50, 1000);
513
514 advanceToNextCallback();
515 mDispatch.schedule(cb, 50, 2000);
516
517 mMockClock.advanceBy(800);
518 mDispatch.schedule(cb, 100, 2000);
519}
520
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800521TEST_F(VSyncDispatchTimerQueueTest, lateModifications) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700522 Sequence seq;
523 EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
524 EXPECT_CALL(mMockClock, alarmIn(_, 400)).InSequence(seq);
525 EXPECT_CALL(mMockClock, alarmIn(_, 350)).InSequence(seq);
526 EXPECT_CALL(mMockClock, alarmIn(_, 950)).InSequence(seq);
527
528 CountingCallback cb0(mDispatch);
529 CountingCallback cb1(mDispatch);
530
531 mDispatch.schedule(cb0, 500, 1000);
532 mDispatch.schedule(cb1, 100, 1000);
533
534 advanceToNextCallback();
535 mDispatch.schedule(cb0, 200, 2000);
536 mDispatch.schedule(cb1, 150, 1000);
537
538 advanceToNextCallback();
539 advanceToNextCallback();
540}
541
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800542TEST_F(VSyncDispatchTimerQueueTest, doesntCancelPriorValidTimerForFutureMod) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700543 Sequence seq;
544 EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
545
546 CountingCallback cb0(mDispatch);
547 CountingCallback cb1(mDispatch);
548 mDispatch.schedule(cb0, 500, 1000);
549 mDispatch.schedule(cb1, 500, 20000);
550}
551
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800552TEST_F(VSyncDispatchTimerQueueTest, setsTimerAfterCancellation) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700553 Sequence seq;
554 EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
555 EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
556 EXPECT_CALL(mMockClock, alarmIn(_, 900)).InSequence(seq);
557
558 CountingCallback cb0(mDispatch);
559 mDispatch.schedule(cb0, 500, 1000);
560 mDispatch.cancel(cb0);
561 mDispatch.schedule(cb0, 100, 1000);
562}
563
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800564TEST_F(VSyncDispatchTimerQueueTest, makingUpIdsError) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700565 VSyncDispatch::CallbackToken token(100);
566 EXPECT_THAT(mDispatch.schedule(token, 100, 1000), Eq(ScheduleResult::Error));
567 EXPECT_THAT(mDispatch.cancel(token), Eq(CancelResult::Error));
568}
569
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800570TEST_F(VSyncDispatchTimerQueueTest, canMoveCallbackBackwardsInTime) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700571 CountingCallback cb0(mDispatch);
572 EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800573 EXPECT_EQ(mDispatch.schedule(cb0, 100, 1000), ScheduleResult::Scheduled);
574}
575
576// b/1450138150
577TEST_F(VSyncDispatchTimerQueueTest, doesNotMoveCallbackBackwardsAndSkipAScheduledTargetVSync) {
578 EXPECT_CALL(mMockClock, alarmIn(_, 500));
579 CountingCallback cb(mDispatch);
580 EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled);
581 mMockClock.advanceBy(400);
582
583 EXPECT_EQ(mDispatch.schedule(cb, 800, 1000), ScheduleResult::Scheduled);
584 advanceToNextCallback();
585 ASSERT_THAT(cb.mCalls.size(), Eq(1));
586}
587
588TEST_F(VSyncDispatchTimerQueueTest, targetOffsetMovingBackALittleCanStillSchedule) {
589 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
590 .Times(2)
591 .WillOnce(Return(1000))
592 .WillOnce(Return(1002));
593 CountingCallback cb(mDispatch);
594 EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled);
595 mMockClock.advanceBy(400);
596 EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
Kevin DuBois305bef12019-10-09 13:23:27 -0700597}
598
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800599TEST_F(VSyncDispatchTimerQueueTest, canScheduleNegativeOffsetAgainstDifferentPeriods) {
600 CountingCallback cb0(mDispatch);
601 EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
602 advanceToNextCallback();
603 EXPECT_EQ(mDispatch.schedule(cb0, 1100, 2000), ScheduleResult::Scheduled);
604}
605
606TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) {
607 Sequence seq;
608 EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
609 EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
610 CountingCallback cb0(mDispatch);
611 EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
612 advanceToNextCallback();
613 EXPECT_EQ(mDispatch.schedule(cb0, 1900, 2000), ScheduleResult::Scheduled);
614}
615
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800616TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesNotAffectSchedulingState) {
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800617 EXPECT_CALL(mMockClock, alarmIn(_, 600));
618
619 CountingCallback cb(mDispatch);
620 EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800621
622 EXPECT_EQ(mDispatch.schedule(cb, 1400, 1000), ScheduleResult::Scheduled);
623
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800624 advanceToNextCallback();
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800625}
626
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800627TEST_F(VSyncDispatchTimerQueueTest, helperMove) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700628 EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1);
629 EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
630
631 VSyncCallbackRegistration cb(
Kevin DuBois2968afc2020-01-14 09:48:50 -0800632 mDispatch, [](auto, auto) {}, "");
Kevin DuBois305bef12019-10-09 13:23:27 -0700633 VSyncCallbackRegistration cb1(std::move(cb));
634 cb.schedule(100, 1000);
635 cb.cancel();
636
637 cb1.schedule(500, 1000);
638 cb1.cancel();
639}
640
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800641TEST_F(VSyncDispatchTimerQueueTest, helperMoveAssign) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700642 EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1);
643 EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
644
645 VSyncCallbackRegistration cb(
Kevin DuBois2968afc2020-01-14 09:48:50 -0800646 mDispatch, [](auto, auto) {}, "");
Kevin DuBois305bef12019-10-09 13:23:27 -0700647 VSyncCallbackRegistration cb1(
Kevin DuBois2968afc2020-01-14 09:48:50 -0800648 mDispatch, [](auto, auto) {}, "");
Kevin DuBois305bef12019-10-09 13:23:27 -0700649 cb1 = std::move(cb);
650 cb.schedule(100, 1000);
651 cb.cancel();
652
653 cb1.schedule(500, 1000);
654 cb1.cancel();
655}
656
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800657class VSyncDispatchTimerQueueEntryTest : public testing::Test {
Kevin DuBois305bef12019-10-09 13:23:27 -0700658protected:
659 nsecs_t const mPeriod = 1000;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800660 nsecs_t const mVsyncMoveThreshold = 200;
Kevin DuBois305bef12019-10-09 13:23:27 -0700661 NiceMock<MockVSyncTracker> mStubTracker{mPeriod};
662};
663
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800664TEST_F(VSyncDispatchTimerQueueEntryTest, stateAfterInitialization) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700665 std::string name("basicname");
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800666 VSyncDispatchTimerQueueEntry entry(
Kevin DuBois2968afc2020-01-14 09:48:50 -0800667 name, [](auto, auto) {}, mVsyncMoveThreshold);
Kevin DuBois305bef12019-10-09 13:23:27 -0700668 EXPECT_THAT(entry.name(), Eq(name));
669 EXPECT_FALSE(entry.lastExecutedVsyncTarget());
670 EXPECT_FALSE(entry.wakeupTime());
671}
672
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800673TEST_F(VSyncDispatchTimerQueueEntryTest, stateScheduling) {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800674 VSyncDispatchTimerQueueEntry entry(
Kevin DuBois2968afc2020-01-14 09:48:50 -0800675 "test", [](auto, auto) {}, mVsyncMoveThreshold);
Kevin DuBois305bef12019-10-09 13:23:27 -0700676
677 EXPECT_FALSE(entry.wakeupTime());
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800678 EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
679 auto const wakeup = entry.wakeupTime();
680 ASSERT_TRUE(wakeup);
681 EXPECT_THAT(*wakeup, Eq(900));
Kevin DuBois305bef12019-10-09 13:23:27 -0700682
683 entry.disarm();
684 EXPECT_FALSE(entry.wakeupTime());
685}
686
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800687TEST_F(VSyncDispatchTimerQueueEntryTest, stateSchedulingReallyLongWakeupLatency) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700688 auto const duration = 500;
689 auto const now = 8750;
690
691 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(now + duration))
692 .Times(1)
693 .WillOnce(Return(10000));
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800694 VSyncDispatchTimerQueueEntry entry(
Kevin DuBois2968afc2020-01-14 09:48:50 -0800695 "test", [](auto, auto) {}, mVsyncMoveThreshold);
Kevin DuBois305bef12019-10-09 13:23:27 -0700696
697 EXPECT_FALSE(entry.wakeupTime());
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800698 EXPECT_THAT(entry.schedule(500, 994, mStubTracker, now), Eq(ScheduleResult::Scheduled));
699 auto const wakeup = entry.wakeupTime();
700 ASSERT_TRUE(wakeup);
701 EXPECT_THAT(*wakeup, Eq(9500));
Kevin DuBois305bef12019-10-09 13:23:27 -0700702}
703
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800704TEST_F(VSyncDispatchTimerQueueEntryTest, runCallback) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700705 auto callCount = 0;
Kevin DuBois2968afc2020-01-14 09:48:50 -0800706 auto vsyncCalledTime = 0;
707 auto wakeupCalledTime = 0;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800708 VSyncDispatchTimerQueueEntry entry(
709 "test",
Kevin DuBois2968afc2020-01-14 09:48:50 -0800710 [&](auto vsyncTime, auto wakeupTime) {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800711 callCount++;
Kevin DuBois2968afc2020-01-14 09:48:50 -0800712 vsyncCalledTime = vsyncTime;
713 wakeupCalledTime = wakeupTime;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800714 },
715 mVsyncMoveThreshold);
Kevin DuBois305bef12019-10-09 13:23:27 -0700716
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800717 EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
718 auto const wakeup = entry.wakeupTime();
719 ASSERT_TRUE(wakeup);
720 EXPECT_THAT(*wakeup, Eq(900));
Kevin DuBois305bef12019-10-09 13:23:27 -0700721
Kevin DuBois2968afc2020-01-14 09:48:50 -0800722 entry.callback(entry.executing(), *wakeup);
Kevin DuBois305bef12019-10-09 13:23:27 -0700723
724 EXPECT_THAT(callCount, Eq(1));
Kevin DuBois2968afc2020-01-14 09:48:50 -0800725 EXPECT_THAT(vsyncCalledTime, Eq(mPeriod));
726 EXPECT_THAT(wakeupCalledTime, Eq(*wakeup));
Kevin DuBois305bef12019-10-09 13:23:27 -0700727 EXPECT_FALSE(entry.wakeupTime());
728 auto lastCalledTarget = entry.lastExecutedVsyncTarget();
729 ASSERT_TRUE(lastCalledTarget);
730 EXPECT_THAT(*lastCalledTarget, Eq(mPeriod));
731}
732
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800733TEST_F(VSyncDispatchTimerQueueEntryTest, updateCallback) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700734 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
735 .Times(2)
736 .WillOnce(Return(1000))
737 .WillOnce(Return(1020));
738
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800739 VSyncDispatchTimerQueueEntry entry(
Kevin DuBois2968afc2020-01-14 09:48:50 -0800740 "test", [](auto, auto) {}, mVsyncMoveThreshold);
Kevin DuBois305bef12019-10-09 13:23:27 -0700741
742 EXPECT_FALSE(entry.wakeupTime());
743 entry.update(mStubTracker, 0);
744 EXPECT_FALSE(entry.wakeupTime());
745
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800746 EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
747 auto wakeup = entry.wakeupTime();
748 ASSERT_TRUE(wakeup);
Kevin DuBois305bef12019-10-09 13:23:27 -0700749 EXPECT_THAT(wakeup, Eq(900));
750
751 entry.update(mStubTracker, 0);
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800752 wakeup = entry.wakeupTime();
753 ASSERT_TRUE(wakeup);
754 EXPECT_THAT(*wakeup, Eq(920));
Kevin DuBois305bef12019-10-09 13:23:27 -0700755}
756
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800757TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800758 VSyncDispatchTimerQueueEntry entry(
Kevin DuBois2968afc2020-01-14 09:48:50 -0800759 "test", [](auto, auto) {}, mVsyncMoveThreshold);
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800760 EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
Kevin DuBois305bef12019-10-09 13:23:27 -0700761 entry.update(mStubTracker, 0);
762
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800763 auto const wakeup = entry.wakeupTime();
764 ASSERT_TRUE(wakeup);
765 EXPECT_THAT(*wakeup, Eq(wakeup));
766}
767
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800768TEST_F(VSyncDispatchTimerQueueEntryTest, willSnapToNextTargettableVSync) {
769 VSyncDispatchTimerQueueEntry entry(
Kevin DuBois2968afc2020-01-14 09:48:50 -0800770 "test", [](auto, auto) {}, mVsyncMoveThreshold);
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800771 EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800772 entry.executing(); // 1000 is executing
773 // had 1000 not been executing, this could have been scheduled for time 800.
774 EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
775 EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
776
777 EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
778 EXPECT_THAT(*entry.wakeupTime(), Eq(1950));
779
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800780 EXPECT_THAT(entry.schedule(200, 1001, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800781 EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800782}
783
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800784TEST_F(VSyncDispatchTimerQueueEntryTest,
785 willRequestNextEstimateWhenSnappingToNextTargettableVSync) {
786 VSyncDispatchTimerQueueEntry entry(
Kevin DuBois2968afc2020-01-14 09:48:50 -0800787 "test", [](auto, auto) {}, mVsyncMoveThreshold);
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800788
789 Sequence seq;
790 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500))
791 .InSequence(seq)
792 .WillOnce(Return(1000));
793 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500))
794 .InSequence(seq)
795 .WillOnce(Return(1000));
796 EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000 + mVsyncMoveThreshold))
797 .InSequence(seq)
798 .WillOnce(Return(2000));
799
Kevin DuBois2311b1a2019-11-18 16:19:08 -0800800 EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800801
802 entry.executing(); // 1000 is executing
803
804 EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
805}
806
807TEST_F(VSyncDispatchTimerQueueEntryTest, reportsScheduledIfStillTime) {
808 VSyncDispatchTimerQueueEntry entry(
Kevin DuBois2968afc2020-01-14 09:48:50 -0800809 "test", [](auto, auto) {}, mVsyncMoveThreshold);
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800810 EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
811 EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
812 EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
813 EXPECT_THAT(entry.schedule(1200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
Kevin DuBois305bef12019-10-09 13:23:27 -0700814}
815
816} // namespace android::scheduler
Ady Abrahamb0dbdaa2020-01-06 16:19:42 -0800817
818// TODO(b/129481165): remove the #pragma below and fix conversion issues
819#pragma clang diagnostic pop // ignored "-Wconversion"