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

Commit 19239b76 authored by Adithya Srinivasan's avatar Adithya Srinivasan Committed by Android (Google) Code Review
Browse files

Merge changes I7bae2f9d,I0e8f0b15,I09cbb0cb into sc-dev

* changes:
  Consider GPU comp info for jank classification
  Remove hwcDuration from FrameTimeline
  Report deltas as 0 instead of -1 for prediction expired display frames
parents 31dfd6a4 36b01af6
Loading
Loading
Loading
Loading
+32 −24
Original line number Original line Diff line number Diff line
@@ -752,14 +752,13 @@ void TokenManager::flushTokens(nsecs_t flushTime) {
}
}


FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
                             JankClassificationThresholds thresholds, nsecs_t hwcDuration)
                             JankClassificationThresholds thresholds)
      : mMaxDisplayFrames(kDefaultMaxDisplayFrames),
      : mMaxDisplayFrames(kDefaultMaxDisplayFrames),
        mTimeStats(std::move(timeStats)),
        mTimeStats(std::move(timeStats)),
        mSurfaceFlingerPid(surfaceFlingerPid),
        mSurfaceFlingerPid(surfaceFlingerPid),
        mJankClassificationThresholds(thresholds),
        mJankClassificationThresholds(thresholds) {
        mHwcDuration(hwcDuration) {
    mCurrentDisplayFrame =
    mCurrentDisplayFrame = std::make_shared<DisplayFrame>(mTimeStats, thresholds, hwcDuration,
            std::make_shared<DisplayFrame>(mTimeStats, thresholds, &mTraceCookieCounter);
                                                          &mTraceCookieCounter);
}
}


