Skip to content

Commit 74962b7

Browse files
Treehugger RobotAndroid (Google) Code Review
authored andcommitted
Merge "SF: VSyncDispatchTimerQueueEntry::update should not skip a frame" into main
2 parents 69aea02 + da8af4c commit 74962b7

4 files changed

Lines changed: 82 additions & 35 deletions

File tree

services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.cpp

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -43,16 +43,6 @@ nsecs_t getExpectedCallbackTime(nsecs_t nextVsyncTime,
4343
return nextVsyncTime - timing.readyDuration - timing.workDuration;
4444
}
4545

46-
nsecs_t getExpectedCallbackTime(VSyncTracker& tracker, nsecs_t now,
47-
const VSyncDispatch::ScheduleTiming& timing) {
48-
const auto nextVsyncTime =
49-
tracker.nextAnticipatedVSyncTimeFrom(std::max(timing.lastVsync,
50-
now + timing.workDuration +
51-
timing.readyDuration),
52-
timing.lastVsync);
53-
return getExpectedCallbackTime(nextVsyncTime, timing);
54-
}
55-
5646
} // namespace
5747

5848
VSyncDispatch::~VSyncDispatch() = default;
@@ -128,8 +118,11 @@ ScheduleResult VSyncDispatchTimerQueueEntry::schedule(VSyncDispatch::ScheduleTim
128118
return nextWakeupTime;
129119
}
130120

