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

Commit 7d436ecf authored by Alec Mouri's avatar Alec Mouri
Browse files

Plumb refresh and render rates into shared timeline

* Make the overridden frame rate from the Scheduler public so that
SurfaceFlinger can access it for each uid.
* Add the display refresh rate on each display frame
* Add the application rendering rate on each SurfaceFrame created
* If there is no application rendering rate, then set it to the display
refresh rate.
* Plumb all those metrics into TimeStats.
* Change global metrics to increment for every SurfaceFrame instead of
every DisplayFrame, so that the rendering rate dimension can be
accurately captured.

Bug: 172937287
Test: builds, boots, timestats dump
Change-Id: Icfd4cecfdfa5d6c434661cab91c624eb08e8baea
parent 4cd01842
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -366,8 +366,11 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display,
        mFrameTracker.setFrameReadyTime(desiredPresentTime);
    }

    const Fps refreshRate = mFlinger->mRefreshRateConfigs->getCurrentRefreshRate().getFps();
    const std::optional<Fps> renderRate = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
    if (presentFence->isValid()) {
        mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence);
        mFlinger->mTimeStats->setPresentFence(layerId, mCurrentFrameNumber, presentFence,
                                              refreshRate, renderRate);
        mFlinger->mFrameTracer->traceFence(layerId, getCurrentBufferId(), mCurrentFrameNumber,
                                           presentFence, FrameTracer::FrameEvent::PRESENT_FENCE);
        mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
@@ -378,7 +381,8 @@ bool BufferLayer::onPostComposition(const DisplayDevice* display,
        // The HWC doesn't support present fences, so use the refresh
        // timestamp instead.
        const nsecs_t actualPresentTime = display->getRefreshTimestamp();
        mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime);
        mFlinger->mTimeStats->setPresentTime(layerId, mCurrentFrameNumber, actualPresentTime,
                                             refreshRate, renderRate);
        mFlinger->mFrameTracer->traceTimestamp(layerId, getCurrentBufferId(), mCurrentFrameNumber,
                                               actualPresentTime,
                                               FrameTracer::FrameEvent::PRESENT_FENCE);
+1 −1
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@ namespace android {

// Value which represents "frames per second". This class is a wrapper around
// float, providing some useful utilities, such as comparisons with tolerance
// and converting between period duruation and frequency.
// and converting between period duration and frequency.
class Fps {
public:
    static constexpr Fps fromPeriodNsecs(nsecs_t period) { return Fps(1e9f / period, period); }
+30 −32
Original line number Diff line number Diff line
@@ -320,6 +320,11 @@ void SurfaceFrame::setPresentState(PresentState presentState, nsecs_t lastLatchT
    mLastLatchTime = lastLatchTime;
}

void SurfaceFrame::setRenderRate(Fps renderRate) {
    std::lock_guard<std::mutex> lock(mMutex);
    mRenderRate = renderRate;
}

std::optional<int32_t> SurfaceFrame::getJankType() const {
    std::scoped_lock lock(mMutex);
    if (mActuals.presentTime == 0) {
@@ -367,6 +372,9 @@ void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t
    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",
                  mRenderRate ? mRenderRate->getIntValue() : 0);
    StringAppendF(&result, "%s", indent.c_str());
    StringAppendF(&result, "Present State : %s\n", toString(mPresentState).c_str());
    StringAppendF(&result, "%s", indent.c_str());
    StringAppendF(&result, "Prediction State : %s\n", toString(mPredictionState).c_str());
@@ -391,9 +399,10 @@ void SurfaceFrame::dump(std::string& result, const std::string& indent, nsecs_t
    dumpTable(result, mPredictions, mActuals, indent, mPredictionState, baseTime);
}

void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
                             nsecs_t vsyncPeriod) {
void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType, Fps refreshRate) {
    std::scoped_lock lock(mMutex);

    const Fps renderRate = mRenderRate ? *mRenderRate : refreshRate;
    if (mPresentState != PresentState::Presented) {
        // No need to update dropped buffers
        return;
@@ -412,13 +421,13 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
        mJankType = JankType::Unknown;
        mFramePresentMetadata = FramePresentMetadata::UnknownPresent;
        mFrameReadyMetadata = FrameReadyMetadata::UnknownFinish;
        mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType);
        mTimeStats->incrementJankyFrames(refreshRate, renderRate, mOwnerUid, mLayerName, mJankType);
        return;
    }

    const nsecs_t presentDelta = mActuals.presentTime - mPredictions.presentTime;
    const nsecs_t deadlineDelta = mActuals.endTime - mPredictions.endTime;
    const nsecs_t deltaToVsync = std::abs(presentDelta) % vsyncPeriod;
    const nsecs_t deltaToVsync = std::abs(presentDelta) % refreshRate.getPeriodNsecs();

    if (deadlineDelta > mJankClassificationThresholds.deadlineThreshold) {
        mFrameReadyMetadata = FrameReadyMetadata::LateFinish;
@@ -440,7 +449,8 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
        if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
            // Finish on time, Present early
            if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
                deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) {
                deltaToVsync >= refreshRate.getPeriodNsecs() -
                                mJankClassificationThresholds.presentThreshold) {
                // Delta factor of vsync
                mJankType = JankType::SurfaceFlingerScheduling;
            } else {
@@ -463,7 +473,8 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
                mJankType |= displayFrameJankType;
            } else {
                if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
                    deltaToVsync >= vsyncPeriod - mJankClassificationThresholds.presentThreshold) {
                    deltaToVsync >= refreshRate.getPeriodNsecs() -
                                    mJankClassificationThresholds.presentThreshold) {
                    // Delta factor of vsync
                    mJankType |= JankType::SurfaceFlingerScheduling;
                } else {
@@ -482,7 +493,7 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
            }
        }
    }
    mTimeStats->incrementJankyFrames(mOwnerUid, mLayerName, mJankType);
    mTimeStats->incrementJankyFrames(refreshRate, renderRate, mOwnerUid, mLayerName, mJankType);
}

