blob: 1925f1165cd5da2c81075c40d95a749933074744 [file] [log] [blame]
Kevin DuBois305bef12019-10-09 13:23:27 -07001/*
2 * Copyright 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define ATRACE_TAG ATRACE_TAG_GRAPHICS
Dominik Laskowski62eff352021-12-06 09:59:41 -080018
Kevin DuBois305bef12019-10-09 13:23:27 -070019#include <vector>
20
Dominik Laskowski62eff352021-12-06 09:59:41 -080021#include <android-base/stringprintf.h>
Vishnu Nairbe0ad902024-06-27 23:38:43 +000022#include <common/trace.h>
Dominik Laskowski62eff352021-12-06 09:59:41 -080023#include <ftl/concat.h>
Leon Scroggins III07738132023-04-24 11:43:53 -040024#include <log/log_main.h>
Dominik Laskowski62eff352021-12-06 09:59:41 -080025
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080026#include <scheduler/TimeKeeper.h>
27
Alec Mouri9b133ca2023-11-14 19:00:01 +000028#include <common/FlagManager.h>
Kevin DuBoise4f27a82019-11-12 11:41:41 -080029#include "VSyncDispatchTimerQueue.h"
Kevin DuBois305bef12019-10-09 13:23:27 -070030#include "VSyncTracker.h"
31
Leon Scroggins III07738132023-04-24 11:43:53 -040032#undef LOG_TAG
33#define LOG_TAG "VSyncDispatch"
34
Kevin DuBois305bef12019-10-09 13:23:27 -070035namespace android::scheduler {
Dominik Laskowski62eff352021-12-06 09:59:41 -080036
Ady Abraham5e7371c2020-03-24 14:47:24 -070037using base::StringAppendF;
Kevin DuBois305bef12019-10-09 13:23:27 -070038
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070039namespace {
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080040
ramindani32a88b12024-01-31 18:45:30 -080041ScheduleResult getExpectedCallbackTime(nsecs_t nextVsyncTime,
42 const VSyncDispatch::ScheduleTiming& timing) {
43 return {TimePoint::fromNs(nextVsyncTime - timing.readyDuration - timing.workDuration),
44 TimePoint::fromNs(nextVsyncTime)};
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070045}
46
Ady Abraham20024aa2024-03-05 01:32:49 +000047void traceEntry(const VSyncDispatchTimerQueueEntry& entry, nsecs_t now) {
Vishnu Nair2665ca92024-07-09 22:08:15 +000048 if (!SFTRACE_ENABLED() || !entry.wakeupTime().has_value() || !entry.targetVsync().has_value()) {
Ady Abraham20024aa2024-03-05 01:32:49 +000049 return;
50 }
51
52 ftl::Concat trace(ftl::truncated<5>(entry.name()), " alarm in ",
53 ns2us(*entry.wakeupTime() - now), "us; VSYNC in ",
54 ns2us(*entry.targetVsync() - now), "us");
Vishnu Nairbe0ad902024-06-27 23:38:43 +000055 SFTRACE_FORMAT_INSTANT(trace.c_str());
Ady Abraham20024aa2024-03-05 01:32:49 +000056}
57
Ady Abrahamb5d3afa2021-05-07 11:22:23 -070058} // namespace
59
Kevin DuBoise4f27a82019-11-12 11:41:41 -080060VSyncDispatch::~VSyncDispatch() = default;
Kevin DuBois305bef12019-10-09 13:23:27 -070061VSyncTracker::~VSyncTracker() = default;
Kevin DuBois305bef12019-10-09 13:23:27 -070062
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080063VSyncDispatchTimerQueueEntry::VSyncDispatchTimerQueueEntry(std::string name,
64 VSyncDispatch::Callback callback,
Kevin DuBoisc94ca832019-11-26 12:56:24 -080065 nsecs_t minVsyncDistance)
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -080066 : mName(std::move(name)),
67 mCallback(std::move(callback)),
Kevin DuBoisc94ca832019-11-26 12:56:24 -080068 mMinVsyncDistance(minVsyncDistance) {}
Kevin DuBois305bef12019-10-09 13:23:27 -070069
Kevin DuBoise4f27a82019-11-12 11:41:41 -080070std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::lastExecutedVsyncTarget() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070071 return mLastDispatchTime;
72}
73
Kevin DuBoise4f27a82019-11-12 11:41:41 -080074std::string_view VSyncDispatchTimerQueueEntry::name() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070075 return mName;
76}
77
Kevin DuBoise4f27a82019-11-12 11:41:41 -080078std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::wakeupTime() const {
Kevin DuBois305bef12019-10-09 13:23:27 -070079 if (!mArmedInfo) {
80 return {};
81 }
82 return {mArmedInfo->mActualWakeupTime};
83}
84
Ady Abraham9c53ee72020-07-22 21:16:18 -070085std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::readyTime() const {
86 if (!mArmedInfo) {
87 return {};
88 }
89 return {mArmedInfo->mActualReadyTime};
90}
91
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -080092std::optional<nsecs_t> VSyncDispatchTimerQueueEntry::targetVsync() const {
93 if (!mArmedInfo) {
94 return {};
95 }
96 return {mArmedInfo->mActualVsyncTime};
97}
98
ramindani558f4a92024-02-16 15:49:23 -080099ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTiming timing,
100 VSyncTracker& tracker, nsecs_t now) {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000101 SFTRACE_NAME("VSyncDispatchTimerQueueEntry::schedule");
Ady Abraham4335afd2023-12-18 19:10:47 -0800102 auto nextVsyncTime =
103 tracker.nextAnticipatedVSyncTimeFrom(std::max(timing.lastVsync,
104 now + timing.workDuration +
105 timing.readyDuration),
ramindani92ab9872024-07-26 15:09:37 -0700106 timing.committedVsyncOpt.value_or(
107 timing.lastVsync));
Ady Abraham69b9e622021-07-19 12:24:31 -0700108 auto nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800109
110 bool const wouldSkipAVsyncTarget =
111 mArmedInfo && (nextVsyncTime > (mArmedInfo->mActualVsyncTime + mMinVsyncDistance));
Ady Abraham69b9e622021-07-19 12:24:31 -0700112 bool const wouldSkipAWakeup =
113 mArmedInfo && ((nextWakeupTime > (mArmedInfo->mActualWakeupTime + mMinVsyncDistance)));
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000114 SFTRACE_FORMAT_INSTANT("%s: wouldSkipAVsyncTarget=%d wouldSkipAWakeup=%d", mName.c_str(),
115 wouldSkipAVsyncTarget, wouldSkipAWakeup);
Ady Abrahambf554892024-02-14 18:18:21 +0000116 if (FlagManager::getInstance().dont_skip_on_early_ro()) {
Ady Abraham529bd9f2023-10-05 14:55:30 -0700117 if (wouldSkipAVsyncTarget || wouldSkipAWakeup) {
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700118 nextVsyncTime = mArmedInfo->mActualVsyncTime;
119 } else {
120 nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
Ady Abraham529bd9f2023-10-05 14:55:30 -0700121 }
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700122 nextWakeupTime = std::max(now, nextVsyncTime - timing.workDuration - timing.readyDuration);
Ady Abraham529bd9f2023-10-05 14:55:30 -0700123 } else {
124 if (wouldSkipAVsyncTarget && wouldSkipAWakeup) {
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700125 return getExpectedCallbackTime(nextVsyncTime, timing);
Ady Abraham529bd9f2023-10-05 14:55:30 -0700126 }
Ady Abrahamb0d3d982023-10-30 11:29:51 -0700127 nextVsyncTime = adjustVsyncIfNeeded(tracker, nextVsyncTime);
128 nextWakeupTime = nextVsyncTime - timing.workDuration - timing.readyDuration;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800129 }
130
Ady Abraham9c53ee72020-07-22 21:16:18 -0700131 auto const nextReadyTime = nextVsyncTime - timing.readyDuration;
132 mScheduleTiming = timing;
133 mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
ramindani32a88b12024-01-31 18:45:30 -0800134 return ScheduleResult{TimePoint::fromNs(nextWakeupTime), TimePoint::fromNs(nextVsyncTime)};
Kevin DuBois305bef12019-10-09 13:23:27 -0700135}
136
ramindani32a88b12024-01-31 18:45:30 -0800137ScheduleResult VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(
Ady Abrahamda8af4c2024-02-14 00:24:34 +0000138 VSyncTracker& tracker, nsecs_t now, VSyncDispatch::ScheduleTiming timing) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700139 mWorkloadUpdateInfo = timing;
Ady Abraham20024aa2024-03-05 01:32:49 +0000140 const auto armedInfo = getArmedInfo(tracker, now, timing, mArmedInfo);
ramindani32a88b12024-01-31 18:45:30 -0800141 return {TimePoint::fromNs(armedInfo.mActualWakeupTime),
142 TimePoint::fromNs(armedInfo.mActualVsyncTime)};
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700143}
144
145bool VSyncDispatchTimerQueueEntry::hasPendingWorkloadUpdate() const {
146 return mWorkloadUpdateInfo.has_value();
147}
148
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700149nsecs_t VSyncDispatchTimerQueueEntry::adjustVsyncIfNeeded(VSyncTracker& tracker,
150 nsecs_t nextVsyncTime) const {
151 bool const alreadyDispatchedForVsync = mLastDispatchTime &&
152 ((*mLastDispatchTime + mMinVsyncDistance) >= nextVsyncTime &&
153 (*mLastDispatchTime - mMinVsyncDistance) <= nextVsyncTime);
154 const nsecs_t currentPeriod = tracker.currentPeriod();
155 bool const nextVsyncTooClose = mLastDispatchTime &&
156 (nextVsyncTime - *mLastDispatchTime + mMinVsyncDistance) <= currentPeriod;
157 if (alreadyDispatchedForVsync) {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000158 SFTRACE_FORMAT_INSTANT("alreadyDispatchedForVsync");
Ady Abraham4335afd2023-12-18 19:10:47 -0800159 return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + mMinVsyncDistance,
160 *mLastDispatchTime);
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700161 }
162
163 if (nextVsyncTooClose) {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000164 SFTRACE_FORMAT_INSTANT("nextVsyncTooClose");
Ady Abraham4335afd2023-12-18 19:10:47 -0800165 return tracker.nextAnticipatedVSyncTimeFrom(*mLastDispatchTime + currentPeriod,
166 *mLastDispatchTime + currentPeriod);
Ady Abraham3fcfd8b2022-07-12 12:31:00 -0700167 }
168
169 return nextVsyncTime;
170}
171
Ady Abraham20024aa2024-03-05 01:32:49 +0000172auto VSyncDispatchTimerQueueEntry::getArmedInfo(VSyncTracker& tracker, nsecs_t now,
173 VSyncDispatch::ScheduleTiming timing,
174 std::optional<ArmingInfo> armedInfo) const
175 -> ArmingInfo {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000176 SFTRACE_NAME("VSyncDispatchTimerQueueEntry::getArmedInfo");
Ady Abrahamda8af4c2024-02-14 00:24:34 +0000177 const auto earliestReadyBy = now + timing.workDuration + timing.readyDuration;
178 const auto earliestVsync = std::max(earliestReadyBy, timing.lastVsync);
179
180 const auto nextVsyncTime =
181 adjustVsyncIfNeeded(tracker, /*nextVsyncTime*/
182 tracker.nextAnticipatedVSyncTimeFrom(earliestVsync,
183 timing.lastVsync));
184 const auto nextReadyTime = nextVsyncTime - timing.readyDuration;
185 const auto nextWakeupTime = nextReadyTime - timing.workDuration;
186
Ady Abraham20024aa2024-03-05 01:32:49 +0000187 if (FlagManager::getInstance().dont_skip_on_early_ro()) {
188 bool const wouldSkipAVsyncTarget =
189 armedInfo && (nextVsyncTime > (armedInfo->mActualVsyncTime + mMinVsyncDistance));
190 bool const wouldSkipAWakeup =
191 armedInfo && (nextWakeupTime > (armedInfo->mActualWakeupTime + mMinVsyncDistance));
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000192 SFTRACE_FORMAT_INSTANT("%s: wouldSkipAVsyncTarget=%d wouldSkipAWakeup=%d", mName.c_str(),
193 wouldSkipAVsyncTarget, wouldSkipAWakeup);
Ady Abraham20024aa2024-03-05 01:32:49 +0000194 if (wouldSkipAVsyncTarget || wouldSkipAWakeup) {
195 return *armedInfo;
196 }
Ady Abrahamda8af4c2024-02-14 00:24:34 +0000197 }
198
199 return ArmingInfo{nextWakeupTime, nextVsyncTime, nextReadyTime};
200}
201
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800202void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000203 SFTRACE_NAME("VSyncDispatchTimerQueueEntry::update");
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700204 if (!mArmedInfo && !mWorkloadUpdateInfo) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700205 return;
206 }
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700207
208 if (mWorkloadUpdateInfo) {
Ady Abraham20024aa2024-03-05 01:32:49 +0000209 const auto workDelta = mWorkloadUpdateInfo->workDuration - mScheduleTiming.workDuration;
210 const auto readyDelta = mWorkloadUpdateInfo->readyDuration - mScheduleTiming.readyDuration;
211 const auto lastVsyncDelta = mWorkloadUpdateInfo->lastVsync - mScheduleTiming.lastVsync;
ramindani92ab9872024-07-26 15:09:37 -0700212 const auto lastCommittedVsyncDelta =
213 mWorkloadUpdateInfo->committedVsyncOpt.value_or(mWorkloadUpdateInfo->lastVsync) -
214 mScheduleTiming.committedVsyncOpt.value_or(mScheduleTiming.lastVsync);
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000215 SFTRACE_FORMAT_INSTANT("Workload updated workDelta=%" PRId64 " readyDelta=%" PRId64
ramindani92ab9872024-07-26 15:09:37 -0700216 " lastVsyncDelta=%" PRId64 " committedVsyncDelta=%" PRId64,
217 workDelta, readyDelta, lastVsyncDelta, lastCommittedVsyncDelta);
Ady Abraham9c53ee72020-07-22 21:16:18 -0700218 mScheduleTiming = *mWorkloadUpdateInfo;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700219 mWorkloadUpdateInfo.reset();
220 }
221
Ady Abraham20024aa2024-03-05 01:32:49 +0000222 mArmedInfo = getArmedInfo(tracker, now, mScheduleTiming, mArmedInfo);
Kevin DuBois305bef12019-10-09 13:23:27 -0700223}
224
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800225void VSyncDispatchTimerQueueEntry::disarm() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700226 mArmedInfo.reset();
227}
228
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800229nsecs_t VSyncDispatchTimerQueueEntry::executing() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700230 mLastDispatchTime = mArmedInfo->mActualVsyncTime;
231 disarm();
232 return *mLastDispatchTime;
233}
234
Ady Abraham9c53ee72020-07-22 21:16:18 -0700235void VSyncDispatchTimerQueueEntry::callback(nsecs_t vsyncTimestamp, nsecs_t wakeupTimestamp,
236 nsecs_t deadlineTimestamp) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700237 {
238 std::lock_guard<std::mutex> lk(mRunningMutex);
239 mRunning = true;
240 }
241
Ady Abraham9c53ee72020-07-22 21:16:18 -0700242 mCallback(vsyncTimestamp, wakeupTimestamp, deadlineTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700243
244 std::lock_guard<std::mutex> lk(mRunningMutex);
245 mRunning = false;
246 mCv.notify_all();
247}
248
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800249void VSyncDispatchTimerQueueEntry::ensureNotRunning() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700250 std::unique_lock<std::mutex> lk(mRunningMutex);
251 mCv.wait(lk, [this]() REQUIRES(mRunningMutex) { return !mRunning; });
252}
253
Ady Abraham5e7371c2020-03-24 14:47:24 -0700254void VSyncDispatchTimerQueueEntry::dump(std::string& result) const {
255 std::lock_guard<std::mutex> lk(mRunningMutex);
256 std::string armedInfo;
257 if (mArmedInfo) {
Ady Abraham9c53ee72020-07-22 21:16:18 -0700258 StringAppendF(&armedInfo,
259 "[wake up in %.2fms deadline in %.2fms for vsync %.2fms from now]",
Ady Abraham5e7371c2020-03-24 14:47:24 -0700260 (mArmedInfo->mActualWakeupTime - systemTime()) / 1e6f,
Ady Abraham9c53ee72020-07-22 21:16:18 -0700261 (mArmedInfo->mActualReadyTime - systemTime()) / 1e6f,
Ady Abraham5e7371c2020-03-24 14:47:24 -0700262 (mArmedInfo->mActualVsyncTime - systemTime()) / 1e6f);
263 }
264
265 StringAppendF(&result, "\t\t%s: %s %s\n", mName.c_str(),
266 mRunning ? "(in callback function)" : "", armedInfo.c_str());
Ady Abraham9c53ee72020-07-22 21:16:18 -0700267 StringAppendF(&result,
ramindani92ab9872024-07-26 15:09:37 -0700268 "\t\t\tworkDuration: %.2fms readyDuration: %.2fms "
269 "lastVsync: %.2fms relative to now "
270 "committedVsync: %.2fms relative to now\n",
Ady Abraham9c53ee72020-07-22 21:16:18 -0700271 mScheduleTiming.workDuration / 1e6f, mScheduleTiming.readyDuration / 1e6f,
ramindani92ab9872024-07-26 15:09:37 -0700272 (mScheduleTiming.lastVsync - systemTime()) / 1e6f,
273 (mScheduleTiming.committedVsyncOpt.value_or(mScheduleTiming.lastVsync) -
274 systemTime()) /
275 1e6f);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700276
277 if (mLastDispatchTime) {
278 StringAppendF(&result, "\t\t\tmLastDispatchTime: %.2fms ago\n",
279 (systemTime() - *mLastDispatchTime) / 1e6f);
280 } else {
281 StringAppendF(&result, "\t\t\tmLastDispatchTime unknown\n");
282 }
283}
284
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800285VSyncDispatchTimerQueue::VSyncDispatchTimerQueue(std::unique_ptr<TimeKeeper> tk,
Leon Scroggins III67388622023-02-06 20:36:20 -0500286 VsyncSchedule::TrackerPtr tracker,
287 nsecs_t timerSlack, nsecs_t minVsyncDistance)
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800288 : mTimeKeeper(std::move(tk)),
Leon Scroggins III67388622023-02-06 20:36:20 -0500289 mTracker(std::move(tracker)),
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800290 mTimerSlack(timerSlack),
291 mMinVsyncDistance(minVsyncDistance) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700292
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800293VSyncDispatchTimerQueue::~VSyncDispatchTimerQueue() {
Ady Abraham8cb21882020-08-26 18:22:05 -0700294 std::lock_guard lock(mMutex);
en.liu07e0e292023-07-05 19:01:52 +0800295 mRunning = false;
Kevin DuBois305bef12019-10-09 13:23:27 -0700296 cancelTimer();
Leon Scroggins III07738132023-04-24 11:43:53 -0400297 for (auto& [_, entry] : mCallbacks) {
298 ALOGE("Forgot to unregister a callback on VSyncDispatch!");
299 entry->ensureNotRunning();
300 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700301}
302
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800303void VSyncDispatchTimerQueue::cancelTimer() {
Kevin DuBois305bef12019-10-09 13:23:27 -0700304 mIntendedWakeupTime = kInvalidTime;
305 mTimeKeeper->alarmCancel();
306}
307
Ady Abrahamb491c902020-08-15 15:47:56 -0700308void VSyncDispatchTimerQueue::setTimer(nsecs_t targetTime, nsecs_t /*now*/) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700309 mIntendedWakeupTime = targetTime;
Ady Abrahamb491c902020-08-15 15:47:56 -0700310 mTimeKeeper->alarmAt(std::bind(&VSyncDispatchTimerQueue::timerCallback, this),
311 mIntendedWakeupTime);
Ady Abraham75398722020-04-07 14:08:45 -0700312 mLastTimerSchedule = mTimeKeeper->now();
Kevin DuBois305bef12019-10-09 13:23:27 -0700313}
314
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800315void VSyncDispatchTimerQueue::rearmTimer(nsecs_t now) {
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500316 rearmTimerSkippingUpdateFor(now, mCallbacks.cend());
Kevin DuBois305bef12019-10-09 13:23:27 -0700317}
318
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800319void VSyncDispatchTimerQueue::rearmTimerSkippingUpdateFor(
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500320 nsecs_t now, CallbackMap::const_iterator skipUpdateIt) {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000321 SFTRACE_CALL();
Kevin DuBois305bef12019-10-09 13:23:27 -0700322 std::optional<nsecs_t> min;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800323 std::optional<nsecs_t> targetVsync;
324 std::optional<std::string_view> nextWakeupName;
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500325 for (auto it = mCallbacks.cbegin(); it != mCallbacks.cend(); ++it) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700326 auto& callback = it->second;
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700327 if (!callback->wakeupTime() && !callback->hasPendingWorkloadUpdate()) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700328 continue;
329 }
330
331 if (it != skipUpdateIt) {
Leon Scroggins III67388622023-02-06 20:36:20 -0500332 callback->update(*mTracker, now);
Kevin DuBois305bef12019-10-09 13:23:27 -0700333 }
Ady Abraham20024aa2024-03-05 01:32:49 +0000334
335 traceEntry(*callback, now);
336
337 const auto wakeupTime = *callback->wakeupTime();
Dominik Laskowski62eff352021-12-06 09:59:41 -0800338 if (!min || *min > wakeupTime) {
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800339 nextWakeupName = callback->name();
Kevin DuBois305bef12019-10-09 13:23:27 -0700340 min = wakeupTime;
Kevin DuBoisecb1f0d2019-12-12 10:47:41 -0800341 targetVsync = callback->targetVsync();
Kevin DuBois305bef12019-10-09 13:23:27 -0700342 }
343 }
344
Dominik Laskowski62eff352021-12-06 09:59:41 -0800345 if (min && min < mIntendedWakeupTime) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700346 setTimer(*min, now);
347 } else {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000348 SFTRACE_NAME("cancel timer");
Kevin DuBois305bef12019-10-09 13:23:27 -0700349 cancelTimer();
350 }
351}
352
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800353void VSyncDispatchTimerQueue::timerCallback() {
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000354 SFTRACE_CALL();
Kevin DuBois305bef12019-10-09 13:23:27 -0700355 struct Invocation {
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800356 std::shared_ptr<VSyncDispatchTimerQueueEntry> callback;
Kevin DuBois2968afc2020-01-14 09:48:50 -0800357 nsecs_t vsyncTimestamp;
358 nsecs_t wakeupTimestamp;
Ady Abraham9c53ee72020-07-22 21:16:18 -0700359 nsecs_t deadlineTimestamp;
Kevin DuBois305bef12019-10-09 13:23:27 -0700360 };
361 std::vector<Invocation> invocations;
362 {
Ady Abraham8cb21882020-08-26 18:22:05 -0700363 std::lock_guard lock(mMutex);
en.liu07e0e292023-07-05 19:01:52 +0800364 if (!mRunning) {
365 ALOGD("TimerQueue is not running. Skipping callback.");
366 return;
367 }
Kevin DuBoisf9477832020-07-16 10:21:36 -0700368 auto const now = mTimeKeeper->now();
369 mLastTimerCallback = now;
Kevin DuBois305bef12019-10-09 13:23:27 -0700370 for (auto it = mCallbacks.begin(); it != mCallbacks.end(); it++) {
371 auto& callback = it->second;
372 auto const wakeupTime = callback->wakeupTime();
373 if (!wakeupTime) {
374 continue;
375 }
376
Ady Abraham20024aa2024-03-05 01:32:49 +0000377 traceEntry(*callback, now);
Ady Abraham9633f8e2024-03-04 19:38:12 +0000378
Ady Abraham20024aa2024-03-05 01:32:49 +0000379 auto const readyTime = callback->readyTime();
Kevin DuBoisf9477832020-07-16 10:21:36 -0700380 auto const lagAllowance = std::max(now - mIntendedWakeupTime, static_cast<nsecs_t>(0));
381 if (*wakeupTime < mIntendedWakeupTime + mTimerSlack + lagAllowance) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700382 callback->executing();
Ady Abraham9c53ee72020-07-22 21:16:18 -0700383 invocations.emplace_back(Invocation{callback, *callback->lastExecutedVsyncTarget(),
384 *wakeupTime, *readyTime});
Kevin DuBois305bef12019-10-09 13:23:27 -0700385 }
386 }
387
388 mIntendedWakeupTime = kInvalidTime;
389 rearmTimer(mTimeKeeper->now());
390 }
391
392 for (auto const& invocation : invocations) {
Ady Abraham20024aa2024-03-05 01:32:49 +0000393 ftl::Concat trace(ftl::truncated<5>(invocation.callback->name()));
Vishnu Nairbe0ad902024-06-27 23:38:43 +0000394 SFTRACE_FORMAT("%s: %s", __func__, trace.c_str());
Ady Abraham9c53ee72020-07-22 21:16:18 -0700395 invocation.callback->callback(invocation.vsyncTimestamp, invocation.wakeupTimestamp,
396 invocation.deadlineTimestamp);
Kevin DuBois305bef12019-10-09 13:23:27 -0700397 }
398}
399
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800400VSyncDispatchTimerQueue::CallbackToken VSyncDispatchTimerQueue::registerCallback(
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800401 Callback callback, std::string callbackName) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700402 std::lock_guard lock(mMutex);
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500403 return mCallbacks
Dominik Laskowski43baf902023-11-17 18:13:11 -0500404 .try_emplace(++mCallbackToken,
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500405 std::make_shared<VSyncDispatchTimerQueueEntry>(std::move(callbackName),
406 std::move(callback),
407 mMinVsyncDistance))
408 .first->first;
Kevin DuBois305bef12019-10-09 13:23:27 -0700409}
410
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800411void VSyncDispatchTimerQueue::unregisterCallback(CallbackToken token) {
412 std::shared_ptr<VSyncDispatchTimerQueueEntry> entry = nullptr;
Kevin DuBois305bef12019-10-09 13:23:27 -0700413 {
Ady Abraham8cb21882020-08-26 18:22:05 -0700414 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700415 auto it = mCallbacks.find(token);
416 if (it != mCallbacks.end()) {
417 entry = it->second;
Dominik Laskowski0f3e5b92023-11-17 18:03:41 -0500418 mCallbacks.erase(it->first);
Kevin DuBois305bef12019-10-09 13:23:27 -0700419 }
420 }
421
422 if (entry) {
423 entry->ensureNotRunning();
424 }
425}
426
ramindani32a88b12024-01-31 18:45:30 -0800427std::optional<ScheduleResult> VSyncDispatchTimerQueue::schedule(CallbackToken token,
428 ScheduleTiming scheduleTiming) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800429 std::lock_guard lock(mMutex);
430 return scheduleLocked(token, scheduleTiming);
431}
Kevin DuBois305bef12019-10-09 13:23:27 -0700432
ramindani32a88b12024-01-31 18:45:30 -0800433std::optional<ScheduleResult> VSyncDispatchTimerQueue::scheduleLocked(
434 CallbackToken token, ScheduleTiming scheduleTiming) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800435 auto it = mCallbacks.find(token);
436 if (it == mCallbacks.end()) {
437 return {};
438 }
439 auto& callback = it->second;
440 auto const now = mTimeKeeper->now();
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700441
Ady Abraham011f8ba2022-11-22 15:09:07 -0800442 /* If the timer thread will run soon, we'll apply this work update via the callback
443 * timer recalculation to avoid cancelling a callback that is about to fire. */
444 auto const rearmImminent = now > mIntendedWakeupTime;
445 if (CC_UNLIKELY(rearmImminent)) {
Ady Abrahamda8af4c2024-02-14 00:24:34 +0000446 return callback->addPendingWorkloadUpdate(*mTracker, now, scheduleTiming);
Ady Abraham011f8ba2022-11-22 15:09:07 -0800447 }
Kevin DuBois5c18c1c2020-05-27 15:50:50 -0700448
ramindani558f4a92024-02-16 15:49:23 -0800449 const auto result = callback->schedule(scheduleTiming, *mTracker, now);
ramindani32a88b12024-01-31 18:45:30 -0800450
Ady Abraham011f8ba2022-11-22 15:09:07 -0800451 if (callback->wakeupTime() < mIntendedWakeupTime - mTimerSlack) {
452 rearmTimerSkippingUpdateFor(now, it);
Kevin DuBois305bef12019-10-09 13:23:27 -0700453 }
454
ramindani558f4a92024-02-16 15:49:23 -0800455 return result;
Kevin DuBois305bef12019-10-09 13:23:27 -0700456}
457
ramindani32a88b12024-01-31 18:45:30 -0800458std::optional<ScheduleResult> VSyncDispatchTimerQueue::update(CallbackToken token,
459 ScheduleTiming scheduleTiming) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800460 std::lock_guard lock(mMutex);
461 const auto it = mCallbacks.find(token);
462 if (it == mCallbacks.end()) {
463 return {};
464 }
465
466 auto& callback = it->second;
467 if (!callback->targetVsync().has_value()) {
468 return {};
469 }
470
471 return scheduleLocked(token, scheduleTiming);
472}
473
Kevin DuBoise4f27a82019-11-12 11:41:41 -0800474CancelResult VSyncDispatchTimerQueue::cancel(CallbackToken token) {
Ady Abraham8cb21882020-08-26 18:22:05 -0700475 std::lock_guard lock(mMutex);
Kevin DuBois305bef12019-10-09 13:23:27 -0700476
477 auto it = mCallbacks.find(token);
478 if (it == mCallbacks.end()) {
479 return CancelResult::Error;
480 }
481 auto& callback = it->second;
482
Kevin DuBoisb340b732020-06-16 09:07:35 -0700483 auto const wakeupTime = callback->wakeupTime();
484 if (wakeupTime) {
Kevin DuBois305bef12019-10-09 13:23:27 -0700485 callback->disarm();
Kevin DuBoisb340b732020-06-16 09:07:35 -0700486
487 if (*wakeupTime == mIntendedWakeupTime) {
488 mIntendedWakeupTime = kInvalidTime;
489 rearmTimer(mTimeKeeper->now());
490 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700491 return CancelResult::Cancelled;
492 }
493 return CancelResult::TooLate;
494}
495
Ady Abraham5e7371c2020-03-24 14:47:24 -0700496void VSyncDispatchTimerQueue::dump(std::string& result) const {
Ady Abraham8cb21882020-08-26 18:22:05 -0700497 std::lock_guard lock(mMutex);
Ady Abraham75398722020-04-07 14:08:45 -0700498 StringAppendF(&result, "\tTimer:\n");
499 mTimeKeeper->dump(result);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700500 StringAppendF(&result, "\tmTimerSlack: %.2fms mMinVsyncDistance: %.2fms\n", mTimerSlack / 1e6f,
501 mMinVsyncDistance / 1e6f);
502 StringAppendF(&result, "\tmIntendedWakeupTime: %.2fms from now\n",
Ady Abraham75398722020-04-07 14:08:45 -0700503 (mIntendedWakeupTime - mTimeKeeper->now()) / 1e6f);
504 StringAppendF(&result, "\tmLastTimerCallback: %.2fms ago mLastTimerSchedule: %.2fms ago\n",
505 (mTimeKeeper->now() - mLastTimerCallback) / 1e6f,
506 (mTimeKeeper->now() - mLastTimerSchedule) / 1e6f);
Ady Abraham5e7371c2020-03-24 14:47:24 -0700507 StringAppendF(&result, "\tCallbacks:\n");
508 for (const auto& [token, entry] : mCallbacks) {
509 entry->dump(result);
510 }
511}
512
Leon Scroggins III67388622023-02-06 20:36:20 -0500513VSyncCallbackRegistration::VSyncCallbackRegistration(std::shared_ptr<VSyncDispatch> dispatch,
Dominik Laskowski4e0d20d2021-12-06 11:31:02 -0800514 VSyncDispatch::Callback callback,
515 std::string callbackName)
Leon Scroggins III67388622023-02-06 20:36:20 -0500516 : mDispatch(std::move(dispatch)),
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400517 mToken(mDispatch->registerCallback(std::move(callback), std::move(callbackName))) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700518
519VSyncCallbackRegistration::VSyncCallbackRegistration(VSyncCallbackRegistration&& other)
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400520 : mDispatch(std::move(other.mDispatch)), mToken(std::exchange(other.mToken, std::nullopt)) {}
Kevin DuBois305bef12019-10-09 13:23:27 -0700521
522VSyncCallbackRegistration& VSyncCallbackRegistration::operator=(VSyncCallbackRegistration&& other) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400523 if (this == &other) return *this;
524 if (mToken) {
525 mDispatch->unregisterCallback(*mToken);
526 }
Kevin DuBois305bef12019-10-09 13:23:27 -0700527 mDispatch = std::move(other.mDispatch);
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400528 mToken = std::exchange(other.mToken, std::nullopt);
Kevin DuBois305bef12019-10-09 13:23:27 -0700529 return *this;
530}
531
532VSyncCallbackRegistration::~VSyncCallbackRegistration() {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400533 if (mToken) mDispatch->unregisterCallback(*mToken);
Kevin DuBois305bef12019-10-09 13:23:27 -0700534}
535
ramindani32a88b12024-01-31 18:45:30 -0800536std::optional<ScheduleResult> VSyncCallbackRegistration::schedule(
537 VSyncDispatch::ScheduleTiming scheduleTiming) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400538 if (!mToken) {
Ady Abrahamb5d3afa2021-05-07 11:22:23 -0700539 return std::nullopt;
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800540 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400541 return mDispatch->schedule(*mToken, scheduleTiming);
Kevin DuBois305bef12019-10-09 13:23:27 -0700542}
543
ramindani32a88b12024-01-31 18:45:30 -0800544std::optional<ScheduleResult> VSyncCallbackRegistration::update(
545 VSyncDispatch::ScheduleTiming scheduleTiming) {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400546 if (!mToken) {
Ady Abraham011f8ba2022-11-22 15:09:07 -0800547 return std::nullopt;
548 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400549 return mDispatch->update(*mToken, scheduleTiming);
Ady Abraham011f8ba2022-11-22 15:09:07 -0800550}
551
Kevin DuBois305bef12019-10-09 13:23:27 -0700552CancelResult VSyncCallbackRegistration::cancel() {
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400553 if (!mToken) {
Kevin DuBoisc94ca832019-11-26 12:56:24 -0800554 return CancelResult::Error;
555 }
Leon Scroggins III6c440ae2023-04-21 15:01:03 -0400556 return mDispatch->cancel(*mToken);
Kevin DuBois305bef12019-10-09 13:23:27 -0700557}
558
559} // namespace android::scheduler