diff options
| author | 2022-02-26 09:17:49 -0800 | |
|---|---|---|
| committer | 2022-03-01 23:51:40 +0000 | |
| commit | 47183ae01af735473ec636e16aa8293da839efac (patch) | |
| tree | df3dd0d5ccffe0b94b3f6bd9e859ca06c7f7cb73 | |
| parent | 7234fa59245e20b934a15ebbd27d4e189ad224d0 (diff) | |
SF: Add composition strategy prediction stats
Track number of frames we attempted to predict
the composition strategy and the number of
frames it was successful. This should only be used
as a convenient way to debug locally. Composition
strategy prediction hit and misses are also tracked
via trace tags and can be extracted for metrics.
Enable stats: adb shell su root dumpsys SurfaceFlinger --timestats -enable
Dump stats: adb shell su root dumpsys SurfaceFlinger --timestats -dump -maxlayers 0
Clear stats: adb shell su root dumpsys SurfaceFlinger --timestats -clear
Test: adb shell
Bug: 220031739
Change-Id: I073172977b3df9c8b6894acdc1e327898cab2580
12 files changed, 155 insertions, 100 deletions
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h index ed1ddc172c..2b1f50ff57 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/GpuCompositionResult.h @@ -22,9 +22,6 @@ namespace android::compositionengine::impl { struct GpuCompositionResult { - // True if composition strategy was predicted successfully. - bool succeeded = false; - // Composition ready fence. base::unique_fd fence{}; diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h index 92f22b6a16..ade9b25b63 100644 --- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h +++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h @@ -141,6 +141,18 @@ struct OutputCompositionState { // This is slightly distinct from nits, in that nits cannot be passed to hw composer. std::optional<float> displayBrightness = std::nullopt; + enum class CompositionStrategyPredictionState : uint32_t { + // Composition strategy prediction did not run for this frame. + DISABLED = 0, + // Composition strategy predicted successfully for this frame. + SUCCESS = 1, + // Composition strategy prediction failed for this frame. + FAIL = 2, + }; + + CompositionStrategyPredictionState strategyPrediction = + CompositionStrategyPredictionState::DISABLED; + // Debugging void dump(std::string& result) const; }; diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp index 8d560d732c..e4bd325f99 100644 --- a/services/surfaceflinger/CompositionEngine/src/Output.cpp +++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp @@ -58,7 +58,8 @@ namespace android::compositionengine { Output::~Output() = default; namespace impl { - +using CompositionStrategyPredictionState = + OutputCompositionState::CompositionStrategyPredictionState; namespace { template <typename T> @@ -966,6 +967,7 @@ void Output::prepareFrame() { } auto changes = chooseCompositionStrategy(); + outputState.strategyPrediction = CompositionStrategyPredictionState::DISABLED; outputState.previousDeviceRequestedChanges = changes; if (changes) { applyCompositionStrategy(changes); @@ -1002,7 +1004,8 @@ GpuCompositionResult Output::prepareFrameAsync(const CompositionRefreshArgs& ref auto changes = hwcResult.valid() ? hwcResult.get() : std::nullopt; const bool predictionSucceeded = dequeueSucceeded && changes == previousChanges; - compositionResult.succeeded = predictionSucceeded; + state.strategyPrediction = predictionSucceeded ? CompositionStrategyPredictionState::SUCCESS + : CompositionStrategyPredictionState::FAIL; if (!predictionSucceeded) { ATRACE_NAME("CompositionStrategyPredictionMiss"); if (changes) { @@ -1044,15 +1047,15 @@ void Output::devOptRepaintFlash(const compositionengine::CompositionRefreshArgs& void Output::finishFrame(const CompositionRefreshArgs& refreshArgs, GpuCompositionResult&& result) { ATRACE_CALL(); ALOGV(__FUNCTION__); - - if (!getState().isEnabled) { + const auto& outputState = getState(); + if (!outputState.isEnabled) { return; } std::optional<base::unique_fd> optReadyFence; std::shared_ptr<renderengine::ExternalTexture> buffer; base::unique_fd bufferFence; - if (result.succeeded) { + if (outputState.strategyPrediction == CompositionStrategyPredictionState::SUCCESS) { optReadyFence = std::move(result.fence); } else { if (result.bufferAvailable()) { diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp index 482250a165..7188281974 100644 --- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp +++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp @@ -18,6 +18,19 @@ #include <compositionengine/impl/OutputCompositionState.h> namespace android::compositionengine::impl { +using CompositionStrategyPredictionState = + OutputCompositionState::CompositionStrategyPredictionState; + +std::string toString(CompositionStrategyPredictionState state) { + switch (state) { + case CompositionStrategyPredictionState::DISABLED: + return "Disabled"; + case CompositionStrategyPredictionState::SUCCESS: + return "Success"; + case CompositionStrategyPredictionState::FAIL: + return "Fail"; + } +} void OutputCompositionState::dump(std::string& out) const { out.append(" "); @@ -56,6 +69,7 @@ void OutputCompositionState::dump(std::string& out) const { dumpVal(out, "sdrWhitePointNits", sdrWhitePointNits); dumpVal(out, "clientTargetBrightness", clientTargetBrightness); dumpVal(out, "displayBrightness", displayBrightness); + dumpVal(out, "compositionStrategyPredictionState", toString(strategyPrediction)); out.append("\n"); } diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp index 4e875c8a25..0c5ea79350 100644 --- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp +++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp @@ -74,6 +74,9 @@ const mat4 kNonIdentityQuarter = mat4() * 0.25f; constexpr OutputColorSetting kVendorSpecifiedOutputColorSetting = static_cast<OutputColorSetting>(0x100); +using CompositionStrategyPredictionState = android::compositionengine::impl:: + OutputCompositionState::CompositionStrategyPredictionState; + struct OutputPartialMockBase : public impl::Output { // compositionengine::Output overrides const OutputCompositionState& getState() const override { return mState; } @@ -1021,6 +1024,7 @@ TEST_F(OutputPrepareFrameTest, delegatesToChooseCompositionStrategyAndRenderSurf EXPECT_CALL(*mRenderSurface, prepareFrame(false, true)); mOutput.prepareFrame(); + EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::DISABLED); } // Note: Use OutputTest and not OutputPrepareFrameTest, so the real @@ -1036,6 +1040,7 @@ TEST_F(OutputTest, prepareFrameSetsClientCompositionOnlyByDefault) { EXPECT_TRUE(mOutput->getState().usesClientComposition); EXPECT_FALSE(mOutput->getState().usesDeviceComposition); + EXPECT_EQ(mOutput->getState().strategyPrediction, CompositionStrategyPredictionState::DISABLED); } struct OutputPrepareFrameAsyncTest : public testing::Test { @@ -1084,7 +1089,7 @@ TEST_F(OutputPrepareFrameAsyncTest, delegatesToChooseCompositionStrategyAndRende EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _)); impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs); - EXPECT_TRUE(result.succeeded); + EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::SUCCESS); EXPECT_FALSE(result.bufferAvailable()); } @@ -1104,7 +1109,7 @@ TEST_F(OutputPrepareFrameAsyncTest, skipCompositionOnDequeueFailure) { EXPECT_CALL(mOutput, chooseCompositionStrategyAsync()).WillOnce([&] { return p.get_future(); }); impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs); - EXPECT_FALSE(result.succeeded); + EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::FAIL); EXPECT_FALSE(result.bufferAvailable()); } @@ -1132,7 +1137,7 @@ TEST_F(OutputPrepareFrameAsyncTest, chooseCompositionStrategyFailureCallsPrepare EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _)); impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs); - EXPECT_FALSE(result.succeeded); + EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::FAIL); EXPECT_TRUE(result.bufferAvailable()); } @@ -1161,7 +1166,7 @@ TEST_F(OutputPrepareFrameAsyncTest, predictionMiss) { EXPECT_CALL(mOutput, composeSurfaces(_, Ref(mRefreshArgs), _, _)); impl::GpuCompositionResult result = mOutput.prepareFrameAsync(mRefreshArgs); - EXPECT_FALSE(result.succeeded); + EXPECT_EQ(mOutput.getState().strategyPrediction, CompositionStrategyPredictionState::FAIL); EXPECT_TRUE(result.bufferAvailable()); } @@ -3005,22 +3010,21 @@ TEST_F(OutputFinishFrameTest, queuesBufferIfComposeSurfacesReturnsAFence) { TEST_F(OutputFinishFrameTest, predictionSucceeded) { mOutput.mState.isEnabled = true; - + mOutput.mState.strategyPrediction = CompositionStrategyPredictionState::SUCCESS; InSequence seq; EXPECT_CALL(*mRenderSurface, queueBuffer(_)); impl::GpuCompositionResult result; - result.succeeded = true; mOutput.finishFrame(mRefreshArgs, std::move(result)); } TEST_F(OutputFinishFrameTest, predictionFailedAndBufferIsReused) { mOutput.mState.isEnabled = true; + mOutput.mState.strategyPrediction = CompositionStrategyPredictionState::FAIL; InSequence seq; impl::GpuCompositionResult result; - result.succeeded = false; result.buffer = std::make_shared<renderengine::mock::FakeExternalTexture>(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index c8f0dfb9d0..688541faf7 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -169,6 +169,8 @@ using aidl::android::hardware::graphics::common::DisplayDecorationSupport; using aidl::android::hardware::graphics::composer3::Capability; using aidl::android::hardware::graphics::composer3::DisplayCapability; +using CompositionStrategyPredictionState = android::compositionengine::impl:: + OutputCompositionState::CompositionStrategyPredictionState; namespace android { @@ -2263,24 +2265,24 @@ void SurfaceFlinger::composite(nsecs_t frameTime) { const bool prevFrameHadClientComposition = mHadClientComposition; - mHadClientComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) { - const auto& state = pair.second->getCompositionDisplay()->getState(); - return state.usesClientComposition && !state.reusedClientComposition; - }); - mHadDeviceComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) { - const auto& state = pair.second->getCompositionDisplay()->getState(); - return state.usesDeviceComposition; - }); - mReusedClientComposition = - std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) { - const auto& state = pair.second->getCompositionDisplay()->getState(); - return state.reusedClientComposition; - }); - // Only report a strategy change if we move in and out of client composition - if (prevFrameHadClientComposition != mHadClientComposition) { - mTimeStats->incrementCompositionStrategyChanges(); + mHadClientComposition = mHadDeviceComposition = mReusedClientComposition = false; + TimeStats::ClientCompositionRecord clientCompositionRecord; + for (const auto& [_, display] : displays) { + const auto& state = display->getCompositionDisplay()->getState(); + mHadClientComposition |= state.usesClientComposition && !state.reusedClientComposition; + mHadDeviceComposition |= state.usesDeviceComposition; + mReusedClientComposition |= state.reusedClientComposition; + clientCompositionRecord.predicted |= + (state.strategyPrediction != CompositionStrategyPredictionState::DISABLED); + clientCompositionRecord.predictionSucceeded |= + (state.strategyPrediction == CompositionStrategyPredictionState::SUCCESS); } + clientCompositionRecord.hadClientComposition = mHadClientComposition; + clientCompositionRecord.reused = mReusedClientComposition; + clientCompositionRecord.changed = prevFrameHadClientComposition != mHadClientComposition; + mTimeStats->pushCompositionStrategyState(clientCompositionRecord); + // TODO: b/160583065 Enable skip validation when SF caches all client composition layers const bool usedGpuComposition = mHadClientComposition || mReusedClientComposition; modulateVsync(&VsyncModulator::onDisplayRefresh, usedGpuComposition); @@ -2535,13 +2537,6 @@ void SurfaceFlinger::postComposition() { } mTimeStats->incrementTotalFrames(); - if (mHadClientComposition) { - mTimeStats->incrementClientCompositionFrames(); - } - - if (mReusedClientComposition) { - mTimeStats->incrementClientCompositionReusedFrames(); - } mTimeStats->setPresentFenceGlobal(mPreviousPresentFences[0].fenceTime); diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp index b1a2bdaa91..e5a9dd47c3 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.cpp +++ b/services/surfaceflinger/TimeStats/TimeStats.cpp @@ -321,22 +321,19 @@ void TimeStats::incrementMissedFrames() { mTimeStats.missedFramesLegacy++; } -void TimeStats::incrementClientCompositionFrames() { - if (!mEnabled.load()) return; - - ATRACE_CALL(); - - std::lock_guard<std::mutex> lock(mMutex); - mTimeStats.clientCompositionFramesLegacy++; -} - -void TimeStats::incrementClientCompositionReusedFrames() { - if (!mEnabled.load()) return; +void TimeStats::pushCompositionStrategyState(const TimeStats::ClientCompositionRecord& record) { + if (!mEnabled.load() || !record.hasInterestingData()) { + return; + } ATRACE_CALL(); std::lock_guard<std::mutex> lock(mMutex); - mTimeStats.clientCompositionReusedFramesLegacy++; + if (record.changed) mTimeStats.compositionStrategyChangesLegacy++; + if (record.hadClientComposition) mTimeStats.clientCompositionFramesLegacy++; + if (record.reused) mTimeStats.clientCompositionReusedFramesLegacy++; + if (record.predicted) mTimeStats.compositionStrategyPredictedLegacy++; + if (record.predictionSucceeded) mTimeStats.compositionStrategyPredictionSucceededLegacy++; } void TimeStats::incrementRefreshRateSwitches() { @@ -348,15 +345,6 @@ void TimeStats::incrementRefreshRateSwitches() { mTimeStats.refreshRateSwitchesLegacy++; } -void TimeStats::incrementCompositionStrategyChanges() { - if (!mEnabled.load()) return; - - ATRACE_CALL(); - - std::lock_guard<std::mutex> lock(mMutex); - mTimeStats.compositionStrategyChangesLegacy++; -} - void TimeStats::recordDisplayEventConnectionCount(int32_t count) { if (!mEnabled.load()) return; @@ -1062,8 +1050,10 @@ void TimeStats::clearGlobalLocked() { mTimeStats.missedFramesLegacy = 0; mTimeStats.clientCompositionFramesLegacy = 0; mTimeStats.clientCompositionReusedFramesLegacy = 0; - mTimeStats.refreshRateSwitchesLegacy = 0; mTimeStats.compositionStrategyChangesLegacy = 0; + mTimeStats.compositionStrategyPredictedLegacy = 0; + mTimeStats.compositionStrategyPredictionSucceededLegacy = 0; + mTimeStats.refreshRateSwitchesLegacy = 0; mTimeStats.displayEventConnectionsCountLegacy = 0; mTimeStats.displayOnTimeLegacy = 0; mTimeStats.presentToPresentLegacy.hist.clear(); diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h index 77c7973532..7a159b8eb7 100644 --- a/services/surfaceflinger/TimeStats/TimeStats.h +++ b/services/surfaceflinger/TimeStats/TimeStats.h @@ -45,7 +45,7 @@ public: virtual ~TimeStats() = default; // Process a pull request from statsd. - virtual bool onPullAtom(const int atomId, std::string* pulledData); + virtual bool onPullAtom(const int atomId, std::string* pulledData) = 0; virtual void parseArgs(bool asProto, const Vector<String16>& args, std::string& result) = 0; virtual bool isEnabled() = 0; @@ -53,14 +53,8 @@ public: virtual void incrementTotalFrames() = 0; virtual void incrementMissedFrames() = 0; - virtual void incrementClientCompositionFrames() = 0; - virtual void incrementClientCompositionReusedFrames() = 0; // Increments the number of times the display refresh rate changed. virtual void incrementRefreshRateSwitches() = 0; - // Increments the number of changes in composition strategy - // The intention is to reflect the number of changes between hwc and gpu - // composition, where "gpu composition" may also include mixed composition. - virtual void incrementCompositionStrategyChanges() = 0; // Records the most up-to-date count of display event connections. // The stored count will be the maximum ever recoded. virtual void recordDisplayEventConnectionCount(int32_t count) = 0; @@ -158,6 +152,24 @@ public: } }; + struct ClientCompositionRecord { + // Frame had client composition or mixed composition + bool hadClientComposition = false; + // Composition changed between hw composition and mixed/client composition + bool changed = false; + // Frame reused the client composition result from a previous frame + bool reused = false; + // Composition strategy predicted for frame + bool predicted = false; + // Composition strategy prediction succeeded + bool predictionSucceeded = false; + + // Whether there is data we want to record. + bool hasInterestingData() const { + return hadClientComposition || changed || reused || predicted; + } + }; + virtual void incrementJankyFrames(const JankyFramesInfo& info) = 0; // Clean up the layer record virtual void onDestroy(int32_t layerId) = 0; @@ -169,6 +181,7 @@ public: // Source of truth is RefrehRateStats. virtual void recordRefreshRate(uint32_t fps, nsecs_t duration) = 0; virtual void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) = 0; + virtual void pushCompositionStrategyState(const ClientCompositionRecord&) = 0; }; namespace impl { @@ -236,10 +249,7 @@ public: void incrementTotalFrames() override; void incrementMissedFrames() override; - void incrementClientCompositionFrames() override; - void incrementClientCompositionReusedFrames() override; void incrementRefreshRateSwitches() override; - void incrementCompositionStrategyChanges() override; void recordDisplayEventConnectionCount(int32_t count) override; void recordFrameDuration(nsecs_t startTime, nsecs_t endTime) override; @@ -275,6 +285,8 @@ public: void recordRefreshRate(uint32_t fps, nsecs_t duration) override; void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) override; + void pushCompositionStrategyState(const ClientCompositionRecord&) override; + static const size_t MAX_NUM_TIME_RECORDS = 64; private: diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp index 69afa2a7a1..cf1ca65972 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp +++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp @@ -143,6 +143,14 @@ std::string TimeStatsHelper::TimeStatsGlobal::toString(std::optional<uint32_t> m clientCompositionReusedFramesLegacy); StringAppendF(&result, "refreshRateSwitches = %d\n", refreshRateSwitchesLegacy); StringAppendF(&result, "compositionStrategyChanges = %d\n", compositionStrategyChangesLegacy); + StringAppendF(&result, "compositionStrategyPredicted = %d\n", + compositionStrategyPredictedLegacy); + StringAppendF(&result, "compositionStrategyPredictionSucceeded = %d\n", + compositionStrategyPredictionSucceededLegacy); + StringAppendF(&result, "compositionStrategyPredictionFailed = %d\n", + compositionStrategyPredictedLegacy - + compositionStrategyPredictionSucceededLegacy); + StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTimeLegacy); StringAppendF(&result, "displayConfigStats is as below:\n"); for (const auto& [fps, duration] : refreshRateStatsLegacy) { diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h index 438561cc05..237ae8d761 100644 --- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h +++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h @@ -178,6 +178,8 @@ public: Histogram frameDurationLegacy; Histogram renderEngineTimingLegacy; std::unordered_map<uint32_t, nsecs_t> refreshRateStatsLegacy; + int32_t compositionStrategyPredictedLegacy = 0; + int32_t compositionStrategyPredictionSucceededLegacy = 0; std::unordered_map<TimelineStatsKey, TimelineStats, TimelineStatsKey::Hasher> stats; diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp index 0ef8456739..6ffc0396d7 100644 --- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp @@ -268,8 +268,11 @@ TEST_F(TimeStatsTest, canIncreaseGlobalStats) { for (size_t i = 0; i < MISSED_FRAMES; i++) { ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames()); } + TimeStats::ClientCompositionRecord record; + record.hadClientComposition = true; + for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) { - ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames()); + ASSERT_NO_FATAL_FAILURE(mTimeStats->pushCompositionStrategyState(record)); } SFTimeStatsGlobalProto globalProto; @@ -459,19 +462,49 @@ TEST_F(TimeStatsTest, canCaptureSetFrameRateVoteAfterZeroForLayer) { EXPECT_THAT(result, HasSubstr(expectedResult)); } -TEST_F(TimeStatsTest, canIncreaseClientCompositionReusedFrames) { +TEST_F(TimeStatsTest, canIncreaseClientCompositionStats) { // this stat is not in the proto so verify by checking the string dump - constexpr size_t CLIENT_COMPOSITION_REUSED_FRAMES = 2; + constexpr size_t COMPOSITION_STRATEGY_CHANGED_FRAMES = 1; + constexpr size_t HAD_CLIENT_COMPOSITION_FRAMES = 2; + constexpr size_t REUSED_CLIENT_COMPOSITION_FRAMES = 3; + constexpr size_t COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES = 4; + constexpr size_t COMPOSITION_STRATEGY_PREDICTED_FRAMES = 5; EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); - for (size_t i = 0; i < CLIENT_COMPOSITION_REUSED_FRAMES; i++) { - ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames()); + for (size_t i = 0; i <= COMPOSITION_STRATEGY_PREDICTED_FRAMES; i++) { + TimeStats::ClientCompositionRecord record; + record.hadClientComposition = i < HAD_CLIENT_COMPOSITION_FRAMES; + record.changed = i < COMPOSITION_STRATEGY_CHANGED_FRAMES; + record.reused = i < REUSED_CLIENT_COMPOSITION_FRAMES; + record.predicted = i < COMPOSITION_STRATEGY_PREDICTED_FRAMES; + record.predictionSucceeded = i < COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES; + mTimeStats->pushCompositionStrategyState(record); } const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING)); - const std::string expectedResult = - "clientCompositionReusedFrames = " + std::to_string(CLIENT_COMPOSITION_REUSED_FRAMES); - EXPECT_THAT(result, HasSubstr(expectedResult)); + std::string expected = + "compositionStrategyChanges = " + std::to_string(COMPOSITION_STRATEGY_CHANGED_FRAMES); + EXPECT_THAT(result, HasSubstr(expected)); + + expected = "clientCompositionFrames = " + std::to_string(HAD_CLIENT_COMPOSITION_FRAMES); + EXPECT_THAT(result, HasSubstr(expected)); + + expected = + "clientCompositionReusedFrames = " + std::to_string(REUSED_CLIENT_COMPOSITION_FRAMES); + EXPECT_THAT(result, HasSubstr(expected)); + + expected = "compositionStrategyPredicted = " + + std::to_string(COMPOSITION_STRATEGY_PREDICTED_FRAMES); + EXPECT_THAT(result, HasSubstr(expected)); + + expected = "compositionStrategyPredictionSucceeded = " + + std::to_string(COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES); + EXPECT_THAT(result, HasSubstr(expected)); + + expected = "compositionStrategyPredictionFailed = " + + std::to_string(COMPOSITION_STRATEGY_PREDICTED_FRAMES - + COMPOSITION_STRATEGY_PREDICTION_SUCCEEDED_FRAMES); + EXPECT_THAT(result, HasSubstr(expected)); } TEST_F(TimeStatsTest, canIncreaseRefreshRateSwitches) { @@ -489,21 +522,6 @@ TEST_F(TimeStatsTest, canIncreaseRefreshRateSwitches) { EXPECT_THAT(result, HasSubstr(expectedResult)); } -TEST_F(TimeStatsTest, canIncreaseCompositionStrategyChanges) { - // this stat is not in the proto so verify by checking the string dump - constexpr size_t COMPOSITION_STRATEGY_CHANGES = 2; - - EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); - for (size_t i = 0; i < COMPOSITION_STRATEGY_CHANGES; i++) { - ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges()); - } - - const std::string result(inputCommand(InputCommand::DUMP_ALL, FMT_STRING)); - const std::string expectedResult = - "compositionStrategyChanges = " + std::to_string(COMPOSITION_STRATEGY_CHANGES); - EXPECT_THAT(result, HasSubstr(expectedResult)); -} - TEST_F(TimeStatsTest, canAverageFrameDuration) { EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); mTimeStats->setPowerMode(PowerMode::ON); @@ -836,7 +854,7 @@ TEST_F(TimeStatsTest, canClearTimeStats) { ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementTotalFrames()); ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames()); - ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames()); + ASSERT_NO_FATAL_FAILURE(mTimeStats->pushCompositionStrategyState({})); ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(PowerMode::ON)); mTimeStats->recordFrameDuration(std::chrono::nanoseconds(3ms).count(), @@ -867,9 +885,8 @@ TEST_F(TimeStatsTest, canClearTimeStats) { TEST_F(TimeStatsTest, canClearDumpOnlyTimeStats) { // These stats are not in the proto so verify by checking the string dump. EXPECT_TRUE(inputCommand(InputCommand::ENABLE, FMT_STRING).empty()); - ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionReusedFrames()); + ASSERT_NO_FATAL_FAILURE(mTimeStats->pushCompositionStrategyState({})); ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementRefreshRateSwitches()); - ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementCompositionStrategyChanges()); mTimeStats->setPowerMode(PowerMode::ON); mTimeStats->recordFrameDuration(std::chrono::nanoseconds(1ms).count(), std::chrono::nanoseconds(5ms).count()); @@ -1032,8 +1049,10 @@ TEST_F(TimeStatsTest, globalStatsCallback) { for (size_t i = 0; i < MISSED_FRAMES; i++) { mTimeStats->incrementMissedFrames(); } + TimeStats::ClientCompositionRecord record; + record.hadClientComposition = true; for (size_t i = 0; i < CLIENT_COMPOSITION_FRAMES; i++) { - mTimeStats->incrementClientCompositionFrames(); + mTimeStats->pushCompositionStrategyState(record); } insertTimeRecord(NORMAL_SEQUENCE, LAYER_ID_0, 1, 1000000); diff --git a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h index 0a69b562ab..0dee800558 100644 --- a/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h +++ b/services/surfaceflinger/tests/unittests/mock/MockTimeStats.h @@ -33,10 +33,7 @@ public: MOCK_METHOD0(miniDump, std::string()); MOCK_METHOD0(incrementTotalFrames, void()); MOCK_METHOD0(incrementMissedFrames, void()); - MOCK_METHOD0(incrementClientCompositionFrames, void()); - MOCK_METHOD0(incrementClientCompositionReusedFrames, void()); MOCK_METHOD0(incrementRefreshRateSwitches, void()); - MOCK_METHOD0(incrementCompositionStrategyChanges, void()); MOCK_METHOD1(recordDisplayEventConnectionCount, void(int32_t)); MOCK_METHOD2(recordFrameDuration, void(nsecs_t, nsecs_t)); MOCK_METHOD2(recordRenderEngineDuration, void(nsecs_t, nsecs_t)); @@ -63,6 +60,8 @@ public: void(hardware::graphics::composer::V2_4::IComposerClient::PowerMode)); MOCK_METHOD2(recordRefreshRate, void(uint32_t, nsecs_t)); MOCK_METHOD1(setPresentFenceGlobal, void(const std::shared_ptr<FenceTime>&)); + MOCK_METHOD(void, pushCompositionStrategyState, + (const android::TimeStats::ClientCompositionRecord&), (override)); }; } // namespace android::mock |