Loading services/surfaceflinger/Scheduler/LayerInfo.cpp +19 −13 Original line number Diff line number Diff line Loading @@ -78,17 +78,16 @@ bool LayerInfo::isFrameTimeValid(const FrameTimeData& frameTime) const { .count(); } bool LayerInfo::isFrequent(nsecs_t now) const { using fps_approx_ops::operator>=; LayerInfo::Frequent LayerInfo::isFrequent(nsecs_t now) const { // If we know nothing about this layer (e.g. after touch event), // we consider it as frequent as it might be the start of an animation. if (mFrameTimes.size() < kFrequentLayerWindowSize) { return true; return {/* isFrequent */ true, /* clearHistory */ false, /* isConclusive */ true}; } // Non-active layers are also infrequent if (mLastUpdatedTime < getActiveLayerThreshold(now)) { return false; return {/* isFrequent */ false, /* clearHistory */ false, /* isConclusive */ true}; } // We check whether we can classify this layer as frequent or infrequent: Loading @@ -111,12 +110,20 @@ bool LayerInfo::isFrequent(nsecs_t now) const { } if (isFrequent || isInfrequent) { return isFrequent; // If the layer was previously inconclusive, we clear // the history as indeterminate layers changed to frequent, // and we should not look at the stale data. return {isFrequent, isFrequent && !mIsFrequencyConclusive, /* isConclusive */ true}; } // If we can't determine whether the layer is frequent or not, we return // the last known classification. return !mLastRefreshRate.infrequent; // the last known classification and mark the layer frequency as inconclusive. isFrequent = !mLastRefreshRate.infrequent; // If the layer was previously tagged as animating, we clear // the history as it is likely the layer just changed its behavior, // and we should not look at stale data. return {isFrequent, isFrequent && mLastRefreshRate.animating, /* isConclusive */ false}; } Fps LayerInfo::getFps(nsecs_t now) const { Loading Loading @@ -273,19 +280,18 @@ LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateSelector& se return {LayerHistory::LayerVoteType::Max, Fps()}; } if (!isFrequent(now)) { const LayerInfo::Frequent frequent = isFrequent(now); mIsFrequencyConclusive = frequent.isConclusive; if (!frequent.isFrequent) { ATRACE_FORMAT_INSTANT("infrequent"); ALOGV("%s is infrequent", mName.c_str()); mLastRefreshRate.infrequent = true; // Infrequent layers vote for mininal refresh rate for // Infrequent layers vote for minimal refresh rate for // battery saving purposes and also to prevent b/135718869. return {LayerHistory::LayerVoteType::Min, Fps()}; } // If the layer was previously tagged as animating or infrequent, we clear // the history as it is likely the layer just changed its behavior // and we should not look at stale data if (mLastRefreshRate.animating || mLastRefreshRate.infrequent) { if (frequent.clearHistory) { clearHistory(now); } Loading services/surfaceflinger/Scheduler/LayerInfo.h +10 −1 Original line number Diff line number Diff line Loading @@ -181,6 +181,7 @@ public: mFrameTimeValidSince = std::chrono::time_point<std::chrono::steady_clock>(timePoint); mLastRefreshRate = {}; mRefreshRateHistory.clear(); mIsFrequencyConclusive = true; } void clearHistory(nsecs_t now) { Loading Loading @@ -251,7 +252,15 @@ private: static constexpr float MARGIN_CONSISTENT_FPS = 1.0; }; bool isFrequent(nsecs_t now) const; // Represents whether we were able to determine either layer is frequent or infrequent bool mIsFrequencyConclusive = true; struct Frequent { bool isFrequent; bool clearHistory; // Represents whether we were able to determine isFrequent conclusively bool isConclusive; }; Frequent isFrequent(nsecs_t now) const; bool isAnimating(nsecs_t now) const; bool hasEnoughDataForHeuristic() const; std::optional<Fps> calculateRefreshRateIfPossible(const RefreshRateSelector&, nsecs_t now); Loading services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +71 −1 Original line number Diff line number Diff line Loading @@ -84,7 +84,7 @@ protected: auto frequentLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS { const auto& infos = history().mActiveLayerInfos; return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) { return pair.second.second->isFrequent(now); return pair.second.second->isFrequent(now).isFrequent; }); } Loading @@ -95,6 +95,13 @@ protected: }); } auto clearLayerHistoryCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS { const auto& infos = history().mActiveLayerInfos; return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) { return pair.second.second->isFrequent(now).clearHistory; }); } void setDefaultLayerVote(Layer* layer, LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS { auto [found, layerPair] = history().findLayer(layer->getSequence()); Loading Loading @@ -764,6 +771,7 @@ TEST_F(LayerHistoryTest, frequentLayerBecomingInfrequentAndBack) { time += std::chrono::nanoseconds(3s).count(); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); Loading @@ -778,6 +786,7 @@ TEST_F(LayerHistoryTest, frequentLayerBecomingInfrequentAndBack) { time += (MAX_FREQUENT_LAYER_PERIOD_NS + 1ms).count(); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); Loading @@ -787,6 +796,7 @@ TEST_F(LayerHistoryTest, frequentLayerBecomingInfrequentAndBack) { // posting another buffer should keep the layer infrequent history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); Loading @@ -798,6 +808,7 @@ TEST_F(LayerHistoryTest, frequentLayerBecomingInfrequentAndBack) { LayerHistory::LayerUpdateType::Buffer); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(1, clearLayerHistoryCount(time)); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); Loading @@ -808,6 +819,7 @@ TEST_F(LayerHistoryTest, frequentLayerBecomingInfrequentAndBack) { time += std::chrono::nanoseconds(3s).count(); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); Loading @@ -818,6 +830,64 @@ TEST_F(LayerHistoryTest, frequentLayerBecomingInfrequentAndBack) { time += (60_Hz).getPeriodNsecs(); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); EXPECT_EQ(0, animatingLayerCount(time)); } TEST_F(LayerHistoryTest, inconclusiveLayerBecomingFrequent) { auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); nsecs_t time = systemTime(); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(0, animatingLayerCount(time)); // Fill up the window with frequent updates for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE; i++) { history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += (60_Hz).getPeriodNsecs(); EXPECT_EQ(1, layerCount()); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); } // posting infrequent buffers after long inactivity should make the layer // inconclusive but frequent. time += std::chrono::nanoseconds(3s).count(); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += (MAX_FREQUENT_LAYER_PERIOD_NS + 1ms).count(); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); EXPECT_EQ(0, animatingLayerCount(time)); // posting more buffers should make the layer frequent and switch the refresh rate to max // by clearing the history history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(1, clearLayerHistoryCount(time)); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); Loading Loading
services/surfaceflinger/Scheduler/LayerInfo.cpp +19 −13 Original line number Diff line number Diff line Loading @@ -78,17 +78,16 @@ bool LayerInfo::isFrameTimeValid(const FrameTimeData& frameTime) const { .count(); } bool LayerInfo::isFrequent(nsecs_t now) const { using fps_approx_ops::operator>=; LayerInfo::Frequent LayerInfo::isFrequent(nsecs_t now) const { // If we know nothing about this layer (e.g. after touch event), // we consider it as frequent as it might be the start of an animation. if (mFrameTimes.size() < kFrequentLayerWindowSize) { return true; return {/* isFrequent */ true, /* clearHistory */ false, /* isConclusive */ true}; } // Non-active layers are also infrequent if (mLastUpdatedTime < getActiveLayerThreshold(now)) { return false; return {/* isFrequent */ false, /* clearHistory */ false, /* isConclusive */ true}; } // We check whether we can classify this layer as frequent or infrequent: Loading @@ -111,12 +110,20 @@ bool LayerInfo::isFrequent(nsecs_t now) const { } if (isFrequent || isInfrequent) { return isFrequent; // If the layer was previously inconclusive, we clear // the history as indeterminate layers changed to frequent, // and we should not look at the stale data. return {isFrequent, isFrequent && !mIsFrequencyConclusive, /* isConclusive */ true}; } // If we can't determine whether the layer is frequent or not, we return // the last known classification. return !mLastRefreshRate.infrequent; // the last known classification and mark the layer frequency as inconclusive. isFrequent = !mLastRefreshRate.infrequent; // If the layer was previously tagged as animating, we clear // the history as it is likely the layer just changed its behavior, // and we should not look at stale data. return {isFrequent, isFrequent && mLastRefreshRate.animating, /* isConclusive */ false}; } Fps LayerInfo::getFps(nsecs_t now) const { Loading Loading @@ -273,19 +280,18 @@ LayerInfo::LayerVote LayerInfo::getRefreshRateVote(const RefreshRateSelector& se return {LayerHistory::LayerVoteType::Max, Fps()}; } if (!isFrequent(now)) { const LayerInfo::Frequent frequent = isFrequent(now); mIsFrequencyConclusive = frequent.isConclusive; if (!frequent.isFrequent) { ATRACE_FORMAT_INSTANT("infrequent"); ALOGV("%s is infrequent", mName.c_str()); mLastRefreshRate.infrequent = true; // Infrequent layers vote for mininal refresh rate for // Infrequent layers vote for minimal refresh rate for // battery saving purposes and also to prevent b/135718869. return {LayerHistory::LayerVoteType::Min, Fps()}; } // If the layer was previously tagged as animating or infrequent, we clear // the history as it is likely the layer just changed its behavior // and we should not look at stale data if (mLastRefreshRate.animating || mLastRefreshRate.infrequent) { if (frequent.clearHistory) { clearHistory(now); } Loading
services/surfaceflinger/Scheduler/LayerInfo.h +10 −1 Original line number Diff line number Diff line Loading @@ -181,6 +181,7 @@ public: mFrameTimeValidSince = std::chrono::time_point<std::chrono::steady_clock>(timePoint); mLastRefreshRate = {}; mRefreshRateHistory.clear(); mIsFrequencyConclusive = true; } void clearHistory(nsecs_t now) { Loading Loading @@ -251,7 +252,15 @@ private: static constexpr float MARGIN_CONSISTENT_FPS = 1.0; }; bool isFrequent(nsecs_t now) const; // Represents whether we were able to determine either layer is frequent or infrequent bool mIsFrequencyConclusive = true; struct Frequent { bool isFrequent; bool clearHistory; // Represents whether we were able to determine isFrequent conclusively bool isConclusive; }; Frequent isFrequent(nsecs_t now) const; bool isAnimating(nsecs_t now) const; bool hasEnoughDataForHeuristic() const; std::optional<Fps> calculateRefreshRateIfPossible(const RefreshRateSelector&, nsecs_t now); Loading
services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +71 −1 Original line number Diff line number Diff line Loading @@ -84,7 +84,7 @@ protected: auto frequentLayerCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS { const auto& infos = history().mActiveLayerInfos; return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) { return pair.second.second->isFrequent(now); return pair.second.second->isFrequent(now).isFrequent; }); } Loading @@ -95,6 +95,13 @@ protected: }); } auto clearLayerHistoryCount(nsecs_t now) const NO_THREAD_SAFETY_ANALYSIS { const auto& infos = history().mActiveLayerInfos; return std::count_if(infos.begin(), infos.end(), [now](const auto& pair) { return pair.second.second->isFrequent(now).clearHistory; }); } void setDefaultLayerVote(Layer* layer, LayerHistory::LayerVoteType vote) NO_THREAD_SAFETY_ANALYSIS { auto [found, layerPair] = history().findLayer(layer->getSequence()); Loading Loading @@ -764,6 +771,7 @@ TEST_F(LayerHistoryTest, frequentLayerBecomingInfrequentAndBack) { time += std::chrono::nanoseconds(3s).count(); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(60_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); Loading @@ -778,6 +786,7 @@ TEST_F(LayerHistoryTest, frequentLayerBecomingInfrequentAndBack) { time += (MAX_FREQUENT_LAYER_PERIOD_NS + 1ms).count(); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); Loading @@ -787,6 +796,7 @@ TEST_F(LayerHistoryTest, frequentLayerBecomingInfrequentAndBack) { // posting another buffer should keep the layer infrequent history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Min, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); Loading @@ -798,6 +808,7 @@ TEST_F(LayerHistoryTest, frequentLayerBecomingInfrequentAndBack) { LayerHistory::LayerUpdateType::Buffer); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(1, clearLayerHistoryCount(time)); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); Loading @@ -808,6 +819,7 @@ TEST_F(LayerHistoryTest, frequentLayerBecomingInfrequentAndBack) { time += std::chrono::nanoseconds(3s).count(); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); Loading @@ -818,6 +830,64 @@ TEST_F(LayerHistoryTest, frequentLayerBecomingInfrequentAndBack) { time += (60_Hz).getPeriodNsecs(); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); EXPECT_EQ(0, animatingLayerCount(time)); } TEST_F(LayerHistoryTest, inconclusiveLayerBecomingFrequent) { auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate())); nsecs_t time = systemTime(); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(0, animatingLayerCount(time)); // Fill up the window with frequent updates for (int i = 0; i < FREQUENT_LAYER_WINDOW_SIZE; i++) { history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += (60_Hz).getPeriodNsecs(); EXPECT_EQ(1, layerCount()); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); } // posting infrequent buffers after long inactivity should make the layer // inconclusive but frequent. time += std::chrono::nanoseconds(3s).count(); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += (MAX_FREQUENT_LAYER_PERIOD_NS + 1ms).count(); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(0, clearLayerHistoryCount(time)); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); EXPECT_EQ(0, animatingLayerCount(time)); // posting more buffers should make the layer frequent and switch the refresh rate to max // by clearing the history history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); EXPECT_EQ(1, clearLayerHistoryCount(time)); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(1, activeLayerCount()); Loading