Loading services/surfaceflinger/Scheduler/LayerInfoV2.cpp +21 −2 Original line number Diff line number Diff line Loading @@ -54,21 +54,40 @@ bool LayerInfoV2::isRecentlyActive(nsecs_t now) const { return mFrameTimes.back().queueTime >= getActiveLayerThreshold(now); } bool LayerInfoV2::isFrameTimeValid(const FrameTimeData& frameTime) const { return frameTime.queueTime >= std::chrono::duration_cast<std::chrono::nanoseconds>( mFrameTimeValidSince.time_since_epoch()) .count(); } bool LayerInfoV2::isFrequent(nsecs_t now) const { // Assume layer is infrequent if too few present times have been recorded. // If we know nothing about this layer we consider it as frequent as it might be the start // of an animation. if (mFrameTimes.size() < FREQUENT_LAYER_WINDOW_SIZE) { return false; return true; } // Layer is frequent if the earliest value in the window of most recent present times is // within threshold. const auto it = mFrameTimes.end() - FREQUENT_LAYER_WINDOW_SIZE; if (!isFrameTimeValid(*it)) { return true; } const nsecs_t threshold = now - MAX_FREQUENT_LAYER_PERIOD_NS.count(); return it->queueTime >= threshold; } bool LayerInfoV2::hasEnoughDataForHeuristic() const { // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates if (mFrameTimes.size() < 2) { return false; } if (!isFrameTimeValid(mFrameTimes.front())) { return false; } if (mFrameTimes.size() < HISTORY_SIZE && mFrameTimes.back().queueTime - mFrameTimes.front().queueTime < HISTORY_TIME.count()) { return false; Loading services/surfaceflinger/Scheduler/LayerInfoV2.h +16 −6 Original line number Diff line number Diff line Loading @@ -82,12 +82,25 @@ public: // updated time, the updated time is the present time. nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; } void clearHistory() { mFrameTimes.clear(); } void clearHistory() { // Mark mFrameTimeValidSince to now to ignore all previous frame times. // We are not deleting the old frame to keep track of whether we should treat the first // buffer as Max as we don't know anything about this layer or Min as this layer is // posting infrequent updates. mFrameTimeValidSince = std::chrono::steady_clock::now(); } private: // Used to store the layer timestamps struct FrameTimeData { nsecs_t presetTime; // desiredPresentTime, if provided nsecs_t queueTime; // buffer queue time }; bool isFrequent(nsecs_t now) const; bool hasEnoughDataForHeuristic() const; std::optional<float> calculateRefreshRateIfPossible(); bool isFrameTimeValid(const FrameTimeData&) const; // Used for sanitizing the heuristic data const nsecs_t mHighRefreshRatePeriod; Loading @@ -103,12 +116,9 @@ private: float fps; } mLayerVote; // Used to store the layer timestamps struct FrameTimeData { nsecs_t presetTime; // desiredPresentTime, if provided nsecs_t queueTime; // buffer queue time }; std::deque<FrameTimeData> mFrameTimes; std::chrono::time_point<std::chrono::steady_clock> mFrameTimeValidSince = std::chrono::steady_clock::now(); static constexpr size_t HISTORY_SIZE = 90; static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s; }; Loading services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp +24 −25 Original line number Diff line number Diff line Loading @@ -34,7 +34,6 @@ namespace android::scheduler { class LayerHistoryTestV2 : public testing::Test { protected: static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfoV2::FREQUENT_LAYER_WINDOW_SIZE; static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfoV2::HISTORY_SIZE; static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfoV2::MAX_FREQUENT_LAYER_PERIOD_NS; Loading Loading @@ -84,7 +83,6 @@ protected: TestableScheduler* const mScheduler{new TestableScheduler(mConfigs, true)}; TestableSurfaceFlinger mFlinger; const nsecs_t mTime = systemTime(); }; namespace { Loading @@ -97,26 +95,25 @@ TEST_F(LayerHistoryTestV2, oneLayer) { EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); const nsecs_t time = systemTime(); // No layers returned if no layers are active. EXPECT_TRUE(history().summarize(mTime).empty()); EXPECT_TRUE(history().summarize(time).empty()); EXPECT_EQ(0, activeLayerCount()); // Max returned if active layers have insufficient history. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) { history().record(layer.get(), 0, mTime); ASSERT_EQ(1, history().summarize(mTime).size()); const auto expectedType = (i + 1 < FREQUENT_LAYER_WINDOW_SIZE) ? LayerHistory::LayerVoteType::Min : LayerHistory::LayerVoteType::Max; EXPECT_EQ(expectedType, history().summarize(mTime)[0].vote); history().record(layer.get(), 0, time); ASSERT_EQ(1, history().summarize(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); } // Max is returned since we have enough history but there is no timestamp votes. for (int i = 0; i < 10; i++) { history().record(layer.get(), 0, mTime); ASSERT_EQ(1, history().summarize(mTime).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(mTime)[0].vote); history().record(layer.get(), 0, time); ASSERT_EQ(1, history().summarize(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); } } Loading @@ -129,17 +126,19 @@ TEST_F(LayerHistoryTestV2, oneInvisibleLayer) { EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); history().record(layer.get(), 0, mTime); auto summary = history().summarize(mTime); ASSERT_EQ(1, history().summarize(mTime).size()); nsecs_t time = systemTime(); history().record(layer.get(), 0, time); auto summary = history().summarize(time); ASSERT_EQ(1, history().summarize(time).size()); // Layer is still considered inactive so we expect to get Min EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(mTime)[0].vote); EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false)); summary = history().summarize(mTime); EXPECT_TRUE(history().summarize(mTime).empty()); summary = history().summarize(time); EXPECT_TRUE(history().summarize(time).empty()); EXPECT_EQ(0, activeLayerCount()); } Loading @@ -151,7 +150,7 @@ TEST_F(LayerHistoryTestV2, explicitTimestamp) { EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); nsecs_t time = mTime; nsecs_t time = systemTime(); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer.get(), time, time); time += LO_FPS_PERIOD; Loading @@ -174,7 +173,7 @@ TEST_F(LayerHistoryTestV2, oneLayerNoVote) { EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); nsecs_t time = mTime; nsecs_t time = systemTime(); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer.get(), time, time); time += HI_FPS_PERIOD; Loading @@ -201,7 +200,7 @@ TEST_F(LayerHistoryTestV2, oneLayerMinVote) { EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); nsecs_t time = mTime; nsecs_t time = systemTime(); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer.get(), time, time); time += HI_FPS_PERIOD; Loading Loading @@ -229,7 +228,7 @@ TEST_F(LayerHistoryTestV2, oneLayerMaxVote) { EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); nsecs_t time = mTime; nsecs_t time = systemTime(); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer.get(), time, time); time += LO_FPS_PERIOD; Loading @@ -255,7 +254,7 @@ TEST_F(LayerHistoryTestV2, oneLayerExplicitVote) { EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); nsecs_t time = mTime; nsecs_t time = systemTime(); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer.get(), time, time); time += HI_FPS_PERIOD; Loading Loading @@ -290,7 +289,7 @@ TEST_F(LayerHistoryTestV2, multipleLayers) { EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(std::nullopt)); nsecs_t time = mTime; nsecs_t time = systemTime(); EXPECT_EQ(3, layerCount()); EXPECT_EQ(0, activeLayerCount()); Loading Loading @@ -318,7 +317,7 @@ TEST_F(LayerHistoryTestV2, multipleLayers) { ASSERT_EQ(2, history().summarize(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[1].vote); ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[1].vote); EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate); EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); Loading Loading
services/surfaceflinger/Scheduler/LayerInfoV2.cpp +21 −2 Original line number Diff line number Diff line Loading @@ -54,21 +54,40 @@ bool LayerInfoV2::isRecentlyActive(nsecs_t now) const { return mFrameTimes.back().queueTime >= getActiveLayerThreshold(now); } bool LayerInfoV2::isFrameTimeValid(const FrameTimeData& frameTime) const { return frameTime.queueTime >= std::chrono::duration_cast<std::chrono::nanoseconds>( mFrameTimeValidSince.time_since_epoch()) .count(); } bool LayerInfoV2::isFrequent(nsecs_t now) const { // Assume layer is infrequent if too few present times have been recorded. // If we know nothing about this layer we consider it as frequent as it might be the start // of an animation. if (mFrameTimes.size() < FREQUENT_LAYER_WINDOW_SIZE) { return false; return true; } // Layer is frequent if the earliest value in the window of most recent present times is // within threshold. const auto it = mFrameTimes.end() - FREQUENT_LAYER_WINDOW_SIZE; if (!isFrameTimeValid(*it)) { return true; } const nsecs_t threshold = now - MAX_FREQUENT_LAYER_PERIOD_NS.count(); return it->queueTime >= threshold; } bool LayerInfoV2::hasEnoughDataForHeuristic() const { // The layer had to publish at least HISTORY_SIZE or HISTORY_TIME of updates if (mFrameTimes.size() < 2) { return false; } if (!isFrameTimeValid(mFrameTimes.front())) { return false; } if (mFrameTimes.size() < HISTORY_SIZE && mFrameTimes.back().queueTime - mFrameTimes.front().queueTime < HISTORY_TIME.count()) { return false; Loading
services/surfaceflinger/Scheduler/LayerInfoV2.h +16 −6 Original line number Diff line number Diff line Loading @@ -82,12 +82,25 @@ public: // updated time, the updated time is the present time. nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; } void clearHistory() { mFrameTimes.clear(); } void clearHistory() { // Mark mFrameTimeValidSince to now to ignore all previous frame times. // We are not deleting the old frame to keep track of whether we should treat the first // buffer as Max as we don't know anything about this layer or Min as this layer is // posting infrequent updates. mFrameTimeValidSince = std::chrono::steady_clock::now(); } private: // Used to store the layer timestamps struct FrameTimeData { nsecs_t presetTime; // desiredPresentTime, if provided nsecs_t queueTime; // buffer queue time }; bool isFrequent(nsecs_t now) const; bool hasEnoughDataForHeuristic() const; std::optional<float> calculateRefreshRateIfPossible(); bool isFrameTimeValid(const FrameTimeData&) const; // Used for sanitizing the heuristic data const nsecs_t mHighRefreshRatePeriod; Loading @@ -103,12 +116,9 @@ private: float fps; } mLayerVote; // Used to store the layer timestamps struct FrameTimeData { nsecs_t presetTime; // desiredPresentTime, if provided nsecs_t queueTime; // buffer queue time }; std::deque<FrameTimeData> mFrameTimes; std::chrono::time_point<std::chrono::steady_clock> mFrameTimeValidSince = std::chrono::steady_clock::now(); static constexpr size_t HISTORY_SIZE = 90; static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s; }; Loading
services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp +24 −25 Original line number Diff line number Diff line Loading @@ -34,7 +34,6 @@ namespace android::scheduler { class LayerHistoryTestV2 : public testing::Test { protected: static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfoV2::FREQUENT_LAYER_WINDOW_SIZE; static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfoV2::HISTORY_SIZE; static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfoV2::MAX_FREQUENT_LAYER_PERIOD_NS; Loading Loading @@ -84,7 +83,6 @@ protected: TestableScheduler* const mScheduler{new TestableScheduler(mConfigs, true)}; TestableSurfaceFlinger mFlinger; const nsecs_t mTime = systemTime(); }; namespace { Loading @@ -97,26 +95,25 @@ TEST_F(LayerHistoryTestV2, oneLayer) { EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); const nsecs_t time = systemTime(); // No layers returned if no layers are active. EXPECT_TRUE(history().summarize(mTime).empty()); EXPECT_TRUE(history().summarize(time).empty()); EXPECT_EQ(0, activeLayerCount()); // Max returned if active layers have insufficient history. for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE - 1; i++) { history().record(layer.get(), 0, mTime); ASSERT_EQ(1, history().summarize(mTime).size()); const auto expectedType = (i + 1 < FREQUENT_LAYER_WINDOW_SIZE) ? LayerHistory::LayerVoteType::Min : LayerHistory::LayerVoteType::Max; EXPECT_EQ(expectedType, history().summarize(mTime)[0].vote); history().record(layer.get(), 0, time); ASSERT_EQ(1, history().summarize(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); } // Max is returned since we have enough history but there is no timestamp votes. for (int i = 0; i < 10; i++) { history().record(layer.get(), 0, mTime); ASSERT_EQ(1, history().summarize(mTime).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(mTime)[0].vote); history().record(layer.get(), 0, time); ASSERT_EQ(1, history().summarize(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); } } Loading @@ -129,17 +126,19 @@ TEST_F(LayerHistoryTestV2, oneInvisibleLayer) { EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); history().record(layer.get(), 0, mTime); auto summary = history().summarize(mTime); ASSERT_EQ(1, history().summarize(mTime).size()); nsecs_t time = systemTime(); history().record(layer.get(), 0, time); auto summary = history().summarize(time); ASSERT_EQ(1, history().summarize(time).size()); // Layer is still considered inactive so we expect to get Min EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(mTime)[0].vote); EXPECT_EQ(LayerHistory::LayerVoteType::Max, history().summarize(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(false)); summary = history().summarize(mTime); EXPECT_TRUE(history().summarize(mTime).empty()); summary = history().summarize(time); EXPECT_TRUE(history().summarize(time).empty()); EXPECT_EQ(0, activeLayerCount()); } Loading @@ -151,7 +150,7 @@ TEST_F(LayerHistoryTestV2, explicitTimestamp) { EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); nsecs_t time = mTime; nsecs_t time = systemTime(); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer.get(), time, time); time += LO_FPS_PERIOD; Loading @@ -174,7 +173,7 @@ TEST_F(LayerHistoryTestV2, oneLayerNoVote) { EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); nsecs_t time = mTime; nsecs_t time = systemTime(); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer.get(), time, time); time += HI_FPS_PERIOD; Loading @@ -201,7 +200,7 @@ TEST_F(LayerHistoryTestV2, oneLayerMinVote) { EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); nsecs_t time = mTime; nsecs_t time = systemTime(); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer.get(), time, time); time += HI_FPS_PERIOD; Loading Loading @@ -229,7 +228,7 @@ TEST_F(LayerHistoryTestV2, oneLayerMaxVote) { EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); nsecs_t time = mTime; nsecs_t time = systemTime(); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer.get(), time, time); time += LO_FPS_PERIOD; Loading @@ -255,7 +254,7 @@ TEST_F(LayerHistoryTestV2, oneLayerExplicitVote) { EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); nsecs_t time = mTime; nsecs_t time = systemTime(); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer.get(), time, time); time += HI_FPS_PERIOD; Loading Loading @@ -290,7 +289,7 @@ TEST_F(LayerHistoryTestV2, multipleLayers) { EXPECT_CALL(*layer3, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer3, getFrameRate()).WillRepeatedly(Return(std::nullopt)); nsecs_t time = mTime; nsecs_t time = systemTime(); EXPECT_EQ(3, layerCount()); EXPECT_EQ(0, activeLayerCount()); Loading Loading @@ -318,7 +317,7 @@ TEST_F(LayerHistoryTestV2, multipleLayers) { ASSERT_EQ(2, history().summarize(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Min, history().summarize(time)[0].vote); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[1].vote); ASSERT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[1].vote); EXPECT_FLOAT_EQ(HI_FPS, history().summarize(time)[1].desiredRefreshRate); EXPECT_EQ(2, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); Loading