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

Commit 96eb5353 authored by Ying Wei's avatar Ying Wei
Browse files

Add jank severity type for actual frame timeline.

Bug: 311760225
Test: capture Perfetto trace locally
Change-Id: I591f3730f74dd05f64538caacfe56b8c60404bb6
parent be6e8dc3
Loading
Loading
Loading
Loading
+13 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@

namespace android {

// Jank information tracked by SurfaceFlinger(SF) for perfetto tracing and telemetry.
// Jank type tracked by SurfaceFlinger(SF) for Perfetto tracing and telemetry.
enum JankType {
    // No Jank
    None = 0x0,
@@ -50,4 +50,16 @@ enum JankType {
    Dropped = 0x200,
};

// Jank severity type tracked by SurfaceFlinger(SF) for Perfetto tracing and telemetry.
enum class JankSeverityType {
    // Unknown: not enough information to classify the severity of a jank
    Unknown = 0,
    // None: no jank
    None = 1,
    // Partial: jank caused by missing the deadline by less than the app's frame interval
    Partial = 2,
    // Full: jank caused by missing the deadline by more than the app's frame interval
    Full = 3,
};

} // namespace android
+41 −2
Original line number Diff line number Diff line
@@ -280,6 +280,19 @@ int32_t jankTypeBitmaskToProto(int32_t jankType) {
    return protoJank;
}

FrameTimelineEvent::JankSeverityType toProto(JankSeverityType jankSeverityType) {
    switch (jankSeverityType) {
        case JankSeverityType::Unknown:
            return FrameTimelineEvent::SEVERITY_UNKNOWN;
        case JankSeverityType::None:
            return FrameTimelineEvent::SEVERITY_NONE;
        case JankSeverityType::Partial:
            return FrameTimelineEvent::SEVERITY_PARTIAL;
        case JankSeverityType::Full:
            return FrameTimelineEvent::SEVERITY_FULL;
    }
}

// Returns the smallest timestamp from the set of predictions and actuals.
nsecs_t getMinTime(PredictionState predictionState, TimelineItem predictions,
                   TimelineItem actuals) {
@@ -389,6 +402,15 @@ std::optional<int32_t> SurfaceFrame::getJankType() const {
    return mJankType;
}

std::optional<JankSeverityType> SurfaceFrame::getJankSeverityType() const {
    std::scoped_lock lock(mMutex);
    if (mActuals.presentTime == 0) {
        // Frame hasn't been presented yet.
        return std::nullopt;
    }
    return mJankSeverityType;
}

nsecs_t SurfaceFrame::getBaseTime() const {
    std::scoped_lock lock(mMutex);
    return getMinTime(mPredictionState, mPredictions, mActuals);
@@ -505,10 +527,11 @@ std::string SurfaceFrame::miniDump() const {
}

void SurfaceFrame::classifyJankLocked(int32_t displayFrameJankType, const Fps& refreshRate,
                                      nsecs_t& deadlineDelta) {
                                      Fps displayFrameRenderRate, nsecs_t& deadlineDelta) {
    if (mActuals.presentTime == Fence::SIGNAL_TIME_INVALID) {
        // Cannot do any classification for invalid present time.
        mJankType = JankType::Unknown;
        mJankSeverityType = JankSeverityType::Unknown;
        deadlineDelta = -1;
        return;
    }
@@ -519,6 +542,7 @@ void SurfaceFrame::classifyJankLocked(int32_t displayFrameJankType, const Fps& r
        // reasonable app, so prediction expire would mean a huge scheduling delay.
        mJankType = mPresentState != PresentState::Presented ? JankType::Dropped
                                                             : JankType::AppDeadlineMissed;
        mJankSeverityType = JankSeverityType::Unknown;
        deadlineDelta = -1;
        return;
    }
@@ -543,6 +567,11 @@ void SurfaceFrame::classifyJankLocked(int32_t displayFrameJankType, const Fps& r
    if (std::abs(presentDelta) > mJankClassificationThresholds.presentThreshold) {
        mFramePresentMetadata = presentDelta > 0 ? FramePresentMetadata::LatePresent
                                                 : FramePresentMetadata::EarlyPresent;
        // Jank that is missing by less than the render rate period is classified as partial jank,
        // otherwise it is a full jank.
        mJankSeverityType = std::abs(presentDelta) < displayFrameRenderRate.getPeriodNsecs()
                ? JankSeverityType::Partial
                : JankSeverityType::Full;
    } else {
        mFramePresentMetadata = FramePresentMetadata::OnTimePresent;
    }
@@ -613,6 +642,7 @@ void SurfaceFrame::classifyJankLocked(int32_t displayFrameJankType, const Fps& r
        mJankType = JankType::Dropped;
        // Since frame was not presented, lets drop any present value
        mActuals.presentTime = 0;
        mJankSeverityType = JankSeverityType::Unknown;
    }
}

@@ -625,7 +655,7 @@ void SurfaceFrame::onPresent(nsecs_t presentTime, int32_t displayFrameJankType,
    mActuals.presentTime = presentTime;
    nsecs_t deadlineDelta = 0;

    classifyJankLocked(displayFrameJankType, refreshRate, deadlineDelta);
    classifyJankLocked(displayFrameJankType, refreshRate, displayFrameRenderRate, deadlineDelta);

    if (mPredictionState != PredictionState::None) {
        // Only update janky frames if the app used vsync predictions
@@ -718,6 +748,7 @@ void SurfaceFrame::traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffse
        actualSurfaceFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(mJankType));
        actualSurfaceFrameStartEvent->set_prediction_type(toProto(mPredictionState));
        actualSurfaceFrameStartEvent->set_is_buffer(mIsBuffer);
        actualSurfaceFrameStartEvent->set_jank_severity_type(toProto(mJankSeverityType));
    });

    // Actual timeline end
@@ -910,6 +941,7 @@ void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t&
        // Cannot do jank classification with expired predictions or invalid signal times. Set the
        // deltas to 0 as both negative and positive deltas are used as real values.
        mJankType = JankType::Unknown;
        mJankSeverityType = JankSeverityType::Unknown;
        deadlineDelta = 0;
        deltaToVsync = 0;
        if (!presentTimeValid) {
@@ -941,6 +973,11 @@ void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t&
    if (std::abs(presentDelta) > mJankClassificationThresholds.presentThreshold) {
        mFramePresentMetadata = presentDelta > 0 ? FramePresentMetadata::LatePresent
                                                 : FramePresentMetadata::EarlyPresent;
        // Jank that is missing by less than the render rate period is classified as partial jank,
        // otherwise it is a full jank.
        mJankSeverityType = std::abs(presentDelta) < mRenderRate.getPeriodNsecs()
                ? JankSeverityType::Partial
                : JankSeverityType::Full;
    } else {
        mFramePresentMetadata = FramePresentMetadata::OnTimePresent;
    }
@@ -1119,6 +1156,7 @@ void FrameTimeline::DisplayFrame::addSkippedFrame(pid_t surfaceFlingerPid, nsecs
            actualDisplayFrameStartEvent->set_prediction_type(toProto(PredictionState::Valid));
            actualDisplayFrameStartEvent->set_present_type(FrameTimelineEvent::PRESENT_DROPPED);
            actualDisplayFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(JankType::Dropped));
            actualDisplayFrameStartEvent->set_jank_severity_type(toProto(JankSeverityType::None));
        });

        // Actual timeline end
@@ -1160,6 +1198,7 @@ void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid,
        actualDisplayFrameStartEvent->set_gpu_composition(mGpuFence != FenceTime::NO_FENCE);
        actualDisplayFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(mJankType));
        actualDisplayFrameStartEvent->set_prediction_type(toProto(mPredictionState));
        actualDisplayFrameStartEvent->set_jank_severity_type(toProto(mJankSeverityType));
    });

    // Actual timeline end
