diff options
| author | 2023-04-03 10:56:05 -0700 | |
|---|---|---|
| committer | 2023-04-10 12:10:35 -0700 | |
| commit | 63db24e62af7cd27b5ab49d735b2fddae3f2fa5c (patch) | |
| tree | 6e51a42d9de89719dccd1fffce4104a68d4afe83 | |
| parent | 4d6d28e6f55d67bc05c70fa7d2be0435ff2497d7 (diff) | |
SF: Clear layer history when inconclusive to frequent
layer transition
BUG: 265561529
Test: atest LayerHistoryTest
Benchmark shows improvement with the changes https://android-build.googleplex.com/builds/abtd/run/L82600000959656128
Change-Id: I152aa97f00592960411133de150990747ca8b31d
| -rw-r--r-- | services/surfaceflinger/Scheduler/LayerInfo.cpp | 32 | ||||
| -rw-r--r-- | services/surfaceflinger/Scheduler/LayerInfo.h | 11 | ||||
| -rw-r--r-- | services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp | 72 |
3 files changed, 100 insertions, 15 deletions
diff --git a/services/surfaceflinger/Scheduler/LayerInfo.cpp b/services/surfaceflinger/Scheduler/LayerInfo.cpp index 5a90d5866e..bae3739501 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfo.cpp @@ -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: @@ -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 { @@ -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); } diff --git a/services/surfaceflinger/Scheduler/LayerInfo.h b/services/surfaceflinger/Scheduler/LayerInfo.h index a3523ac25e..c5a60573f5 100644 --- a/services/surfaceflinger/Scheduler/LayerInfo.h +++ b/services/surfaceflinger/Scheduler/LayerInfo.h @@ -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) { @@ -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); diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp index b7672768b4..85d86a7acc 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp @@ -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; }); } @@ -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()); @@ -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); @@ -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()); @@ -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()); @@ -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()); @@ -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()); @@ -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()); |