Loading services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -192,7 +192,7 @@ void LayerHistoryV2::partitionLayers(nsecs_t now) { trace(weak, LayerHistory::LayerVoteType::NoVote, 0); } info->clearHistory(); info->onLayerInactive(now); std::swap(mLayerInfos[i], mLayerInfos[--mActiveLayersEnd]); } Loading @@ -213,7 +213,7 @@ void LayerHistoryV2::clear() { std::lock_guard lock(mLock); for (const auto& [layer, info] : activeLayers()) { info->clearHistory(); info->clearHistory(systemTime()); } } } // namespace android::scheduler::impl services/surfaceflinger/Scheduler/LayerInfoV2.cpp +2 −9 Original line number Diff line number Diff line Loading @@ -57,21 +57,14 @@ bool LayerInfoV2::isFrameTimeValid(const FrameTimeData& frameTime) const { } bool LayerInfoV2::isFrequent(nsecs_t now) const { // Find the first valid frame time auto it = mFrameTimes.begin(); for (; it != mFrameTimes.end(); ++it) { if (isFrameTimeValid(*it)) { break; } } // If we know nothing about this layer we consider it as frequent as it might be the start // of an animation. if (std::distance(it, mFrameTimes.end()) < FREQUENT_LAYER_WINDOW_SIZE) { if (mFrameTimes.size() < FREQUENT_LAYER_WINDOW_SIZE) { return true; } // Find the first active frame auto it = mFrameTimes.begin(); for (; it != mFrameTimes.end(); ++it) { if (it->queueTime >= getActiveLayerThreshold(now)) { break; Loading services/surfaceflinger/Scheduler/LayerInfoV2.h +8 −2 Original line number Diff line number Diff line Loading @@ -83,15 +83,21 @@ public: // updated time, the updated time is the present time. nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; } void clearHistory() { void onLayerInactive(nsecs_t now) { // 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(); const auto timePoint = std::chrono::nanoseconds(now); mFrameTimeValidSince = std::chrono::time_point<std::chrono::steady_clock>(timePoint); mLastReportedRefreshRate = 0.0f; } void clearHistory(nsecs_t now) { onLayerInactive(now); mFrameTimes.clear(); } private: // Used to store the layer timestamps struct FrameTimeData { Loading services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp +74 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ protected: static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfoV2::HISTORY_SIZE; static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfoV2::MAX_FREQUENT_LAYER_PERIOD_NS; static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfoV2::FREQUENT_LAYER_WINDOW_SIZE; static constexpr auto PRESENT_TIME_HISTORY_TIME = LayerInfoV2::HISTORY_TIME; static constexpr float LO_FPS = 30.f; static constexpr auto LO_FPS_PERIOD = static_cast<nsecs_t>(1e9f / LO_FPS); Loading Loading @@ -71,6 +72,9 @@ protected: } auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); } auto createLayer(std::string name) { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger(), std::move(name))); } Hwc2::mock::Display mDisplay; RefreshRateConfigs mConfigs{{HWC2::Display::Config::Builder(mDisplay, 0) Loading Loading @@ -541,5 +545,75 @@ TEST_F(LayerHistoryTestV2, invisibleExplicitLayer) { EXPECT_EQ(2, frequentLayerCount(time)); } class LayerHistoryTestV2Parameterized : public LayerHistoryTestV2, public testing::WithParamInterface<std::chrono::nanoseconds> {}; TEST_P(LayerHistoryTestV2Parameterized, HeuristicLayerWithInfrequentLayer) { std::chrono::nanoseconds infrequentUpdateDelta = GetParam(); auto heuristicLayer = createLayer("HeuristicLayer"); EXPECT_CALL(*heuristicLayer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*heuristicLayer, getFrameRateForLayerTree()) .WillRepeatedly(Return(Layer::FrameRate())); auto infrequentLayer = createLayer("InfrequentLayer"); EXPECT_CALL(*infrequentLayer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*infrequentLayer, getFrameRateForLayerTree()) .WillRepeatedly(Return(Layer::FrameRate())); const nsecs_t startTime = systemTime(); const std::chrono::nanoseconds heuristicUpdateDelta = 41'666'667ns; history().record(heuristicLayer.get(), startTime, startTime); history().record(infrequentLayer.get(), startTime, startTime); nsecs_t time = startTime; nsecs_t lastInfrequentUpdate = startTime; const int totalInfrequentLayerUpdates = FREQUENT_LAYER_WINDOW_SIZE * 5; int infrequentLayerUpdates = 0; while (infrequentLayerUpdates <= totalInfrequentLayerUpdates) { time += heuristicUpdateDelta.count(); history().record(heuristicLayer.get(), time, time); if (time - lastInfrequentUpdate >= infrequentUpdateDelta.count()) { ALOGI("submitting infrequent frame [%d/%d]", infrequentLayerUpdates, totalInfrequentLayerUpdates); lastInfrequentUpdate = time; history().record(infrequentLayer.get(), time, time); infrequentLayerUpdates++; } if (time - startTime > PRESENT_TIME_HISTORY_TIME.count()) { ASSERT_NE(0, history().summarize(time).size()); ASSERT_GE(2, history().summarize(time).size()); bool max = false; bool min = false; float heuristic = 0; for (const auto& layer : history().summarize(time)) { if (layer.vote == LayerHistory::LayerVoteType::Heuristic) { heuristic = layer.desiredRefreshRate; } else if (layer.vote == LayerHistory::LayerVoteType::Max) { max = true; } else if (layer.vote == LayerHistory::LayerVoteType::Min) { min = true; } } if (infrequentLayerUpdates > FREQUENT_LAYER_WINDOW_SIZE) { EXPECT_FLOAT_EQ(24.0f, heuristic); EXPECT_FALSE(max); if (history().summarize(time).size() == 2) { EXPECT_TRUE(min); } } } } } INSTANTIATE_TEST_CASE_P(LeapYearTests, LayerHistoryTestV2Parameterized, ::testing::Values(1s, 2s, 3s, 4s, 5s)); } // namespace } // namespace android::scheduler services/surfaceflinger/tests/unittests/mock/MockLayer.h +3 −2 Original line number Diff line number Diff line Loading @@ -24,8 +24,9 @@ namespace android::mock { class MockLayer : public Layer { public: explicit MockLayer(SurfaceFlinger* flinger) : Layer(LayerCreationArgs(flinger, nullptr, "TestLayer", 800, 600, 0, {})) {} MockLayer(SurfaceFlinger* flinger, std::string name) : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 800, 600, 0, {})) {} explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {} MOCK_CONST_METHOD0(getType, const char*()); MOCK_METHOD0(getFrameSelectionPriority, int32_t()); Loading Loading
services/surfaceflinger/Scheduler/LayerHistoryV2.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -192,7 +192,7 @@ void LayerHistoryV2::partitionLayers(nsecs_t now) { trace(weak, LayerHistory::LayerVoteType::NoVote, 0); } info->clearHistory(); info->onLayerInactive(now); std::swap(mLayerInfos[i], mLayerInfos[--mActiveLayersEnd]); } Loading @@ -213,7 +213,7 @@ void LayerHistoryV2::clear() { std::lock_guard lock(mLock); for (const auto& [layer, info] : activeLayers()) { info->clearHistory(); info->clearHistory(systemTime()); } } } // namespace android::scheduler::impl
services/surfaceflinger/Scheduler/LayerInfoV2.cpp +2 −9 Original line number Diff line number Diff line Loading @@ -57,21 +57,14 @@ bool LayerInfoV2::isFrameTimeValid(const FrameTimeData& frameTime) const { } bool LayerInfoV2::isFrequent(nsecs_t now) const { // Find the first valid frame time auto it = mFrameTimes.begin(); for (; it != mFrameTimes.end(); ++it) { if (isFrameTimeValid(*it)) { break; } } // If we know nothing about this layer we consider it as frequent as it might be the start // of an animation. if (std::distance(it, mFrameTimes.end()) < FREQUENT_LAYER_WINDOW_SIZE) { if (mFrameTimes.size() < FREQUENT_LAYER_WINDOW_SIZE) { return true; } // Find the first active frame auto it = mFrameTimes.begin(); for (; it != mFrameTimes.end(); ++it) { if (it->queueTime >= getActiveLayerThreshold(now)) { break; Loading
services/surfaceflinger/Scheduler/LayerInfoV2.h +8 −2 Original line number Diff line number Diff line Loading @@ -83,15 +83,21 @@ public: // updated time, the updated time is the present time. nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; } void clearHistory() { void onLayerInactive(nsecs_t now) { // 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(); const auto timePoint = std::chrono::nanoseconds(now); mFrameTimeValidSince = std::chrono::time_point<std::chrono::steady_clock>(timePoint); mLastReportedRefreshRate = 0.0f; } void clearHistory(nsecs_t now) { onLayerInactive(now); mFrameTimes.clear(); } private: // Used to store the layer timestamps struct FrameTimeData { Loading
services/surfaceflinger/tests/unittests/LayerHistoryTestV2.cpp +74 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ protected: static constexpr auto PRESENT_TIME_HISTORY_SIZE = LayerInfoV2::HISTORY_SIZE; static constexpr auto MAX_FREQUENT_LAYER_PERIOD_NS = LayerInfoV2::MAX_FREQUENT_LAYER_PERIOD_NS; static constexpr auto FREQUENT_LAYER_WINDOW_SIZE = LayerInfoV2::FREQUENT_LAYER_WINDOW_SIZE; static constexpr auto PRESENT_TIME_HISTORY_TIME = LayerInfoV2::HISTORY_TIME; static constexpr float LO_FPS = 30.f; static constexpr auto LO_FPS_PERIOD = static_cast<nsecs_t>(1e9f / LO_FPS); Loading Loading @@ -71,6 +72,9 @@ protected: } auto createLayer() { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger())); } auto createLayer(std::string name) { return sp<mock::MockLayer>(new mock::MockLayer(mFlinger.flinger(), std::move(name))); } Hwc2::mock::Display mDisplay; RefreshRateConfigs mConfigs{{HWC2::Display::Config::Builder(mDisplay, 0) Loading Loading @@ -541,5 +545,75 @@ TEST_F(LayerHistoryTestV2, invisibleExplicitLayer) { EXPECT_EQ(2, frequentLayerCount(time)); } class LayerHistoryTestV2Parameterized : public LayerHistoryTestV2, public testing::WithParamInterface<std::chrono::nanoseconds> {}; TEST_P(LayerHistoryTestV2Parameterized, HeuristicLayerWithInfrequentLayer) { std::chrono::nanoseconds infrequentUpdateDelta = GetParam(); auto heuristicLayer = createLayer("HeuristicLayer"); EXPECT_CALL(*heuristicLayer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*heuristicLayer, getFrameRateForLayerTree()) .WillRepeatedly(Return(Layer::FrameRate())); auto infrequentLayer = createLayer("InfrequentLayer"); EXPECT_CALL(*infrequentLayer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*infrequentLayer, getFrameRateForLayerTree()) .WillRepeatedly(Return(Layer::FrameRate())); const nsecs_t startTime = systemTime(); const std::chrono::nanoseconds heuristicUpdateDelta = 41'666'667ns; history().record(heuristicLayer.get(), startTime, startTime); history().record(infrequentLayer.get(), startTime, startTime); nsecs_t time = startTime; nsecs_t lastInfrequentUpdate = startTime; const int totalInfrequentLayerUpdates = FREQUENT_LAYER_WINDOW_SIZE * 5; int infrequentLayerUpdates = 0; while (infrequentLayerUpdates <= totalInfrequentLayerUpdates) { time += heuristicUpdateDelta.count(); history().record(heuristicLayer.get(), time, time); if (time - lastInfrequentUpdate >= infrequentUpdateDelta.count()) { ALOGI("submitting infrequent frame [%d/%d]", infrequentLayerUpdates, totalInfrequentLayerUpdates); lastInfrequentUpdate = time; history().record(infrequentLayer.get(), time, time); infrequentLayerUpdates++; } if (time - startTime > PRESENT_TIME_HISTORY_TIME.count()) { ASSERT_NE(0, history().summarize(time).size()); ASSERT_GE(2, history().summarize(time).size()); bool max = false; bool min = false; float heuristic = 0; for (const auto& layer : history().summarize(time)) { if (layer.vote == LayerHistory::LayerVoteType::Heuristic) { heuristic = layer.desiredRefreshRate; } else if (layer.vote == LayerHistory::LayerVoteType::Max) { max = true; } else if (layer.vote == LayerHistory::LayerVoteType::Min) { min = true; } } if (infrequentLayerUpdates > FREQUENT_LAYER_WINDOW_SIZE) { EXPECT_FLOAT_EQ(24.0f, heuristic); EXPECT_FALSE(max); if (history().summarize(time).size() == 2) { EXPECT_TRUE(min); } } } } } INSTANTIATE_TEST_CASE_P(LeapYearTests, LayerHistoryTestV2Parameterized, ::testing::Values(1s, 2s, 3s, 4s, 5s)); } // namespace } // namespace android::scheduler
services/surfaceflinger/tests/unittests/mock/MockLayer.h +3 −2 Original line number Diff line number Diff line Loading @@ -24,8 +24,9 @@ namespace android::mock { class MockLayer : public Layer { public: explicit MockLayer(SurfaceFlinger* flinger) : Layer(LayerCreationArgs(flinger, nullptr, "TestLayer", 800, 600, 0, {})) {} MockLayer(SurfaceFlinger* flinger, std::string name) : Layer(LayerCreationArgs(flinger, nullptr, std::move(name), 800, 600, 0, {})) {} explicit MockLayer(SurfaceFlinger* flinger) : MockLayer(flinger, "TestLayer") {} MOCK_CONST_METHOD0(getType, const char*()); MOCK_METHOD0(getFrameSelectionPriority, int32_t()); Loading