Loading services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp +16 −15 Original line number Diff line number Diff line Loading @@ -47,22 +47,26 @@ std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::wakeupTime() const { return {mArmedInfo->mActualWakeupTime}; } nsecs_t VSyncDispatchTimerQueueEntry::schedule(nsecs_t workDuration, nsecs_t earliestVsync, ScheduleResult VSyncDispatchTimerQueueEntry::schedule(nsecs_t workDuration, nsecs_t earliestVsync, VSyncTracker& tracker, nsecs_t now) { auto const nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(std::max(earliestVsync, now + workDuration)); if (mLastDispatchTime >= nextVsyncTime) { // already dispatched a callback for this vsync return ScheduleResult::CannotSchedule; } auto const nextWakeupTime = nextVsyncTime - workDuration; auto result = mArmedInfo ? ScheduleResult::ReScheduled : ScheduleResult::Scheduled; mWorkDuration = workDuration; mEarliestVsync = earliestVsync; arm(tracker, now); return mArmedInfo->mActualWakeupTime; mArmedInfo = {nextWakeupTime, nextVsyncTime}; return result; } void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) { if (!mArmedInfo) { return; } arm(tracker, now); } void VSyncDispatchTimerQueueEntry::arm(VSyncTracker& tracker, nsecs_t now) { auto const nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(std::max(mEarliestVsync, now + mWorkDuration)); mArmedInfo = {nextVsyncTime - mWorkDuration, nextVsyncTime}; Loading Loading @@ -214,16 +218,13 @@ ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, nsecs_t wo return result; } auto& callback = it->second; result = callback->wakeupTime() ? ScheduleResult::ReScheduled : ScheduleResult::Scheduled; auto const now = mTimeKeeper->now(); auto const wakeupTime = callback->schedule(workDuration, earliestVsync, mTracker, now); if (wakeupTime < now - mTimerSlack || callback->lastExecutedVsyncTarget() > wakeupTime) { return ScheduleResult::CannotSchedule; result = callback->schedule(workDuration, earliestVsync, mTracker, now); if (result == ScheduleResult::CannotSchedule) { return result; } if (wakeupTime < mIntendedWakeupTime - mTimerSlack) { if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) { rearmTimerSkippingUpdateFor(now, it); } } Loading services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h +2 −3 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ public: std::optional<nsecs_t> lastExecutedVsyncTarget() const; // This moves the state from disarmed->armed and will calculate the wakeupTime. nsecs_t schedule(nsecs_t workDuration, nsecs_t earliestVsync, VSyncTracker& tracker, ScheduleResult schedule(nsecs_t workDuration, nsecs_t earliestVsync, VSyncTracker& tracker, nsecs_t now); // This will update armed entries with the latest vsync information. Entry remains armed. void update(VSyncTracker& tracker, nsecs_t now); Loading @@ -67,7 +67,6 @@ public: void ensureNotRunning(); private: void arm(VSyncTracker& tracker, nsecs_t now); std::string const mName; std::function<void(nsecs_t)> const mCallback; Loading services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +63 −20 Original line number Diff line number Diff line Loading @@ -551,6 +551,32 @@ TEST_F(VSyncDispatchTimerQueueTest, distinguishesScheduleAndReschedule) { EXPECT_EQ(mDispatch.schedule(cb0, 100, 1000), ScheduleResult::ReScheduled); } TEST_F(VSyncDispatchTimerQueueTest, canScheduleNegativeOffsetAgainstDifferentPeriods) { CountingCallback cb0(mDispatch); EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled); advanceToNextCallback(); EXPECT_EQ(mDispatch.schedule(cb0, 1100, 2000), ScheduleResult::Scheduled); } TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) { Sequence seq; EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq); EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq); CountingCallback cb0(mDispatch); EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled); advanceToNextCallback(); EXPECT_EQ(mDispatch.schedule(cb0, 1900, 2000), ScheduleResult::Scheduled); } TEST_F(VSyncDispatchTimerQueueTest, cannotScheduleDoesNotAffectSchedulingState) { EXPECT_CALL(mMockClock, alarmIn(_, 600)); CountingCallback cb(mDispatch); EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled); advanceToNextCallback(); EXPECT_EQ(mDispatch.schedule(cb, 100, 1000), ScheduleResult::CannotSchedule); } TEST_F(VSyncDispatchTimerQueueTest, helperMove) { EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1); EXPECT_CALL(mMockClock, alarmCancel()).Times(1); Loading Loading @@ -599,11 +625,10 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, stateScheduling) { VSyncDispatchTimerQueueEntry entry("test", [](auto) {}); EXPECT_FALSE(entry.wakeupTime()); auto const wakeup = entry.schedule(100, 500, mStubTracker, 0); auto const queried = entry.wakeupTime(); ASSERT_TRUE(queried); EXPECT_THAT(*queried, Eq(wakeup)); EXPECT_THAT(*queried, Eq(900)); EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); auto const wakeup = entry.wakeupTime(); ASSERT_TRUE(wakeup); EXPECT_THAT(*wakeup, Eq(900)); entry.disarm(); EXPECT_FALSE(entry.wakeupTime()); Loading @@ -619,11 +644,10 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, stateSchedulingReallyLongWakeupLatency) VSyncDispatchTimerQueueEntry entry("test", [](auto) {}); EXPECT_FALSE(entry.wakeupTime()); auto const wakeup = entry.schedule(500, 994, mStubTracker, now); auto const queried = entry.wakeupTime(); ASSERT_TRUE(queried); EXPECT_THAT(*queried, Eq(wakeup)); EXPECT_THAT(*queried, Eq(9500)); EXPECT_THAT(entry.schedule(500, 994, mStubTracker, now), Eq(ScheduleResult::Scheduled)); auto const wakeup = entry.wakeupTime(); ASSERT_TRUE(wakeup); EXPECT_THAT(*wakeup, Eq(9500)); } TEST_F(VSyncDispatchTimerQueueEntryTest, runCallback) { Loading @@ -634,8 +658,10 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, runCallback) { calledTime = time; }); auto const wakeup = entry.schedule(100, 500, mStubTracker, 0); EXPECT_THAT(wakeup, Eq(900)); EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); auto const wakeup = entry.wakeupTime(); ASSERT_TRUE(wakeup); EXPECT_THAT(*wakeup, Eq(900)); entry.callback(entry.executing()); Loading @@ -659,23 +685,40 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, updateCallback) { entry.update(mStubTracker, 0); EXPECT_FALSE(entry.wakeupTime()); auto const wakeup = entry.schedule(100, 500, mStubTracker, 0); EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); auto wakeup = entry.wakeupTime(); ASSERT_TRUE(wakeup); EXPECT_THAT(wakeup, Eq(900)); entry.update(mStubTracker, 0); auto const queried = entry.wakeupTime(); ASSERT_TRUE(queried); EXPECT_THAT(*queried, Eq(920)); wakeup = entry.wakeupTime(); ASSERT_TRUE(wakeup); EXPECT_THAT(*wakeup, Eq(920)); } TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) { VSyncDispatchTimerQueueEntry entry("test", [](auto) {}); auto const wakeup = entry.schedule(100, 500, mStubTracker, 0); EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); entry.update(mStubTracker, 0); auto const queried = entry.wakeupTime(); ASSERT_TRUE(queried); EXPECT_THAT(*queried, Eq(wakeup)); auto const wakeup = entry.wakeupTime(); ASSERT_TRUE(wakeup); EXPECT_THAT(*wakeup, Eq(wakeup)); } TEST_F(VSyncDispatchTimerQueueEntryTest, reportsCannotScheduleIfMissedOpportunity) { VSyncDispatchTimerQueueEntry entry("test", [](auto) {}); EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); entry.executing(); EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::CannotSchedule)); EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::CannotSchedule)); EXPECT_THAT(entry.schedule(200, 1001, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); } TEST_F(VSyncDispatchTimerQueueEntryTest, reportsReScheduleIfStillTime) { VSyncDispatchTimerQueueEntry entry("test", [](auto) {}); EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::ReScheduled)); } } // namespace android::scheduler Loading
services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp +16 −15 Original line number Diff line number Diff line Loading @@ -47,22 +47,26 @@ std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::wakeupTime() const { return {mArmedInfo->mActualWakeupTime}; } nsecs_t VSyncDispatchTimerQueueEntry::schedule(nsecs_t workDuration, nsecs_t earliestVsync, ScheduleResult VSyncDispatchTimerQueueEntry::schedule(nsecs_t workDuration, nsecs_t earliestVsync, VSyncTracker& tracker, nsecs_t now) { auto const nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(std::max(earliestVsync, now + workDuration)); if (mLastDispatchTime >= nextVsyncTime) { // already dispatched a callback for this vsync return ScheduleResult::CannotSchedule; } auto const nextWakeupTime = nextVsyncTime - workDuration; auto result = mArmedInfo ? ScheduleResult::ReScheduled : ScheduleResult::Scheduled; mWorkDuration = workDuration; mEarliestVsync = earliestVsync; arm(tracker, now); return mArmedInfo->mActualWakeupTime; mArmedInfo = {nextWakeupTime, nextVsyncTime}; return result; } void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) { if (!mArmedInfo) { return; } arm(tracker, now); } void VSyncDispatchTimerQueueEntry::arm(VSyncTracker& tracker, nsecs_t now) { auto const nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(std::max(mEarliestVsync, now + mWorkDuration)); mArmedInfo = {nextVsyncTime - mWorkDuration, nextVsyncTime}; Loading Loading @@ -214,16 +218,13 @@ ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, nsecs_t wo return result; } auto& callback = it->second; result = callback->wakeupTime() ? ScheduleResult::ReScheduled : ScheduleResult::Scheduled; auto const now = mTimeKeeper->now(); auto const wakeupTime = callback->schedule(workDuration, earliestVsync, mTracker, now); if (wakeupTime < now - mTimerSlack || callback->lastExecutedVsyncTarget() > wakeupTime) { return ScheduleResult::CannotSchedule; result = callback->schedule(workDuration, earliestVsync, mTracker, now); if (result == ScheduleResult::CannotSchedule) { return result; } if (wakeupTime < mIntendedWakeupTime - mTimerSlack) { if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) { rearmTimerSkippingUpdateFor(now, it); } } Loading
services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h +2 −3 Original line number Diff line number Diff line Loading @@ -44,7 +44,7 @@ public: std::optional<nsecs_t> lastExecutedVsyncTarget() const; // This moves the state from disarmed->armed and will calculate the wakeupTime. nsecs_t schedule(nsecs_t workDuration, nsecs_t earliestVsync, VSyncTracker& tracker, ScheduleResult schedule(nsecs_t workDuration, nsecs_t earliestVsync, VSyncTracker& tracker, nsecs_t now); // This will update armed entries with the latest vsync information. Entry remains armed. void update(VSyncTracker& tracker, nsecs_t now); Loading @@ -67,7 +67,6 @@ public: void ensureNotRunning(); private: void arm(VSyncTracker& tracker, nsecs_t now); std::string const mName; std::function<void(nsecs_t)> const mCallback; Loading
services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp +63 −20 Original line number Diff line number Diff line Loading @@ -551,6 +551,32 @@ TEST_F(VSyncDispatchTimerQueueTest, distinguishesScheduleAndReschedule) { EXPECT_EQ(mDispatch.schedule(cb0, 100, 1000), ScheduleResult::ReScheduled); } TEST_F(VSyncDispatchTimerQueueTest, canScheduleNegativeOffsetAgainstDifferentPeriods) { CountingCallback cb0(mDispatch); EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled); advanceToNextCallback(); EXPECT_EQ(mDispatch.schedule(cb0, 1100, 2000), ScheduleResult::Scheduled); } TEST_F(VSyncDispatchTimerQueueTest, canScheduleLargeNegativeOffset) { Sequence seq; EXPECT_CALL(mMockClock, alarmIn(_, 500)).InSequence(seq); EXPECT_CALL(mMockClock, alarmIn(_, 600)).InSequence(seq); CountingCallback cb0(mDispatch); EXPECT_EQ(mDispatch.schedule(cb0, 500, 1000), ScheduleResult::Scheduled); advanceToNextCallback(); EXPECT_EQ(mDispatch.schedule(cb0, 1900, 2000), ScheduleResult::Scheduled); } TEST_F(VSyncDispatchTimerQueueTest, cannotScheduleDoesNotAffectSchedulingState) { EXPECT_CALL(mMockClock, alarmIn(_, 600)); CountingCallback cb(mDispatch); EXPECT_EQ(mDispatch.schedule(cb, 400, 1000), ScheduleResult::Scheduled); advanceToNextCallback(); EXPECT_EQ(mDispatch.schedule(cb, 100, 1000), ScheduleResult::CannotSchedule); } TEST_F(VSyncDispatchTimerQueueTest, helperMove) { EXPECT_CALL(mMockClock, alarmIn(_, 500)).Times(1); EXPECT_CALL(mMockClock, alarmCancel()).Times(1); Loading Loading @@ -599,11 +625,10 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, stateScheduling) { VSyncDispatchTimerQueueEntry entry("test", [](auto) {}); EXPECT_FALSE(entry.wakeupTime()); auto const wakeup = entry.schedule(100, 500, mStubTracker, 0); auto const queried = entry.wakeupTime(); ASSERT_TRUE(queried); EXPECT_THAT(*queried, Eq(wakeup)); EXPECT_THAT(*queried, Eq(900)); EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); auto const wakeup = entry.wakeupTime(); ASSERT_TRUE(wakeup); EXPECT_THAT(*wakeup, Eq(900)); entry.disarm(); EXPECT_FALSE(entry.wakeupTime()); Loading @@ -619,11 +644,10 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, stateSchedulingReallyLongWakeupLatency) VSyncDispatchTimerQueueEntry entry("test", [](auto) {}); EXPECT_FALSE(entry.wakeupTime()); auto const wakeup = entry.schedule(500, 994, mStubTracker, now); auto const queried = entry.wakeupTime(); ASSERT_TRUE(queried); EXPECT_THAT(*queried, Eq(wakeup)); EXPECT_THAT(*queried, Eq(9500)); EXPECT_THAT(entry.schedule(500, 994, mStubTracker, now), Eq(ScheduleResult::Scheduled)); auto const wakeup = entry.wakeupTime(); ASSERT_TRUE(wakeup); EXPECT_THAT(*wakeup, Eq(9500)); } TEST_F(VSyncDispatchTimerQueueEntryTest, runCallback) { Loading @@ -634,8 +658,10 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, runCallback) { calledTime = time; }); auto const wakeup = entry.schedule(100, 500, mStubTracker, 0); EXPECT_THAT(wakeup, Eq(900)); EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); auto const wakeup = entry.wakeupTime(); ASSERT_TRUE(wakeup); EXPECT_THAT(*wakeup, Eq(900)); entry.callback(entry.executing()); Loading @@ -659,23 +685,40 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, updateCallback) { entry.update(mStubTracker, 0); EXPECT_FALSE(entry.wakeupTime()); auto const wakeup = entry.schedule(100, 500, mStubTracker, 0); EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); auto wakeup = entry.wakeupTime(); ASSERT_TRUE(wakeup); EXPECT_THAT(wakeup, Eq(900)); entry.update(mStubTracker, 0); auto const queried = entry.wakeupTime(); ASSERT_TRUE(queried); EXPECT_THAT(*queried, Eq(920)); wakeup = entry.wakeupTime(); ASSERT_TRUE(wakeup); EXPECT_THAT(*wakeup, Eq(920)); } TEST_F(VSyncDispatchTimerQueueEntryTest, skipsUpdateIfJustScheduled) { VSyncDispatchTimerQueueEntry entry("test", [](auto) {}); auto const wakeup = entry.schedule(100, 500, mStubTracker, 0); EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); entry.update(mStubTracker, 0); auto const queried = entry.wakeupTime(); ASSERT_TRUE(queried); EXPECT_THAT(*queried, Eq(wakeup)); auto const wakeup = entry.wakeupTime(); ASSERT_TRUE(wakeup); EXPECT_THAT(*wakeup, Eq(wakeup)); } TEST_F(VSyncDispatchTimerQueueEntryTest, reportsCannotScheduleIfMissedOpportunity) { VSyncDispatchTimerQueueEntry entry("test", [](auto) {}); EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); entry.executing(); EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::CannotSchedule)); EXPECT_THAT(entry.schedule(50, 500, mStubTracker, 0), Eq(ScheduleResult::CannotSchedule)); EXPECT_THAT(entry.schedule(200, 1001, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); } TEST_F(VSyncDispatchTimerQueueEntryTest, reportsReScheduleIfStillTime) { VSyncDispatchTimerQueueEntry entry("test", [](auto) {}); EXPECT_THAT(entry.schedule(100, 500, mStubTracker, 0), Eq(ScheduleResult::Scheduled)); EXPECT_THAT(entry.schedule(200, 500, mStubTracker, 0), Eq(ScheduleResult::ReScheduled)); } } // namespace android::scheduler