131-
void VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(VSyncDispatch::ScheduleTiming timing) {
121+
nsecs_t VSyncDispatchTimerQueueEntry::addPendingWorkloadUpdate(
122+
VSyncTracker& tracker, nsecs_t now, VSyncDispatch::ScheduleTiming timing) {
132123
mWorkloadUpdateInfo = timing;
124+
const auto armedInfo = update(tracker, now, timing, mArmedInfo);
125+
return armedInfo.mActualWakeupTime;
133126
}
134127

135128
bool VSyncDispatchTimerQueueEntry::hasPendingWorkloadUpdate() const {
@@ -157,6 +150,31 @@ nsecs_t VSyncDispatchTimerQueueEntry::adjustVsyncIfNeeded(VSyncTracker& tracker,
157150
return nextVsyncTime;
158151
}
159152

153+
auto VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now,
154+
VSyncDispatch::ScheduleTiming timing,
155+
std::optional<ArmingInfo> armedInfo) const -> ArmingInfo {
156+
const auto earliestReadyBy = now + timing.workDuration + timing.readyDuration;
157+
const auto earliestVsync = std::max(earliestReadyBy, timing.lastVsync);
158+
159+
const auto nextVsyncTime =
160+
adjustVsyncIfNeeded(tracker, /*nextVsyncTime*/
161+
tracker.nextAnticipatedVSyncTimeFrom(earliestVsync,
162+
timing.lastVsync));
163+
const auto nextReadyTime = nextVsyncTime - timing.readyDuration;
164+
const auto nextWakeupTime = nextReadyTime - timing.workDuration;
165+
166+
bool const wouldSkipAVsyncTarget =
167+
armedInfo && (nextVsyncTime > (armedInfo->mActualVsyncTime + mMinVsyncDistance));
168+
bool const wouldSkipAWakeup =
169+
armedInfo && (nextWakeupTime > (armedInfo->mActualWakeupTime + mMinVsyncDistance));
170+
if (FlagManager::getInstance().dont_skip_on_early_ro() &&
171+
(wouldSkipAVsyncTarget || wouldSkipAWakeup)) {
172+
return *armedInfo;
173+
}
174+
175+
return ArmingInfo{nextWakeupTime, nextVsyncTime, nextReadyTime};
176+
}
177+
160178
void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) {
161179
if (!mArmedInfo && !mWorkloadUpdateInfo) {
162180
return;
@@ -167,17 +185,7 @@ void VSyncDispatchTimerQueueEntry::update(VSyncTracker& tracker, nsecs_t now) {
167185
mWorkloadUpdateInfo.reset();
168186
}
169187

170-
const auto earliestReadyBy = now + mScheduleTiming.workDuration + mScheduleTiming.readyDuration;
171-
const auto earliestVsync = std::max(earliestReadyBy, mScheduleTiming.lastVsync);
172-
173-
const auto nextVsyncTime =
174-
adjustVsyncIfNeeded(tracker, /*nextVsyncTime*/
175-
tracker.nextAnticipatedVSyncTimeFrom(earliestVsync,
176-
mScheduleTiming.lastVsync));
177-
const auto nextReadyTime = nextVsyncTime - mScheduleTiming.readyDuration;
178-
const auto nextWakeupTime = nextReadyTime - mScheduleTiming.workDuration;
179-
180-
mArmedInfo = {nextWakeupTime, nextVsyncTime, nextReadyTime};
188+
mArmedInfo = update(tracker, now, mScheduleTiming, mArmedInfo);
181189
}
182190

183191
void VSyncDispatchTimerQueueEntry::disarm() {
@@ -394,8 +402,7 @@ ScheduleResult VSyncDispatchTimerQueue::scheduleLocked(CallbackToken token,
394402
* timer recalculation to avoid cancelling a callback that is about to fire. */
395403
auto const rearmImminent = now > mIntendedWakeupTime;
396404
if (CC_UNLIKELY(rearmImminent)) {
397-
callback->addPendingWorkloadUpdate(scheduleTiming);
398-
return getExpectedCallbackTime(*mTracker, now, scheduleTiming);
405+
return callback->addPendingWorkloadUpdate(*mTracker, now, scheduleTiming);
399406
}
400407

401408
const ScheduleResult result = callback->schedule(scheduleTiming, *mTracker, now);

services/surfaceflinger/Scheduler/VSyncDispatchTimerQueue.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class VSyncDispatchTimerQueueEntry {
6969

7070
// Adds a pending upload of the earliestVSync and workDuration that will be applied on the next
7171
// call to update()
72-
void addPendingWorkloadUpdate(VSyncDispatch::ScheduleTiming);
72+
nsecs_t addPendingWorkloadUpdate(VSyncTracker&, nsecs_t now, VSyncDispatch::ScheduleTiming);
7373

7474
// Checks if there is a pending update to the workload, returning true if so.
7575
bool hasPendingWorkloadUpdate() const;
@@ -83,19 +83,22 @@ class VSyncDispatchTimerQueueEntry {
8383
void dump(std::string& result) const;
8484

8585
private:
86+
struct ArmingInfo {
87+
nsecs_t mActualWakeupTime;
88+
nsecs_t mActualVsyncTime;
89+
nsecs_t mActualReadyTime;
90+
};
91+
8692
nsecs_t adjustVsyncIfNeeded(VSyncTracker& tracker, nsecs_t nextVsyncTime) const;
93+
ArmingInfo update(VSyncTracker&, nsecs_t now, VSyncDispatch::ScheduleTiming,
94+
std::optional<ArmingInfo>) const;
8795

8896
const std::string mName;
8997
const VSyncDispatch::Callback mCallback;
9098

9199
VSyncDispatch::ScheduleTiming mScheduleTiming;
92100
const nsecs_t mMinVsyncDistance;
93101

94-
struct ArmingInfo {
95-
nsecs_t mActualWakeupTime;
96-
nsecs_t mActualVsyncTime;
97-
nsecs_t mActualReadyTime;
98-
};
99102
std::optional<ArmingInfo> mArmedInfo;
100103
std::optional<nsecs_t> mLastDispatchTime;
101104

services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,8 @@ void SchedulerFuzzer::fuzzVSyncDispatchTimerQueue() {
175175
auto const wakeup = entry.wakeupTime();
176176
auto const ready = entry.readyTime();
177177
entry.callback(entry.executing(), *wakeup, *ready);
178-
entry.addPendingWorkloadUpdate({.workDuration = mFdp.ConsumeIntegral<nsecs_t>(),
178+
entry.addPendingWorkloadUpdate(*stubTracker, 0,
179+
{.workDuration = mFdp.ConsumeIntegral<nsecs_t>(),
179180
.readyDuration = mFdp.ConsumeIntegral<nsecs_t>(),
180181
.lastVsync = mFdp.ConsumeIntegral<nsecs_t>()});
181182
dump<scheduler::VSyncDispatchTimerQueueEntry>(&entry, &mFdp);

services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -917,6 +917,8 @@ TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminent
917917
// If the same callback tries to reschedule itself after it's too late, timer opts to apply the
918918
// update later, as opposed to blocking the calling thread.
919919
TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminentSameCallback) {
920+
SET_FLAG_FOR_TEST(flags::dont_skip_on_early_ro, false);
921+
920922
Sequence seq;
921923
EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
922924
EXPECT_CALL(mMockClock, alarmAt(_, 1630)).InSequence(seq);
@@ -938,6 +940,37 @@ TEST_F(VSyncDispatchTimerQueueTest, skipsSchedulingIfTimerReschedulingIsImminent
938940
EXPECT_THAT(cb.mCalls.size(), Eq(1));
939941
}
940942

943+
// b/154303580.
944+
// If the same callback tries to reschedule itself after it's too late, timer opts to apply the
945+
// update later, as opposed to blocking the calling thread.
946+
TEST_F(VSyncDispatchTimerQueueTest, doesntSkipSchedulingIfTimerReschedulingIsImminentSameCallback) {
947+
SET_FLAG_FOR_TEST(flags::dont_skip_on_early_ro, true);
948+
949+
Sequence seq;
950+
EXPECT_CALL(mMockClock, alarmAt(_, 600)).InSequence(seq);
951+
EXPECT_CALL(mMockClock, alarmAt(_, 1630)).InSequence(seq);
952+
CountingCallback cb(mDispatch);
953+
954+
auto result =
955+
mDispatch->schedule(cb, {.workDuration = 400, .readyDuration = 0, .lastVsync = 1000});
956+
EXPECT_TRUE(result.has_value());
957+
EXPECT_EQ(600, *result);
958+
959+
mMockClock.setLag(100);
960+
mMockClock.advanceBy(620);
961+
962+
result = mDispatch->schedule(cb, {.workDuration = 370, .readyDuration = 0, .lastVsync = 2000});
963+
EXPECT_TRUE(result.has_value());
964+
EXPECT_EQ(600, *result);
965+
mMockClock.advanceBy(80);
966+
967+
ASSERT_EQ(1, cb.mCalls.size());
968+
EXPECT_EQ(1000, cb.mCalls[0]);
969+
970+
ASSERT_EQ(1, cb.mWakeupTime.size());
971+
EXPECT_EQ(600, cb.mWakeupTime[0]);
972+
}
973+
941974
// b/154303580.
942975
TEST_F(VSyncDispatchTimerQueueTest, skipsRearmingWhenNotNextScheduled) {
943976
Sequence seq;
@@ -1344,14 +1377,17 @@ TEST_F(VSyncDispatchTimerQueueEntryTest, reportsScheduledIfStillTime) {
13441377
.has_value());
13451378
}
13461379

1347-
TEST_F(VSyncDispatchTimerQueueEntryTest, storesPendingUpdatesUntilUpdate) {
1380+
TEST_F(VSyncDispatchTimerQueueEntryTest, storesPendingUpdatesUntilUpdateAndDontSkip) {
13481381
static constexpr auto effectualOffset = 200;
13491382
VSyncDispatchTimerQueueEntry entry(
13501383
"test", [](auto, auto, auto) {}, mVsyncMoveThreshold);
13511384
EXPECT_FALSE(entry.hasPendingWorkloadUpdate());
1352-
entry.addPendingWorkloadUpdate({.workDuration = 100, .readyDuration = 0, .lastVsync = 400});
1353-
entry.addPendingWorkloadUpdate(
1354-
{.workDuration = effectualOffset, .readyDuration = 0, .lastVsync = 400});
1385+
entry.addPendingWorkloadUpdate(*mStubTracker.get(), 0,
1386+
{.workDuration = 100, .readyDuration = 0, .lastVsync = 400});
1387+
entry.addPendingWorkloadUpdate(*mStubTracker.get(), 0,
1388+
{.workDuration = effectualOffset,
1389+
.readyDuration = 0,
1390+
.lastVsync = 400});
13551391
EXPECT_TRUE(entry.hasPendingWorkloadUpdate());
13561392
entry.update(*mStubTracker.get(), 0);
13571393
EXPECT_FALSE(entry.hasPendingWorkloadUpdate());

0 commit comments

Comments
 (0)