[SurfaceFlinger] Add refresh rate counts to TimeStats
This count will be exposed to lab tests as a breakdown metric for
uncovering jank.
Bug: 144526027
Test: dumpsys SurfaceFlinger --timestats -dump
Test: libsurfaceflinger_unittest
Change-Id: I921e147e96212ad6a08fa14d6e3d7a98893a8602
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 29fe5d9..bbb07a8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -990,6 +990,9 @@
return;
}
+ auto& oldRefreshRate =
+ mRefreshRateConfigs->getRefreshRateFromConfigId(display->getActiveConfig());
+
std::lock_guard<std::mutex> lock(mActiveConfigLock);
mRefreshRateConfigs->setCurrentConfigId(mUpcomingActiveConfig.configId);
mRefreshRateStats->setConfigMode(mUpcomingActiveConfig.configId);
@@ -997,6 +1000,9 @@
auto& refreshRate =
mRefreshRateConfigs->getRefreshRateFromConfigId(mUpcomingActiveConfig.configId);
+ if (refreshRate.vsyncPeriod != oldRefreshRate.vsyncPeriod) {
+ mTimeStats->incrementRefreshRateSwitches();
+ }
mPhaseConfiguration->setRefreshRateFps(refreshRate.fps);
mVSyncModulator->setPhaseOffsets(mPhaseConfiguration->getCurrentOffsets());
ATRACE_INT("ActiveConfigFPS", refreshRate.fps);
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 8038eba..96fd03a 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -282,6 +282,15 @@
mTimeStats.clientCompositionReusedFrames++;
}
+void TimeStats::incrementRefreshRateSwitches() {
+ if (!mEnabled.load()) return;
+
+ ATRACE_CALL();
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ mTimeStats.refreshRateSwitches++;
+}
+
void TimeStats::recordDisplayEventConnectionCount(int32_t count) {
if (!mEnabled.load()) return;
@@ -835,6 +844,7 @@
mTimeStats.missedFrames = 0;
mTimeStats.clientCompositionFrames = 0;
mTimeStats.clientCompositionReusedFrames = 0;
+ mTimeStats.refreshRateSwitches = 0;
mTimeStats.displayEventConnectionsCount = 0;
mTimeStats.displayOnTime = 0;
mTimeStats.presentToPresent.hist.clear();
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index ddebeb1..8bbae1f 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -52,6 +52,8 @@
virtual void incrementMissedFrames() = 0;
virtual void incrementClientCompositionFrames() = 0;
virtual void incrementClientCompositionReusedFrames() = 0;
+ // Increments the number of times the display refresh rate changed.
+ virtual void incrementRefreshRateSwitches() = 0;
// Records the most up-to-date count of display event connections.
// The stored count will be the maximum ever recoded.
virtual void recordDisplayEventConnectionCount(int32_t count) = 0;
@@ -215,6 +217,7 @@
void incrementMissedFrames() override;
void incrementClientCompositionFrames() override;
void incrementClientCompositionReusedFrames() override;
+ void incrementRefreshRateSwitches() override;
void recordDisplayEventConnectionCount(int32_t count) override;
void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) override;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index e2f85cc..5305de9 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -105,6 +105,7 @@
StringAppendF(&result, "missedFrames = %d\n", missedFrames);
StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
StringAppendF(&result, "clientCompositionReusedFrames = %d\n", clientCompositionReusedFrames);
+ StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitches);
StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime);
StringAppendF(&result, "displayConfigStats is as below:\n");
for (const auto& [fps, duration] : refreshRateStats) {
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 5e7c449..afb98e0 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -62,6 +62,7 @@
int32_t missedFrames = 0;
int32_t clientCompositionFrames = 0;
int32_t clientCompositionReusedFrames = 0;
+ int32_t refreshRateSwitches = 0;
int32_t displayEventConnectionsCount = 0;
int64_t displayOnTime = 0;
Histogram presentToPresent;
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index a7a4d48..45f7ed3 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -362,6 +362,21 @@
EXPECT_THAT(result, HasSubstr(expectedResult));
}
+TEST_F(TimeStatsTest, canIncreaseRefreshRateSwitches) {
+ // this stat is not in the proto so verify by checking the string dump
+ constexpr size_t REFRESH_RATE_SWITCHES = 2;
+
+ EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
+ for (size_t i = 0; i < REFRESH_RATE_SWITCHES; i++) {
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementRefreshRateSwitches());
+ }
+
+ const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
+ const std::string expectedResult =
+ "refreshRateSwitches = " + std::to_string(REFRESH_RATE_SWITCHES);
+ EXPECT_THAT(result, HasSubstr(expectedResult));
+}
+
TEST_F(TimeStatsTest, canAverageFrameDuration) {
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
@@ -744,6 +759,7 @@
// These stats are not in the proto so verify by checking the string dump.
EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty());
ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames());
+ ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementRefreshRateSwitches());
mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL);
mTimeStats
->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(1ms).count(),
@@ -759,6 +775,7 @@
const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING));
EXPECT_THAT(result, HasSubstr("clientCompositionReusedFrames = 0"));
+ EXPECT_THAT(result, HasSubstr("refreshRateSwitches = 0"));
EXPECT_THAT(result, HasSubstr("averageFrameDuration = 0.000 ms"));
EXPECT_THAT(result, HasSubstr("averageRenderEngineTiming = 0.000 ms"));
}
diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
index c45d584..9ea4dd0 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h
@@ -36,6 +36,7 @@
MOCK_METHOD0(incrementMissedFrames, void());
MOCK_METHOD0(incrementClientCompositionFrames, void());
MOCK_METHOD0(incrementClientCompositionReusedFrames, void());
+ MOCK_METHOD0(incrementRefreshRateSwitches, void());
MOCK_METHOD1(recordDisplayEventConnectionCount, void(int32_t));
MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t));
MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t));