void FrameTimeline::onBootFinished() {
void FrameTimeline::onBootFinished() {
@@ -804,13 +803,11 @@ std::shared_ptr<SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(


FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr<TimeStats> timeStats,
FrameTimeline::DisplayFrame::DisplayFrame(std::shared_ptr<TimeStats> timeStats,
                                          JankClassificationThresholds thresholds,
                                          JankClassificationThresholds thresholds,
                                          nsecs_t hwcDuration,
                                          TraceCookieCounter* traceCookieCounter)
                                          TraceCookieCounter* traceCookieCounter)
      : mSurfaceFlingerPredictions(TimelineItem()),
      : mSurfaceFlingerPredictions(TimelineItem()),
        mSurfaceFlingerActuals(TimelineItem()),
        mSurfaceFlingerActuals(TimelineItem()),
        mTimeStats(timeStats),
        mTimeStats(timeStats),
        mJankClassificationThresholds(thresholds),
        mJankClassificationThresholds(thresholds),
        mHwcDuration(hwcDuration),
        mTraceCookieCounter(*traceCookieCounter) {
        mTraceCookieCounter(*traceCookieCounter) {
    mSurfaceFrames.reserve(kNumSurfaceFramesInitial);
    mSurfaceFrames.reserve(kNumSurfaceFramesInitial);
}
}
@@ -830,13 +827,11 @@ void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime, Fps refreshRa


void FrameTimeline::setSfPresent(nsecs_t sfPresentTime,
void FrameTimeline::setSfPresent(nsecs_t sfPresentTime,
                                 const std::shared_ptr<FenceTime>& presentFence,
                                 const std::shared_ptr<FenceTime>& presentFence,
                                 bool gpuComposition) {
                                 const std::shared_ptr<FenceTime>& gpuFence) {
    ATRACE_CALL();
    ATRACE_CALL();
    std::scoped_lock lock(mMutex);
    std::scoped_lock lock(mMutex);
    mCurrentDisplayFrame->setActualEndTime(sfPresentTime);
    mCurrentDisplayFrame->setActualEndTime(sfPresentTime);
    if (gpuComposition) {
    mCurrentDisplayFrame->setGpuFence(gpuFence);
        mCurrentDisplayFrame->setGpuComposition();
    }
    mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame));
    mPendingPresentFences.emplace_back(std::make_pair(presentFence, mCurrentDisplayFrame));
    flushPendingPresentFences();
    flushPendingPresentFences();
    finalizeCurrentDisplayFrame();
    finalizeCurrentDisplayFrame();
@@ -874,25 +869,32 @@ void FrameTimeline::DisplayFrame::setActualEndTime(nsecs_t actualEndTime) {
    mSurfaceFlingerActuals.endTime = actualEndTime;
    mSurfaceFlingerActuals.endTime = actualEndTime;
}
}


void FrameTimeline::DisplayFrame::setGpuComposition() {
void FrameTimeline::DisplayFrame::setGpuFence(const std::shared_ptr<FenceTime>& gpuFence) {
    mGpuComposition = true;
    mGpuFence = gpuFence;
}
}


void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t& deltaToVsync) {
void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t& deltaToVsync) {
    if (mPredictionState == PredictionState::Expired ||
    if (mPredictionState == PredictionState::Expired ||
        mSurfaceFlingerActuals.presentTime == Fence::SIGNAL_TIME_INVALID) {
        mSurfaceFlingerActuals.presentTime == Fence::SIGNAL_TIME_INVALID) {
        // Cannot do jank classification with expired predictions or invalid signal times.
        // 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;
        mJankType = JankType::Unknown;
        deadlineDelta = -1;
        deadlineDelta = 0;
        deltaToVsync = -1;
        deltaToVsync = 0;
        return;
        return;
    }
    }


    // Delta between the expected present and the actual present
    // Delta between the expected present and the actual present
    const nsecs_t presentDelta =
    const nsecs_t presentDelta =
            mSurfaceFlingerActuals.presentTime - mSurfaceFlingerPredictions.presentTime;
            mSurfaceFlingerActuals.presentTime - mSurfaceFlingerPredictions.presentTime;
    deadlineDelta =
    // Sf actual end time represents the CPU end time. In case of HWC, SF's end time would have
            mSurfaceFlingerActuals.endTime - (mSurfaceFlingerPredictions.endTime - mHwcDuration);
    // included the time for composition. However, for GPU composition, the final end time is max(sf
    // end time, gpu fence time).
    nsecs_t combinedEndTime = mSurfaceFlingerActuals.endTime;
    if (mGpuFence != FenceTime::NO_FENCE) {
        combinedEndTime = std::max(combinedEndTime, mGpuFence->getSignalTime());
    }
    deadlineDelta = combinedEndTime - mSurfaceFlingerPredictions.endTime;


    // How far off was the presentDelta when compared to the vsyncPeriod. Used in checking if there
    // How far off was the presentDelta when compared to the vsyncPeriod. Used in checking if there
    // was a prediction error or not.
    // was a prediction error or not.
@@ -907,9 +909,7 @@ void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t&
        mFramePresentMetadata = FramePresentMetadata::OnTimePresent;
        mFramePresentMetadata = FramePresentMetadata::OnTimePresent;
    }
    }


    if (mSurfaceFlingerActuals.endTime > mSurfaceFlingerPredictions.endTime - mHwcDuration) {
    if (combinedEndTime > mSurfaceFlingerPredictions.endTime) {
        // SF needs to have finished at least mHwcDuration ahead of the deadline for it to be
        // on time.
        mFrameReadyMetadata = FrameReadyMetadata::LateFinish;
        mFrameReadyMetadata = FrameReadyMetadata::LateFinish;
    } else {
    } else {
        mFrameReadyMetadata = FrameReadyMetadata::OnTimeFinish;
        mFrameReadyMetadata = FrameReadyMetadata::OnTimeFinish;
@@ -966,8 +966,16 @@ void FrameTimeline::DisplayFrame::classifyJank(nsecs_t& deadlineDelta, nsecs_t&
                    mJankType = JankType::SurfaceFlingerScheduling;
                    mJankType = JankType::SurfaceFlingerScheduling;
                } else {
                } else {
                    // OnTime start, Finish late, Present late
                    // OnTime start, Finish late, Present late
                    if (mGpuFence != FenceTime::NO_FENCE &&
                        mSurfaceFlingerActuals.endTime - mSurfaceFlingerActuals.startTime <
                                mRefreshRate.getPeriodNsecs()) {
                        // If SF was in GPU composition and the CPU work finished before the vsync
                        // period, classify it as GPU deadline missed.
                        mJankType = JankType::SurfaceFlingerGpuDeadlineMissed;
                    } else {
                        mJankType = JankType::SurfaceFlingerCpuDeadlineMissed;
                        mJankType = JankType::SurfaceFlingerCpuDeadlineMissed;
                    }
                    }
                }
            } else {
            } else {
                // Finish time unknown
                // Finish time unknown
                mJankType = JankType::Unknown;
                mJankType = JankType::Unknown;
@@ -1041,7 +1049,7 @@ void FrameTimeline::DisplayFrame::traceActuals(pid_t surfaceFlingerPid) const {
        actualDisplayFrameStartEvent->set_present_type(toProto(mFramePresentMetadata));
        actualDisplayFrameStartEvent->set_present_type(toProto(mFramePresentMetadata));
        actualDisplayFrameStartEvent->set_on_time_finish(mFrameReadyMetadata ==
        actualDisplayFrameStartEvent->set_on_time_finish(mFrameReadyMetadata ==
                                                         FrameReadyMetadata::OnTimeFinish);
                                                         FrameReadyMetadata::OnTimeFinish);
        actualDisplayFrameStartEvent->set_gpu_composition(mGpuComposition);
        actualDisplayFrameStartEvent->set_gpu_composition(mGpuFence != FenceTime::NO_FENCE);
        actualDisplayFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(mJankType));
        actualDisplayFrameStartEvent->set_jank_type(jankTypeBitmaskToProto(mJankType));
        actualDisplayFrameStartEvent->set_prediction_type(toProto(mPredictionState));
        actualDisplayFrameStartEvent->set_prediction_type(toProto(mPredictionState));
    });
    });