+7 −1
Original line number Diff line number Diff line
@@ -168,6 +168,7 @@ public:
    // Returns std::nullopt if the frame hasn't been classified yet.
    // Used by both SF and FrameTimeline.
    std::optional<int32_t> getJankType() const;
    std::optional<JankSeverityType> getJankSeverityType() const;

    // Functions called by SF
    int64_t getToken() const { return mToken; };
@@ -232,7 +233,7 @@ private:
    void tracePredictions(int64_t displayFrameToken, nsecs_t monoBootOffset) const;
    void traceActuals(int64_t displayFrameToken, nsecs_t monoBootOffset) const;
    void classifyJankLocked(int32_t displayFrameJankType, const Fps& refreshRate,
                            nsecs_t& deadlineDelta) REQUIRES(mMutex);
                            Fps displayFrameRenderRate, nsecs_t& deadlineDelta) REQUIRES(mMutex);

    const int64_t mToken;
    const int32_t mInputEventId;
@@ -252,6 +253,8 @@ private:
    mutable std::mutex mMutex;
    // Bitmask for the type of jank
    int32_t mJankType GUARDED_BY(mMutex) = JankType::None;
    // Enum for the severity of jank
    JankSeverityType mJankSeverityType GUARDED_BY(mMutex) = JankSeverityType::None;
    // Indicates if this frame was composited by the GPU or not
    bool mGpuComposition GUARDED_BY(mMutex) = false;
    // Refresh rate for this frame.
@@ -404,6 +407,7 @@ public:
        FramePresentMetadata getFramePresentMetadata() const { return mFramePresentMetadata; };
        FrameReadyMetadata getFrameReadyMetadata() const { return mFrameReadyMetadata; };
        int32_t getJankType() const { return mJankType; }
        JankSeverityType getJankSeverityType() const { return mJankSeverityType; }
        const std::vector<std::shared_ptr<SurfaceFrame>>& getSurfaceFrames() const {
            return mSurfaceFrames;
        }
@@ -435,6 +439,8 @@ public:
        PredictionState mPredictionState = PredictionState::None;
        // Bitmask for the type of jank
        int32_t mJankType = JankType::None;
        // Enum for the severity of jank
        JankSeverityType mJankSeverityType = JankSeverityType::None;
        // A valid gpu fence indicates that the DisplayFrame was composited by the GPU
        std::shared_ptr<FenceTime> mGpuFence = FenceTime::NO_FENCE;
        // Enum for the type of present
+67 −2

File changed.

Preview size limit exceeded, changes collapsed.