Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 785adddc authored by Adithya Srinivasan's avatar Adithya Srinivasan
Browse files

Add isBuffer to SurfaceFrame

Add a boolean that tells if the SurfaceFrame is representing a buffer or
not. This makes it easy to debug lost/stuck frames in the pending
classification list. Also add a miniDump for SurfaceFrame to enable
debugging the lost frame.

Bug: 182214639
Test: Build and flash
Change-Id: I6ceef46887a021c2f36e76f37fab8368802465a4
parent 7c4ac7a3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -177,6 +177,8 @@ void BufferStateLayer::onSurfaceFrameCreated(
        // leak.
        ALOGW("Removing the front of pending jank deque from layer - %s to prevent memory leak",
              mName.c_str());
        std::string miniDump = mPendingJankClassifications.front()->miniDump();
        ALOGD("Head SurfaceFrame mini dump\n%s", miniDump.c_str());
        mPendingJankClassifications.pop_front();
    }
    mPendingJankClassifications.emplace_back(surfaceFrame);
+40 −6
Original line number Diff line number Diff line
@@ -296,7 +296,7 @@ SurfaceFrame::SurfaceFrame(const FrameTimelineInfo& frameTimelineInfo, pid_t own
                           frametimeline::TimelineItem&& predictions,
                           std::shared_ptr<TimeStats> timeStats,
                           JankClassificationThresholds thresholds,
                           TraceCookieCounter* traceCookieCounter)
                           TraceCookieCounter* traceCookieCounter, bool isBuffer)
      : mToken(frameTimelineInfo.vsyncId),
        mInputEventId(frameTimelineInfo.inputEventId),
        mOwnerPid(ownerPid),