@@ -1164,7 +1172,7 @@ void FrameTimeline::finalizeCurrentDisplayFrame() {
    mDisplayFrames.push_back(mCurrentDisplayFrame);
    mDisplayFrames.push_back(mCurrentDisplayFrame);
    mCurrentDisplayFrame.reset();
    mCurrentDisplayFrame.reset();
    mCurrentDisplayFrame = std::make_shared<DisplayFrame>(mTimeStats, mJankClassificationThresholds,
    mCurrentDisplayFrame = std::make_shared<DisplayFrame>(mTimeStats, mJankClassificationThresholds,
                                                          mHwcDuration, &mTraceCookieCounter);
                                                          &mTraceCookieCounter);
}
}


nsecs_t FrameTimeline::DisplayFrame::getBaseTime() const {
nsecs_t FrameTimeline::DisplayFrame::getBaseTime() const {
+10 −16
Original line number Original line Diff line number Diff line
@@ -293,11 +293,12 @@ public:
    // the token and sets the actualSfWakeTime for the current DisplayFrame.
    // the token and sets the actualSfWakeTime for the current DisplayFrame.
    virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) = 0;
    virtual void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) = 0;


    // Sets the sfPresentTime, gpuComposition and finalizes the current DisplayFrame. Tracks the
    // 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
    // given present fence until it's signaled, and updates the present timestamps of all presented
    // SurfaceFrames in that vsync.
    // SurfaceFrames in that vsync. If a gpuFence was also provided, its tracked in the
    // corresponding DisplayFrame.
    virtual void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence,
    virtual void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence,
                              bool gpuComposition) = 0;
                              const std::shared_ptr<FenceTime>& gpuFence) = 0;


    // Args:
    // Args:
    // -jank : Dumps only the Display Frames that are either janky themselves
    // -jank : Dumps only the Display Frames that are either janky themselves
