Loading services/surfaceflinger/BufferQueueLayer.cpp +4 −2 Original line number Diff line number Diff line Loading @@ -442,7 +442,8 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { } auto surfaceFrame = mFlinger->mFrameTimeline->createSurfaceFrameForToken(mName, mFrameTimelineVsyncId); mFlinger->mFrameTimeline->createSurfaceFrameForToken(mOwnerUid, mName, mName, mFrameTimelineVsyncId); surfaceFrame->setActualQueueTime(systemTime()); mQueueItems.push_back({item, std::move(surfaceFrame)}); Loading Loading @@ -480,7 +481,8 @@ void BufferQueueLayer::onFrameReplaced(const BufferItem& item) { } auto surfaceFrame = mFlinger->mFrameTimeline->createSurfaceFrameForToken(mName, mFrameTimelineVsyncId); mFlinger->mFrameTimeline->createSurfaceFrameForToken(mOwnerUid, mName, mName, mFrameTimelineVsyncId); surfaceFrame->setActualQueueTime(systemTime()); mQueueItems[mQueueItems.size() - 1].item = item; mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame); Loading services/surfaceflinger/BufferStateLayer.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -277,7 +277,7 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence const int32_t layerId = getSequence(); mFlinger->mTimeStats->setPostTime(layerId, mCurrentState.frameNumber, getName().c_str(), postTime); mOwnerUid, postTime); desiredPresentTime = desiredPresentTime <= 0 ? 0 : desiredPresentTime; mCurrentState.desiredPresentTime = desiredPresentTime; Loading services/surfaceflinger/FrameTimeline/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -5,10 +5,12 @@ cc_library_static { "FrameTimeline.cpp", ], shared_libs: [ "android.hardware.graphics.composer@2.4", "libbase", "libcutils", "liblog", "libgui", "libtimestats", "libui", "libutils", ], Loading services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +62 −36 Original line number Diff line number Diff line Loading @@ -93,19 +93,19 @@ std::string toString(PredictionState predictionState) { } } std::string toString(JankType jankType) { std::string toString(TimeStats::JankType jankType) { switch (jankType) { case JankType::None: case TimeStats::JankType::None: return "None"; case JankType::Display: case TimeStats::JankType::Display: return "Composer/Display - outside SF and App"; case JankType::SurfaceFlingerDeadlineMissed: case TimeStats::JankType::SurfaceFlingerDeadlineMissed: return "SurfaceFlinger Deadline Missed"; case JankType::AppDeadlineMissed: case TimeStats::JankType::AppDeadlineMissed: return "App Deadline Missed"; case JankType::PredictionExpired: case TimeStats::JankType::PredictionExpired: return "Prediction Expired"; case JankType::SurfaceFlingerEarlyLatch: case TimeStats::JankType::SurfaceFlingerEarlyLatch: return "SurfaceFlinger Early Latch"; default: return "Unclassified"; Loading Loading @@ -177,15 +177,18 @@ void TokenManager::flushTokens(nsecs_t flushTime) { } } SurfaceFrame::SurfaceFrame(const std::string& layerName, PredictionState predictionState, SurfaceFrame::SurfaceFrame(uid_t ownerUid, std::string layerName, std::string debugName, PredictionState predictionState, frametimeline::TimelineItem&& predictions) : mLayerName(layerName), : mOwnerUid(ownerUid), mLayerName(std::move(layerName)), mDebugName(std::move(debugName)), mPresentState(PresentState::Unknown), mPredictionState(predictionState), mPredictions(predictions), mActuals({0, 0, 0}), mActualQueueTime(0), mJankType(JankType::None), mJankType(TimeStats::JankType::None), mJankMetadata(0) {} void SurfaceFrame::setPresentState(PresentState state) { Loading Loading @@ -227,17 +230,25 @@ void SurfaceFrame::setActualPresentTime(nsecs_t presentTime) { mActuals.presentTime = presentTime; } void SurfaceFrame::setJankInfo(JankType jankType, int32_t jankMetadata) { void SurfaceFrame::setJankInfo(TimeStats::JankType jankType, int32_t jankMetadata) { std::lock_guard<std::mutex> lock(mMutex); mJankType = jankType; mJankMetadata = jankMetadata; } JankType SurfaceFrame::getJankType() const { TimeStats::JankType SurfaceFrame::getJankType() const { std::lock_guard<std::mutex> lock(mMutex); return mJankType; } uid_t SurfaceFrame::getOwnerUid() const { return mOwnerUid; } const std::string& SurfaceFrame::getName() const { return mLayerName; } nsecs_t SurfaceFrame::getBaseTime() const { std::lock_guard<std::mutex> lock(mMutex); nsecs_t baseTime = std::numeric_limits<nsecs_t>::max(); Loading Loading @@ -267,8 +278,8 @@ std::string presentStateToString(SurfaceFrame::PresentState presentState) { void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) { std::lock_guard<std::mutex> lock(mMutex); StringAppendF(&result, "%s", indent.c_str()); StringAppendF(&result, "Layer - %s", mLayerName.c_str()); if (mJankType != JankType::None) { StringAppendF(&result, "Layer - %s", mDebugName.c_str()); if (mJankType != TimeStats::JankType::None) { // Easily identify a janky Surface Frame in the dump StringAppendF(&result, " [*] "); } Loading @@ -285,33 +296,35 @@ void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime); } FrameTimeline::FrameTimeline() FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats) : mCurrentDisplayFrame(std::make_shared<DisplayFrame>()), mMaxDisplayFrames(kDefaultMaxDisplayFrames) {} mMaxDisplayFrames(kDefaultMaxDisplayFrames), mTimeStats(std::move(timeStats)) {} FrameTimeline::DisplayFrame::DisplayFrame() : surfaceFlingerPredictions(TimelineItem()), surfaceFlingerActuals(TimelineItem()), predictionState(PredictionState::None), jankType(JankType::None), jankType(TimeStats::JankType::None), jankMetadata(0) { this->surfaceFrames.reserve(kNumSurfaceFramesInitial); } std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken( const std::string& layerName, std::optional<int64_t> token) { uid_t uid, std::string layerName, std::string debugName, std::optional<int64_t> token) { ATRACE_CALL(); if (!token) { return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::None, TimelineItem()); return std::make_unique<impl::SurfaceFrame>(uid, std::move(layerName), std::move(debugName), PredictionState::None, TimelineItem()); } std::optional<TimelineItem> predictions = mTokenManager.getPredictionsForToken(*token); if (predictions) { return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::Valid, return std::make_unique<impl::SurfaceFrame>(uid, std::move(layerName), std::move(debugName), PredictionState::Valid, std::move(*predictions)); } return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::Expired, TimelineItem()); return std::make_unique<impl::SurfaceFrame>(uid, std::move(layerName), std::move(debugName), PredictionState::Expired, TimelineItem()); } void FrameTimeline::addSurfaceFrame( Loading Loading @@ -359,6 +372,7 @@ void FrameTimeline::flushPendingPresentFences() { } } if (signalTime != Fence::SIGNAL_TIME_INVALID) { int32_t totalJankReasons = TimeStats::JankType::None; auto& displayFrame = pendingPresentFence.second; displayFrame->surfaceFlingerActuals.presentTime = signalTime; Loading @@ -377,21 +391,26 @@ void FrameTimeline::flushPendingPresentFences() { displayFrame->jankMetadata |= EarlyFinish; } if (displayFrame->jankMetadata & EarlyFinish & EarlyPresent) { displayFrame->jankType = JankType::SurfaceFlingerEarlyLatch; } else if (displayFrame->jankMetadata & LateFinish & LatePresent) { displayFrame->jankType = JankType::SurfaceFlingerDeadlineMissed; if ((displayFrame->jankMetadata & EarlyFinish) && (displayFrame->jankMetadata & EarlyPresent)) { displayFrame->jankType = TimeStats::JankType::SurfaceFlingerEarlyLatch; } else if ((displayFrame->jankMetadata & LateFinish) && (displayFrame->jankMetadata & LatePresent)) { displayFrame->jankType = TimeStats::JankType::SurfaceFlingerDeadlineMissed; } else if (displayFrame->jankMetadata & EarlyPresent || displayFrame->jankMetadata & LatePresent) { // Cases where SF finished early but frame was presented late and vice versa displayFrame->jankType = JankType::Display; displayFrame->jankType = TimeStats::JankType::Display; } } if (std::abs(sfActuals.startTime - sfPredictions.startTime) > kSFStartThreshold) { displayFrame->jankMetadata |= sfActuals.startTime > sfPredictions.startTime ? LateStart : EarlyStart; } totalJankReasons |= displayFrame->jankType; for (auto& surfaceFrame : displayFrame->surfaceFrames) { if (surfaceFrame->getPresentState() == SurfaceFrame::PresentState::Presented) { // Only presented SurfaceFrames need to be updated Loading @@ -401,13 +420,13 @@ void FrameTimeline::flushPendingPresentFences() { const auto& predictionState = surfaceFrame->getPredictionState(); if (predictionState == PredictionState::Expired) { // Jank analysis cannot be done on apps that don't use predictions surfaceFrame->setJankInfo(JankType::PredictionExpired, 0); surfaceFrame->setJankInfo(TimeStats::JankType::PredictionExpired, 0); continue; } else if (predictionState == PredictionState::Valid) { const auto& actuals = surfaceFrame->getActuals(); const auto& predictions = surfaceFrame->getPredictions(); int32_t jankMetadata = 0; JankType jankType = JankType::None; TimeStats::JankType jankType = TimeStats::JankType::None; if (std::abs(actuals.endTime - predictions.endTime) > kDeadlineThreshold) { jankMetadata |= actuals.endTime > predictions.endTime ? LateFinish : EarlyFinish; Loading @@ -419,19 +438,26 @@ void FrameTimeline::flushPendingPresentFences() { : EarlyPresent; } if (jankMetadata & EarlyPresent) { jankType = JankType::SurfaceFlingerEarlyLatch; jankType = TimeStats::JankType::SurfaceFlingerEarlyLatch; } else if (jankMetadata & LatePresent) { if (jankMetadata & EarlyFinish) { // TODO(b/169890654): Classify this properly jankType = JankType::Display; jankType = TimeStats::JankType::Display; } else { jankType = JankType::AppDeadlineMissed; jankType = TimeStats::JankType::AppDeadlineMissed; } } totalJankReasons |= jankType; mTimeStats->incrementJankyFrames(surfaceFrame->getOwnerUid(), surfaceFrame->getName(), jankType | displayFrame->jankType); surfaceFrame->setJankInfo(jankType, jankMetadata); } } } mTimeStats->incrementJankyFrames(totalJankReasons); } mPendingPresentFences.erase(mPendingPresentFences.begin() + static_cast<int>(i)); Loading Loading @@ -467,7 +493,7 @@ nsecs_t FrameTimeline::findBaseTime(const std::shared_ptr<DisplayFrame>& display void FrameTimeline::dumpDisplayFrame(std::string& result, const std::shared_ptr<DisplayFrame>& displayFrame, nsecs_t baseTime) { if (displayFrame->jankType != JankType::None) { if (displayFrame->jankType != TimeStats::JankType::None) { // Easily identify a janky Display Frame in the dump StringAppendF(&result, " [*] "); } Loading Loading @@ -501,11 +527,11 @@ void FrameTimeline::dumpJank(std::string& result) { nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : findBaseTime(mDisplayFrames[0]); for (size_t i = 0; i < mDisplayFrames.size(); i++) { const auto& displayFrame = mDisplayFrames[i]; if (displayFrame->jankType == JankType::None) { if (displayFrame->jankType == TimeStats::JankType::None) { // Check if any Surface Frame has been janky bool isJanky = false; for (const auto& surfaceFrame : displayFrame->surfaceFrames) { if (surfaceFrame->getJankType() != JankType::None) { if (surfaceFrame->getJankType() != TimeStats::JankType::None) { isJanky = true; break; } Loading services/surfaceflinger/FrameTimeline/FrameTimeline.h +21 −31 Original line number Diff line number Diff line Loading @@ -16,9 +16,7 @@ #pragma once #include <deque> #include <mutex> #include <../TimeStats/TimeStats.h> #include <gui/ISurfaceComposer.h> #include <ui/FenceTime.h> #include <utils/RefBase.h> Loading @@ -26,26 +24,10 @@ #include <utils/Timers.h> #include <utils/Vector.h> namespace android::frametimeline { #include <deque> #include <mutex> /* * The type of jank that is associated with a Display/Surface frame */ enum class JankType { // No Jank None, // Jank not related to SurfaceFlinger or the App Display, // SF took too long on the CPU SurfaceFlingerDeadlineMissed, // Either App or GPU took too long on the frame AppDeadlineMissed, // Predictions live for 120ms, if prediction is expired for a frame, there is definitely a jank // associated with the App if this is for a SurfaceFrame, and SF for a DisplayFrame. PredictionExpired, // Latching a buffer early might cause an early present of the frame SurfaceFlingerEarlyLatch, }; namespace android::frametimeline { enum JankMetadata { // Frame was presented earlier than expected Loading Loading @@ -147,8 +129,10 @@ public: // Create a new surface frame, set the predictions based on a token and return it to the caller. // Sets the PredictionState of SurfaceFrame. // Debug name is the human-readable debugging string for dumpsys. virtual std::unique_ptr<SurfaceFrame> createSurfaceFrameForToken( const std::string& layerName, std::optional<int64_t> token) = 0; uid_t uid, std::string layerName, std::string debugName, std::optional<int64_t> token) = 0; // Adds a new SurfaceFrame to the current DisplayFrame. Frames from multiple layers can be // composited into one display frame. Loading Loading @@ -206,8 +190,8 @@ private: class SurfaceFrame : public android::frametimeline::SurfaceFrame { public: SurfaceFrame(const std::string& layerName, PredictionState predictionState, TimelineItem&& predictions); SurfaceFrame(uid_t uid, std::string layerName, std::string debugName, PredictionState predictionState, TimelineItem&& predictions); ~SurfaceFrame() = default; TimelineItem getPredictions() const override { return mPredictions; }; Loading @@ -221,32 +205,37 @@ public: void setAcquireFenceTime(nsecs_t acquireFenceTime) override; void setPresentState(PresentState state) override; void setActualPresentTime(nsecs_t presentTime); void setJankInfo(JankType jankType, int32_t jankMetadata); JankType getJankType() const; void setJankInfo(TimeStats::JankType jankType, int32_t jankMetadata); TimeStats::JankType getJankType() const; nsecs_t getBaseTime() const; uid_t getOwnerUid() const; const std::string& getName() const; // All the timestamps are dumped relative to the baseTime void dump(std::string& result, const std::string& indent, nsecs_t baseTime); private: const uid_t mOwnerUid; const std::string mLayerName; const std::string mDebugName; PresentState mPresentState GUARDED_BY(mMutex); const PredictionState mPredictionState; const TimelineItem mPredictions; TimelineItem mActuals GUARDED_BY(mMutex); nsecs_t mActualQueueTime GUARDED_BY(mMutex); mutable std::mutex mMutex; JankType mJankType GUARDED_BY(mMutex); // Enum for the type of jank TimeStats::JankType mJankType GUARDED_BY(mMutex); // Enum for the type of jank int32_t mJankMetadata GUARDED_BY(mMutex); // Additional details about the jank }; class FrameTimeline : public android::frametimeline::FrameTimeline { public: FrameTimeline(); FrameTimeline(std::shared_ptr<TimeStats> timeStats); ~FrameTimeline() = default; frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; } std::unique_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForToken( const std::string& layerName, std::optional<int64_t> token) override; uid_t ownerUid, std::string layerName, std::string debugName, std::optional<int64_t> token) override; void addSurfaceFrame(std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame, SurfaceFrame::PresentState state) override; void setSfWakeUp(int64_t token, nsecs_t wakeupTime) override; Loading Loading @@ -278,7 +267,7 @@ private: std::vector<std::unique_ptr<SurfaceFrame>> surfaceFrames; PredictionState predictionState; JankType jankType = JankType::None; // Enum for the type of jank TimeStats::JankType jankType = TimeStats::JankType::None; // Enum for the type of jank int32_t jankMetadata = 0x0; // Additional details about the jank }; Loading @@ -300,6 +289,7 @@ private: TokenManager mTokenManager; std::mutex mMutex; uint32_t mMaxDisplayFrames; std::shared_ptr<TimeStats> mTimeStats; 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 display Loading Loading
services/surfaceflinger/BufferQueueLayer.cpp +4 −2 Original line number Diff line number Diff line Loading @@ -442,7 +442,8 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) { } auto surfaceFrame = mFlinger->mFrameTimeline->createSurfaceFrameForToken(mName, mFrameTimelineVsyncId); mFlinger->mFrameTimeline->createSurfaceFrameForToken(mOwnerUid, mName, mName, mFrameTimelineVsyncId); surfaceFrame->setActualQueueTime(systemTime()); mQueueItems.push_back({item, std::move(surfaceFrame)}); Loading Loading @@ -480,7 +481,8 @@ void BufferQueueLayer::onFrameReplaced(const BufferItem& item) { } auto surfaceFrame = mFlinger->mFrameTimeline->createSurfaceFrameForToken(mName, mFrameTimelineVsyncId); mFlinger->mFrameTimeline->createSurfaceFrameForToken(mOwnerUid, mName, mName, mFrameTimelineVsyncId); surfaceFrame->setActualQueueTime(systemTime()); mQueueItems[mQueueItems.size() - 1].item = item; mQueueItems[mQueueItems.size() - 1].surfaceFrame = std::move(surfaceFrame); Loading
services/surfaceflinger/BufferStateLayer.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -277,7 +277,7 @@ bool BufferStateLayer::setBuffer(const sp<GraphicBuffer>& buffer, const sp<Fence const int32_t layerId = getSequence(); mFlinger->mTimeStats->setPostTime(layerId, mCurrentState.frameNumber, getName().c_str(), postTime); mOwnerUid, postTime); desiredPresentTime = desiredPresentTime <= 0 ? 0 : desiredPresentTime; mCurrentState.desiredPresentTime = desiredPresentTime; Loading
services/surfaceflinger/FrameTimeline/Android.bp +2 −0 Original line number Diff line number Diff line Loading @@ -5,10 +5,12 @@ cc_library_static { "FrameTimeline.cpp", ], shared_libs: [ "android.hardware.graphics.composer@2.4", "libbase", "libcutils", "liblog", "libgui", "libtimestats", "libui", "libutils", ], Loading
services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +62 −36 Original line number Diff line number Diff line Loading @@ -93,19 +93,19 @@ std::string toString(PredictionState predictionState) { } } std::string toString(JankType jankType) { std::string toString(TimeStats::JankType jankType) { switch (jankType) { case JankType::None: case TimeStats::JankType::None: return "None"; case JankType::Display: case TimeStats::JankType::Display: return "Composer/Display - outside SF and App"; case JankType::SurfaceFlingerDeadlineMissed: case TimeStats::JankType::SurfaceFlingerDeadlineMissed: return "SurfaceFlinger Deadline Missed"; case JankType::AppDeadlineMissed: case TimeStats::JankType::AppDeadlineMissed: return "App Deadline Missed"; case JankType::PredictionExpired: case TimeStats::JankType::PredictionExpired: return "Prediction Expired"; case JankType::SurfaceFlingerEarlyLatch: case TimeStats::JankType::SurfaceFlingerEarlyLatch: return "SurfaceFlinger Early Latch"; default: return "Unclassified"; Loading Loading @@ -177,15 +177,18 @@ void TokenManager::flushTokens(nsecs_t flushTime) { } } SurfaceFrame::SurfaceFrame(const std::string& layerName, PredictionState predictionState, SurfaceFrame::SurfaceFrame(uid_t ownerUid, std::string layerName, std::string debugName, PredictionState predictionState, frametimeline::TimelineItem&& predictions) : mLayerName(layerName), : mOwnerUid(ownerUid), mLayerName(std::move(layerName)), mDebugName(std::move(debugName)), mPresentState(PresentState::Unknown), mPredictionState(predictionState), mPredictions(predictions), mActuals({0, 0, 0}), mActualQueueTime(0), mJankType(JankType::None), mJankType(TimeStats::JankType::None), mJankMetadata(0) {} void SurfaceFrame::setPresentState(PresentState state) { Loading Loading @@ -227,17 +230,25 @@ void SurfaceFrame::setActualPresentTime(nsecs_t presentTime) { mActuals.presentTime = presentTime; } void SurfaceFrame::setJankInfo(JankType jankType, int32_t jankMetadata) { void SurfaceFrame::setJankInfo(TimeStats::JankType jankType, int32_t jankMetadata) { std::lock_guard<std::mutex> lock(mMutex); mJankType = jankType; mJankMetadata = jankMetadata; } JankType SurfaceFrame::getJankType() const { TimeStats::JankType SurfaceFrame::getJankType() const { std::lock_guard<std::mutex> lock(mMutex); return mJankType; } uid_t SurfaceFrame::getOwnerUid() const { return mOwnerUid; } const std::string& SurfaceFrame::getName() const { return mLayerName; } nsecs_t SurfaceFrame::getBaseTime() const { std::lock_guard<std::mutex> lock(mMutex); nsecs_t baseTime = std::numeric_limits<nsecs_t>::max(); Loading Loading @@ -267,8 +278,8 @@ std::string presentStateToString(SurfaceFrame::PresentState presentState) { void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) { std::lock_guard<std::mutex> lock(mMutex); StringAppendF(&result, "%s", indent.c_str()); StringAppendF(&result, "Layer - %s", mLayerName.c_str()); if (mJankType != JankType::None) { StringAppendF(&result, "Layer - %s", mDebugName.c_str()); if (mJankType != TimeStats::JankType::None) { // Easily identify a janky Surface Frame in the dump StringAppendF(&result, " [*] "); } Loading @@ -285,33 +296,35 @@ void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime); } FrameTimeline::FrameTimeline() FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats) : mCurrentDisplayFrame(std::make_shared<DisplayFrame>()), mMaxDisplayFrames(kDefaultMaxDisplayFrames) {} mMaxDisplayFrames(kDefaultMaxDisplayFrames), mTimeStats(std::move(timeStats)) {} FrameTimeline::DisplayFrame::DisplayFrame() : surfaceFlingerPredictions(TimelineItem()), surfaceFlingerActuals(TimelineItem()), predictionState(PredictionState::None), jankType(JankType::None), jankType(TimeStats::JankType::None), jankMetadata(0) { this->surfaceFrames.reserve(kNumSurfaceFramesInitial); } std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken( const std::string& layerName, std::optional<int64_t> token) { uid_t uid, std::string layerName, std::string debugName, std::optional<int64_t> token) { ATRACE_CALL(); if (!token) { return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::None, TimelineItem()); return std::make_unique<impl::SurfaceFrame>(uid, std::move(layerName), std::move(debugName), PredictionState::None, TimelineItem()); } std::optional<TimelineItem> predictions = mTokenManager.getPredictionsForToken(*token); if (predictions) { return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::Valid, return std::make_unique<impl::SurfaceFrame>(uid, std::move(layerName), std::move(debugName), PredictionState::Valid, std::move(*predictions)); } return std::make_unique<impl::SurfaceFrame>(layerName, PredictionState::Expired, TimelineItem()); return std::make_unique<impl::SurfaceFrame>(uid, std::move(layerName), std::move(debugName), PredictionState::Expired, TimelineItem()); } void FrameTimeline::addSurfaceFrame( Loading Loading @@ -359,6 +372,7 @@ void FrameTimeline::flushPendingPresentFences() { } } if (signalTime != Fence::SIGNAL_TIME_INVALID) { int32_t totalJankReasons = TimeStats::JankType::None; auto& displayFrame = pendingPresentFence.second; displayFrame->surfaceFlingerActuals.presentTime = signalTime; Loading @@ -377,21 +391,26 @@ void FrameTimeline::flushPendingPresentFences() { displayFrame->jankMetadata |= EarlyFinish; } if (displayFrame->jankMetadata & EarlyFinish & EarlyPresent) { displayFrame->jankType = JankType::SurfaceFlingerEarlyLatch; } else if (displayFrame->jankMetadata & LateFinish & LatePresent) { displayFrame->jankType = JankType::SurfaceFlingerDeadlineMissed; if ((displayFrame->jankMetadata & EarlyFinish) && (displayFrame->jankMetadata & EarlyPresent)) { displayFrame->jankType = TimeStats::JankType::SurfaceFlingerEarlyLatch; } else if ((displayFrame->jankMetadata & LateFinish) && (displayFrame->jankMetadata & LatePresent)) { displayFrame->jankType = TimeStats::JankType::SurfaceFlingerDeadlineMissed; } else if (displayFrame->jankMetadata & EarlyPresent || displayFrame->jankMetadata & LatePresent) { // Cases where SF finished early but frame was presented late and vice versa displayFrame->jankType = JankType::Display; displayFrame->jankType = TimeStats::JankType::Display; } } if (std::abs(sfActuals.startTime - sfPredictions.startTime) > kSFStartThreshold) { displayFrame->jankMetadata |= sfActuals.startTime > sfPredictions.startTime ? LateStart : EarlyStart; } totalJankReasons |= displayFrame->jankType; for (auto& surfaceFrame : displayFrame->surfaceFrames) { if (surfaceFrame->getPresentState() == SurfaceFrame::PresentState::Presented) { // Only presented SurfaceFrames need to be updated Loading @@ -401,13 +420,13 @@ void FrameTimeline::flushPendingPresentFences() { const auto& predictionState = surfaceFrame->getPredictionState(); if (predictionState == PredictionState::Expired) { // Jank analysis cannot be done on apps that don't use predictions surfaceFrame->setJankInfo(JankType::PredictionExpired, 0); surfaceFrame->setJankInfo(TimeStats::JankType::PredictionExpired, 0); continue; } else if (predictionState == PredictionState::Valid) { const auto& actuals = surfaceFrame->getActuals(); const auto& predictions = surfaceFrame->getPredictions(); int32_t jankMetadata = 0; JankType jankType = JankType::None; TimeStats::JankType jankType = TimeStats::JankType::None; if (std::abs(actuals.endTime - predictions.endTime) > kDeadlineThreshold) { jankMetadata |= actuals.endTime > predictions.endTime ? LateFinish : EarlyFinish; Loading @@ -419,19 +438,26 @@ void FrameTimeline::flushPendingPresentFences() { : EarlyPresent; } if (jankMetadata & EarlyPresent) { jankType = JankType::SurfaceFlingerEarlyLatch; jankType = TimeStats::JankType::SurfaceFlingerEarlyLatch; } else if (jankMetadata & LatePresent) { if (jankMetadata & EarlyFinish) { // TODO(b/169890654): Classify this properly jankType = JankType::Display; jankType = TimeStats::JankType::Display; } else { jankType = JankType::AppDeadlineMissed; jankType = TimeStats::JankType::AppDeadlineMissed; } } totalJankReasons |= jankType; mTimeStats->incrementJankyFrames(surfaceFrame->getOwnerUid(), surfaceFrame->getName(), jankType | displayFrame->jankType); surfaceFrame->setJankInfo(jankType, jankMetadata); } } } mTimeStats->incrementJankyFrames(totalJankReasons); } mPendingPresentFences.erase(mPendingPresentFences.begin() + static_cast<int>(i)); Loading Loading @@ -467,7 +493,7 @@ nsecs_t FrameTimeline::findBaseTime(const std::shared_ptr<DisplayFrame>& display void FrameTimeline::dumpDisplayFrame(std::string& result, const std::shared_ptr<DisplayFrame>& displayFrame, nsecs_t baseTime) { if (displayFrame->jankType != JankType::None) { if (displayFrame->jankType != TimeStats::JankType::None) { // Easily identify a janky Display Frame in the dump StringAppendF(&result, " [*] "); } Loading Loading @@ -501,11 +527,11 @@ void FrameTimeline::dumpJank(std::string& result) { nsecs_t baseTime = (mDisplayFrames.empty()) ? 0 : findBaseTime(mDisplayFrames[0]); for (size_t i = 0; i < mDisplayFrames.size(); i++) { const auto& displayFrame = mDisplayFrames[i]; if (displayFrame->jankType == JankType::None) { if (displayFrame->jankType == TimeStats::JankType::None) { // Check if any Surface Frame has been janky bool isJanky = false; for (const auto& surfaceFrame : displayFrame->surfaceFrames) { if (surfaceFrame->getJankType() != JankType::None) { if (surfaceFrame->getJankType() != TimeStats::JankType::None) { isJanky = true; break; } Loading
services/surfaceflinger/FrameTimeline/FrameTimeline.h +21 −31 Original line number Diff line number Diff line Loading @@ -16,9 +16,7 @@ #pragma once #include <deque> #include <mutex> #include <../TimeStats/TimeStats.h> #include <gui/ISurfaceComposer.h> #include <ui/FenceTime.h> #include <utils/RefBase.h> Loading @@ -26,26 +24,10 @@ #include <utils/Timers.h> #include <utils/Vector.h> namespace android::frametimeline { #include <deque> #include <mutex> /* * The type of jank that is associated with a Display/Surface frame */ enum class JankType { // No Jank None, // Jank not related to SurfaceFlinger or the App Display, // SF took too long on the CPU SurfaceFlingerDeadlineMissed, // Either App or GPU took too long on the frame AppDeadlineMissed, // Predictions live for 120ms, if prediction is expired for a frame, there is definitely a jank // associated with the App if this is for a SurfaceFrame, and SF for a DisplayFrame. PredictionExpired, // Latching a buffer early might cause an early present of the frame SurfaceFlingerEarlyLatch, }; namespace android::frametimeline { enum JankMetadata { // Frame was presented earlier than expected Loading Loading @@ -147,8 +129,10 @@ public: // Create a new surface frame, set the predictions based on a token and return it to the caller. // Sets the PredictionState of SurfaceFrame. // Debug name is the human-readable debugging string for dumpsys. virtual std::unique_ptr<SurfaceFrame> createSurfaceFrameForToken( const std::string& layerName, std::optional<int64_t> token) = 0; uid_t uid, std::string layerName, std::string debugName, std::optional<int64_t> token) = 0; // Adds a new SurfaceFrame to the current DisplayFrame. Frames from multiple layers can be // composited into one display frame. Loading Loading @@ -206,8 +190,8 @@ private: class SurfaceFrame : public android::frametimeline::SurfaceFrame { public: SurfaceFrame(const std::string& layerName, PredictionState predictionState, TimelineItem&& predictions); SurfaceFrame(uid_t uid, std::string layerName, std::string debugName, PredictionState predictionState, TimelineItem&& predictions); ~SurfaceFrame() = default; TimelineItem getPredictions() const override { return mPredictions; }; Loading @@ -221,32 +205,37 @@ public: void setAcquireFenceTime(nsecs_t acquireFenceTime) override; void setPresentState(PresentState state) override; void setActualPresentTime(nsecs_t presentTime); void setJankInfo(JankType jankType, int32_t jankMetadata); JankType getJankType() const; void setJankInfo(TimeStats::JankType jankType, int32_t jankMetadata); TimeStats::JankType getJankType() const; nsecs_t getBaseTime() const; uid_t getOwnerUid() const; const std::string& getName() const; // All the timestamps are dumped relative to the baseTime void dump(std::string& result, const std::string& indent, nsecs_t baseTime); private: const uid_t mOwnerUid; const std::string mLayerName; const std::string mDebugName; PresentState mPresentState GUARDED_BY(mMutex); const PredictionState mPredictionState; const TimelineItem mPredictions; TimelineItem mActuals GUARDED_BY(mMutex); nsecs_t mActualQueueTime GUARDED_BY(mMutex); mutable std::mutex mMutex; JankType mJankType GUARDED_BY(mMutex); // Enum for the type of jank TimeStats::JankType mJankType GUARDED_BY(mMutex); // Enum for the type of jank int32_t mJankMetadata GUARDED_BY(mMutex); // Additional details about the jank }; class FrameTimeline : public android::frametimeline::FrameTimeline { public: FrameTimeline(); FrameTimeline(std::shared_ptr<TimeStats> timeStats); ~FrameTimeline() = default; frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; } std::unique_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForToken( const std::string& layerName, std::optional<int64_t> token) override; uid_t ownerUid, std::string layerName, std::string debugName, std::optional<int64_t> token) override; void addSurfaceFrame(std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame, SurfaceFrame::PresentState state) override; void setSfWakeUp(int64_t token, nsecs_t wakeupTime) override; Loading Loading @@ -278,7 +267,7 @@ private: std::vector<std::unique_ptr<SurfaceFrame>> surfaceFrames; PredictionState predictionState; JankType jankType = JankType::None; // Enum for the type of jank TimeStats::JankType jankType = TimeStats::JankType::None; // Enum for the type of jank int32_t jankMetadata = 0x0; // Additional details about the jank }; Loading @@ -300,6 +289,7 @@ private: TokenManager mTokenManager; std::mutex mMutex; uint32_t mMaxDisplayFrames; std::shared_ptr<TimeStats> mTimeStats; 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 display Loading