@@ -310,7 +310,8 @@ SurfaceFrame::SurfaceFrame(const FrameTimelineInfo& frameTimelineInfo, pid_t own
        mActuals({0, 0, 0}),
        mTimeStats(timeStats),
        mJankClassificationThresholds(thresholds),
        mTraceCookieCounter(*traceCookieCounter) {}
        mTraceCookieCounter(*traceCookieCounter),
        mIsBuffer(isBuffer) {}

void SurfaceFrame::setActualStartTime(nsecs_t actualStartTime) {
    std::scoped_lock lock(mMutex);
@@ -395,6 +396,20 @@ nsecs_t SurfaceFrame::getDropTime() const {
    return mDropTime;
}

void SurfaceFrame::promoteToBuffer() {
    std::scoped_lock lock(mMutex);
    LOG_ALWAYS_FATAL_IF(mIsBuffer == true,
                        "Trying to promote an already promoted BufferSurfaceFrame from layer %s "
                        "with token %" PRId64 "",
                        mDebugName.c_str(), mToken);
    mIsBuffer = true;
}

bool SurfaceFrame::getIsBuffer() const {
    std::scoped_lock lock(mMutex);
    return mIsBuffer;
}

void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t baseTime) const {
    std::scoped_lock lock(mMutex);
    StringAppendF(&result, "%s", indent.c_str());
@@ -407,6 +422,8 @@ void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t
    StringAppendF(&result, "%s", indent.c_str());
    StringAppendF(&result, "Token: %" PRId64 "\n", mToken);
    StringAppendF(&result, "%s", indent.c_str());
    StringAppendF(&result, "Is Buffer?: %d\n", mIsBuffer);
    StringAppendF(&result, "%s", indent.c_str());
    StringAppendF(&result, "Owner Pid : %d\n", mOwnerPid);
    StringAppendF(&result, "%s", indent.c_str());
    StringAppendF(&result, "Scheduled rendering rate: %d fps\n",
@@ -444,6 +461,21 @@ void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t
    dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime);
}

std::string SurfaceFrame::miniDump() const {
    std::scoped_lock lock(mMutex);
    std::string result;
    StringAppendF(&result, "Layer - %s\n", mDebugName.c_str());
    StringAppendF(&result, "Token: %" PRId64 "\n", mToken);
    StringAppendF(&result, "Is Buffer?: %d\n", mIsBuffer);
    StringAppendF(&result, "Present State : %s\n", toString(mPresentState).c_str());
    StringAppendF(&result, "Prediction State : %s\n", toString(mPredictionState).c_str());
    StringAppendF(&result, "Jank Type : %s\n", jankTypeBitmaskToString(mJankType).c_str());
    StringAppendF(&result, "Present Metadata : %s\n", toString(mFramePresentMetadata).c_str());
    StringAppendF(&result, "Finish Metadata: %s\n", toString(mFrameReadyMetadata).c_str());
    StringAppendF(&result, "Present time: %" PRId64 "", mActuals.presentTime);
    return result;
}

void SurfaceFrame::classifyJankLocked(int32_t displayFrameJankType, const Fps& refreshRate,
                                      nsecs_t& deadlineDelta) {
    if (mPredictionState == PredictionState::Expired ||
@@ -744,13 +776,14 @@ void FrameTimeline::registerDataSource() {

std::shared_ptr<SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
        const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid, int32_t layerId,
        std::string layerName, std::string debugName) {
        std::string layerName, std::string debugName, bool isBuffer) {
    ATRACE_CALL();
    if (frameTimelineInfo.vsyncId == FrameTimelineInfo::INVALID_VSYNC_ID) {
        return std::make_shared<SurfaceFrame>(frameTimelineInfo, ownerPid, ownerUid, layerId,
                                              std::move(layerName), std::move(debugName),
                                              PredictionState::None, TimelineItem(), mTimeStats,
                                              mJankClassificationThresholds, &mTraceCookieCounter);
                                              mJankClassificationThresholds, &mTraceCookieCounter,
                                              isBuffer);
    }
    std::optional<TimelineItem> predictions =
            mTokenManager.getPredictionsForToken(frameTimelineInfo.vsyncId);
@@ -759,12 +792,13 @@ std::shared_ptr<SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
                                              std::move(layerName), std::move(debugName),
                                              PredictionState::Valid, std::move(*predictions),
                                              mTimeStats, mJankClassificationThresholds,
                                              &mTraceCookieCounter);
                                              &mTraceCookieCounter, isBuffer);
    }
    return std::make_shared<SurfaceFrame>(frameTimelineInfo, ownerPid, ownerUid, layerId,
                                          std::move(layerName), std::move(debugName),
                                          PredictionState::Expired, TimelineItem(), mTimeStats,
                                          mJankClassificationThresholds, &mTraceCookieCounter);
                                          mJankClassificationThresholds, &mTraceCookieCounter,
                                          isBuffer);
}

FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr<TimeStats> timeStats,
+13 −3
Original line number Diff line number Diff line
@@ -159,7 +159,7 @@ public:
                 int32_t layerId, std::string layerName, std::string debugName,
                 PredictionState predictionState, TimelineItem&& predictions,
                 std::shared_ptr<TimeStats> timeStats, JankClassificationThresholds thresholds,
                 TraceCookieCounter* traceCookieCounter);
                 TraceCookieCounter* traceCookieCounter, bool isBuffer);
    ~SurfaceFrame() = default;

    // Returns std::nullopt if the frame hasn't been classified yet.
@@ -181,6 +181,10 @@ public:
    void setPresentState(PresentState presentState, nsecs_t lastLatchTime = 0);
    void setRenderRate(Fps renderRate);

    // When a bufferless SurfaceFrame is promoted to a buffer SurfaceFrame, we also have to update
    // isBuffer.
    void promoteToBuffer();

    // Functions called by FrameTimeline
    // BaseTime is the smallest timestamp in this SurfaceFrame.
    // Used for dumping all timestamps relative to the oldest, making it easy to read.
