Plumb refresh and render rates into shared timeline
* Make the overridden frame rate from the Scheduler public so that
SurfaceFlinger can access it for each uid.
* Add the display refresh rate on each display frame
* Add the application rendering rate on each SurfaceFrame created
* If there is no application rendering rate, then set it to the display
refresh rate.
* Plumb all those metrics into TimeStats.
* Change global metrics to increment for every SurfaceFrame instead of
every DisplayFrame, so that the rendering rate dimension can be
accurately captured.
Bug: 172937287
Test: builds, boots, timestats dump
Change-Id: Icfd4cecfdfa5d6c434661cab91c624eb08e8baea
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index 3f833f4..3f368c3 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -320,6 +320,11 @@
mLastLatchTime = lastLatchTime;
}
+void SurfaceFrame::setRenderRate(Fps renderRate) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mRenderRate = renderRate;
+}
+
std::optional<int32_t> SurfaceFrame::getJankType() const {
std::scoped_lock lock(mMutex);
if (mActuals.presentTime == 0) {
@@ -367,6 +372,9 @@
StringAppendF(&result, "%s", indent.c_str());
StringAppendF(&result, "Owner Pid : %d\n", mOwnerPid);
StringAppendF(&result, "%s", indent.c_str());
+ StringAppendF(&result, "Scheduled rendering rate: %d fps\n",
+ mRenderRate ? mRenderRate->getIntValue() : 0);
+ StringAppendF(&result, "%s", indent.c_str());
StringAppendF(&result, "Present State : %s\n", toString(mPresentState).c_str());
StringAppendF(&result, "%s", indent.c_str());
StringAppendF(&result, "Prediction State : %s\n", toString(mPredictionState).c_str());
@@ -391,9 +399,10 @@
dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime);
}
-void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
- nsecs_t vsyncPeriod) {
+void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, Fps refreshRate) {
std::scoped_lock lock(mMutex);
+
+ const Fps renderRate = mRenderRate ? *mRenderRate : refreshRate;
if (mPresentState != PresentState::Presented) {
// No need to update dropped buffers
return;
@@ -412,13 +421,13 @@
mJankType = JankType::Unknown;
mFramePresentMetadata = FramePresentMetadata::UnknownPresent;
mFrameReadyMetadata = FrameReadyMetadata::UnknownFinish;
- mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType);
+ mTimeStats->incrementJankyFrames(refreshRate, renderRate, mOwnerUid, mLayerName, mJankType);
return;
}
const nsecs_t presentDelta = mActuals.presentTime - mPredictions.presentTime;
const nsecs_t deadlineDelta = mActuals.endTime - mPredictions.endTime;
- const nsecs_t deltaToVsync = std::abs(presentDelta) % vsyncPeriod;
+ const nsecs_t deltaToVsync = std::abs(presentDelta) % refreshRate.getPeriodNsecs();
if (deadlineDelta > mJankClassificationThresholds.deadlineThreshold) {
mFrameReadyMetadata = FrameReadyMetadata::LateFinish;
@@ -440,7 +449,8 @@
if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
// Finish on time, Present early
if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
- deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) {
+ deltaToVsync >= refreshRate.getPeriodNsecs() -
+ mJankClassificationThresholds.presentThreshold) {
// Delta factor of vsync
mJankType = JankType::SurfaceFlingerScheduling;
} else {
@@ -463,7 +473,8 @@
mJankType |= displayFrameJankType;
} else {
if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
- deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) {
+ deltaToVsync >= refreshRate.getPeriodNsecs() -
+ mJankClassificationThresholds.presentThreshold) {
// Delta factor of vsync
mJankType |= JankType::SurfaceFlingerScheduling;
} else {
@@ -482,7 +493,7 @@
}
}
}
- mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType);
+ mTimeStats->incrementJankyFrames(refreshRate, renderRate, mOwnerUid, mLayerName, mJankType);
}
/**
@@ -684,10 +695,10 @@
mCurrentDisplayFrame->addSurfaceFrame(surfaceFrame);
}
-void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, nsecs_t vsyncPeriod) {
+void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, Fps refreshRate) {
ATRACE_CALL();
std::scoped_lock lock(mMutex);
- mCurrentDisplayFrame->onSfWakeUp(token, vsyncPeriod,
+ mCurrentDisplayFrame->onSfWakeUp(token, refreshRate,
mTokenManager.getPredictionsForToken(token), wakeUpTime);
}
@@ -705,11 +716,11 @@
mSurfaceFrames.push_back(surfaceFrame);
}
-void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, nsecs_t vsyncPeriod,
+void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, Fps refreshRate,
std::optional<TimelineItem> predictions,
nsecs_t wakeUpTime) {
mToken = token;
- mVsyncPeriod = vsyncPeriod;
+ mRefreshRate = refreshRate;
if (!predictions) {
mPredictionState = PredictionState::Expired;
} else {
@@ -719,11 +730,6 @@
mSurfaceFlingerActuals.startTime = wakeUpTime;
}
-void FrameTimeline::DisplayFrame::setTokenAndVsyncPeriod(int64_t token, nsecs_t vsyncPeriod) {
- mToken = token;
- mVsyncPeriod = vsyncPeriod;
-}
-
void FrameTimeline::DisplayFrame::setPredictions(PredictionState predictionState,
TimelineItem predictions) {
mPredictionState = predictionState;
@@ -740,14 +746,13 @@
void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) {
mSurfaceFlingerActuals.presentTime = signalTime;
- int32_t totalJankReasons = JankType::None;
// Delta between the expected present and the actual present
const nsecs_t presentDelta =
mSurfaceFlingerActuals.presentTime - mSurfaceFlingerPredictions.presentTime;
// How far off was the presentDelta when compared to the vsyncPeriod. Used in checking if there
// was a prediction error or not.
- nsecs_t deltaToVsync = std::abs(presentDelta) % mVsyncPeriod;
+ nsecs_t deltaToVsync = std::abs(presentDelta) % mRefreshRate.getPeriodNsecs();
if (std::abs(presentDelta) > mJankClassificationThresholds.presentThreshold) {
mFramePresentMetadata = presentDelta > 0 ? FramePresentMetadata::LatePresent
: FramePresentMetadata::EarlyPresent;
@@ -776,8 +781,8 @@
if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
// Finish on time, Present early
if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
- deltaToVsync >=
- (mVsyncPeriod - mJankClassificationThresholds.presentThreshold)) {
+ deltaToVsync >= (mRefreshRate.getPeriodNsecs() -
+ mJankClassificationThresholds.presentThreshold)) {
// Delta is a factor of vsync if its within the presentTheshold on either side
// of the vsyncPeriod. Example: 0-2ms and 9-11ms are both within the threshold
// of the vsyncPeriod if the threshold was 2ms and the vsyncPeriod was 11ms.
@@ -797,8 +802,8 @@
if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
// Finish on time, Present late
if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
- deltaToVsync >=
- (mVsyncPeriod - mJankClassificationThresholds.presentThreshold)) {
+ deltaToVsync >= (mRefreshRate.getPeriodNsecs() -
+ mJankClassificationThresholds.presentThreshold)) {
// Delta is a factor of vsync if its within the presentTheshold on either side
// of the vsyncPeriod. Example: 0-2ms and 9-11ms are both within the threshold
// of the vsyncPeriod if the threshold was 2ms and the vsyncPeriod was 11ms.
@@ -819,16 +824,9 @@
mJankType = JankType::Unknown;
}
}
- totalJankReasons |= mJankType;
-
for (auto& surfaceFrame : mSurfaceFrames) {
- surfaceFrame->onPresent(signalTime, mJankType, mVsyncPeriod);
- auto surfaceFrameJankType = surfaceFrame->getJankType();
- if (surfaceFrameJankType != std::nullopt) {
- totalJankReasons |= *surfaceFrameJankType;
- }
+ surfaceFrame->onPresent(signalTime, mJankType, mRefreshRate);
}
- mTimeStats->incrementJankyFrames(totalJankReasons);
}
void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
@@ -988,7 +986,7 @@
StringAppendF(&result, "Present Metadata : %s\n", toString(mFramePresentMetadata).c_str());
StringAppendF(&result, "Finish Metadata: %s\n", toString(mFrameReadyMetadata).c_str());
StringAppendF(&result, "Start Metadata: %s\n", toString(mFrameStartMetadata).c_str());
- std::chrono::nanoseconds vsyncPeriod(mVsyncPeriod);
+ std::chrono::nanoseconds vsyncPeriod(mRefreshRate.getPeriodNsecs());
StringAppendF(&result, "Vsync Period: %10f\n",
std::chrono::duration<double, std::milli>(vsyncPeriod).count());
nsecs_t presentDelta =
@@ -996,7 +994,7 @@
std::chrono::nanoseconds presentDeltaNs(std::abs(presentDelta));
StringAppendF(&result, "Present delta: %10f\n",
std::chrono::duration<double, std::milli>(presentDeltaNs).count());
- std::chrono::nanoseconds deltaToVsync(std::abs(presentDelta) % mVsyncPeriod);
+ std::chrono::nanoseconds deltaToVsync(std::abs(presentDelta) % mRefreshRate.getPeriodNsecs());
StringAppendF(&result, "Present delta %% refreshrate: %10f\n",
std::chrono::duration<double, std::milli>(deltaToVsync).count());
dumpTable(result, mSurfaceFlingerPredictions, mSurfaceFlingerActuals, "", mPredictionState,