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 
21 #undef LOG_TAG
22 #define LOG_TAG "LibSurfaceFlingerUnittests"
23 #define LOG_NDEBUG 0
24 
25 #include "Scheduler/TimeKeeper.h"
26 #include "Scheduler/VSyncDispatchTimerQueue.h"
27 #include "Scheduler/VSyncTracker.h"
28 
29 #include <gmock/gmock.h>
30 #include <gtest/gtest.h>
31 #include <thread>
32 
33 using namespace testing;
34 using namespace std::literals;
35 namespace android::scheduler {
36 
37 class MockVSyncTracker : public VSyncTracker {
38 public:
MockVSyncTracker(nsecs_t period)39     MockVSyncTracker(nsecs_t period) : mPeriod{period} {
40         ON_CALL(*this, nextAnticipatedVSyncTimeFrom(_))
41                 .WillByDefault(Invoke(this, &MockVSyncTracker::nextVSyncTime));
42         ON_CALL(*this, addVsyncTimestamp(_)).WillByDefault(Return(true));
43     }
44 
45     MOCK_METHOD1(addVsyncTimestamp, bool(nsecs_t));
46     MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
47     MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
48     MOCK_METHOD1(setPeriod, void(nsecs_t));
49     MOCK_METHOD0(resetModel, void());
50     MOCK_CONST_METHOD1(dump, void(std::string&));
51 
nextVSyncTime(nsecs_t timePoint) const52     nsecs_t nextVSyncTime(nsecs_t timePoint) const {
53         if (timePoint % mPeriod == 0) {
54             return timePoint;
55         }
56         return (timePoint - (timePoint % mPeriod) + mPeriod);
57     }
58 
59 protected:
60     nsecs_t const mPeriod;
61 };
62 
63 class ControllableClock : public TimeKeeper {
64 public:
ControllableClock()65     ControllableClock() {
66         ON_CALL(*this, alarmIn(_, _))
67                 .WillByDefault(Invoke(this, &ControllableClock::alarmInDefaultBehavior));
68         ON_CALL(*this, now()).WillByDefault(Invoke(this, &ControllableClock::fakeTime));
69     }
70 
71     MOCK_CONST_METHOD0(now, nsecs_t());
72     MOCK_METHOD2(alarmIn, void(std::function<void()> const&, nsecs_t time));
73     MOCK_METHOD0(alarmCancel, void());
74     MOCK_CONST_METHOD1(dump, void(std::string&));
75 
alarmInDefaultBehavior(std::function<void ()> const & callback,nsecs_t time)76     void alarmInDefaultBehavior(std::function<void()> const& callback, nsecs_t time) {
77         mCallback = callback;
78         mNextCallbackTime = time + mCurrentTime;
79     }
80 
fakeTime() const81     nsecs_t fakeTime() const { return mCurrentTime; }
82 
advanceToNextCallback()83     void advanceToNextCallback() {
84         mCurrentTime = mNextCallbackTime;
85         if (mCallback) {
86             mCallback();
87         }
88     }
89 
advanceBy(nsecs_t advancement)90     void advanceBy(nsecs_t advancement) {
91         mCurrentTime += advancement;
92         if (mCurrentTime >= (mNextCallbackTime + mLag) && mCallback) {
93             mCallback();
94         }
95     };
96 
setLag(nsecs_t lag)97     void setLag(nsecs_t lag) { mLag = lag; }
98 
99 private:
100     std::function<void()> mCallback;
101     nsecs_t mNextCallbackTime = 0;
102     nsecs_t mCurrentTime = 0;
103     nsecs_t mLag = 0;
104 };
105 
106 class CountingCallback {
107 public:
CountingCallback(VSyncDispatch & dispatch)108     CountingCallback(VSyncDispatch& dispatch)
109           : mDispatch(dispatch),
110             mToken(dispatch.registerCallback(std::bind(&CountingCallback::counter, this,
111                                                        std::placeholders::_1,
112                                                        std::placeholders::_2),
113                                              "test")) {}
~CountingCallback()114     ~CountingCallback() { mDispatch.unregisterCallback(mToken); }
115 
operator VSyncDispatch::CallbackToken() const116     operator VSyncDispatch::CallbackToken() const { return mToken; }
117 
counter(nsecs_t time,nsecs_t)118     void counter(nsecs_t time, nsecs_t) { mCalls.push_back(time); }
119 
120     VSyncDispatch& mDispatch;
121     VSyncDispatch::CallbackToken mToken;
122     std::vector<nsecs_t> mCalls;
123 };
124 
125 class PausingCallback {
126 public:
PausingCallback(VSyncDispatch & dispatch,std::chrono::milliseconds pauseAmount)127     PausingCallback(VSyncDispatch& dispatch, std::chrono::milliseconds pauseAmount)
128           : mDispatch(dispatch),
129             mToken(dispatch.registerCallback(std::bind(&PausingCallback::pause, this,
130                                                        std::placeholders::_1,
131                                                        std::placeholders::_2),
132                                              "test")),
133             mRegistered(true),
134             mPauseAmount(pauseAmount) {}
~PausingCallback()135     ~PausingCallback() { unregister(); }
136 
operator VSyncDispatch::CallbackToken() const137     operator VSyncDispatch::CallbackToken() const { return mToken; }
138 
pause(nsecs_t,nsecs_t)139     void pause(nsecs_t, nsecs_t) {
140         std::unique_lock<std::mutex> lk(mMutex);
141         mPause = true;
142         mCv.notify_all();
143 
144         mCv.wait_for(lk, mPauseAmount, [this] { return !mPause; });
145 
146         mResourcePresent = (mResource.lock() != nullptr);
147     }
148 
waitForPause()149     bool waitForPause() {
150         std::unique_lock<std::mutex> lk(mMutex);
151         auto waiting = mCv.wait_for(lk, 10s, [this] { return mPause; });
152         return waiting;
153     }
154 
stashResource(std::weak_ptr<void> const & resource)155     void stashResource(std::weak_ptr<void> const& resource) { mResource = resource; }
156 
resourcePresent()157     bool resourcePresent() { return mResourcePresent; }
158 
unpause()159     void unpause() {
160         std::unique_lock<std::mutex> lk(mMutex);
161         mPause = false;
162         mCv.notify_all();
163     }
164 
unregister()165     void unregister() {
166         if (mRegistered) {
167             mDispatch.unregisterCallback(mToken);
168             mRegistered = false;
169         }
170     }
171 
172     VSyncDispatch& mDispatch;
173     VSyncDispatch::CallbackToken mToken;
174     bool mRegistered = true;
175 
176     std::mutex mMutex;
177     std::condition_variable mCv;
178     bool mPause = false;
179     std::weak_ptr<void> mResource;
180     bool mResourcePresent = false;
181     std::chrono::milliseconds const mPauseAmount;
182 };
183 
184 class VSyncDispatchTimerQueueTest : public testing::Test {
185 protected:
createTimeKeeper()186     std::unique_ptr<TimeKeeper> createTimeKeeper() {
187         class TimeKeeperWrapper : public TimeKeeper {
188         public:
189             TimeKeeperWrapper(TimeKeeper& control) : mControllableClock(control) {}
190             void alarmIn(std::function<void()> const& callback, nsecs_t time) final {
191                 mControllableClock.alarmIn(callback, time);
192             }
193             void alarmCancel() final { mControllableClock.alarmCancel(); }
194             nsecs_t now() const final { return mControllableClock.now(); }
195             void dump(std::string&) const final {}
196 
197         private:
198             TimeKeeper& mControllableClock;
199         };
200         return std::make_unique<TimeKeeperWrapper>(mMockClock);
201     }
202 
~VSyncDispatchTimerQueueTest()203     ~VSyncDispatchTimerQueueTest() {
204         // destructor of  dispatch will cancelAlarm(). Ignore final cancel in common test.
205         Mock::VerifyAndClearExpectations(&mMockClock);
206     }
207 
advanceToNextCallback()208     void advanceToNextCallback() { mMockClock.advanceToNextCallback(); }
209 
210     NiceMock<ControllableClock> mMockClock;
211     static nsecs_t constexpr mDispatchGroupThreshold = 5;
212     nsecs_t const mPeriod = 1000;
213     nsecs_t const mVsyncMoveThreshold = 300;
214     NiceMock<MockVSyncTracker> mStubTracker{mPeriod};
215     VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold,
216                                       mVsyncMoveThreshold};
217 };
218 
TEST_F(VSyncDispatchTimerQueueTest,unregistersSetAlarmOnDestruction)219 TEST_F(VSyncDispatchTimerQueueTest, unregistersSetAlarmOnDestruction) {
220     EXPECT_CALL(mMockClock, alarmIn(_, 900));
221     EXPECT_CALL(mMockClock, alarmCancel());
222     {
223         VSyncDispatchTimerQueue mDispatch{createTimeKeeper(), mStubTracker, mDispatchGroupThreshold,
224                                           mVsyncMoveThreshold};
225         CountingCallback cb(mDispatch);
226         EXPECT_EQ(mDispatch.schedule(cb, 100, 1000), ScheduleResult::Scheduled);
227     }
228 }
229 
TEST_F(VSyncDispatchTimerQueueTest,basicAlarmSettingFuture)230 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFuture) {
231     auto intended = mPeriod - 230;
232     EXPECT_CALL(mMockClock, alarmIn(_, 900));
233 
234     CountingCallback cb(mDispatch);
235     EXPECT_EQ(mDispatch.schedule(cb, 100, intended), ScheduleResult::Scheduled);
236     advanceToNextCallback();
237 
238     ASSERT_THAT(cb.mCalls.size(), Eq(1));
239     EXPECT_THAT(cb.mCalls[0], Eq(mPeriod));
240 }
241 
TEST_F(VSyncDispatchTimerQueueTest,basicAlarmSettingFutureWithAdjustmentToTrueVsync)242 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingFutureWithAdjustmentToTrueVsync) {
243     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000)).WillOnce(Return(1150));
244     EXPECT_CALL(mMockClock, alarmIn(_, 1050));
245 
246     CountingCallback cb(mDispatch);
247     mDispatch.schedule(cb, 100, mPeriod);
248     advanceToNextCallback();
249 
250     ASSERT_THAT(cb.mCalls.size(), Eq(1));
251     EXPECT_THAT(cb.mCalls[0], Eq(1150));
252 }
253 
TEST_F(VSyncDispatchTimerQueueTest,basicAlarmSettingAdjustmentPast)254 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmSettingAdjustmentPast) {
255     auto const now = 234;
256     mMockClock.advanceBy(234);
257     auto const workDuration = 10 * mPeriod;
258     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(now + workDuration))
259             .WillOnce(Return(mPeriod * 11));
260     EXPECT_CALL(mMockClock, alarmIn(_, mPeriod - now));
261 
262     CountingCallback cb(mDispatch);
263     EXPECT_EQ(mDispatch.schedule(cb, workDuration, mPeriod), ScheduleResult::Scheduled);
264 }
265 
TEST_F(VSyncDispatchTimerQueueTest,basicAlarmCancel)266 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancel) {
267     EXPECT_CALL(mMockClock, alarmIn(_, 900));
268     EXPECT_CALL(mMockClock, alarmCancel());
269 
270     CountingCallback cb(mDispatch);
271     EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
272     EXPECT_EQ(mDispatch.cancel(cb), CancelResult::Cancelled);
273 }
274 
TEST_F(VSyncDispatchTimerQueueTest,basicAlarmCancelTooLate)275 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLate) {
276     EXPECT_CALL(mMockClock, alarmIn(_, 900));
277     EXPECT_CALL(mMockClock, alarmCancel());
278 
279     CountingCallback cb(mDispatch);
280     EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
281     mMockClock.advanceBy(950);
282     EXPECT_EQ(mDispatch.cancel(cb), CancelResult::TooLate);
283 }
284 
TEST_F(VSyncDispatchTimerQueueTest,basicAlarmCancelTooLateWhenRunning)285 TEST_F(VSyncDispatchTimerQueueTest, basicAlarmCancelTooLateWhenRunning) {
286     EXPECT_CALL(mMockClock, alarmIn(_, 900));
287     EXPECT_CALL(mMockClock, alarmCancel());
288 
289     PausingCallback cb(mDispatch, std::chrono::duration_cast<std::chrono::milliseconds>(1s));
290     EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
291 
292     std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
293     EXPECT_TRUE(cb.waitForPause());
294     EXPECT_EQ(mDispatch.cancel(cb), CancelResult::TooLate);
295     cb.unpause();
296     pausingThread.join();
297 }
298 
TEST_F(VSyncDispatchTimerQueueTest,unregisterSynchronizes)299 TEST_F(VSyncDispatchTimerQueueTest, unregisterSynchronizes) {
300     EXPECT_CALL(mMockClock, alarmIn(_, 900));
301     EXPECT_CALL(mMockClock, alarmCancel());
302 
303     auto resource = std::make_shared<int>(110);
304 
305     PausingCallback cb(mDispatch, 50ms);
306     cb.stashResource(resource);
307     EXPECT_EQ(mDispatch.schedule(cb, 100, mPeriod), ScheduleResult::Scheduled);
308 
309     std::thread pausingThread([&] { mMockClock.advanceToNextCallback(); });
310     EXPECT_TRUE(cb.waitForPause());
311 
312     cb.unregister();
313     resource.reset();
314 
315     cb.unpause();
316     pausingThread.join();
317 
318     EXPECT_TRUE(cb.resourcePresent());
319 }
320 
TEST_F(VSyncDispatchTimerQueueTest,basicTwoAlarmSetting)321 TEST_F(VSyncDispatchTimerQueueTest, basicTwoAlarmSetting) {
322     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
323             .Times(4)
324             .WillOnce(Return(1055))
325             .WillOnce(Return(1063))
326             .WillOnce(Return(1063))
327             .WillOnce(Return(1075));
328 
329     Sequence seq;
330     EXPECT_CALL(mMockClock, alarmIn(_, 955)).InSequence(seq);
331     EXPECT_CALL(mMockClock, alarmIn(_, 813)).InSequence(seq);
332     EXPECT_CALL(mMockClock, alarmIn(_, 162)).InSequence(seq);
333 
334     CountingCallback cb0(mDispatch);
335     CountingCallback cb1(mDispatch);
336 
337     mDispatch.schedule(cb0, 100, mPeriod);
338     mDispatch.schedule(cb1, 250, mPeriod);
339 
340     advanceToNextCallback();
341     advanceToNextCallback();
342 
343     ASSERT_THAT(cb0.mCalls.size(), Eq(1));
344     EXPECT_THAT(cb0.mCalls[0], Eq(1075));
345     ASSERT_THAT(cb1.mCalls.size(), Eq(1));
346     EXPECT_THAT(cb1.mCalls[0], Eq(1063));
347 }
348 
TEST_F(VSyncDispatchTimerQueueTest,rearmsFaroutTimeoutWhenCancellingCloseOne)349 TEST_F(VSyncDispatchTimerQueueTest, rearmsFaroutTimeoutWhenCancellingCloseOne) {
350     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
351             .Times(4)
352             .WillOnce(Return(10000))
353             .WillOnce(Return(1000))
354             .WillOnce(Return(10000))
355             .WillOnce(Return(10000));
356 
357     Sequence seq;
358     EXPECT_CALL(mMockClock, alarmIn(_, 9900)).InSequence(seq);
359     EXPECT_CALL(mMockClock, alarmIn(_, 750)).InSequence(seq);
360     EXPECT_CALL(mMockClock, alarmIn(_, 9900)).InSequence(seq);
361 
362     CountingCallback cb0(mDispatch);
363     CountingCallback cb1(mDispatch);
364 
365     mDispatch.schedule(cb0, 100, mPeriod * 10);
366     mDispatch.schedule(cb1, 250, mPeriod);
367     mDispatch.cancel(cb1);
368 }
369 
TEST_F(VSyncDispatchTimerQueueTest,noUnnecessaryRearmsWhenRescheduling)370 TEST_F(VSyncDispatchTimerQueueTest, noUnnecessaryRearmsWhenRescheduling) {
371     Sequence seq;
372     EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
373     EXPECT_CALL(mMockClock, alarmIn(_, 100)).InSequence(seq);
374 
375     CountingCallback cb0(mDispatch);
376     CountingCallback cb1(mDispatch);
377 
378     mDispatch.schedule(cb0, 400, 1000);
379     mDispatch.schedule(cb1, 200, 1000);
380     mDispatch.schedule(cb1, 300, 1000);
381     advanceToNextCallback();
382 }
383 
TEST_F(VSyncDispatchTimerQueueTest,necessaryRearmsWhenModifying)384 TEST_F(VSyncDispatchTimerQueueTest, necessaryRearmsWhenModifying) {
385     Sequence seq;
386     EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
387     EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
388     EXPECT_CALL(mMockClock, alarmIn(_, 100)).InSequence(seq);
389 
390     CountingCallback cb0(mDispatch);
391     CountingCallback cb1(mDispatch);
392 
393     mDispatch.schedule(cb0, 400, 1000);
394     mDispatch.schedule(cb1, 200, 1000);
395     mDispatch.schedule(cb1, 500, 1000);
396     advanceToNextCallback();
397 }
398 
TEST_F(VSyncDispatchTimerQueueTest,modifyIntoGroup)399 TEST_F(VSyncDispatchTimerQueueTest, modifyIntoGroup) {
400     Sequence seq;
401     EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
402     EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
403     EXPECT_CALL(mMockClock, alarmIn(_, 990)).InSequence(seq);
404     EXPECT_CALL(mMockClock, alarmIn(_, 10)).InSequence(seq);
405 
406     auto offset = 400;
407     auto closeOffset = offset + mDispatchGroupThreshold - 1;
408     auto notCloseOffset = offset + 2 * mDispatchGroupThreshold;
409 
410     CountingCallback cb0(mDispatch);
411     CountingCallback cb1(mDispatch);
412 
413     mDispatch.schedule(cb0, 400, 1000);
414     mDispatch.schedule(cb1, 200, 1000);
415     mDispatch.schedule(cb1, closeOffset, 1000);
416 
417     advanceToNextCallback();
418     ASSERT_THAT(cb0.mCalls.size(), Eq(1));
419     EXPECT_THAT(cb0.mCalls[0], Eq(mPeriod));
420     ASSERT_THAT(cb1.mCalls.size(), Eq(1));
421     EXPECT_THAT(cb1.mCalls[0], Eq(mPeriod));
422 
423     mDispatch.schedule(cb0, 400, 2000);
424     mDispatch.schedule(cb1, notCloseOffset, 2000);
425     advanceToNextCallback();
426     ASSERT_THAT(cb1.mCalls.size(), Eq(2));
427     EXPECT_THAT(cb1.mCalls[1], Eq(2000));
428 
429     advanceToNextCallback();
430     ASSERT_THAT(cb0.mCalls.size(), Eq(2));
431     EXPECT_THAT(cb0.mCalls[1], Eq(2000));
432 }
433 
TEST_F(VSyncDispatchTimerQueueTest,rearmsWhenEndingAndDoesntCancel)434 TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenEndingAndDoesntCancel) {
435     EXPECT_CALL(mMockClock, alarmIn(_, 900));
436     EXPECT_CALL(mMockClock, alarmIn(_, 800));
437     EXPECT_CALL(mMockClock, alarmIn(_, 100));
438     EXPECT_CALL(mMockClock, alarmCancel());
439 
440     CountingCallback cb0(mDispatch);
441     CountingCallback cb1(mDispatch);
442 
443     mDispatch.schedule(cb0, 100, 1000);
444     mDispatch.schedule(cb1, 200, 1000);
445     advanceToNextCallback();
446     EXPECT_EQ(mDispatch.cancel(cb0), CancelResult::Cancelled);
447 }
448 
TEST_F(VSyncDispatchTimerQueueTest,setAlarmCallsAtCorrectTimeWithChangingVsync)449 TEST_F(VSyncDispatchTimerQueueTest, setAlarmCallsAtCorrectTimeWithChangingVsync) {
450     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
451             .Times(3)
452             .WillOnce(Return(950))
453             .WillOnce(Return(1975))
454             .WillOnce(Return(2950));
455 
456     CountingCallback cb(mDispatch);
457     mDispatch.schedule(cb, 100, 920);
458 
459     mMockClock.advanceBy(850);
460     EXPECT_THAT(cb.mCalls.size(), Eq(1));
461 
462     mDispatch.schedule(cb, 100, 1900);
463     mMockClock.advanceBy(900);
464     EXPECT_THAT(cb.mCalls.size(), Eq(1));
465     mMockClock.advanceBy(125);
466     EXPECT_THAT(cb.mCalls.size(), Eq(2));
467 
468     mDispatch.schedule(cb, 100, 2900);
469     mMockClock.advanceBy(975);
470     EXPECT_THAT(cb.mCalls.size(), Eq(3));
471 }
472 
TEST_F(VSyncDispatchTimerQueueTest,callbackReentrancy)473 TEST_F(VSyncDispatchTimerQueueTest, callbackReentrancy) {
474     Sequence seq;
475     EXPECT_CALL(mMockClock, alarmIn(_, 900)).InSequence(seq);
476     EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
477 
478     VSyncDispatch::CallbackToken tmp;
479     tmp = mDispatch.registerCallback([&](auto, auto) { mDispatch.schedule(tmp, 100, 2000); },
480                                      "o.o");
481 
482     mDispatch.schedule(tmp, 100, 1000);
483     advanceToNextCallback();
484 }
485 
TEST_F(VSyncDispatchTimerQueueTest,callbackReentrantWithPastWakeup)486 TEST_F(VSyncDispatchTimerQueueTest, callbackReentrantWithPastWakeup) {
487     VSyncDispatch::CallbackToken tmp;
488     std::optional<nsecs_t> lastTarget;
489     tmp = mDispatch.registerCallback(
490             [&](auto timestamp, auto) {
491                 EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp - mVsyncMoveThreshold),
492                           ScheduleResult::Scheduled);
493                 EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp), ScheduleResult::Scheduled);
494                 EXPECT_EQ(mDispatch.schedule(tmp, 400, timestamp + mVsyncMoveThreshold),
495                           ScheduleResult::Scheduled);
496                 lastTarget = timestamp;
497             },
498             "oo");
499 
500     mDispatch.schedule(tmp, 999, 1000);
501     advanceToNextCallback();
502     EXPECT_THAT(lastTarget, Eq(1000));
503 
504     advanceToNextCallback();
505     EXPECT_THAT(lastTarget, Eq(2000));
506 }
507 
TEST_F(VSyncDispatchTimerQueueTest,modificationsAroundVsyncTime)508 TEST_F(VSyncDispatchTimerQueueTest, modificationsAroundVsyncTime) {
509     Sequence seq;
510     EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
511     EXPECT_CALL(mMockClock, alarmIn(_, 200)).InSequence(seq);
512     EXPECT_CALL(mMockClock, alarmIn(_, 1000)).InSequence(seq);
513     EXPECT_CALL(mMockClock, alarmIn(_, 150)).InSequence(seq);
514 
515     CountingCallback cb(mDispatch);
516     mDispatch.schedule(cb, 0, 1000);
517 
518     mMockClock.advanceBy(750);
519     mDispatch.schedule(cb, 50, 1000);
520 
521     advanceToNextCallback();
522     mDispatch.schedule(cb, 50, 2000);
523 
524     mMockClock.advanceBy(800);
525     mDispatch.schedule(cb, 100, 2000);
526 }
527 
TEST_F(VSyncDispatchTimerQueueTest,lateModifications)528 TEST_F(VSyncDispatchTimerQueueTest, lateModifications) {
529     Sequence seq;
530     EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
531     EXPECT_CALL(mMockClock, alarmIn(_, 400)).InSequence(seq);
532     EXPECT_CALL(mMockClock, alarmIn(_, 350)).InSequence(seq);
533     EXPECT_CALL(mMockClock, alarmIn(_, 950)).InSequence(seq);
534 
535     CountingCallback cb0(mDispatch);
536     CountingCallback cb1(mDispatch);
537 
538     mDispatch.schedule(cb0, 500, 1000);
539     mDispatch.schedule(cb1, 100, 1000);
540 
541     advanceToNextCallback();
542     mDispatch.schedule(cb0, 200, 2000);
543     mDispatch.schedule(cb1, 150, 1000);
544 
545     advanceToNextCallback();
546     advanceToNextCallback();
547 }
548 
TEST_F(VSyncDispatchTimerQueueTest,doesntCancelPriorValidTimerForFutureMod)549 TEST_F(VSyncDispatchTimerQueueTest, doesntCancelPriorValidTimerForFutureMod) {
550     Sequence seq;
551     EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
552 
553     CountingCallback cb0(mDispatch);
554     CountingCallback cb1(mDispatch);
555     mDispatch.schedule(cb0, 500, 1000);
556     mDispatch.schedule(cb1, 500, 20000);
557 }
558 
TEST_F(VSyncDispatchTimerQueueTest,setsTimerAfterCancellation)559 TEST_F(VSyncDispatchTimerQueueTest, setsTimerAfterCancellation) {
560     Sequence seq;
561     EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
562     EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
563     EXPECT_CALL(mMockClock, alarmIn(_, 900)).InSequence(seq);
564 
565     CountingCallback cb0(mDispatch);
566     mDispatch.schedule(cb0, 500, 1000);
567     mDispatch.cancel(cb0);
568     mDispatch.schedule(cb0, 100, 1000);
569 }
570 
TEST_F(VSyncDispatchTimerQueueTest,makingUpIdsError)571 TEST_F(VSyncDispatchTimerQueueTest, makingUpIdsError) {
572     VSyncDispatch::CallbackToken token(100);
573     EXPECT_THAT(mDispatch.schedule(token, 100, 1000), Eq(ScheduleResult::Error));
574     EXPECT_THAT(mDispatch.cancel(token), Eq(CancelResult::Error));
575 }
576 
TEST_F(VSyncDispatchTimerQueueTest,canMoveCallbackBackwardsInTime)577 TEST_F(VSyncDispatchTimerQueueTest, canMoveCallbackBackwardsInTime) {
578     CountingCallback cb0(mDispatch);
579     EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
580     EXPECT_EQ(mDispatch.schedule(cb0, 100, 1000), ScheduleResult::Scheduled);
581 }
582 
583 // b/1450138150
TEST_F(VSyncDispatchTimerQueueTest,doesNotMoveCallbackBackwardsAndSkipAScheduledTargetVSync)584 TEST_F(VSyncDispatchTimerQueueTest, doesNotMoveCallbackBackwardsAndSkipAScheduledTargetVSync) {
585     EXPECT_CALL(mMockClock, alarmIn(_, 500));
586     CountingCallback cb(mDispatch);
587     EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled);
588     mMockClock.advanceBy(400);
589 
590     EXPECT_EQ(mDispatch.schedule(cb, 800, 1000), ScheduleResult::Scheduled);
591     advanceToNextCallback();
592     ASSERT_THAT(cb.mCalls.size(), Eq(1));
593 }
594 
TEST_F(VSyncDispatchTimerQueueTest,targetOffsetMovingBackALittleCanStillSchedule)595 TEST_F(VSyncDispatchTimerQueueTest, targetOffsetMovingBackALittleCanStillSchedule) {
596     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000))
597             .Times(2)
598             .WillOnce(Return(1000))
599             .WillOnce(Return(1002));
600     CountingCallback cb(mDispatch);
601     EXPECT_EQ(mDispatch.schedule(cb, 500, 1000), ScheduleResult::Scheduled);
602     mMockClock.advanceBy(400);
603     EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
604 }
605 
TEST_F(VSyncDispatchTimerQueueTest,canScheduleNegativeOffsetAgainstDifferentPeriods)606 TEST_F(VSyncDispatchTimerQueueTest, canScheduleNegativeOffsetAgainstDifferentPeriods) {
607     CountingCallback cb0(mDispatch);
608     EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
609     advanceToNextCallback();
610     EXPECT_EQ(mDispatch.schedule(cb0, 1100, 2000), ScheduleResult::Scheduled);
611 }
612 
TEST_F(VSyncDispatchTimerQueueTest,canScheduleLargeNegativeOffset)613 TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) {
614     Sequence seq;
615     EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq);
616     EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
617     CountingCallback cb0(mDispatch);
618     EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled);
619     advanceToNextCallback();
620     EXPECT_EQ(mDispatch.schedule(cb0, 1900, 2000), ScheduleResult::Scheduled);
621 }
622 
TEST_F(VSyncDispatchTimerQueueTest,scheduleUpdatesDoesNotAffectSchedulingState)623 TEST_F(VSyncDispatchTimerQueueTest, scheduleUpdatesDoesNotAffectSchedulingState) {
624     EXPECT_CALL(mMockClock, alarmIn(_, 600));
625 
626     CountingCallback cb(mDispatch);
627     EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
628 
629     EXPECT_EQ(mDispatch.schedule(cb, 1400, 1000), ScheduleResult::Scheduled);
630 
631     advanceToNextCallback();
632 }
633 
TEST_F(VSyncDispatchTimerQueueTest,helperMove)634 TEST_F(VSyncDispatchTimerQueueTest, helperMove) {
635     EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1);
636     EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
637 
638     VSyncCallbackRegistration cb(
639             mDispatch, [](auto, auto) {}, "");
640     VSyncCallbackRegistration cb1(std::move(cb));
641     cb.schedule(100, 1000);
642     cb.cancel();
643 
644     cb1.schedule(500, 1000);
645     cb1.cancel();
646 }
647 
TEST_F(VSyncDispatchTimerQueueTest,helperMoveAssign)648 TEST_F(VSyncDispatchTimerQueueTest, helperMoveAssign) {
649     EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1);
650     EXPECT_CALL(mMockClock, alarmCancel()).Times(1);
651 
652     VSyncCallbackRegistration cb(
653             mDispatch, [](auto, auto) {}, "");
654     VSyncCallbackRegistration cb1(
655             mDispatch, [](auto, auto) {}, "");
656     cb1 = std::move(cb);
657     cb.schedule(100, 1000);
658     cb.cancel();
659 
660     cb1.schedule(500, 1000);
661     cb1.cancel();
662 }
663 
664 // b/154303580
TEST_F(VSyncDispatchTimerQueueTest,skipsSchedulingIfTimerReschedulingIsImminent)665 TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminent) {
666     Sequence seq;
667     EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
668     EXPECT_CALL(mMockClock, alarmIn(_, 1200)).InSequence(seq);
669     CountingCallback cb1(mDispatch);
670     CountingCallback cb2(mDispatch);
671 
672     EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
673 
674     mMockClock.setLag(100);
675     mMockClock.advanceBy(620);
676 
677     EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled);
678     mMockClock.advanceBy(80);
679 
680     EXPECT_THAT(cb1.mCalls.size(), Eq(1));
681     EXPECT_THAT(cb2.mCalls.size(), Eq(0));
682 }
683 
684 // b/154303580.
685 // If the same callback tries to reschedule itself after it's too late, timer opts to apply the
686 // update later, as opposed to blocking the calling thread.
TEST_F(VSyncDispatchTimerQueueTest,skipsSchedulingIfTimerReschedulingIsImminentSameCallback)687 TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminentSameCallback) {
688     Sequence seq;
689     EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
690     EXPECT_CALL(mMockClock, alarmIn(_, 930)).InSequence(seq);
691     CountingCallback cb(mDispatch);
692 
693     EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled);
694 
695     mMockClock.setLag(100);
696     mMockClock.advanceBy(620);
697 
698     EXPECT_EQ(mDispatch.schedule(cb, 370, 2000), ScheduleResult::Scheduled);
699     mMockClock.advanceBy(80);
700 
701     EXPECT_THAT(cb.mCalls.size(), Eq(1));
702 }
703 
704 // b/154303580.
TEST_F(VSyncDispatchTimerQueueTest,skipsRearmingWhenNotNextScheduled)705 TEST_F(VSyncDispatchTimerQueueTest, skipsRearmingWhenNotNextScheduled) {
706     Sequence seq;
707     EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
708     EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
709     CountingCallback cb1(mDispatch);
710     CountingCallback cb2(mDispatch);
711 
712     EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
713     EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled);
714 
715     mMockClock.setLag(100);
716     mMockClock.advanceBy(620);
717 
718     EXPECT_EQ(mDispatch.cancel(cb2), CancelResult::Cancelled);
719 
720     mMockClock.advanceBy(80);
721 
722     EXPECT_THAT(cb1.mCalls.size(), Eq(1));
723     EXPECT_THAT(cb2.mCalls.size(), Eq(0));
724 }
725 
TEST_F(VSyncDispatchTimerQueueTest,rearmsWhenCancelledAndIsNextScheduled)726 TEST_F(VSyncDispatchTimerQueueTest, rearmsWhenCancelledAndIsNextScheduled) {
727     Sequence seq;
728     EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq);
729     EXPECT_CALL(mMockClock, alarmIn(_, 1280)).InSequence(seq);
730     EXPECT_CALL(mMockClock, alarmCancel()).InSequence(seq);
731     CountingCallback cb1(mDispatch);
732     CountingCallback cb2(mDispatch);
733 
734     EXPECT_EQ(mDispatch.schedule(cb1, 400, 1000), ScheduleResult::Scheduled);
735     EXPECT_EQ(mDispatch.schedule(cb2, 100, 2000), ScheduleResult::Scheduled);
736 
737     mMockClock.setLag(100);
738     mMockClock.advanceBy(620);
739 
740     EXPECT_EQ(mDispatch.cancel(cb1), CancelResult::Cancelled);
741 
742     EXPECT_THAT(cb1.mCalls.size(), Eq(0));
743     EXPECT_THAT(cb2.mCalls.size(), Eq(0));
744     mMockClock.advanceToNextCallback();
745 
746     EXPECT_THAT(cb1.mCalls.size(), Eq(0));
747     EXPECT_THAT(cb2.mCalls.size(), Eq(1));
748 }
749 
750 class VSyncDispatchTimerQueueEntryTest : public testing::Test {
751 protected:
752     nsecs_t const mPeriod = 1000;
753     nsecs_t const mVsyncMoveThreshold = 200;
754     NiceMock<MockVSyncTracker> mStubTracker{mPeriod};
755 };
756 
TEST_F(VSyncDispatchTimerQueueEntryTest,stateAfterInitialization)757 TEST_F(VSyncDispatchTimerQueueEntryTest, stateAfterInitialization) {
758     std::string name("basicname");
759     VSyncDispatchTimerQueueEntry entry(
760             name, [](auto, auto) {}, mVsyncMoveThreshold);
761     EXPECT_THAT(entry.name(), Eq(name));
762     EXPECT_FALSE(entry.lastExecutedVsyncTarget());
763     EXPECT_FALSE(entry.wakeupTime());
764 }
765 
TEST_F(VSyncDispatchTimerQueueEntryTest,stateScheduling)766 TEST_F(VSyncDispatchTimerQueueEntryTest, stateScheduling) {
767     VSyncDispatchTimerQueueEntry entry(
768             "test", [](auto, auto) {}, mVsyncMoveThreshold);
769 
770     EXPECT_FALSE(entry.wakeupTime());
771     EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
772     auto const wakeup = entry.wakeupTime();
773     ASSERT_TRUE(wakeup);
774     EXPECT_THAT(*wakeup, Eq(900));
775 
776     entry.disarm();
777     EXPECT_FALSE(entry.wakeupTime());
778 }
779 
TEST_F(VSyncDispatchTimerQueueEntryTest,stateSchedulingReallyLongWakeupLatency)780 TEST_F(VSyncDispatchTimerQueueEntryTest, stateSchedulingReallyLongWakeupLatency) {
781     auto const duration = 500;
782     auto const now = 8750;
783 
784     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(now + duration))
785             .Times(1)
786             .WillOnce(Return(10000));
787     VSyncDispatchTimerQueueEntry entry(
788             "test", [](auto, auto) {}, mVsyncMoveThreshold);
789 
790     EXPECT_FALSE(entry.wakeupTime());
791     EXPECT_THAT(entry.schedule(500, 994, mStubTracker, now), Eq(ScheduleResult::Scheduled));
792     auto const wakeup = entry.wakeupTime();
793     ASSERT_TRUE(wakeup);
794     EXPECT_THAT(*wakeup, Eq(9500));
795 }
796 
TEST_F(VSyncDispatchTimerQueueEntryTest,runCallback)797 TEST_F(VSyncDispatchTimerQueueEntryTest, runCallback) {
798     auto callCount = 0;
799     auto vsyncCalledTime = 0;
800     auto wakeupCalledTime = 0;
801     VSyncDispatchTimerQueueEntry entry(
802             "test",
803             [&](auto vsyncTime, auto wakeupTime) {
804                 callCount++;
805                 vsyncCalledTime = vsyncTime;
806                 wakeupCalledTime = wakeupTime;
807             },
808             mVsyncMoveThreshold);
809 
810     EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
811     auto const wakeup = entry.wakeupTime();
812     ASSERT_TRUE(wakeup);
813     EXPECT_THAT(*wakeup, Eq(900));
814 
815     entry.callback(entry.executing(), *wakeup);
816 
817     EXPECT_THAT(callCount, Eq(1));
818     EXPECT_THAT(vsyncCalledTime, Eq(mPeriod));
819     EXPECT_THAT(wakeupCalledTime, Eq(*wakeup));
820     EXPECT_FALSE(entry.wakeupTime());
821     auto lastCalledTarget = entry.lastExecutedVsyncTarget();
822     ASSERT_TRUE(lastCalledTarget);
823     EXPECT_THAT(*lastCalledTarget, Eq(mPeriod));
824 }
825 
TEST_F(VSyncDispatchTimerQueueEntryTest,updateCallback)826 TEST_F(VSyncDispatchTimerQueueEntryTest, updateCallback) {
827     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(_))
828             .Times(2)
829             .WillOnce(Return(1000))
830             .WillOnce(Return(1020));
831 
832     VSyncDispatchTimerQueueEntry entry(
833             "test", [](auto, auto) {}, mVsyncMoveThreshold);
834 
835     EXPECT_FALSE(entry.wakeupTime());
836     entry.update(mStubTracker, 0);
837     EXPECT_FALSE(entry.wakeupTime());
838 
839     EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
840     auto wakeup = entry.wakeupTime();
841     ASSERT_TRUE(wakeup);
842     EXPECT_THAT(wakeup, Eq(900));
843 
844     entry.update(mStubTracker, 0);
845     wakeup = entry.wakeupTime();
846     ASSERT_TRUE(wakeup);
847     EXPECT_THAT(*wakeup, Eq(920));
848 }
849 
TEST_F(VSyncDispatchTimerQueueEntryTest,skipsUpdateIfJustScheduled)850 TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) {
851     VSyncDispatchTimerQueueEntry entry(
852             "test", [](auto, auto) {}, mVsyncMoveThreshold);
853     EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
854     entry.update(mStubTracker, 0);
855 
856     auto const wakeup = entry.wakeupTime();
857     ASSERT_TRUE(wakeup);
858     EXPECT_THAT(*wakeup, Eq(wakeup));
859 }
860 
TEST_F(VSyncDispatchTimerQueueEntryTest,willSnapToNextTargettableVSync)861 TEST_F(VSyncDispatchTimerQueueEntryTest, willSnapToNextTargettableVSync) {
862     VSyncDispatchTimerQueueEntry entry(
863             "test", [](auto, auto) {}, mVsyncMoveThreshold);
864     EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
865     entry.executing(); // 1000 is executing
866     // had 1000 not been executing, this could have been scheduled for time 800.
867     EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
868     EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
869 
870     EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
871     EXPECT_THAT(*entry.wakeupTime(), Eq(1950));
872 
873     EXPECT_THAT(entry.schedule(200, 1001, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
874     EXPECT_THAT(*entry.wakeupTime(), Eq(1800));
875 }
876 
TEST_F(VSyncDispatchTimerQueueEntryTest,willRequestNextEstimateWhenSnappingToNextTargettableVSync)877 TEST_F(VSyncDispatchTimerQueueEntryTest,
878        willRequestNextEstimateWhenSnappingToNextTargettableVSync) {
879     VSyncDispatchTimerQueueEntry entry(
880             "test", [](auto, auto) {}, mVsyncMoveThreshold);
881 
882     Sequence seq;
883     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500))
884             .InSequence(seq)
885             .WillOnce(Return(1000));
886     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(500))
887             .InSequence(seq)
888             .WillOnce(Return(1000));
889     EXPECT_CALL(mStubTracker, nextAnticipatedVSyncTimeFrom(1000 + mVsyncMoveThreshold))
890             .InSequence(seq)
891             .WillOnce(Return(2000));
892 
893     EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
894 
895     entry.executing(); // 1000 is executing
896 
897     EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
898 }
899 
TEST_F(VSyncDispatchTimerQueueEntryTest,reportsScheduledIfStillTime)900 TEST_F(VSyncDispatchTimerQueueEntryTest, reportsScheduledIfStillTime) {
901     VSyncDispatchTimerQueueEntry entry(
902             "test", [](auto, auto) {}, mVsyncMoveThreshold);
903     EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
904     EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
905     EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
906     EXPECT_THAT(entry.schedule(1200, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled));
907 }
908 
TEST_F(VSyncDispatchTimerQueueEntryTest,storesPendingUpdatesUntilUpdate)909 TEST_F(VSyncDispatchTimerQueueEntryTest, storesPendingUpdatesUntilUpdate) {
910     static constexpr auto effectualOffset = 200;
911     VSyncDispatchTimerQueueEntry entry(
912             "test", [](auto, auto) {}, mVsyncMoveThreshold);
913     EXPECT_FALSE(entry.hasPendingWorkloadUpdate());
914     entry.addPendingWorkloadUpdate(100, 400);
915     entry.addPendingWorkloadUpdate(effectualOffset, 700);
916     EXPECT_TRUE(entry.hasPendingWorkloadUpdate());
917     entry.update(mStubTracker, 0);
918     EXPECT_FALSE(entry.hasPendingWorkloadUpdate());
919     EXPECT_THAT(*entry.wakeupTime(), Eq(mPeriod - effectualOffset));
920 }
921 
922 } // namespace android::scheduler
923 
924 // TODO(b/129481165): remove the #pragma below and fix conversion issues
925 #pragma clang diagnostic pop // ignored "-Wconversion"
926