Loading services/surfaceflinger/CompositionEngine/src/Display.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -261,7 +261,7 @@ bool Display::chooseCompositionStrategy( } if (isPowerHintSessionEnabled()) { mPowerAdvisor->setValidateTiming(mId, startTime, systemTime()); mPowerAdvisor->setHwcValidateTiming(mId, startTime, systemTime()); mPowerAdvisor->setRequiresClientComposition(mId, requiresClientComposition); } Loading Loading @@ -371,7 +371,7 @@ compositionengine::Output::FrameFences Display::presentAndGetFrameFences() { if (!getCompositionEngine().getHwComposer().getComposer()->isSupported( Hwc2::Composer::OptionalFeature::ExpectedPresentTime) && getState().previousPresentFence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) { mPowerAdvisor->setPresentDelayedTime(mId, getState().earliestPresentTime); mPowerAdvisor->setHwcPresentDelayedTime(mId, getState().earliestPresentTime); } } Loading @@ -379,7 +379,7 @@ compositionengine::Output::FrameFences Display::presentAndGetFrameFences() { getState().previousPresentFence); if (isPowerHintSessionEnabled()) { mPowerAdvisor->setPresentTiming(mId, startTime, systemTime()); mPowerAdvisor->setHwcPresentTiming(mId, startTime, systemTime()); } fences.presentFence = hwc.getPresentFence(*halDisplayIdOpt); Loading services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h +3 −3 Original line number Diff line number Diff line Loading @@ -45,17 +45,17 @@ public: MOCK_METHOD(bool, startPowerHintSession, (const std::vector<int32_t>& threadIds), (override)); MOCK_METHOD(void, setGpuFenceTime, (DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override)); MOCK_METHOD(void, setValidateTiming, MOCK_METHOD(void, setHwcValidateTiming, (DisplayId displayId, nsecs_t valiateStartTime, nsecs_t validateEndTime), (override)); MOCK_METHOD(void, setPresentTiming, MOCK_METHOD(void, setHwcPresentTiming, (DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime), (override)); MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override)); MOCK_METHOD(void, setRequiresClientComposition, (DisplayId displayId, bool requiresClientComposition), (override)); MOCK_METHOD(void, setExpectedPresentTime, (nsecs_t expectedPresentTime), (override)); MOCK_METHOD(void, setPresentDelayedTime, MOCK_METHOD(void, setHwcPresentDelayedTime, (DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime)); MOCK_METHOD(void, setFrameDelay, (nsecs_t frameDelayDuration), (override)); Loading services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +57 −50 Original line number Diff line number Diff line Loading @@ -287,18 +287,18 @@ void PowerAdvisor::setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTim displayData.gpuStartTime = systemTime(); } void PowerAdvisor::setValidateTiming(DisplayId displayId, nsecs_t validateStartTime, void PowerAdvisor::setHwcValidateTiming(DisplayId displayId, nsecs_t validateStartTime, nsecs_t validateEndTime) { DisplayTimingData& displayData = mDisplayTimingData[displayId]; displayData.validateStartTime = validateStartTime; displayData.validateEndTime = validateEndTime; displayData.hwcValidateStartTime = validateStartTime; displayData.hwcValidateEndTime = validateEndTime; } void PowerAdvisor::setPresentTiming(DisplayId displayId, nsecs_t presentStartTime, void PowerAdvisor::setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime) { DisplayTimingData& displayData = mDisplayTimingData[displayId]; displayData.presentStartTime = presentStartTime; displayData.presentEndTime = presentEndTime; displayData.hwcPresentStartTime = presentStartTime; displayData.hwcPresentEndTime = presentEndTime; } void PowerAdvisor::setSkippedValidate(DisplayId displayId, bool skipped) { Loading @@ -318,9 +318,9 @@ void PowerAdvisor::setFrameDelay(nsecs_t frameDelayDuration) { mFrameDelayDuration = frameDelayDuration; } void PowerAdvisor::setPresentDelayedTime( void PowerAdvisor::setHwcPresentDelayedTime( DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime) { mDisplayTimingData[displayId].presentDelayedTime = mDisplayTimingData[displayId].hwcPresentDelayedTime = (earliestFrameStartTime - std::chrono::steady_clock::now()).count() + systemTime(); } Loading @@ -331,10 +331,11 @@ void PowerAdvisor::setCommitStart(nsecs_t commitStartTime) { void PowerAdvisor::setCompositeEnd(nsecs_t compositeEnd) { mLastCompositeEndTime = compositeEnd; // calculate the postcomp time here as well std::vector<DisplayId>&& displays = getOrderedDisplayIds(&DisplayTimingData::presentEndTime); std::vector<DisplayId>&& displays = getOrderedDisplayIds(&DisplayTimingData::hwcPresentEndTime); DisplayTimingData& timingData = mDisplayTimingData[displays.back()]; mLastPostcompDuration = compositeEnd - (timingData.skippedValidate ? *timingData.validateEndTime : *timingData.presentEndTime); (timingData.skippedValidate ? *timingData.hwcValidateEndTime : *timingData.hwcPresentEndTime); } void PowerAdvisor::setDisplays(std::vector<DisplayId>& displayIds) { Loading Loading @@ -390,7 +391,7 @@ std::optional<nsecs_t> PowerAdvisor::estimateWorkDuration(bool earlyHint) { // The timing info for the previously calculated display, if there was one std::optional<DisplayTimeline> previousDisplayReferenceTiming; std::vector<DisplayId>&& displayIds = getOrderedDisplayIds(&DisplayTimingData::presentStartTime); getOrderedDisplayIds(&DisplayTimingData::hwcPresentStartTime); DisplayTimeline referenceTiming, estimatedTiming; // Iterate over the displays in the same order they are presented Loading @@ -402,27 +403,26 @@ std::optional<nsecs_t> PowerAdvisor::estimateWorkDuration(bool earlyHint) { auto& displayData = mDisplayTimingData.at(displayId); referenceTiming = displayData.calculateDisplayTimeline(referenceFenceTime); // If this is the first display, add the pre-present time to the total // If this is the first display, include the duration before hwc present starts if (!previousDisplayReferenceTiming.has_value()) { estimatedEndTime += referenceTiming.prePresentTime - referenceFrameStartTime; } else { // Otherwise add last display's postprocessing time to the total estimatedEndTime += referenceTiming.prePresentTime - previousDisplayReferenceTiming->postPresentTime; estimatedEndTime += referenceTiming.hwcPresentStartTime - referenceFrameStartTime; } else { // Otherwise add the time since last display's hwc present finished estimatedEndTime += referenceTiming.hwcPresentStartTime - previousDisplayReferenceTiming->hwcPresentEndTime; } estimatedTiming = referenceTiming.estimateTimelineFromReference(mExpectedPresentTimes[-1], estimatedEndTime); // Update predicted present finish time with this display's present time estimatedEndTime = estimatedTiming.postPresentTime; estimatedEndTime = estimatedTiming.hwcPresentEndTime; // Track how long we spent waiting for the fence, can be excluded from the timing estimate idleDuration += estimatedTiming.probablyWaitsForFence ? mExpectedPresentTimes[-1] - estimatedTiming.preFenceWaitTime idleDuration += estimatedTiming.probablyWaitsForReleaseFence ? mExpectedPresentTimes[-1] - estimatedTiming.releaseFenceWaitStartTime : 0; // Track how long we spent waiting to present, can be excluded from the timing estimate idleDuration += !earlyHint ? referenceTiming.presentStartTime - referenceTiming.prePresentTime : 0; idleDuration += earlyHint ? 0 : referenceTiming.hwcPresentDelayDuration; // Estimate the reference frame's gpu timing auto gpuTiming = displayData.estimateGpuTiming(previousValidGpuEndTime); Loading @@ -431,7 +431,7 @@ std::optional<nsecs_t> PowerAdvisor::estimateWorkDuration(bool earlyHint) { // Estimate the prediction frame's gpu end time from the reference frame estimatedGpuEndTime = std::max(estimatedTiming.prePresentTime, estimatedGpuEndTime.value_or(0)) + std::max(estimatedTiming.hwcPresentStartTime, estimatedGpuEndTime.value_or(0)) + gpuTiming->duration; } previousDisplayReferenceTiming = referenceTiming; Loading Loading @@ -470,48 +470,55 @@ nsecs_t PowerAdvisor::combineTimingEstimates(nsecs_t totalDuration, nsecs_t flin PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimeline::estimateTimelineFromReference( nsecs_t fenceTime, nsecs_t displayStartTime) { DisplayTimeline estimated; estimated.prePresentTime = displayStartTime; estimated.hwcPresentStartTime = displayStartTime; // We don't predict waiting for vsync alignment yet estimated.presentStartTime = estimated.prePresentTime; estimated.hwcPresentDelayDuration = 0; // For now just re-use last frame's post-present duration and assume it will not change much // How long we expect to run before we start waiting for the fence estimated.preFenceWaitTime = estimated.presentStartTime + (preFenceWaitTime - presentStartTime); estimated.probablyWaitsForFence = fenceTime > estimated.preFenceWaitTime; estimated.postPresentTime = postFenceDuration + (estimated.probablyWaitsForFence ? fenceTime : estimated.preFenceWaitTime); // If it's the early hint we exclude time we spent waiting for a vsync, otherwise don't estimated.releaseFenceWaitStartTime = estimated.hwcPresentStartTime + (releaseFenceWaitStartTime - (hwcPresentStartTime + hwcPresentDelayDuration)); estimated.probablyWaitsForReleaseFence = fenceTime > estimated.releaseFenceWaitStartTime; estimated.hwcPresentEndTime = postReleaseFenceHwcPresentDuration + (estimated.probablyWaitsForReleaseFence ? fenceTime : estimated.releaseFenceWaitStartTime); return estimated; } PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimingData::calculateDisplayTimeline( nsecs_t fenceTime) { DisplayTimeline timeline; // How long between calling present from flinger and trying to wait on the fence in HWC const nsecs_t preFenceWaitDelay = (skippedValidate ? kPrefenceDelaySkippedValidate : kPrefenceDelayValidated).count(); // How long between calling hwc present and trying to wait on the fence const nsecs_t fenceWaitStartDelay = (skippedValidate ? kFenceWaitStartDelaySkippedValidate : kFenceWaitStartDelayValidated) .count(); // Did our reference frame wait for an earliest present time before calling the HWC const bool waitedOnPresentTime = presentDelayedTime.has_value() && *presentDelayedTime > *presentStartTime && *presentDelayedTime < *presentEndTime; // Did our reference frame wait for an appropriate vsync before calling into hwc const bool waitedOnHwcPresentTime = hwcPresentDelayedTime.has_value() && *hwcPresentDelayedTime > *hwcPresentStartTime && *hwcPresentDelayedTime < *hwcPresentEndTime; // Use validate start here if we skipped it because we did validate + present together timeline.prePresentTime = skippedValidate ? *validateStartTime : *presentStartTime; timeline.hwcPresentStartTime = skippedValidate ? *hwcValidateStartTime : *hwcPresentStartTime; // Use validate end here if we skipped it because we did validate + present together timeline.postPresentTime = skippedValidate ? *validateEndTime : *presentEndTime; // When we think we started waiting for the fence after calling into present // This is after any time spent waiting for the earliest present time timeline.presentStartTime = (waitedOnPresentTime ? *presentDelayedTime : timeline.prePresentTime); timeline.preFenceWaitTime = timeline.presentStartTime + preFenceWaitDelay; timeline.probablyWaitsForFence = fenceTime > timeline.preFenceWaitTime && fenceTime < timeline.postPresentTime; // How long we ran after we finished waiting for the fence but before present happened timeline.postFenceDuration = timeline.postPresentTime - (timeline.probablyWaitsForFence ? fenceTime : timeline.preFenceWaitTime); timeline.hwcPresentEndTime = skippedValidate ? *hwcValidateEndTime : *hwcPresentEndTime; // How long hwc present was delayed waiting for the next appropriate vsync timeline.hwcPresentDelayDuration = (waitedOnHwcPresentTime ? *hwcPresentDelayedTime - *hwcPresentStartTime : 0); // When we started waiting for the release fence after calling into hwc present timeline.releaseFenceWaitStartTime = timeline.hwcPresentStartTime + timeline.hwcPresentDelayDuration + fenceWaitStartDelay; timeline.probablyWaitsForReleaseFence = fenceTime > timeline.releaseFenceWaitStartTime && fenceTime < timeline.hwcPresentEndTime; // How long we ran after we finished waiting for the fence but before hwc present finished timeline.postReleaseFenceHwcPresentDuration = timeline.hwcPresentEndTime - (timeline.probablyWaitsForReleaseFence ? fenceTime : timeline.releaseFenceWaitStartTime); return timeline; } Loading services/surfaceflinger/DisplayHardware/PowerAdvisor.h +32 −30 Original line number Diff line number Diff line Loading @@ -64,11 +64,11 @@ public: virtual bool startPowerHintSession(const std::vector<int32_t>& threadIds) = 0; // Provides PowerAdvisor with a copy of the gpu fence so it can determine the gpu end time virtual void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) = 0; // Reports the start and end times of a present call this frame for a given display virtual void setValidateTiming(DisplayId displayId, nsecs_t validateStartTime, // Reports the start and end times of a hwc validate call this frame for a given display virtual void setHwcValidateTiming(DisplayId displayId, nsecs_t validateStartTime, nsecs_t validateEndTime) = 0; // Reports the start and end times of a present call this frame for a given display virtual void setPresentTiming(DisplayId displayId, nsecs_t presentStartTime, // Reports the start and end times of a hwc present call this frame for a given display virtual void setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime) = 0; virtual void setExpectedPresentTime(nsecs_t expectedPresentTime) = 0; // Reports whether a display used client composition this frame Loading @@ -76,8 +76,8 @@ public: bool requiresClientComposition) = 0; // Reports whether a given display skipped validation this frame virtual void setSkippedValidate(DisplayId displayId, bool skipped) = 0; // Reports how much a given display delayed its present call this frame virtual void setPresentDelayedTime( // Reports when a hwc present is delayed, and the time that it will resume virtual void setHwcPresentDelayedTime( DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime) = 0; // Reports the start delay for SurfaceFlinger this frame virtual void setFrameDelay(nsecs_t frameDelayDuration) = 0; Loading Loading @@ -132,14 +132,14 @@ public: void enablePowerHint(bool enabled) override; bool startPowerHintSession(const std::vector<int32_t>& threadIds) override; void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime); void setValidateTiming(DisplayId displayId, nsecs_t valiateStartTime, void setHwcValidateTiming(DisplayId displayId, nsecs_t valiateStartTime, nsecs_t validateEndTime) override; void setPresentTiming(DisplayId displayId, nsecs_t presentStartTime, void setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime) override; void setSkippedValidate(DisplayId displayId, bool skipped) override; void setRequiresClientComposition(DisplayId displayId, bool requiresClientComposition) override; void setExpectedPresentTime(nsecs_t expectedPresentTime) override; void setPresentDelayedTime( void setHwcPresentDelayedTime( DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime) override; Loading @@ -166,17 +166,19 @@ private: // Higher-level timing data used for estimation struct DisplayTimeline { nsecs_t prePresentTime = -1; nsecs_t postPresentTime = -1; // Usually equals prePresentTime but can be delayed if we wait for the next valid vsync nsecs_t presentStartTime = -1; // When we think we started waiting for the fence after calling into present and // The start of hwc present, or the start of validate if it happened there instead nsecs_t hwcPresentStartTime = -1; // The end of hwc present or validate, whichever one actually presented nsecs_t hwcPresentEndTime = -1; // How long the actual hwc present was delayed after hwcPresentStartTime nsecs_t hwcPresentDelayDuration = 0; // When we think we started waiting for the release fence after calling into hwc present and // after potentially waiting for the earliest present time nsecs_t preFenceWaitTime = -1; // How long we ran after we finished waiting for the fence but before present happened nsecs_t postFenceDuration = 0; nsecs_t releaseFenceWaitStartTime = -1; // How long we ran after we finished waiting for the fence but before hwc present finished nsecs_t postReleaseFenceHwcPresentDuration = 0; // Are we likely to have waited for the present fence during composition bool probablyWaitsForFence = false; bool probablyWaitsForReleaseFence = false; // Estimate one frame's timeline from that of a previous frame DisplayTimeline estimateTimelineFromReference(nsecs_t fenceTime, nsecs_t displayStartTime); }; Loading @@ -192,11 +194,11 @@ private: std::optional<nsecs_t> gpuStartTime; std::optional<nsecs_t> lastValidGpuEndTime; std::optional<nsecs_t> lastValidGpuStartTime; std::optional<nsecs_t> presentStartTime; std::optional<nsecs_t> presentEndTime; std::optional<nsecs_t> validateStartTime; std::optional<nsecs_t> validateEndTime; std::optional<nsecs_t> presentDelayedTime; std::optional<nsecs_t> hwcPresentStartTime; std::optional<nsecs_t> hwcPresentEndTime; std::optional<nsecs_t> hwcValidateStartTime; std::optional<nsecs_t> hwcValidateEndTime; std::optional<nsecs_t> hwcPresentDelayedTime; bool usedClientComposition = false; bool skippedValidate = false; // Calculate high-level timing milestones from more granular display timing data Loading Loading @@ -258,13 +260,13 @@ private: // An adjustable safety margin which moves the "target" earlier to allow flinger to // go a bit over without dropping a frame, especially since we can't measure // the exact time HWC finishes composition so "actual" durations are measured // the exact time hwc finishes composition so "actual" durations are measured // from the end of present() instead, which is a bit later. static constexpr const std::chrono::nanoseconds kTargetSafetyMargin = 1ms; // How long we expect hwc to run after the present call until it waits for the fence static constexpr const std::chrono::nanoseconds kPrefenceDelayValidated = 150us; static constexpr const std::chrono::nanoseconds kPrefenceDelaySkippedValidate = 250us; static constexpr const std::chrono::nanoseconds kFenceWaitStartDelayValidated = 150us; static constexpr const std::chrono::nanoseconds kFenceWaitStartDelaySkippedValidate = 250us; }; class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper { Loading services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h +3 −3 Original line number Diff line number Diff line Loading @@ -43,17 +43,17 @@ public: MOCK_METHOD(bool, startPowerHintSession, (const std::vector<int32_t>& threadIds), (override)); MOCK_METHOD(void, setGpuFenceTime, (DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override)); MOCK_METHOD(void, setValidateTiming, MOCK_METHOD(void, setHwcValidateTiming, (DisplayId displayId, nsecs_t valiateStartTime, nsecs_t validateEndTime), (override)); MOCK_METHOD(void, setPresentTiming, MOCK_METHOD(void, setHwcPresentTiming, (DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime), (override)); MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override)); MOCK_METHOD(void, setRequiresClientComposition, (DisplayId displayId, bool requiresClientComposition), (override)); MOCK_METHOD(void, setExpectedPresentTime, (nsecs_t expectedPresentTime), (override)); MOCK_METHOD(void, setPresentDelayedTime, MOCK_METHOD(void, setHwcPresentDelayedTime, (DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime)); MOCK_METHOD(void, setFrameDelay, (nsecs_t frameDelayDuration), (override)); Loading Loading
services/surfaceflinger/CompositionEngine/src/Display.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -261,7 +261,7 @@ bool Display::chooseCompositionStrategy( } if (isPowerHintSessionEnabled()) { mPowerAdvisor->setValidateTiming(mId, startTime, systemTime()); mPowerAdvisor->setHwcValidateTiming(mId, startTime, systemTime()); mPowerAdvisor->setRequiresClientComposition(mId, requiresClientComposition); } Loading Loading @@ -371,7 +371,7 @@ compositionengine::Output::FrameFences Display::presentAndGetFrameFences() { if (!getCompositionEngine().getHwComposer().getComposer()->isSupported( Hwc2::Composer::OptionalFeature::ExpectedPresentTime) && getState().previousPresentFence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) { mPowerAdvisor->setPresentDelayedTime(mId, getState().earliestPresentTime); mPowerAdvisor->setHwcPresentDelayedTime(mId, getState().earliestPresentTime); } } Loading @@ -379,7 +379,7 @@ compositionengine::Output::FrameFences Display::presentAndGetFrameFences() { getState().previousPresentFence); if (isPowerHintSessionEnabled()) { mPowerAdvisor->setPresentTiming(mId, startTime, systemTime()); mPowerAdvisor->setHwcPresentTiming(mId, startTime, systemTime()); } fences.presentFence = hwc.getPresentFence(*halDisplayIdOpt); Loading
services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h +3 −3 Original line number Diff line number Diff line Loading @@ -45,17 +45,17 @@ public: MOCK_METHOD(bool, startPowerHintSession, (const std::vector<int32_t>& threadIds), (override)); MOCK_METHOD(void, setGpuFenceTime, (DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override)); MOCK_METHOD(void, setValidateTiming, MOCK_METHOD(void, setHwcValidateTiming, (DisplayId displayId, nsecs_t valiateStartTime, nsecs_t validateEndTime), (override)); MOCK_METHOD(void, setPresentTiming, MOCK_METHOD(void, setHwcPresentTiming, (DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime), (override)); MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override)); MOCK_METHOD(void, setRequiresClientComposition, (DisplayId displayId, bool requiresClientComposition), (override)); MOCK_METHOD(void, setExpectedPresentTime, (nsecs_t expectedPresentTime), (override)); MOCK_METHOD(void, setPresentDelayedTime, MOCK_METHOD(void, setHwcPresentDelayedTime, (DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime)); MOCK_METHOD(void, setFrameDelay, (nsecs_t frameDelayDuration), (override)); Loading
services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp +57 −50 Original line number Diff line number Diff line Loading @@ -287,18 +287,18 @@ void PowerAdvisor::setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTim displayData.gpuStartTime = systemTime(); } void PowerAdvisor::setValidateTiming(DisplayId displayId, nsecs_t validateStartTime, void PowerAdvisor::setHwcValidateTiming(DisplayId displayId, nsecs_t validateStartTime, nsecs_t validateEndTime) { DisplayTimingData& displayData = mDisplayTimingData[displayId]; displayData.validateStartTime = validateStartTime; displayData.validateEndTime = validateEndTime; displayData.hwcValidateStartTime = validateStartTime; displayData.hwcValidateEndTime = validateEndTime; } void PowerAdvisor::setPresentTiming(DisplayId displayId, nsecs_t presentStartTime, void PowerAdvisor::setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime) { DisplayTimingData& displayData = mDisplayTimingData[displayId]; displayData.presentStartTime = presentStartTime; displayData.presentEndTime = presentEndTime; displayData.hwcPresentStartTime = presentStartTime; displayData.hwcPresentEndTime = presentEndTime; } void PowerAdvisor::setSkippedValidate(DisplayId displayId, bool skipped) { Loading @@ -318,9 +318,9 @@ void PowerAdvisor::setFrameDelay(nsecs_t frameDelayDuration) { mFrameDelayDuration = frameDelayDuration; } void PowerAdvisor::setPresentDelayedTime( void PowerAdvisor::setHwcPresentDelayedTime( DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime) { mDisplayTimingData[displayId].presentDelayedTime = mDisplayTimingData[displayId].hwcPresentDelayedTime = (earliestFrameStartTime - std::chrono::steady_clock::now()).count() + systemTime(); } Loading @@ -331,10 +331,11 @@ void PowerAdvisor::setCommitStart(nsecs_t commitStartTime) { void PowerAdvisor::setCompositeEnd(nsecs_t compositeEnd) { mLastCompositeEndTime = compositeEnd; // calculate the postcomp time here as well std::vector<DisplayId>&& displays = getOrderedDisplayIds(&DisplayTimingData::presentEndTime); std::vector<DisplayId>&& displays = getOrderedDisplayIds(&DisplayTimingData::hwcPresentEndTime); DisplayTimingData& timingData = mDisplayTimingData[displays.back()]; mLastPostcompDuration = compositeEnd - (timingData.skippedValidate ? *timingData.validateEndTime : *timingData.presentEndTime); (timingData.skippedValidate ? *timingData.hwcValidateEndTime : *timingData.hwcPresentEndTime); } void PowerAdvisor::setDisplays(std::vector<DisplayId>& displayIds) { Loading Loading @@ -390,7 +391,7 @@ std::optional<nsecs_t> PowerAdvisor::estimateWorkDuration(bool earlyHint) { // The timing info for the previously calculated display, if there was one std::optional<DisplayTimeline> previousDisplayReferenceTiming; std::vector<DisplayId>&& displayIds = getOrderedDisplayIds(&DisplayTimingData::presentStartTime); getOrderedDisplayIds(&DisplayTimingData::hwcPresentStartTime); DisplayTimeline referenceTiming, estimatedTiming; // Iterate over the displays in the same order they are presented Loading @@ -402,27 +403,26 @@ std::optional<nsecs_t> PowerAdvisor::estimateWorkDuration(bool earlyHint) { auto& displayData = mDisplayTimingData.at(displayId); referenceTiming = displayData.calculateDisplayTimeline(referenceFenceTime); // If this is the first display, add the pre-present time to the total // If this is the first display, include the duration before hwc present starts if (!previousDisplayReferenceTiming.has_value()) { estimatedEndTime += referenceTiming.prePresentTime - referenceFrameStartTime; } else { // Otherwise add last display's postprocessing time to the total estimatedEndTime += referenceTiming.prePresentTime - previousDisplayReferenceTiming->postPresentTime; estimatedEndTime += referenceTiming.hwcPresentStartTime - referenceFrameStartTime; } else { // Otherwise add the time since last display's hwc present finished estimatedEndTime += referenceTiming.hwcPresentStartTime - previousDisplayReferenceTiming->hwcPresentEndTime; } estimatedTiming = referenceTiming.estimateTimelineFromReference(mExpectedPresentTimes[-1], estimatedEndTime); // Update predicted present finish time with this display's present time estimatedEndTime = estimatedTiming.postPresentTime; estimatedEndTime = estimatedTiming.hwcPresentEndTime; // Track how long we spent waiting for the fence, can be excluded from the timing estimate idleDuration += estimatedTiming.probablyWaitsForFence ? mExpectedPresentTimes[-1] - estimatedTiming.preFenceWaitTime idleDuration += estimatedTiming.probablyWaitsForReleaseFence ? mExpectedPresentTimes[-1] - estimatedTiming.releaseFenceWaitStartTime : 0; // Track how long we spent waiting to present, can be excluded from the timing estimate idleDuration += !earlyHint ? referenceTiming.presentStartTime - referenceTiming.prePresentTime : 0; idleDuration += earlyHint ? 0 : referenceTiming.hwcPresentDelayDuration; // Estimate the reference frame's gpu timing auto gpuTiming = displayData.estimateGpuTiming(previousValidGpuEndTime); Loading @@ -431,7 +431,7 @@ std::optional<nsecs_t> PowerAdvisor::estimateWorkDuration(bool earlyHint) { // Estimate the prediction frame's gpu end time from the reference frame estimatedGpuEndTime = std::max(estimatedTiming.prePresentTime, estimatedGpuEndTime.value_or(0)) + std::max(estimatedTiming.hwcPresentStartTime, estimatedGpuEndTime.value_or(0)) + gpuTiming->duration; } previousDisplayReferenceTiming = referenceTiming; Loading Loading @@ -470,48 +470,55 @@ nsecs_t PowerAdvisor::combineTimingEstimates(nsecs_t totalDuration, nsecs_t flin PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimeline::estimateTimelineFromReference( nsecs_t fenceTime, nsecs_t displayStartTime) { DisplayTimeline estimated; estimated.prePresentTime = displayStartTime; estimated.hwcPresentStartTime = displayStartTime; // We don't predict waiting for vsync alignment yet estimated.presentStartTime = estimated.prePresentTime; estimated.hwcPresentDelayDuration = 0; // For now just re-use last frame's post-present duration and assume it will not change much // How long we expect to run before we start waiting for the fence estimated.preFenceWaitTime = estimated.presentStartTime + (preFenceWaitTime - presentStartTime); estimated.probablyWaitsForFence = fenceTime > estimated.preFenceWaitTime; estimated.postPresentTime = postFenceDuration + (estimated.probablyWaitsForFence ? fenceTime : estimated.preFenceWaitTime); // If it's the early hint we exclude time we spent waiting for a vsync, otherwise don't estimated.releaseFenceWaitStartTime = estimated.hwcPresentStartTime + (releaseFenceWaitStartTime - (hwcPresentStartTime + hwcPresentDelayDuration)); estimated.probablyWaitsForReleaseFence = fenceTime > estimated.releaseFenceWaitStartTime; estimated.hwcPresentEndTime = postReleaseFenceHwcPresentDuration + (estimated.probablyWaitsForReleaseFence ? fenceTime : estimated.releaseFenceWaitStartTime); return estimated; } PowerAdvisor::DisplayTimeline PowerAdvisor::DisplayTimingData::calculateDisplayTimeline( nsecs_t fenceTime) { DisplayTimeline timeline; // How long between calling present from flinger and trying to wait on the fence in HWC const nsecs_t preFenceWaitDelay = (skippedValidate ? kPrefenceDelaySkippedValidate : kPrefenceDelayValidated).count(); // How long between calling hwc present and trying to wait on the fence const nsecs_t fenceWaitStartDelay = (skippedValidate ? kFenceWaitStartDelaySkippedValidate : kFenceWaitStartDelayValidated) .count(); // Did our reference frame wait for an earliest present time before calling the HWC const bool waitedOnPresentTime = presentDelayedTime.has_value() && *presentDelayedTime > *presentStartTime && *presentDelayedTime < *presentEndTime; // Did our reference frame wait for an appropriate vsync before calling into hwc const bool waitedOnHwcPresentTime = hwcPresentDelayedTime.has_value() && *hwcPresentDelayedTime > *hwcPresentStartTime && *hwcPresentDelayedTime < *hwcPresentEndTime; // Use validate start here if we skipped it because we did validate + present together timeline.prePresentTime = skippedValidate ? *validateStartTime : *presentStartTime; timeline.hwcPresentStartTime = skippedValidate ? *hwcValidateStartTime : *hwcPresentStartTime; // Use validate end here if we skipped it because we did validate + present together timeline.postPresentTime = skippedValidate ? *validateEndTime : *presentEndTime; // When we think we started waiting for the fence after calling into present // This is after any time spent waiting for the earliest present time timeline.presentStartTime = (waitedOnPresentTime ? *presentDelayedTime : timeline.prePresentTime); timeline.preFenceWaitTime = timeline.presentStartTime + preFenceWaitDelay; timeline.probablyWaitsForFence = fenceTime > timeline.preFenceWaitTime && fenceTime < timeline.postPresentTime; // How long we ran after we finished waiting for the fence but before present happened timeline.postFenceDuration = timeline.postPresentTime - (timeline.probablyWaitsForFence ? fenceTime : timeline.preFenceWaitTime); timeline.hwcPresentEndTime = skippedValidate ? *hwcValidateEndTime : *hwcPresentEndTime; // How long hwc present was delayed waiting for the next appropriate vsync timeline.hwcPresentDelayDuration = (waitedOnHwcPresentTime ? *hwcPresentDelayedTime - *hwcPresentStartTime : 0); // When we started waiting for the release fence after calling into hwc present timeline.releaseFenceWaitStartTime = timeline.hwcPresentStartTime + timeline.hwcPresentDelayDuration + fenceWaitStartDelay; timeline.probablyWaitsForReleaseFence = fenceTime > timeline.releaseFenceWaitStartTime && fenceTime < timeline.hwcPresentEndTime; // How long we ran after we finished waiting for the fence but before hwc present finished timeline.postReleaseFenceHwcPresentDuration = timeline.hwcPresentEndTime - (timeline.probablyWaitsForReleaseFence ? fenceTime : timeline.releaseFenceWaitStartTime); return timeline; } Loading
services/surfaceflinger/DisplayHardware/PowerAdvisor.h +32 −30 Original line number Diff line number Diff line Loading @@ -64,11 +64,11 @@ public: virtual bool startPowerHintSession(const std::vector<int32_t>& threadIds) = 0; // Provides PowerAdvisor with a copy of the gpu fence so it can determine the gpu end time virtual void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) = 0; // Reports the start and end times of a present call this frame for a given display virtual void setValidateTiming(DisplayId displayId, nsecs_t validateStartTime, // Reports the start and end times of a hwc validate call this frame for a given display virtual void setHwcValidateTiming(DisplayId displayId, nsecs_t validateStartTime, nsecs_t validateEndTime) = 0; // Reports the start and end times of a present call this frame for a given display virtual void setPresentTiming(DisplayId displayId, nsecs_t presentStartTime, // Reports the start and end times of a hwc present call this frame for a given display virtual void setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime) = 0; virtual void setExpectedPresentTime(nsecs_t expectedPresentTime) = 0; // Reports whether a display used client composition this frame Loading @@ -76,8 +76,8 @@ public: bool requiresClientComposition) = 0; // Reports whether a given display skipped validation this frame virtual void setSkippedValidate(DisplayId displayId, bool skipped) = 0; // Reports how much a given display delayed its present call this frame virtual void setPresentDelayedTime( // Reports when a hwc present is delayed, and the time that it will resume virtual void setHwcPresentDelayedTime( DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime) = 0; // Reports the start delay for SurfaceFlinger this frame virtual void setFrameDelay(nsecs_t frameDelayDuration) = 0; Loading Loading @@ -132,14 +132,14 @@ public: void enablePowerHint(bool enabled) override; bool startPowerHintSession(const std::vector<int32_t>& threadIds) override; void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime); void setValidateTiming(DisplayId displayId, nsecs_t valiateStartTime, void setHwcValidateTiming(DisplayId displayId, nsecs_t valiateStartTime, nsecs_t validateEndTime) override; void setPresentTiming(DisplayId displayId, nsecs_t presentStartTime, void setHwcPresentTiming(DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime) override; void setSkippedValidate(DisplayId displayId, bool skipped) override; void setRequiresClientComposition(DisplayId displayId, bool requiresClientComposition) override; void setExpectedPresentTime(nsecs_t expectedPresentTime) override; void setPresentDelayedTime( void setHwcPresentDelayedTime( DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime) override; Loading @@ -166,17 +166,19 @@ private: // Higher-level timing data used for estimation struct DisplayTimeline { nsecs_t prePresentTime = -1; nsecs_t postPresentTime = -1; // Usually equals prePresentTime but can be delayed if we wait for the next valid vsync nsecs_t presentStartTime = -1; // When we think we started waiting for the fence after calling into present and // The start of hwc present, or the start of validate if it happened there instead nsecs_t hwcPresentStartTime = -1; // The end of hwc present or validate, whichever one actually presented nsecs_t hwcPresentEndTime = -1; // How long the actual hwc present was delayed after hwcPresentStartTime nsecs_t hwcPresentDelayDuration = 0; // When we think we started waiting for the release fence after calling into hwc present and // after potentially waiting for the earliest present time nsecs_t preFenceWaitTime = -1; // How long we ran after we finished waiting for the fence but before present happened nsecs_t postFenceDuration = 0; nsecs_t releaseFenceWaitStartTime = -1; // How long we ran after we finished waiting for the fence but before hwc present finished nsecs_t postReleaseFenceHwcPresentDuration = 0; // Are we likely to have waited for the present fence during composition bool probablyWaitsForFence = false; bool probablyWaitsForReleaseFence = false; // Estimate one frame's timeline from that of a previous frame DisplayTimeline estimateTimelineFromReference(nsecs_t fenceTime, nsecs_t displayStartTime); }; Loading @@ -192,11 +194,11 @@ private: std::optional<nsecs_t> gpuStartTime; std::optional<nsecs_t> lastValidGpuEndTime; std::optional<nsecs_t> lastValidGpuStartTime; std::optional<nsecs_t> presentStartTime; std::optional<nsecs_t> presentEndTime; std::optional<nsecs_t> validateStartTime; std::optional<nsecs_t> validateEndTime; std::optional<nsecs_t> presentDelayedTime; std::optional<nsecs_t> hwcPresentStartTime; std::optional<nsecs_t> hwcPresentEndTime; std::optional<nsecs_t> hwcValidateStartTime; std::optional<nsecs_t> hwcValidateEndTime; std::optional<nsecs_t> hwcPresentDelayedTime; bool usedClientComposition = false; bool skippedValidate = false; // Calculate high-level timing milestones from more granular display timing data Loading Loading @@ -258,13 +260,13 @@ private: // An adjustable safety margin which moves the "target" earlier to allow flinger to // go a bit over without dropping a frame, especially since we can't measure // the exact time HWC finishes composition so "actual" durations are measured // the exact time hwc finishes composition so "actual" durations are measured // from the end of present() instead, which is a bit later. static constexpr const std::chrono::nanoseconds kTargetSafetyMargin = 1ms; // How long we expect hwc to run after the present call until it waits for the fence static constexpr const std::chrono::nanoseconds kPrefenceDelayValidated = 150us; static constexpr const std::chrono::nanoseconds kPrefenceDelaySkippedValidate = 250us; static constexpr const std::chrono::nanoseconds kFenceWaitStartDelayValidated = 150us; static constexpr const std::chrono::nanoseconds kFenceWaitStartDelaySkippedValidate = 250us; }; class AidlPowerHalWrapper : public PowerAdvisor::HalWrapper { Loading
services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h +3 −3 Original line number Diff line number Diff line Loading @@ -43,17 +43,17 @@ public: MOCK_METHOD(bool, startPowerHintSession, (const std::vector<int32_t>& threadIds), (override)); MOCK_METHOD(void, setGpuFenceTime, (DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override)); MOCK_METHOD(void, setValidateTiming, MOCK_METHOD(void, setHwcValidateTiming, (DisplayId displayId, nsecs_t valiateStartTime, nsecs_t validateEndTime), (override)); MOCK_METHOD(void, setPresentTiming, MOCK_METHOD(void, setHwcPresentTiming, (DisplayId displayId, nsecs_t presentStartTime, nsecs_t presentEndTime), (override)); MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override)); MOCK_METHOD(void, setRequiresClientComposition, (DisplayId displayId, bool requiresClientComposition), (override)); MOCK_METHOD(void, setExpectedPresentTime, (nsecs_t expectedPresentTime), (override)); MOCK_METHOD(void, setPresentDelayedTime, MOCK_METHOD(void, setHwcPresentDelayedTime, (DisplayId displayId, std::chrono::steady_clock::time_point earliestFrameStartTime)); MOCK_METHOD(void, setFrameDelay, (nsecs_t frameDelayDuration), (override)); Loading