Loading services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +42 −18 Original line number Diff line number Diff line Loading @@ -504,6 +504,17 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, if (mLastLatchTime != 0 && mPredictions.endTime <= mLastLatchTime) { // Buffer Stuffing. mJankType |= JankType::BufferStuffing; // In a stuffed state, the frame could be stuck on a dequeue wait for quite some time. // Because of this dequeue wait, it can be hard to tell if a frame was genuinely late. // We try to do this by moving the deadline. Since the queue could be stuffed by more // than one buffer, we take the last latch time as reference and give one vsync // worth of time for the frame to be ready. nsecs_t adjustedDeadline = mLastLatchTime + refreshRate.getPeriodNsecs(); if (adjustedDeadline > mActuals.endTime) { mFrameReadyMetadata = FrameReadyMetadata::OnTimeFinish; } else { mFrameReadyMetadata = FrameReadyMetadata::LateFinish; } } if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) { // Finish on time, Present late Loading @@ -511,6 +522,9 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, // Propagate displayFrame's jank if it exists mJankType |= displayFrameJankType; } else { if (!(mJankType & JankType::BufferStuffing)) { // In a stuffed state, if the app finishes on time and there is no display frame // jank, only buffer stuffing is the root cause of the jank. if (deltaToVsync < mJankClassificationThresholds.presentThreshold || deltaToVsync >= refreshRate.getPeriodNsecs() - mJankClassificationThresholds.presentThreshold) { Loading @@ -521,6 +535,7 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, mJankType |= JankType::PredictionError; } } } } else if (mFrameReadyMetadata == FrameReadyMetadata::LateFinish) { // Finish late, Present late if (displayFrameJankType == JankType::None) { Loading Loading @@ -683,13 +698,14 @@ void TokenManager::flushTokens(nsecs_t flushTime) { } FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid, JankClassificationThresholds thresholds) JankClassificationThresholds thresholds, nsecs_t hwcDuration) : mMaxDisplayFrames(kDefaultMaxDisplayFrames), mTimeStats(std::move(timeStats)), mSurfaceFlingerPid(surfaceFlingerPid), mJankClassificationThresholds(thresholds) { mCurrentDisplayFrame = std::make_shared<DisplayFrame>(mTimeStats, thresholds, &mTraceCookieCounter); mJankClassificationThresholds(thresholds), mHwcDuration(hwcDuration) { mCurrentDisplayFrame = std::make_shared<DisplayFrame>(mTimeStats, thresholds, hwcDuration, &mTraceCookieCounter); } void FrameTimeline::onBootFinished() { Loading Loading @@ -732,11 +748,13 @@ std::shared_ptr<SurfaceFrame> FrameTimeline::createSurfaceFrameForToken( FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr<TimeStats> timeStats, JankClassificationThresholds thresholds, nsecs_t hwcDuration, TraceCookieCounter* traceCookieCounter) : mSurfaceFlingerPredictions(TimelineItem()), mSurfaceFlingerActuals(TimelineItem()), mTimeStats(timeStats), mJankClassificationThresholds(thresholds), mHwcDuration(hwcDuration), mTraceCookieCounter(*traceCookieCounter) { mSurfaceFrames.reserve(kNumSurfaceFramesInitial); } Loading Loading @@ -808,7 +826,7 @@ void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) { const nsecs_t presentDelta = mSurfaceFlingerActuals.presentTime - mSurfaceFlingerPredictions.presentTime; const nsecs_t deadlineDelta = mSurfaceFlingerActuals.endTime - mSurfaceFlingerPredictions.endTime; mSurfaceFlingerActuals.endTime - (mSurfaceFlingerPredictions.endTime - mHwcDuration); // How far off was the presentDelta when compared to the vsyncPeriod. Used in checking if there // was a prediction error or not. Loading @@ -822,8 +840,9 @@ void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) { mFramePresentMetadata = FramePresentMetadata::OnTimePresent; } if (mSurfaceFlingerActuals.endTime - mSurfaceFlingerPredictions.endTime > mJankClassificationThresholds.deadlineThreshold) { if (mSurfaceFlingerActuals.endTime > mSurfaceFlingerPredictions.endTime - mHwcDuration) { // SF needs to have finished at least mHwcDuration ahead of the deadline for it to be // on time. mFrameReadyMetadata = FrameReadyMetadata::LateFinish; } else { mFrameReadyMetadata = FrameReadyMetadata::OnTimeFinish; Loading Loading @@ -875,8 +894,13 @@ void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) { mJankType = JankType::PredictionError; } } else if (mFrameReadyMetadata == FrameReadyMetadata::LateFinish) { // Finish late, Present late if (mFrameStartMetadata == FrameStartMetadata::LateStart) { // Late start, Late finish, Late Present mJankType = JankType::SurfaceFlingerScheduling; } else { // OnTime start, Finish late, Present late mJankType = JankType::SurfaceFlingerCpuDeadlineMissed; } } else { // Finish time unknown mJankType = JankType::Unknown; Loading Loading @@ -1066,7 +1090,7 @@ void FrameTimeline::finalizeCurrentDisplayFrame() { mDisplayFrames.push_back(mCurrentDisplayFrame); mCurrentDisplayFrame.reset(); mCurrentDisplayFrame = std::make_shared<DisplayFrame>(mTimeStats, mJankClassificationThresholds, &mTraceCookieCounter); mHwcDuration, &mTraceCookieCounter); } nsecs_t FrameTimeline::DisplayFrame::getBaseTime() const { Loading services/surfaceflinger/FrameTimeline/FrameTimeline.h +10 −2 Original line number Diff line number Diff line Loading @@ -342,7 +342,7 @@ public: class DisplayFrame { public: DisplayFrame(std::shared_ptr<TimeStats> timeStats, JankClassificationThresholds thresholds, TraceCookieCounter* traceCookieCounter); nsecs_t hwcDuration, TraceCookieCounter* traceCookieCounter); virtual ~DisplayFrame() = default; // Dumpsys interface - dumps only if the DisplayFrame itself is janky or is at least one // SurfaceFrame is janky. Loading Loading @@ -371,6 +371,7 @@ public: // Functions to be used only in testing. TimelineItem getActuals() const { return mSurfaceFlingerActuals; }; TimelineItem getPredictions() const { return mSurfaceFlingerPredictions; }; FrameStartMetadata getFrameStartMetadata() const { return mFrameStartMetadata; }; FramePresentMetadata getFramePresentMetadata() const { return mFramePresentMetadata; }; FrameReadyMetadata getFrameReadyMetadata() const { return mFrameReadyMetadata; }; int32_t getJankType() const { return mJankType; } Loading @@ -394,6 +395,7 @@ public: TimelineItem mSurfaceFlingerActuals; std::shared_ptr<TimeStats> mTimeStats; const JankClassificationThresholds mJankClassificationThresholds; const nsecs_t mHwcDuration; // Collection of predictions and actual values sent over by Layers std::vector<std::shared_ptr<SurfaceFrame>> mSurfaceFrames; Loading @@ -419,7 +421,8 @@ public: }; FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid, JankClassificationThresholds thresholds = {}); JankClassificationThresholds thresholds = {}, nsecs_t hwcDuration = kDefaultHwcDuration); ~FrameTimeline() = default; frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; } Loading Loading @@ -464,6 +467,11 @@ private: std::shared_ptr<TimeStats> mTimeStats; const pid_t mSurfaceFlingerPid; const JankClassificationThresholds mJankClassificationThresholds; // In SF Predictions, both end & present are the same. The predictions consider the time used by // composer as well, but we have no way to estimate how much time the composer needs. We are // assuming an arbitrary time for the composer work. const nsecs_t mHwcDuration; static constexpr nsecs_t kDefaultHwcDuration = std::chrono::nanoseconds(3ms).count(); static constexpr uint32_t kDefaultMaxDisplayFrames = 64; // The initial container size for the vector<SurfaceFrames> inside display frame. Although // this number doesn't represent any bounds on the number of surface frames that can go in a Loading services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +216 −162 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +42 −18 Original line number Diff line number Diff line Loading @@ -504,6 +504,17 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, if (mLastLatchTime != 0 && mPredictions.endTime <= mLastLatchTime) { // Buffer Stuffing. mJankType |= JankType::BufferStuffing; // In a stuffed state, the frame could be stuck on a dequeue wait for quite some time. // Because of this dequeue wait, it can be hard to tell if a frame was genuinely late. // We try to do this by moving the deadline. Since the queue could be stuffed by more // than one buffer, we take the last latch time as reference and give one vsync // worth of time for the frame to be ready. nsecs_t adjustedDeadline = mLastLatchTime + refreshRate.getPeriodNsecs(); if (adjustedDeadline > mActuals.endTime) { mFrameReadyMetadata = FrameReadyMetadata::OnTimeFinish; } else { mFrameReadyMetadata = FrameReadyMetadata::LateFinish; } } if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) { // Finish on time, Present late Loading @@ -511,6 +522,9 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, // Propagate displayFrame's jank if it exists mJankType |= displayFrameJankType; } else { if (!(mJankType & JankType::BufferStuffing)) { // In a stuffed state, if the app finishes on time and there is no display frame // jank, only buffer stuffing is the root cause of the jank. if (deltaToVsync < mJankClassificationThresholds.presentThreshold || deltaToVsync >= refreshRate.getPeriodNsecs() - mJankClassificationThresholds.presentThreshold) { Loading @@ -521,6 +535,7 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, mJankType |= JankType::PredictionError; } } } } else if (mFrameReadyMetadata == FrameReadyMetadata::LateFinish) { // Finish late, Present late if (displayFrameJankType == JankType::None) { Loading Loading @@ -683,13 +698,14 @@ void TokenManager::flushTokens(nsecs_t flushTime) { } FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid, JankClassificationThresholds thresholds) JankClassificationThresholds thresholds, nsecs_t hwcDuration) : mMaxDisplayFrames(kDefaultMaxDisplayFrames), mTimeStats(std::move(timeStats)), mSurfaceFlingerPid(surfaceFlingerPid), mJankClassificationThresholds(thresholds) { mCurrentDisplayFrame = std::make_shared<DisplayFrame>(mTimeStats, thresholds, &mTraceCookieCounter); mJankClassificationThresholds(thresholds), mHwcDuration(hwcDuration) { mCurrentDisplayFrame = std::make_shared<DisplayFrame>(mTimeStats, thresholds, hwcDuration, &mTraceCookieCounter); } void FrameTimeline::onBootFinished() { Loading Loading @@ -732,11 +748,13 @@ std::shared_ptr<SurfaceFrame> FrameTimeline::createSurfaceFrameForToken( FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr<TimeStats> timeStats, JankClassificationThresholds thresholds, nsecs_t hwcDuration, TraceCookieCounter* traceCookieCounter) : mSurfaceFlingerPredictions(TimelineItem()), mSurfaceFlingerActuals(TimelineItem()), mTimeStats(timeStats), mJankClassificationThresholds(thresholds), mHwcDuration(hwcDuration), mTraceCookieCounter(*traceCookieCounter) { mSurfaceFrames.reserve(kNumSurfaceFramesInitial); } Loading Loading @@ -808,7 +826,7 @@ void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) { const nsecs_t presentDelta = mSurfaceFlingerActuals.presentTime - mSurfaceFlingerPredictions.presentTime; const nsecs_t deadlineDelta = mSurfaceFlingerActuals.endTime - mSurfaceFlingerPredictions.endTime; mSurfaceFlingerActuals.endTime - (mSurfaceFlingerPredictions.endTime - mHwcDuration); // How far off was the presentDelta when compared to the vsyncPeriod. Used in checking if there // was a prediction error or not. Loading @@ -822,8 +840,9 @@ void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) { mFramePresentMetadata = FramePresentMetadata::OnTimePresent; } if (mSurfaceFlingerActuals.endTime - mSurfaceFlingerPredictions.endTime > mJankClassificationThresholds.deadlineThreshold) { if (mSurfaceFlingerActuals.endTime > mSurfaceFlingerPredictions.endTime - mHwcDuration) { // SF needs to have finished at least mHwcDuration ahead of the deadline for it to be // on time. mFrameReadyMetadata = FrameReadyMetadata::LateFinish; } else { mFrameReadyMetadata = FrameReadyMetadata::OnTimeFinish; Loading Loading @@ -875,8 +894,13 @@ void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) { mJankType = JankType::PredictionError; } } else if (mFrameReadyMetadata == FrameReadyMetadata::LateFinish) { // Finish late, Present late if (mFrameStartMetadata == FrameStartMetadata::LateStart) { // Late start, Late finish, Late Present mJankType = JankType::SurfaceFlingerScheduling; } else { // OnTime start, Finish late, Present late mJankType = JankType::SurfaceFlingerCpuDeadlineMissed; } } else { // Finish time unknown mJankType = JankType::Unknown; Loading Loading @@ -1066,7 +1090,7 @@ void FrameTimeline::finalizeCurrentDisplayFrame() { mDisplayFrames.push_back(mCurrentDisplayFrame); mCurrentDisplayFrame.reset(); mCurrentDisplayFrame = std::make_shared<DisplayFrame>(mTimeStats, mJankClassificationThresholds, &mTraceCookieCounter); mHwcDuration, &mTraceCookieCounter); } nsecs_t FrameTimeline::DisplayFrame::getBaseTime() const { Loading
services/surfaceflinger/FrameTimeline/FrameTimeline.h +10 −2 Original line number Diff line number Diff line Loading @@ -342,7 +342,7 @@ public: class DisplayFrame { public: DisplayFrame(std::shared_ptr<TimeStats> timeStats, JankClassificationThresholds thresholds, TraceCookieCounter* traceCookieCounter); nsecs_t hwcDuration, TraceCookieCounter* traceCookieCounter); virtual ~DisplayFrame() = default; // Dumpsys interface - dumps only if the DisplayFrame itself is janky or is at least one // SurfaceFrame is janky. Loading Loading @@ -371,6 +371,7 @@ public: // Functions to be used only in testing. TimelineItem getActuals() const { return mSurfaceFlingerActuals; }; TimelineItem getPredictions() const { return mSurfaceFlingerPredictions; }; FrameStartMetadata getFrameStartMetadata() const { return mFrameStartMetadata; }; FramePresentMetadata getFramePresentMetadata() const { return mFramePresentMetadata; }; FrameReadyMetadata getFrameReadyMetadata() const { return mFrameReadyMetadata; }; int32_t getJankType() const { return mJankType; } Loading @@ -394,6 +395,7 @@ public: TimelineItem mSurfaceFlingerActuals; std::shared_ptr<TimeStats> mTimeStats; const JankClassificationThresholds mJankClassificationThresholds; const nsecs_t mHwcDuration; // Collection of predictions and actual values sent over by Layers std::vector<std::shared_ptr<SurfaceFrame>> mSurfaceFrames; Loading @@ -419,7 +421,8 @@ public: }; FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid, JankClassificationThresholds thresholds = {}); JankClassificationThresholds thresholds = {}, nsecs_t hwcDuration = kDefaultHwcDuration); ~FrameTimeline() = default; frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; } Loading Loading @@ -464,6 +467,11 @@ private: std::shared_ptr<TimeStats> mTimeStats; const pid_t mSurfaceFlingerPid; const JankClassificationThresholds mJankClassificationThresholds; // In SF Predictions, both end & present are the same. The predictions consider the time used by // composer as well, but we have no way to estimate how much time the composer needs. We are // assuming an arbitrary time for the composer work. const nsecs_t mHwcDuration; static constexpr nsecs_t kDefaultHwcDuration = std::chrono::nanoseconds(3ms).count(); static constexpr uint32_t kDefaultMaxDisplayFrames = 64; // The initial container size for the vector<SurfaceFrames> inside display frame. Although // this number doesn't represent any bounds on the number of surface frames that can go in a Loading
services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +216 −162 File changed.Preview size limit exceeded, changes collapsed. Show changes