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

Commit 9a296f97 authored by Ying Wei's avatar Ying Wei Committed by Android (Google) Code Review
Browse files

Merge "Add jank severity type for actual frame timeline." into main

parents 78239860 96eb5353
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.