/**
@@ -684,10 +695,10 @@ void FrameTimeline::addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame)
    mCurrentDisplayFrame->addSurfaceFrame(surfaceFrame);
}

void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, nsecs_t vsyncPeriod) {
void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, Fps refreshRate) {
    ATRACE_CALL();
    std::scoped_lock lock(mMutex);
    mCurrentDisplayFrame->onSfWakeUp(token, vsyncPeriod,
    mCurrentDisplayFrame->onSfWakeUp(token, refreshRate,
                                     mTokenManager.getPredictionsForToken(token), wakeUpTime);
}

@@ -705,11 +716,11 @@ void FrameTimeline::DisplayFrame::addSurfaceFrame(std::shared_ptr<SurfaceFrame>
    mSurfaceFrames.push_back(surfaceFrame);
}

void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, nsecs_t vsyncPeriod,
void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, Fps refreshRate,
                                             std::optional<TimelineItem> predictions,
                                             nsecs_t wakeUpTime) {
    mToken = token;
    mVsyncPeriod = vsyncPeriod;
    mRefreshRate = refreshRate;
    if (!predictions) {
        mPredictionState = PredictionState::Expired;
    } else {
@@ -719,11 +730,6 @@ void FrameTimeline::DisplayFrame::onSfWakeUp(int64_t token, nsecs_t vsyncPeriod,
    mSurfaceFlingerActuals.startTime = wakeUpTime;
}

void FrameTimeline::DisplayFrame::setTokenAndVsyncPeriod(int64_t token, nsecs_t vsyncPeriod) {
    mToken = token;
    mVsyncPeriod = vsyncPeriod;
}

void FrameTimeline::DisplayFrame::setPredictions(PredictionState predictionState,
                                                 TimelineItem predictions) {
    mPredictionState = predictionState;
@@ -740,14 +746,13 @@ void FrameTimeline::DisplayFrame::setActualEndTime(nsecs_t actualEndTime) {

void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) {
    mSurfaceFlingerActuals.presentTime = signalTime;
    int32_t totalJankReasons = JankType::None;

    // Delta between the expected present and the actual present
    const nsecs_t presentDelta =
            mSurfaceFlingerActuals.presentTime - mSurfaceFlingerPredictions.presentTime;
    // How far off was the presentDelta when compared to the vsyncPeriod. Used in checking if there
    // was a prediction error or not.
    nsecs_t deltaToVsync = std::abs(presentDelta) % mVsyncPeriod;
    nsecs_t deltaToVsync = std::abs(presentDelta) % mRefreshRate.getPeriodNsecs();
    if (std::abs(presentDelta) > mJankClassificationThresholds.presentThreshold) {
        mFramePresentMetadata = presentDelta > 0 ? FramePresentMetadata::LatePresent
                                                 : FramePresentMetadata::EarlyPresent;
@@ -776,8 +781,8 @@ void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) {
            if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
                // Finish on time, Present early
                if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
                    deltaToVsync >=
                            (mVsyncPeriod - mJankClassificationThresholds.presentThreshold)) {
                    deltaToVsync >= (mRefreshRate.getPeriodNsecs() -
                                     mJankClassificationThresholds.presentThreshold)) {
                    // Delta is a factor of vsync if its within the presentTheshold on either side
                    // of the vsyncPeriod. Example: 0-2ms and 9-11ms are both within the threshold
                    // of the vsyncPeriod if the threshold was 2ms and the vsyncPeriod was 11ms.
@@ -797,8 +802,8 @@ void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) {
            if (mFrameReadyMetadata == FrameReadyMetadata::OnTimeFinish) {
                // Finish on time, Present late
                if (deltaToVsync < mJankClassificationThresholds.presentThreshold ||
                    deltaToVsync >=
                            (mVsyncPeriod - mJankClassificationThresholds.presentThreshold)) {
                    deltaToVsync >= (mRefreshRate.getPeriodNsecs() -
                                     mJankClassificationThresholds.presentThreshold)) {
                    // Delta is a factor of vsync if its within the presentTheshold on either side
                    // of the vsyncPeriod. Example: 0-2ms and 9-11ms are both within the threshold
                    // of the vsyncPeriod if the threshold was 2ms and the vsyncPeriod was 11ms.
@@ -819,16 +824,9 @@ void FrameTimeline::DisplayFrame::onPresent(nsecs_t signalTime) {
            mJankType = JankType::Unknown;
        }
    }
    totalJankReasons |= mJankType;

    for (auto& surfaceFrame : mSurfaceFrames) {
        surfaceFrame->onPresent(signalTime, mJankType, mVsyncPeriod);
        auto surfaceFrameJankType = surfaceFrame->getJankType();
        if (surfaceFrameJankType != std::nullopt) {
            totalJankReasons |= *surfaceFrameJankType;
        }
        surfaceFrame->onPresent(signalTime, mJankType, mRefreshRate);
    }
    mTimeStats->incrementJankyFrames(totalJankReasons);
}

void FrameTimeline::DisplayFrame::trace(pid_t surfaceFlingerPid) const {
@@ -988,7 +986,7 @@ void FrameTimeline::DisplayFrame::dump(std::string& result, nsecs_t baseTime) co
    StringAppendF(&result, "Present Metadata : %s\n", toString(mFramePresentMetadata).c_str());
    StringAppendF(&result, "Finish Metadata: %s\n", toString(mFrameReadyMetadata).c_str());
    StringAppendF(&result, "Start Metadata: %s\n", toString(mFrameStartMetadata).c_str());
    std::chrono::nanoseconds vsyncPeriod(mVsyncPeriod);
    std::chrono::nanoseconds vsyncPeriod(mRefreshRate.getPeriodNsecs());
    StringAppendF(&result, "Vsync Period: %10f\n",
                  std::chrono::duration<double, std::milli>(vsyncPeriod).count());
    nsecs_t presentDelta =
@@ -996,7 +994,7 @@ void FrameTimeline::DisplayFrame::dump(std::string& result, nsecs_t baseTime) co
    std::chrono::nanoseconds presentDeltaNs(std::abs(presentDelta));
    StringAppendF(&result, "Present delta: %10f\n",
                  std::chrono::duration<double, std::milli>(presentDeltaNs).count());
    std::chrono::nanoseconds deltaToVsync(std::abs(presentDelta) % mVsyncPeriod);
    std::chrono::nanoseconds deltaToVsync(std::abs(presentDelta) % mRefreshRate.getPeriodNsecs());
    StringAppendF(&result, "Present delta %% refreshrate: %10f\n",
                  std::chrono::duration<double, std::milli>(deltaToVsync).count());
    dumpTable(result, mSurfaceFlingerPredictions, mSurfaceFlingerActuals, "", mPredictionState,
+9 −6
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#pragma once

#include <../Fps.h>
#include <../TimeStats/TimeStats.h>
#include <gui/ISurfaceComposer.h>
#include <gui/JankInfo.h>
@@ -175,13 +176,14 @@ public:
    void setActualQueueTime(nsecs_t actualQueueTime);
    void setAcquireFenceTime(nsecs_t acquireFenceTime);
    void setPresentState(PresentState presentState, nsecs_t lastLatchTime = 0);
    void setRenderRate(Fps renderRate);

    // 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.
    nsecs_t getBaseTime() const;
    // Sets the actual present time, appropriate metadata and classifies the jank.
    void onPresent(nsecs_t presentTime, int32_t displayFrameJankType, nsecs_t vsyncPeriod);
    void onPresent(nsecs_t presentTime, int32_t displayFrameJankType, Fps refreshRate);
    // All the timestamps are dumped relative to the baseTime
    void dump(std::string& result, const std::string& indent, nsecs_t baseTime) const;
    // Emits a packet for perfetto tracing. The function body will be executed only if tracing is
@@ -216,6 +218,8 @@ private:
    int32_t mJankType GUARDED_BY(mMutex) = JankType::None;
    // Indicates if this frame was composited by the GPU or not
    bool mGpuComposition GUARDED_BY(mMutex) = false;
    // Rendering rate for this frame.
    std::optional<Fps> mRenderRate GUARDED_BY(mMutex);
    // Enum for the type of present
    FramePresentMetadata mFramePresentMetadata GUARDED_BY(mMutex) =
            FramePresentMetadata::UnknownPresent;
@@ -255,7 +259,7 @@ public:

    // The first function called by SF for the current DisplayFrame. Fetches SF predictions based on
    // the token and sets the actualSfWakeTime for the current DisplayFrame.
    virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, nsecs_t vsyncPeriod) = 0;
    virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) = 0;

    // Sets the sfPresentTime and finalizes the current DisplayFrame. Tracks the given present fence
    // until it's signaled, and updates the present timestamps of all presented SurfaceFrames in
@@ -325,14 +329,13 @@ public:
        // is enabled.
        void trace(pid_t surfaceFlingerPid) const;
        // Sets the token, vsyncPeriod, predictions and SF start time.
        void onSfWakeUp(int64_t token, nsecs_t vsyncPeriod, std::optional<TimelineItem> predictions,
        void onSfWakeUp(int64_t token, Fps refreshRate, std::optional<TimelineItem> predictions,
                        nsecs_t wakeUpTime);
        // Sets the appropriate metadata, classifies the jank and returns the classified jankType.
        void onPresent(nsecs_t signalTime);
        // Adds the provided SurfaceFrame to the current display frame.
        void addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame);

        void setTokenAndVsyncPeriod(int64_t token, nsecs_t vsyncPeriod);
        void setPredictions(PredictionState predictionState, TimelineItem predictions);
        void setActualStartTime(nsecs_t actualStartTime);
        void setActualEndTime(nsecs_t actualEndTime);
@@ -382,7 +385,7 @@ public:
        FrameStartMetadata mFrameStartMetadata = FrameStartMetadata::UnknownStart;
        // The refresh rate (vsync period) in nanoseconds as seen by SF during this DisplayFrame's
        // timeline
        nsecs_t mVsyncPeriod = 0;
        Fps mRefreshRate;
        // 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
        // DisplayFrame.
@@ -398,7 +401,7 @@ public:
            const FrameTimelineInfo& frameTimelineInfo, pid_t ownerPid, uid_t ownerUid,
            std::string layerName, std::string debugName) override;
    void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame) override;
    void setSfWakeUp(int64_t token, nsecs_t wakeupTime, nsecs_t vsyncPeriod) override;
    void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override;
    void setSfPresent(nsecs_t sfPresentTime,
                      const std::shared_ptr<FenceTime>& presentFence) override;
    void parseArgs(const Vector<String16>& args, std::string& result) override;
+8 −0
Original line number Diff line number Diff line
@@ -1568,6 +1568,10 @@ std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForTransac
    // For Transactions, the post time is considered to be both queue and acquire fence time.
    surfaceFrame->setActualQueueTime(postTime);
    surfaceFrame->setAcquireFenceTime(postTime);
    const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
    if (fps) {
        mSurfaceFrame->setRenderRate(*fps);
    }
    onSurfaceFrameCreated(surfaceFrame);
    return surfaceFrame;
}
@@ -1579,6 +1583,10 @@ std::shared_ptr<frametimeline::SurfaceFrame> Layer::createSurfaceFrameForBuffer(
                                                                 debugName);
    // For buffers, acquire fence time will set during latch.
    surfaceFrame->setActualQueueTime(queueTime);
    const auto fps = mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
    if (fps) {
        mSurfaceFrame->setRenderRate(*fps);
    }
    // TODO(b/178542907): Implement onSurfaceFrameCreated for BQLayer as well.
    onSurfaceFrameCreated(surfaceFrame);
    return surfaceFrame;
Loading