diff options
Diffstat (limited to 'services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp')
-rw-r--r-- | services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp | 132 |
1 files changed, 83 insertions, 49 deletions
diff --git a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp index a596bce002..28be962f2c 100644 --- a/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp +++ b/services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp @@ -26,6 +26,20 @@ namespace android::scheduler { using base::StringAppendF; +namespace { +nsecs_t getExpectedCallbackTime(nsecs_t nextVsyncTime, + const VSyncDispatch::ScheduleTiming& timing) { + return nextVsyncTime - timing.readyDuration - timing.workDuration; +} + +nsecs_t getExpectedCallbackTime(VSyncTracker& tracker, nsecs_t now, + const VSyncDispatch::ScheduleTiming& timing) { + const auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom( + std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration)); + return getExpectedCallbackTime(nextVsyncTime, timing); +} +} // namespace + VSyncDispatch::~VSyncDispatch() = default; VSyncTracker::~VSyncTracker() = default; TimeKeeper::~TimeKeeper() = default; @@ -35,8 +49,6 @@ VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string const& na nsecs_t minVsyncDistance) : mName(name), mCallback(cb), - mWorkDuration(0), - mEarliestVsync(0), mMinVsyncDistance(minVsyncDistance) {} std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::lastExecutedVsyncTarget() const { @@ -54,6 +66,13 @@ std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::wakeupTime() const { return {mArmedInfo->mActualWakeupTime}; } +std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::readyTime() const { + if (!mArmedInfo) { + return {}; + } + return {mArmedInfo->mActualReadyTime}; +} + std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::targetVsync() const { if (!mArmedInfo) { return {}; @@ -61,15 +80,15 @@ std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::targetVsync() const { return {mArmedInfo->mActualVsyncTime}; } -ScheduleResult VSyncDispatchTimerQueueEntry::schedule(nsecs_t workDuration, nsecs_t earliestVsync, +ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTiming timing, VSyncTracker& tracker, nsecs_t now) { - auto nextVsyncTime = - tracker.nextAnticipatedVSyncTimeFrom(std::max(earliestVsync, now + workDuration)); + auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom( + std::max(timing.earliestVsync, now + timing.workDuration + timing.readyDuration)); bool const wouldSkipAVsyncTarget = mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance)); if (wouldSkipAVsyncTarget) { - return ScheduleResult::Scheduled; + return getExpectedCallbackTime(nextVsyncTime, timing); } bool const alreadyDispatchedForVsync = mLastDispatchTime && @@ -80,16 +99,15 @@ ScheduleResult VSyncDispatchTimerQueueEntry::schedule(nsecs_t workDuration, nsec tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance); } - auto const nextWakeupTime = nextVsyncTime - workDuration; - mWorkDuration = workDuration; - mEarliestVsync = earliestVsync; - mArmedInfo = {nextWakeupTime, nextVsyncTime}; - return ScheduleResult::Scheduled; + auto const nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration; + auto const nextReadyTime = nextVsyncTime - timing.readyDuration; + mScheduleTiming = timing; + mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime}; + return getExpectedCallbackTime(nextVsyncTime, timing); } -void VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(nsecs_t workDuration, - nsecs_t earliestVsync) { - mWorkloadUpdateInfo = {.earliestVsync = earliestVsync, .duration = workDuration}; +void VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(VSyncDispatch::ScheduleTiming timing) { + mWorkloadUpdateInfo = timing; } bool VSyncDispatchTimerQueueEntry::hasPendingWorkloadUpdate() const { @@ -102,14 +120,18 @@ void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) { } if (mWorkloadUpdateInfo) { - mEarliestVsync = mWorkloadUpdateInfo->earliestVsync; - mWorkDuration = mWorkloadUpdateInfo->duration; + mScheduleTiming = *mWorkloadUpdateInfo; mWorkloadUpdateInfo.reset(); } - auto const nextVsyncTime = - tracker.nextAnticipatedVSyncTimeFrom(std::max(mEarliestVsync, now + mWorkDuration)); - mArmedInfo = {nextVsyncTime - mWorkDuration, nextVsyncTime}; + const auto earliestReadyBy = now + mScheduleTiming.workDuration + mScheduleTiming.readyDuration; + const auto earliestVsync = std::max(earliestReadyBy, mScheduleTiming.earliestVsync); + + const auto nextVsyncTime = tracker.nextAnticipatedVSyncTimeFrom(earliestVsync); + const auto nextReadyTime = nextVsyncTime - mScheduleTiming.readyDuration; + const auto nextWakeupTime = nextReadyTime - mScheduleTiming.workDuration; + + mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime}; } void VSyncDispatchTimerQueueEntry::disarm() { @@ -122,13 +144,14 @@ nsecs_t VSyncDispatchTimerQueueEntry::executing() { return *mLastDispatchTime; } -void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp) { +void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp, + nsecs_t deadlineTimestamp) { { std::lock_guard<std::mutex> lk(mRunningMutex); mRunning = true; } - mCallback(vsyncTimestamp, wakeupTimestamp); + mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp); std::lock_guard<std::mutex> lk(mRunningMutex); mRunning = false; @@ -144,15 +167,20 @@ void VSyncDispatchTimerQueueEntry::dump(std::string& result) const { std::lock_guard<std::mutex> lk(mRunningMutex); std::string armedInfo; if (mArmedInfo) { - StringAppendF(&armedInfo, "[wake up in %.2fms for vsync %.2fms from now]", + StringAppendF(&armedInfo, + "[wake up in %.2fms deadline in %.2fms for vsync %.2fms from now]", (mArmedInfo->mActualWakeupTime - systemTime()) / 1e6f, + (mArmedInfo->mActualReadyTime - systemTime()) / 1e6f, (mArmedInfo->mActualVsyncTime - systemTime()) / 1e6f); } StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(), mRunning ? "(in callback function)" : "", armedInfo.c_str()); - StringAppendF(&result, "\t\t\tmWorkDuration: %.2fms mEarliestVsync: %.2fms relative to now\n", - mWorkDuration / 1e6f, (mEarliestVsync - systemTime()) / 1e6f); + StringAppendF(&result, + "\t\t\tworkDuration: %.2fms readyDuration: %.2fms earliestVsync: %.2fms relative " + "to now\n", + mScheduleTiming.workDuration / 1e6f, mScheduleTiming.readyDuration / 1e6f, + (mScheduleTiming.earliestVsync - systemTime()) / 1e6f); if (mLastDispatchTime) { StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n", @@ -171,7 +199,7 @@ VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk, mMinVsyncDistance(minVsyncDistance) {} VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() { - std::lock_guard<decltype(mMutex)> lk(mMutex); + std::lock_guard lock(mMutex); cancelTimer(); } @@ -180,10 +208,10 @@ void VSyncDispatchTimerQueue::cancelTimer() { mTimeKeeper->alarmCancel(); } -void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t now) { +void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) { mIntendedWakeupTime = targetTime; - mTimeKeeper->alarmIn(std::bind(&VSyncDispatchTimerQueue::timerCallback, this), - targetTime - now); + mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this), + mIntendedWakeupTime); mLastTimerSchedule = mTimeKeeper->now(); } @@ -239,11 +267,13 @@ void VSyncDispatchTimerQueue::timerCallback() { std::shared_ptr<VSyncDispatchTimerQueueEntry> callback; nsecs_t vsyncTimestamp; nsecs_t wakeupTimestamp; + nsecs_t deadlineTimestamp; }; std::vector<Invocation> invocations; { - std::lock_guard<decltype(mMutex)> lk(mMutex); - mLastTimerCallback = mTimeKeeper->now(); + std::lock_guard lock(mMutex); + auto const now = mTimeKeeper->now(); + mLastTimerCallback = now; for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) { auto& callback = it->second; auto const wakeupTime = callback->wakeupTime(); @@ -251,10 +281,13 @@ void VSyncDispatchTimerQueue::timerCallback() { continue; } - if (*wakeupTime < mIntendedWakeupTime + mTimerSlack) { + auto const readyTime = callback->readyTime(); + + auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast<nsecs_t>(0)); + if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) { callback->executing(); - invocations.emplace_back( - Invocation{callback, *callback->lastExecutedVsyncTarget(), *wakeupTime}); + invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(), + *wakeupTime, *readyTime}); } } @@ -263,13 +296,14 @@ void VSyncDispatchTimerQueue::timerCallback() { } for (auto const& invocation : invocations) { - invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp); + invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp, + invocation.deadlineTimestamp); } } VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback( Callback const& callbackFn, std::string callbackName) { - std::lock_guard<decltype(mMutex)> lk(mMutex); + std::lock_guard lock(mMutex); return CallbackToken{ mCallbacks .emplace(++mCallbackToken, @@ -282,7 +316,7 @@ VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback void VSyncDispatchTimerQueue::unregisterCallback(CallbackToken token) { std::shared_ptr<VSyncDispatchTimerQueueEntry> entry = nullptr; { - std::lock_guard<decltype(mMutex)> lk(mMutex); + std::lock_guard lock(mMutex); auto it = mCallbacks.find(token); if (it != mCallbacks.end()) { entry = it->second; @@ -295,11 +329,11 @@ void VSyncDispatchTimerQueue::unregisterCallback(CallbackToken token) { } } -ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, nsecs_t workDuration, - nsecs_t earliestVsync) { - auto result = ScheduleResult::Error; +ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, + ScheduleTiming scheduleTiming) { + ScheduleResult result; { - std::lock_guard<decltype(mMutex)> lk(mMutex); + std::lock_guard lock(mMutex); auto it = mCallbacks.find(token); if (it == mCallbacks.end()) { @@ -312,12 +346,12 @@ ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, nsecs_t wo * timer recalculation to avoid cancelling a callback that is about to fire. */ auto const rearmImminent = now > mIntendedWakeupTime; if (CC_UNLIKELY(rearmImminent)) { - callback->addPendingWorkloadUpdate(workDuration, earliestVsync); - return ScheduleResult::Scheduled; + callback->addPendingWorkloadUpdate(scheduleTiming); + return getExpectedCallbackTime(mTracker, now, scheduleTiming); } - result = callback->schedule(workDuration, earliestVsync, mTracker, now); - if (result == ScheduleResult::CannotSchedule) { + result = callback->schedule(scheduleTiming, mTracker, now); + if (!result.has_value()) { return result; } @@ -330,7 +364,7 @@ ScheduleResult VSyncDispatchTimerQueue::schedule(CallbackToken token, nsecs_t wo } CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) { - std::lock_guard<decltype(mMutex)> lk(mMutex); + std::lock_guard lock(mMutex); auto it = mCallbacks.find(token); if (it == mCallbacks.end()) { @@ -352,7 +386,7 @@ CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) { } void VSyncDispatchTimerQueue::dump(std::string& result) const { - std::lock_guard<decltype(mMutex)> lk(mMutex); + std::lock_guard lock(mMutex); StringAppendF(&result, "\tTimer:\n"); mTimeKeeper->dump(result); StringAppendF(&result, "\tmTimerSlack: %.2fms mMinVsyncDistance: %.2fms\n", mTimerSlack / 1e6f, @@ -394,11 +428,11 @@ VSyncCallbackRegistration::~VSyncCallbackRegistration() { if (mValidToken) mDispatch.get().unregisterCallback(mToken); } -ScheduleResult VSyncCallbackRegistration::schedule(nsecs_t workDuration, nsecs_t earliestVsync) { +ScheduleResult VSyncCallbackRegistration::schedule(VSyncDispatch::ScheduleTiming scheduleTiming) { if (!mValidToken) { - return ScheduleResult::Error; + return std::nullopt; } - return mDispatch.get().schedule(mToken, workDuration, earliestVsync); + return mDispatch.get().schedule(mToken, scheduleTiming); } CancelResult VSyncCallbackRegistration::cancel() { |