@@ -355,7 +356,7 @@ public:
    class DisplayFrame {
    class DisplayFrame {
    public:
    public:
        DisplayFrame(std::shared_ptr<TimeStats> timeStats, JankClassificationThresholds thresholds,
        DisplayFrame(std::shared_ptr<TimeStats> timeStats, JankClassificationThresholds thresholds,
                     nsecs_t hwcDuration, TraceCookieCounter* traceCookieCounter);
                     TraceCookieCounter* traceCookieCounter);
        virtual ~DisplayFrame() = default;
        virtual ~DisplayFrame() = default;
        // Dumpsys interface - dumps only if the DisplayFrame itself is janky or is at least one
        // Dumpsys interface - dumps only if the DisplayFrame itself is janky or is at least one
        // SurfaceFrame is janky.
        // SurfaceFrame is janky.
@@ -376,7 +377,7 @@ public:
        void setPredictions(PredictionState predictionState, TimelineItem predictions);
        void setPredictions(PredictionState predictionState, TimelineItem predictions);
        void setActualStartTime(nsecs_t actualStartTime);
        void setActualStartTime(nsecs_t actualStartTime);
        void setActualEndTime(nsecs_t actualEndTime);
        void setActualEndTime(nsecs_t actualEndTime);
        void setGpuComposition();
        void setGpuFence(const std::shared_ptr<FenceTime>& gpuFence);


        // BaseTime is the smallest timestamp in a DisplayFrame.
        // BaseTime is the smallest timestamp in a DisplayFrame.
        // Used for dumping all timestamps relative to the oldest, making it easy to read.
        // Used for dumping all timestamps relative to the oldest, making it easy to read.
@@ -410,7 +411,6 @@ public:
        TimelineItem mSurfaceFlingerActuals;
        TimelineItem mSurfaceFlingerActuals;
        std::shared_ptr<TimeStats> mTimeStats;
        std::shared_ptr<TimeStats> mTimeStats;
        const JankClassificationThresholds mJankClassificationThresholds;
        const JankClassificationThresholds mJankClassificationThresholds;
        const nsecs_t mHwcDuration;


        // Collection of predictions and actual values sent over by Layers
        // Collection of predictions and actual values sent over by Layers
        std::vector<std::shared_ptr<SurfaceFrame>> mSurfaceFrames;
        std::vector<std::shared_ptr<SurfaceFrame>> mSurfaceFrames;
@@ -418,8 +418,8 @@ public:
        PredictionState mPredictionState = PredictionState::None;
        PredictionState mPredictionState = PredictionState::None;
        // Bitmask for the type of jank
        // Bitmask for the type of jank
        int32_t mJankType = JankType::None;
        int32_t mJankType = JankType::None;
        // Indicates if this frame was composited by the GPU or not
        // A valid gpu fence indicates that the DisplayFrame was composited by the GPU
        bool mGpuComposition = false;
        std::shared_ptr<FenceTime> mGpuFence = FenceTime::NO_FENCE;
        // Enum for the type of present
        // Enum for the type of present
        FramePresentMetadata mFramePresentMetadata = FramePresentMetadata::UnknownPresent;
        FramePresentMetadata mFramePresentMetadata = FramePresentMetadata::UnknownPresent;
        // Enum for the type of finish
        // Enum for the type of finish
@@ -436,8 +436,7 @@ public:
    };
    };


    FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
    FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid,
                  JankClassificationThresholds thresholds = {},
                  JankClassificationThresholds thresholds = {});
                  nsecs_t hwcDuration = kDefaultHwcDuration);
    ~FrameTimeline() = default;
    ~FrameTimeline() = default;


    frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
    frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
@@ -447,7 +446,7 @@ public:
    void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame) override;
    void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame) override;
    void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override;
    void setSfWakeUp(int64_t token, nsecs_t wakeupTime, Fps refreshRate) override;
    void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence,
    void setSfPresent(nsecs_t sfPresentTime, const std::shared_ptr<FenceTime>& presentFence,
                      bool gpuComposition = false) override;
                      const std::shared_ptr<FenceTime>& gpuFence = FenceTime::NO_FENCE) override;
    void parseArgs(const Vector<String16>& args, std::string& result) override;
    void parseArgs(const Vector<String16>& args, std::string& result) override;
    void setMaxDisplayFrames(uint32_t size) override;
    void setMaxDisplayFrames(uint32_t size) override;
    float computeFps(const std::unordered_set<int32_t>& layerIds) override;
    float computeFps(const std::unordered_set<int32_t>& layerIds) override;
@@ -482,11 +481,6 @@ private:
    std::shared_ptr<TimeStats> mTimeStats;
    std::shared_ptr<TimeStats> mTimeStats;
    const pid_t mSurfaceFlingerPid;
    const pid_t mSurfaceFlingerPid;
    const JankClassificationThresholds mJankClassificationThresholds;
    const JankClassificationThresholds mJankClassificationThresholds;
    // In SF Predictions, both end & present are the same. The predictions consider the time used by
    // composer as well, but we have no way to estimate how much time the composer needs. We are
    // assuming an arbitrary time for the composer work.
    const nsecs_t mHwcDuration;
    static constexpr nsecs_t kDefaultHwcDuration = std::chrono::nanoseconds(3ms).count();
    static constexpr uint32_t kDefaultMaxDisplayFrames = 64;
    static constexpr uint32_t kDefaultMaxDisplayFrames = 64;
    // The initial container size for the vector<SurfaceFrames> inside display frame. Although
    // 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
    // this number doesn't represent any bounds on the number of surface frames that can go in a