@@ -192,6 +196,8 @@ public:
                   nsecs_t displayDeadlineDelta, nsecs_t displayPresentDelta);
    // All the timestamps are dumped relative to the baseTime
    void dump(std::string& result, const std::string& indent, nsecs_t baseTime) const;
    // Dumps only the layer, token, is buffer, jank metadata, prediction and present states.
    std::string miniDump() const;
    // Emits a packet for perfetto tracing. The function body will be executed only if tracing is
    // enabled. The displayFrameToken is needed to link the SurfaceFrame to the corresponding
    // DisplayFrame at the trace processor side.
@@ -206,6 +212,7 @@ public:
    FrameReadyMetadata getFrameReadyMetadata() const;
    FramePresentMetadata getFramePresentMetadata() const;
    nsecs_t getDropTime() const;
    bool getIsBuffer() const;

    // For prediction expired frames, this delta is subtracted from the actual end time to get a
    // start time decent enough to see in traces.
@@ -253,6 +260,9 @@ private:
    // TraceCookieCounter is used to obtain the cookie for sendig trace packets to perfetto. Using a
    // reference here because the counter is owned by FrameTimeline, which outlives SurfaceFrame.
    TraceCookieCounter& mTraceCookieCounter;
    // Tells if the SurfaceFrame is representing a buffer or a transaction without a
    // buffer(animations)
    bool mIsBuffer;
};

/*
@@ -272,7 +282,7 @@ public:
    // Debug name is the human-readable debugging string for dumpsys.
    virtual std::shared_ptr<SurfaceFrame> createSurfaceFrameForToken(
            const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid,
            int32_t layerId, std::string layerName, std::string debugName) = 0;
            int32_t layerId, std::string layerName, std::string debugName, bool isBuffer) = 0;

    // Adds a new SurfaceFrame to the current DisplayFrame. Frames from multiple layers can be
    // composited into one display frame.
@@ -431,7 +441,7 @@ public:
    frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
    std::shared_ptr<SurfaceFrame> createSurfaceFrameForToken(
            const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid,
            int32_t layerId, std::string layerName, std::string debugName) override;
            int32_t layerId, std::string layerName, std::string debugName, bool isBuffer) override;
    void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame) override;
    void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override;
    void setSfPresent(nsecs_t sfPresentTime,
+5 −2
Original line number Diff line number Diff line
@@ -1537,6 +1537,7 @@ void Layer::setFrameTimelineVsyncForBufferTransaction(const FrameTimelineInfo& i
        // Promote the bufferlessSurfaceFrame to a bufferSurfaceFrameTX
        mCurrentState.bufferSurfaceFrameTX = it->second;
        mCurrentState.bufferlessSurfaceFramesTX.erase(it);
        mCurrentState.bufferSurfaceFrameTX->promoteToBuffer();
        mCurrentState.bufferSurfaceFrameTX->setActualQueueTime(postTime);
    } else {
        mCurrentState.bufferSurfaceFrameTX =
@@ -1596,7 +1597,8 @@ std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForTransac
    auto surfaceFrame =
            mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid,
                                                                 getSequence(), mName,
                                                                 mTransactionName);
                                                                 mTransactionName,
                                                                 /*isBuffer*/ false);
    // For Transactions, the post time is considered to be both queue and acquire fence time.
    surfaceFrame->setActualQueueTime(postTime);
    surfaceFrame->setAcquireFenceTime(postTime);
@@ -1612,7 +1614,8 @@ std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForBuffer(
        const FrameTimelineInfo& info, nsecs_t queueTime, std::string debugName) {
    auto surfaceFrame =
            mFlinger->mFrameTimeline->createSurfaceFrameForToken(info, mOwnerPid, mOwnerUid,
                                                                 getSequence(), mName, debugName);
                                                                 getSequence(), mName, debugName,
                                                                 /*isBuffer*/ true);
    // For buffers, acquire fence time will set during latch.
    surfaceFrame->setActualQueueTime(queueTime);
    const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
+88 −60

File changed.

Preview size limit exceeded, changes collapsed.

Loading