SF: VSyncTracker, clear timestamps on beginResync
DispSync would clear its internal model around power events, as the
vsync timings during power mode changes are not accurate for screen-on
vsync prediction. DispSync uses the beginResync signal for this, and the
new system does the same (although once DispSync is deprecated,
begin/endResync should go away too).
Fixes: 146050690
Test: Dogfooding blueline
Test: 2 new unit tests
Change-Id: Ie4b607029516dcea0e5d65afca75a7017bf63e12
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 3b99a58..68d58f0 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -38,7 +38,7 @@
kMinimumSamplesForPrediction(minimumSamplesForPrediction),
kOutlierTolerancePercent(std::min(outlierTolerancePercent, kMaxPercent)),
mIdealPeriod(idealPeriod) {
- mRateMap[mIdealPeriod] = {idealPeriod, 0};
+ resetModel();
}
inline size_t VSyncPredictor::next(int i) const {
@@ -199,6 +199,10 @@
mRateMap[mIdealPeriod] = {period, 0};
}
+ clearTimestamps();
+}
+
+void VSyncPredictor::clearTimestamps() {
if (!timestamps.empty()) {
mKnownTimestamp = *std::max_element(timestamps.begin(), timestamps.end());
timestamps.clear();
@@ -223,4 +227,10 @@
return needsMoreSamples;
}
+void VSyncPredictor::resetModel() {
+ std::lock_guard<std::mutex> lk(mMutex);
+ mRateMap[mIdealPeriod] = {mIdealPeriod, 0};
+ clearTimestamps();
+}
+
} // namespace android::scheduler
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index 4210b3c..41e5469 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -40,6 +40,7 @@
void addVsyncTimestamp(nsecs_t timestamp) final;
nsecs_t nextAnticipatedVSyncTimeFrom(nsecs_t timePoint) const final;
nsecs_t currentPeriod() const final;
+ void resetModel() final;
/*
* Inform the model that the period is anticipated to change to a new value.
@@ -48,7 +49,7 @@
*
* \param [in] period The new period that should be used.
*/
- void setPeriod(nsecs_t period);
+ void setPeriod(nsecs_t period) final;
/* Query if the model is in need of more samples to make a prediction at timePoint.
* \param [in] timePoint The timePoint to inquire of.
@@ -61,6 +62,7 @@
private:
VSyncPredictor(VSyncPredictor const&) = delete;
VSyncPredictor& operator=(VSyncPredictor const&) = delete;
+ void clearTimestamps() REQUIRES(mMutex);
size_t const kHistorySize;
size_t const kMinimumSamplesForPrediction;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index a652053..57e05d3 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -185,7 +185,9 @@
return mTracker->currentPeriod();
}
-void VSyncReactor::beginResync() {}
+void VSyncReactor::beginResync() {
+ mTracker->resetModel();
+}
void VSyncReactor::endResync() {}
diff --git a/services/surfaceflinger/Scheduler/VSyncTracker.h b/services/surfaceflinger/Scheduler/VSyncTracker.h
index 6be63fe..2b27884 100644
--- a/services/surfaceflinger/Scheduler/VSyncTracker.h
+++ b/services/surfaceflinger/Scheduler/VSyncTracker.h
@@ -61,6 +61,9 @@
*/
virtual void setPeriod(nsecs_t period) = 0;
+ /* Inform the tracker that the samples it has are not accurate for prediction. */
+ virtual void resetModel() = 0;
+
protected:
VSyncTracker(VSyncTracker const&) = delete;
VSyncTracker& operator=(VSyncTracker const&) = delete;
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
index 5846c77..9c3d32e 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchRealtimeTest.cpp
@@ -50,6 +50,7 @@
nsecs_t currentPeriod() const final { return mPeriod; }
void setPeriod(nsecs_t) final {}
+ void resetModel() final {}
private:
nsecs_t const mPeriod;
@@ -83,6 +84,7 @@
}
void setPeriod(nsecs_t) final {}
+ void resetModel() final {}
private:
std::mutex mutable mMutex;
diff --git a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
index 5aff429..b23159b 100644
--- a/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncDispatchTimerQueueTest.cpp
@@ -41,6 +41,7 @@
MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
MOCK_METHOD1(setPeriod, void(nsecs_t));
+ MOCK_METHOD0(resetModel, void());
nsecs_t nextVSyncTime(nsecs_t timePoint) const {
if (timePoint % mPeriod == 0) {
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 4cb6a38..afa1481 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -351,4 +351,19 @@
EXPECT_THAT(prediction, Ge(timePoint));
}
+TEST_F(VSyncPredictorTest, resetsWhenInstructed) {
+ auto const idealPeriod = 10000;
+ auto const realPeriod = 10500;
+ tracker.setPeriod(idealPeriod);
+ for (auto i = 0; i < kMinimumSamplesForPrediction; i++) {
+ tracker.addVsyncTimestamp(i * realPeriod);
+ }
+
+ EXPECT_THAT(std::get<0>(tracker.getVSyncPredictionModel()),
+ IsCloseTo(realPeriod, mMaxRoundingError));
+ tracker.resetModel();
+ EXPECT_THAT(std::get<0>(tracker.getVSyncPredictionModel()),
+ IsCloseTo(idealPeriod, mMaxRoundingError));
+}
+
} // namespace android::scheduler
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 72f8bb9..d5e0660 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -39,6 +39,7 @@
MOCK_CONST_METHOD1(nextAnticipatedVSyncTimeFrom, nsecs_t(nsecs_t));
MOCK_CONST_METHOD0(currentPeriod, nsecs_t());
MOCK_METHOD1(setPeriod, void(nsecs_t));
+ MOCK_METHOD0(resetModel, void());
};
class VSyncTrackerWrapper : public VSyncTracker {
@@ -50,7 +51,8 @@
return mTracker->nextAnticipatedVSyncTimeFrom(timePoint);
}
nsecs_t currentPeriod() const final { return mTracker->currentPeriod(); }
- void setPeriod(nsecs_t period) { mTracker->setPeriod(period); }
+ void setPeriod(nsecs_t period) final { mTracker->setPeriod(period); }
+ void resetModel() final { mTracker->resetModel(); }
private:
std::shared_ptr<VSyncTracker> const mTracker;
@@ -515,6 +517,11 @@
mReactor.addEventListener(mName, negativePhase, &outerCb, lastCallbackTime);
}
+TEST_F(VSyncReactorTest, beginResyncResetsModel) {
+ EXPECT_CALL(*mMockTracker, resetModel());
+ mReactor.beginResync();
+}
+
using VSyncReactorDeathTest = VSyncReactorTest;
TEST_F(VSyncReactorDeathTest, invalidRemoval) {
mReactor.addEventListener(mName, mPhase, &outerCb, lastCallbackTime);