From a61edcb5190368d9048d9afda1159070a2d26668 Mon Sep 17 00:00:00 2001 From: Ady Abraham Date: Thu, 30 Jan 2020 18:32:03 -0800 Subject: SurfaceFlinger: keep LayerInfo history for inactive layers Instead if clearing the history for past layers, keep a timestamp that will be used to filter out the frames which are outdated. This allows us to distinguish between frequent vs. infrequent layers when we get a buffer after a long time of inactivity. Test: adb shell /data/nativetest64/libsurfaceflinger_unittest/libsurfaceflinger_unittest Bug: 147516364 Change-Id: Ieb64cf6fc17a306c2db04b734631334af6703e79 --- services/surfaceflinger/Scheduler/LayerInfoV2.cpp | 23 +++++++++- services/surfaceflinger/Scheduler/LayerInfoV2.h | 22 +++++++--- .../tests/unittests/LayerHistoryTestV2.cpp | 49 +++++++++++----------- 3 files changed, 61 insertions(+), 33 deletions(-) diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp index f309d4d889..345b8f93fd 100644 --- a/services/surfaceflinger/Scheduler/LayerInfoV2.cpp +++ b/services/surfaceflinger/Scheduler/LayerInfoV2.cpp @@ -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( + 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; diff --git a/services/surfaceflinger/Scheduler/LayerInfoV2.h b/services/surfaceflinger/Scheduler/LayerInfoV2.h index 564f05efa2..90f6310d3b 100644 --- a/services/surfaceflinger/Scheduler/LayerInfoV2.h +++ b/services/surfaceflinger/Scheduler/LayerInfoV2.h @@ -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 calculateRefreshRateIfPossible(); + bool isFrameTimeValid(const FrameTimeData&) const; // Used for sanitizing the heuristic data const nsecs_t mHighRefreshRatePeriod; @@ -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 mFrameTimes; + std::chrono::time_point mFrameTimeValidSince = + std::chrono::steady_clock::now(); static constexpr size_t HISTORY_SIZE = 90; static constexpr std::chrono::nanoseconds HISTORY_TIME = 1s; }; diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp index 922966a70d..91f97515dd 100644 --- a/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp +++ b/services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp @@ -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; @@ -85,7 +84,6 @@ protected: TestableScheduler* const mScheduler{new TestableScheduler(mConfigs, true)}; TestableSurfaceFlinger mFlinger; - const nsecs_t mTime = systemTime(); }; namespace { @@ -98,26 +96,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()); } } @@ -130,17 +127,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()); } @@ -152,7 +151,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; @@ -175,7 +174,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; @@ -202,7 +201,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; @@ -230,7 +229,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; @@ -256,7 +255,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; @@ -291,7 +290,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()); @@ -319,7 +318,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)); -- cgit v1.2.3-59-g8ed1b