+1 −1
Original line number Original line Diff line number Diff line
@@ -2141,7 +2141,7 @@ void SurfaceFlinger::postComposition() {
    // information from previous' frame classification is already available when sending jank info
    // information from previous' frame classification is already available when sending jank info
    // to clients, so they get jank classification as early as possible.
    // to clients, so they get jank classification as early as possible.
    mFrameTimeline->setSfPresent(systemTime(), mPreviousPresentFences[0].fenceTime,
    mFrameTimeline->setSfPresent(systemTime(), mPreviousPresentFences[0].fenceTime,
                                 glCompositionDoneFenceTime != FenceTime::NO_FENCE);
                                 glCompositionDoneFenceTime);


    nsecs_t dequeueReadyTime = systemTime();
    nsecs_t dequeueReadyTime = systemTime();
    for (const auto& layer : mLayersWithQueuedFrames) {
    for (const auto& layer : mLayersWithQueuedFrames) {
+70 −22
Original line number Original line Diff line number Diff line
@@ -68,7 +68,7 @@ public:
    void SetUp() override {
    void SetUp() override {
        mTimeStats = std::make_shared<mock::TimeStats>();
        mTimeStats = std::make_shared<mock::TimeStats>();
        mFrameTimeline = std::make_unique<impl::FrameTimeline>(mTimeStats, kSurfaceFlingerPid,
        mFrameTimeline = std::make_unique<impl::FrameTimeline>(mTimeStats, kSurfaceFlingerPid,
                                                               kTestThresholds, kHwcDuration);
                                                               kTestThresholds);
        mFrameTimeline->registerDataSource();
        mFrameTimeline->registerDataSource();
        mTokenManager = &mFrameTimeline->mTokenManager;
        mTokenManager = &mFrameTimeline->mTokenManager;
        mTraceCookieCounter = &mFrameTimeline->mTraceCookieCounter;
        mTraceCookieCounter = &mFrameTimeline->mTraceCookieCounter;
@@ -163,7 +163,6 @@ public:
    static constexpr JankClassificationThresholds kTestThresholds{kPresentThreshold,
    static constexpr JankClassificationThresholds kTestThresholds{kPresentThreshold,
                                                                  kDeadlineThreshold,
                                                                  kDeadlineThreshold,
                                                                  kStartThreshold};
                                                                  kStartThreshold};
    static constexpr nsecs_t kHwcDuration = std::chrono::nanoseconds(3ns).count();
};
};


static const std::string sLayerNameOne = "layer1";
static const std::string sLayerNameOne = "layer1";
@@ -483,7 +482,6 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_doesNotReportForInvalidTokens) {


TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) {
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) {
    Fps refreshRate = Fps::fromPeriodNsecs(11);
    Fps refreshRate = Fps::fromPeriodNsecs(11);
    // Deadline delta is 2ms because, sf's adjusted deadline is 60 - composerTime(3) = 57ms.
    EXPECT_CALL(*mTimeStats,
    EXPECT_CALL(*mTimeStats,
                incrementJankyFrames(
                incrementJankyFrames(
                        TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
                        TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
@@ -504,7 +502,34 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) {
    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
    presentFence1->signalForTest(70);
    presentFence1->signalForTest(70);


    mFrameTimeline->setSfPresent(59, presentFence1);
    mFrameTimeline->setSfPresent(62, presentFence1);
}

TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfGpu) {
    Fps refreshRate = Fps::fromPeriodNsecs(11);
    EXPECT_CALL(*mTimeStats,
                incrementJankyFrames(
                        TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
                                                   sLayerNameOne,
                                                   JankType::SurfaceFlingerGpuDeadlineMissed, 4, 10,
                                                   0}));
    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    auto gpuFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});

    auto surfaceFrame1 =
            mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
                                                       sUidOne, sLayerIdOne, sLayerNameOne,
                                                       sLayerNameOne, /*isBuffer*/ true);
    mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
    surfaceFrame1->setAcquireFenceTime(20);
    surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
    mFrameTimeline->addSurfaceFrame(surfaceFrame1);
    gpuFence1->signalForTest(64);
    presentFence1->signalForTest(70);

    mFrameTimeline->setSfPresent(59, presentFence1, gpuFence1);
}
}


TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) {
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) {
@@ -512,7 +537,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) {
    EXPECT_CALL(*mTimeStats,
    EXPECT_CALL(*mTimeStats,
                incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
                incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
                                                                sLayerNameOne, JankType::DisplayHAL,
                                                                sLayerNameOne, JankType::DisplayHAL,
                                                                -1, 0, 0}));
                                                                -4, 0, 0}));


    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
@@ -536,7 +561,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
    EXPECT_CALL(*mTimeStats,
    EXPECT_CALL(*mTimeStats,
                incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
                incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
                                                                sLayerNameOne,
                                                                sLayerNameOne,
                                                                JankType::AppDeadlineMissed, -1, 0,
                                                                JankType::AppDeadlineMissed, -4, 0,
                                                                25}));
                                                                25}));
    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
@@ -563,7 +588,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) {
                incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
                incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
                                                                sLayerNameOne,
                                                                sLayerNameOne,
                                                                JankType::SurfaceFlingerScheduling,
                                                                JankType::SurfaceFlingerScheduling,
                                                                -1, 0, -10}));
                                                                -4, 0, -10}));
    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({40, 60, 92});
    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({40, 60, 92});
    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
@@ -588,7 +613,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) {
    EXPECT_CALL(*mTimeStats,
    EXPECT_CALL(*mTimeStats,
                incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
                incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
                                                                sLayerNameOne,
                                                                sLayerNameOne,
                                                                JankType::PredictionError, -1, 5,
                                                                JankType::PredictionError, -4, 5,
                                                                0}));
                                                                0}));
    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 60});
    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 60});
@@ -614,7 +639,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) {
    EXPECT_CALL(*mTimeStats,
    EXPECT_CALL(*mTimeStats,
                incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
                incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
                                                                sLayerNameOne,
                                                                sLayerNameOne,
                                                                JankType::BufferStuffing, -1, 0,
                                                                JankType::BufferStuffing, -4, 0,
                                                                0}));
                                                                0}));
    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 58});
    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 58});
@@ -642,7 +667,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) {
    EXPECT_CALL(*mTimeStats,
    EXPECT_CALL(*mTimeStats,
                incrementJankyFrames(
                incrementJankyFrames(
                        TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne,
                        TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne,
                                                   JankType::AppDeadlineMissed, -1, 0, 25}));
                                                   JankType::AppDeadlineMissed, -4, 0, 25}));
    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90});
    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90});
@@ -671,7 +696,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_displayFramePredictionExpiredPres
                incrementJankyFrames(
                incrementJankyFrames(
                        TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne,
                        TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne,
                                                   JankType::Unknown | JankType::AppDeadlineMissed,
                                                   JankType::Unknown | JankType::AppDeadlineMissed,
                                                   -1, -1, 25}));
                                                   0, 0, 25}));
    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
    int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90});
    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90});
@@ -1458,24 +1483,47 @@ TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishEarlyPresent)
}
}


TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent) {
TEST_F(FrameTimelineTest, jankClassification_displayFrameLateFinishLatePresent) {
    /*
     * Case 1 - cpu time > vsync period but combined time > deadline > deadline -> cpudeadlinemissed
     * Case 2 - cpu time < vsync period but combined time > deadline -> gpudeadlinemissed
     */
    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    auto gpuFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    auto gpuFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
    int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
    int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 60});
    // case 1 - cpu time = 33 - 12 = 21, vsync period = 11
    mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11));
    mFrameTimeline->setSfWakeUp(sfToken1, 12, Fps::fromPeriodNsecs(11));
    mFrameTimeline->setSfPresent(36, presentFence1);
    mFrameTimeline->setSfPresent(33, presentFence1, gpuFence1);
    auto displayFrame = getDisplayFrame(0);
    auto displayFrame0 = getDisplayFrame(0);
    gpuFence1->signalForTest(36);
    presentFence1->signalForTest(52);
    presentFence1->signalForTest(52);


    // Fences haven't been flushed yet, so it should be 0
    // Fences haven't been flushed yet, so it should be 0
    EXPECT_EQ(displayFrame->getActuals().presentTime, 0);
    EXPECT_EQ(displayFrame0->getActuals().presentTime, 0);

    // case 2 - cpu time = 56 - 52 = 4, vsync period = 11
    mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
    mFrameTimeline->setSfPresent(56, presentFence2, gpuFence2);
    auto displayFrame1 = getDisplayFrame(1);
    gpuFence2->signalForTest(66);
    presentFence2->signalForTest(71);

    EXPECT_EQ(displayFrame1->getActuals().presentTime, 0);
    // Fences have flushed for first displayFrame, so the present timestamps should be updated
    EXPECT_EQ(displayFrame0->getActuals().presentTime, 52);
    EXPECT_EQ(displayFrame0->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
    EXPECT_EQ(displayFrame0->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
    EXPECT_EQ(displayFrame0->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);


    addEmptyDisplayFrame();
    addEmptyDisplayFrame();
    displayFrame = getDisplayFrame(0);


    // Fences have flushed, so the present timestamps should be updated
    // Fences have flushed for second displayFrame, so the present timestamps should be updated
    EXPECT_EQ(displayFrame->getActuals().presentTime, 52);
    EXPECT_EQ(displayFrame1->getActuals().presentTime, 71);
    EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
    EXPECT_EQ(displayFrame1->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
    EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
    EXPECT_EQ(displayFrame1->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
    EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);
    EXPECT_EQ(displayFrame1->getJankType(), JankType::SurfaceFlingerGpuDeadlineMissed);
}
}


TEST_F(FrameTimelineTest, jankClassification_displayFrameLateStartLateFinishLatePresent) {
TEST_F(FrameTimelineTest, jankClassification_displayFrameLateStartLateFinishLatePresent) {
@@ -1562,7 +1610,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresen
    EXPECT_CALL(*mTimeStats,
    EXPECT_CALL(*mTimeStats,
                incrementJankyFrames(
                incrementJankyFrames(
                        TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne,
                        TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne,
                                                   sLayerNameOne, JankType::PredictionError, 0, 5,
                                                   sLayerNameOne, JankType::PredictionError, -3, 5,
                                                   0}));
                                                   0}));


    addEmptyDisplayFrame();
    addEmptyDisplayFrame();
@@ -1642,7 +1690,7 @@ TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent
    EXPECT_CALL(*mTimeStats,
    EXPECT_CALL(*mTimeStats,
                incrementJankyFrames(
                incrementJankyFrames(
                        TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne,
                        TimeStats::JankyFramesInfo{Fps::fromPeriodNsecs(11), std::nullopt, sUidOne,
                                                   sLayerNameOne, JankType::PredictionError, 0, 5,
                                                   sLayerNameOne, JankType::PredictionError, -3, 5,
                                                   0}));
                                                   0}));


    addEmptyDisplayFrame();
    addEmptyDisplayFrame();
+3 −1
Original line number Original line Diff line number Diff line
@@ -32,7 +32,9 @@ public:
    MOCK_METHOD0(onBootFinished, void());
    MOCK_METHOD0(onBootFinished, void());
    MOCK_METHOD1(addSurfaceFrame, void(std::shared_ptr<frametimeline::SurfaceFrame>));
    MOCK_METHOD1(addSurfaceFrame, void(std::shared_ptr<frametimeline::SurfaceFrame>));
    MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, Fps));
    MOCK_METHOD3(setSfWakeUp, void(int64_t, nsecs_t, Fps));
    MOCK_METHOD3(setSfPresent, void(nsecs_t, const std::shared_ptr<FenceTime>&, bool));
    MOCK_METHOD3(setSfPresent,
                 void(nsecs_t, const std::shared_ptr<FenceTime>&,
                      const std::shared_ptr<FenceTime>&));
    MOCK_METHOD1(computeFps, float(const std::unordered_set<int32_t>&));
    MOCK_METHOD1(computeFps, float(const std::unordered_set<int32_t>&));
};
};