Loading services/surfaceflinger/TimeStats/TimeStats.cpp +22 −13 Original line number Diff line number Diff line Loading @@ -140,11 +140,12 @@ AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventLi globalSlice.second.jankPayload.totalSFUnattributed); mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalAppUnattributed); // TODO: populate these with real values mStatsDelegate->statsEventWriteInt32(event, 0); // total_janky_frames_sf_scheduling mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_sf_prediction_error mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_app_buffer_stuffing mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFScheduling); mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFPredictionError); mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalAppBufferStuffing); mStatsDelegate->statsEventWriteInt32(event, globalSlice.first.displayRefreshRateBucket); std::string sfDeadlineMissedBytes = histogramToProtoByteString(globalSlice.second.displayDeadlineDeltas.hist, Loading Loading @@ -222,11 +223,9 @@ AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventLis mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFLongGpu); mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFUnattributed); mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalAppUnattributed); // TODO: populate these with real values mStatsDelegate->statsEventWriteInt32(event, 0); // total_janky_frames_sf_scheduling mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_sf_prediction_error mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_app_buffer_stuffing mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFScheduling); mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFPredictionError); mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalAppBufferStuffing); mStatsDelegate->statsEventWriteInt32( event, layer->displayRefreshRateBucket); // display_refresh_rate_bucket mStatsDelegate->statsEventWriteInt32(event, layer->renderRateBucket); // render_rate_bucket Loading Loading @@ -772,9 +771,10 @@ void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber, flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate); } static const constexpr int32_t kValidJankyReason = JankType::SurfaceFlingerCpuDeadlineMissed | JankType::SurfaceFlingerGpuDeadlineMissed | JankType::AppDeadlineMissed | JankType::DisplayHAL; static const constexpr int32_t kValidJankyReason = JankType::DisplayHAL | JankType::SurfaceFlingerCpuDeadlineMissed | JankType::SurfaceFlingerGpuDeadlineMissed | JankType::AppDeadlineMissed | JankType::PredictionError | JankType::SurfaceFlingerScheduling | JankType::BufferStuffing; template <class T> static void updateJankPayload(T& t, int32_t reasons) { Loading @@ -794,6 +794,15 @@ static void updateJankPayload(T& t, int32_t reasons) { if ((reasons & JankType::AppDeadlineMissed) != 0) { t.jankPayload.totalAppUnattributed++; } if ((reasons & JankType::PredictionError) != 0) { t.jankPayload.totalSFPredictionError++; } if ((reasons & JankType::SurfaceFlingerScheduling) != 0) { t.jankPayload.totalSFScheduling++; } if ((reasons & JankType::BufferStuffing) != 0) { t.jankPayload.totalAppBufferStuffing++; } } } Loading services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp +5 −2 Original line number Diff line number Diff line Loading @@ -83,8 +83,11 @@ std::string TimeStatsHelper::JankPayload::toString() const { StringAppendF(&result, "jankyFrames = %d\n", totalJankyFrames); StringAppendF(&result, "sfLongCpuJankyFrames = %d\n", totalSFLongCpu); StringAppendF(&result, "sfLongGpuJankyFrames = %d\n", totalSFLongGpu); StringAppendF(&result, "sfUnattributedJankyFrame = %d\n", totalSFUnattributed); StringAppendF(&result, "appUnattributedJankyFrame = %d\n", totalAppUnattributed); StringAppendF(&result, "sfUnattributedJankyFrames = %d\n", totalSFUnattributed); StringAppendF(&result, "appUnattributedJankyFrames = %d\n", totalAppUnattributed); StringAppendF(&result, "sfSchedulingJankyFrames = %d\n", totalSFScheduling); StringAppendF(&result, "sfPredictionErrorJankyFrames = %d\n", totalSFPredictionError); StringAppendF(&result, "appBufferStuffingJankyFrames = %d\n", totalAppBufferStuffing); return result; } Loading services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h +3 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,9 @@ public: int32_t totalSFLongGpu = 0; int32_t totalSFUnattributed = 0; int32_t totalAppUnattributed = 0; int32_t totalSFScheduling = 0; int32_t totalSFPredictionError = 0; int32_t totalAppBufferStuffing = 0; std::string toString() const; }; Loading services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +130 −66 Original line number Diff line number Diff line Loading @@ -156,12 +156,9 @@ public: uint32_t* maxDisplayFrames; nsecs_t maxTokenRetentionTime; static constexpr pid_t kSurfaceFlingerPid = 666; static constexpr nsecs_t kPresentThreshold = std::chrono::duration_cast<std::chrono::nanoseconds>(2ns).count(); static constexpr nsecs_t kDeadlineThreshold = std::chrono::duration_cast<std::chrono::nanoseconds>(2ns).count(); static constexpr nsecs_t kStartThreshold = std::chrono::duration_cast<std::chrono::nanoseconds>(2ns).count(); static constexpr nsecs_t kPresentThreshold = std::chrono::nanoseconds(2ns).count(); static constexpr nsecs_t kDeadlineThreshold = std::chrono::nanoseconds(2ns).count(); static constexpr nsecs_t kStartThreshold = std::chrono::nanoseconds(2ns).count(); static constexpr JankClassificationThresholds kTestThresholds{kPresentThreshold, kDeadlineThreshold, kStartThreshold}; Loading Loading @@ -430,28 +427,21 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()}); {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(), std::chrono::nanoseconds(60ms).count()}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()}); {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(), std::chrono::nanoseconds(60ms).count()}); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(), refreshRate); surfaceFrame1->setAcquireFenceTime( std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate); surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(20ms).count()); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); presentFence1->signalForTest( std::chrono::duration_cast<std::chrono::nanoseconds>(70ms).count()); presentFence1->signalForTest(std::chrono::nanoseconds(70ms).count()); mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(59ms).count(), presentFence1); mFrameTimeline->setSfPresent(std::chrono::nanoseconds(59ms).count(), presentFence1); } TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { Loading @@ -463,27 +453,20 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()}); {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(), std::chrono::nanoseconds(60ms).count()}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()}); {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(), std::chrono::nanoseconds(60ms).count()}); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(), refreshRate); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); surfaceFrame1->setAcquireFenceTime( std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count()); surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(20ms).count()); mFrameTimeline->addSurfaceFrame(surfaceFrame1); presentFence1->signalForTest( std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count()); mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(), presentFence1); presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count()); mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1); EXPECT_EQ(surfaceFrame1->getJankType(), JankType::DisplayHAL); } Loading @@ -498,32 +481,120 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) { .count()})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()}); {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(), std::chrono::nanoseconds(60ms).count()}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast<std::chrono::nanoseconds>(82ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(86ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count()}); {std::chrono::nanoseconds(82ms).count(), std::chrono::nanoseconds(86ms).count(), std::chrono::nanoseconds(90ms).count()}); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime( std::chrono::duration_cast<std::chrono::nanoseconds>(45ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(), refreshRate); surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(45ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); presentFence1->signalForTest( std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count()); mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(86ms).count(), presentFence1); presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count()); mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1); EXPECT_EQ(surfaceFrame1->getJankType(), JankType::AppDeadlineMissed); } TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) { Fps refreshRate = Fps::fromPeriodNsecs(std::chrono::nanoseconds(32ms).count()); EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, sLayerNameOne, JankType::SurfaceFlingerScheduling, 0, 0, std::chrono::duration_cast< std::chrono::nanoseconds>(-10ms) .count()})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::nanoseconds(40ms).count(), std::chrono::nanoseconds(60ms).count(), std::chrono::nanoseconds(92ms).count()}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(), std::chrono::nanoseconds(60ms).count()}); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(50ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); presentFence1->signalForTest(std::chrono::nanoseconds(60ms).count()); mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1); EXPECT_EQ(surfaceFrame1->getJankType(), JankType::SurfaceFlingerScheduling); } TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) { Fps refreshRate = Fps(16.66f); EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, sLayerNameOne, JankType::PredictionError, 0, std::chrono::duration_cast< std::chrono::nanoseconds>(5ms) .count(), 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::nanoseconds(30ms).count(), std::chrono::nanoseconds(40ms).count(), std::chrono::nanoseconds(60ms).count()}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(), std::chrono::nanoseconds(60ms).count()}); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(40ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); presentFence1->signalForTest(std::chrono::nanoseconds(65ms).count()); mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1); EXPECT_EQ(surfaceFrame1->getJankType(), JankType::PredictionError); } TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) { Fps refreshRate = Fps::fromPeriodNsecs(std::chrono::nanoseconds(32ms).count()); EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, sLayerNameOne, JankType::BufferStuffing | JankType::SurfaceFlingerScheduling, 0, 0, 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::nanoseconds(30ms).count(), std::chrono::nanoseconds(40ms).count(), std::chrono::nanoseconds(58ms).count()}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::nanoseconds(82ms).count(), std::chrono::nanoseconds(86ms).count(), std::chrono::nanoseconds(90ms).count()}); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(40ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(82ms).count(), refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented, /*previousLatchTime*/ std::chrono::nanoseconds(56ms).count()); mFrameTimeline->addSurfaceFrame(surfaceFrame1); presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count()); mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1); EXPECT_EQ(surfaceFrame1->getJankType(), JankType::BufferStuffing | JankType::SurfaceFlingerScheduling); } TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) { Fps refreshRate = Fps(11.0); Fps renderRate = Fps(30.0); Loading @@ -536,29 +607,22 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) { .count()})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()}); {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(), std::chrono::nanoseconds(60ms).count()}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast<std::chrono::nanoseconds>(82ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(86ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count()}); {std::chrono::nanoseconds(82ms).count(), std::chrono::nanoseconds(86ms).count(), std::chrono::nanoseconds(90ms).count()}); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime( std::chrono::duration_cast<std::chrono::nanoseconds>(45ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(), refreshRate); surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(45ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); surfaceFrame1->setRenderRate(renderRate); mFrameTimeline->addSurfaceFrame(surfaceFrame1); presentFence1->signalForTest( std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count()); mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(86ms).count(), presentFence1); presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count()); mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1); EXPECT_EQ(surfaceFrame1->getJankType(), JankType::AppDeadlineMissed); } Loading services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +79 −67 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/surfaceflinger/TimeStats/TimeStats.cpp +22 −13 Original line number Diff line number Diff line Loading @@ -140,11 +140,12 @@ AStatsManager_PullAtomCallbackReturn TimeStats::populateGlobalAtom(AStatsEventLi globalSlice.second.jankPayload.totalSFUnattributed); mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalAppUnattributed); // TODO: populate these with real values mStatsDelegate->statsEventWriteInt32(event, 0); // total_janky_frames_sf_scheduling mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_sf_prediction_error mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_app_buffer_stuffing mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFScheduling); mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalSFPredictionError); mStatsDelegate->statsEventWriteInt32(event, globalSlice.second.jankPayload.totalAppBufferStuffing); mStatsDelegate->statsEventWriteInt32(event, globalSlice.first.displayRefreshRateBucket); std::string sfDeadlineMissedBytes = histogramToProtoByteString(globalSlice.second.displayDeadlineDeltas.hist, Loading Loading @@ -222,11 +223,9 @@ AStatsManager_PullAtomCallbackReturn TimeStats::populateLayerAtom(AStatsEventLis mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFLongGpu); mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFUnattributed); mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalAppUnattributed); // TODO: populate these with real values mStatsDelegate->statsEventWriteInt32(event, 0); // total_janky_frames_sf_scheduling mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_sf_prediction_error mStatsDelegate->statsEventWriteInt32(event, 0); // total_jank_frames_app_buffer_stuffing mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFScheduling); mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalSFPredictionError); mStatsDelegate->statsEventWriteInt32(event, layer->jankPayload.totalAppBufferStuffing); mStatsDelegate->statsEventWriteInt32( event, layer->displayRefreshRateBucket); // display_refresh_rate_bucket mStatsDelegate->statsEventWriteInt32(event, layer->renderRateBucket); // render_rate_bucket Loading Loading @@ -772,9 +771,10 @@ void TimeStats::setPresentFence(int32_t layerId, uint64_t frameNumber, flushAvailableRecordsToStatsLocked(layerId, displayRefreshRate, renderRate); } static const constexpr int32_t kValidJankyReason = JankType::SurfaceFlingerCpuDeadlineMissed | JankType::SurfaceFlingerGpuDeadlineMissed | JankType::AppDeadlineMissed | JankType::DisplayHAL; static const constexpr int32_t kValidJankyReason = JankType::DisplayHAL | JankType::SurfaceFlingerCpuDeadlineMissed | JankType::SurfaceFlingerGpuDeadlineMissed | JankType::AppDeadlineMissed | JankType::PredictionError | JankType::SurfaceFlingerScheduling | JankType::BufferStuffing; template <class T> static void updateJankPayload(T& t, int32_t reasons) { Loading @@ -794,6 +794,15 @@ static void updateJankPayload(T& t, int32_t reasons) { if ((reasons & JankType::AppDeadlineMissed) != 0) { t.jankPayload.totalAppUnattributed++; } if ((reasons & JankType::PredictionError) != 0) { t.jankPayload.totalSFPredictionError++; } if ((reasons & JankType::SurfaceFlingerScheduling) != 0) { t.jankPayload.totalSFScheduling++; } if ((reasons & JankType::BufferStuffing) != 0) { t.jankPayload.totalAppBufferStuffing++; } } } Loading
services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp +5 −2 Original line number Diff line number Diff line Loading @@ -83,8 +83,11 @@ std::string TimeStatsHelper::JankPayload::toString() const { StringAppendF(&result, "jankyFrames = %d\n", totalJankyFrames); StringAppendF(&result, "sfLongCpuJankyFrames = %d\n", totalSFLongCpu); StringAppendF(&result, "sfLongGpuJankyFrames = %d\n", totalSFLongGpu); StringAppendF(&result, "sfUnattributedJankyFrame = %d\n", totalSFUnattributed); StringAppendF(&result, "appUnattributedJankyFrame = %d\n", totalAppUnattributed); StringAppendF(&result, "sfUnattributedJankyFrames = %d\n", totalSFUnattributed); StringAppendF(&result, "appUnattributedJankyFrames = %d\n", totalAppUnattributed); StringAppendF(&result, "sfSchedulingJankyFrames = %d\n", totalSFScheduling); StringAppendF(&result, "sfPredictionErrorJankyFrames = %d\n", totalSFPredictionError); StringAppendF(&result, "appBufferStuffingJankyFrames = %d\n", totalAppBufferStuffing); return result; } Loading
services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h +3 −0 Original line number Diff line number Diff line Loading @@ -48,6 +48,9 @@ public: int32_t totalSFLongGpu = 0; int32_t totalSFUnattributed = 0; int32_t totalAppUnattributed = 0; int32_t totalSFScheduling = 0; int32_t totalSFPredictionError = 0; int32_t totalAppBufferStuffing = 0; std::string toString() const; }; Loading
services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +130 −66 Original line number Diff line number Diff line Loading @@ -156,12 +156,9 @@ public: uint32_t* maxDisplayFrames; nsecs_t maxTokenRetentionTime; static constexpr pid_t kSurfaceFlingerPid = 666; static constexpr nsecs_t kPresentThreshold = std::chrono::duration_cast<std::chrono::nanoseconds>(2ns).count(); static constexpr nsecs_t kDeadlineThreshold = std::chrono::duration_cast<std::chrono::nanoseconds>(2ns).count(); static constexpr nsecs_t kStartThreshold = std::chrono::duration_cast<std::chrono::nanoseconds>(2ns).count(); static constexpr nsecs_t kPresentThreshold = std::chrono::nanoseconds(2ns).count(); static constexpr nsecs_t kDeadlineThreshold = std::chrono::nanoseconds(2ns).count(); static constexpr nsecs_t kStartThreshold = std::chrono::nanoseconds(2ns).count(); static constexpr JankClassificationThresholds kTestThresholds{kPresentThreshold, kDeadlineThreshold, kStartThreshold}; Loading Loading @@ -430,28 +427,21 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) { 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()}); {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(), std::chrono::nanoseconds(60ms).count()}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()}); {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(), std::chrono::nanoseconds(60ms).count()}); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(), refreshRate); surfaceFrame1->setAcquireFenceTime( std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate); surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(20ms).count()); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); presentFence1->signalForTest( std::chrono::duration_cast<std::chrono::nanoseconds>(70ms).count()); presentFence1->signalForTest(std::chrono::nanoseconds(70ms).count()); mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(59ms).count(), presentFence1); mFrameTimeline->setSfPresent(std::chrono::nanoseconds(59ms).count(), presentFence1); } TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { Loading @@ -463,27 +453,20 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) { auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()}); {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(), std::chrono::nanoseconds(60ms).count()}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()}); {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(), std::chrono::nanoseconds(60ms).count()}); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(), refreshRate); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); surfaceFrame1->setAcquireFenceTime( std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count()); surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(20ms).count()); mFrameTimeline->addSurfaceFrame(surfaceFrame1); presentFence1->signalForTest( std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count()); mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(), presentFence1); presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count()); mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1); EXPECT_EQ(surfaceFrame1->getJankType(), JankType::DisplayHAL); } Loading @@ -498,32 +481,120 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) { .count()})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()}); {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(), std::chrono::nanoseconds(60ms).count()}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast<std::chrono::nanoseconds>(82ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(86ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count()}); {std::chrono::nanoseconds(82ms).count(), std::chrono::nanoseconds(86ms).count(), std::chrono::nanoseconds(90ms).count()}); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime( std::chrono::duration_cast<std::chrono::nanoseconds>(45ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(), refreshRate); surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(45ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); presentFence1->signalForTest( std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count()); mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(86ms).count(), presentFence1); presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count()); mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1); EXPECT_EQ(surfaceFrame1->getJankType(), JankType::AppDeadlineMissed); } TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) { Fps refreshRate = Fps::fromPeriodNsecs(std::chrono::nanoseconds(32ms).count()); EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, sLayerNameOne, JankType::SurfaceFlingerScheduling, 0, 0, std::chrono::duration_cast< std::chrono::nanoseconds>(-10ms) .count()})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::nanoseconds(40ms).count(), std::chrono::nanoseconds(60ms).count(), std::chrono::nanoseconds(92ms).count()}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(), std::chrono::nanoseconds(60ms).count()}); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(50ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); presentFence1->signalForTest(std::chrono::nanoseconds(60ms).count()); mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1); EXPECT_EQ(surfaceFrame1->getJankType(), JankType::SurfaceFlingerScheduling); } TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) { Fps refreshRate = Fps(16.66f); EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, sLayerNameOne, JankType::PredictionError, 0, std::chrono::duration_cast< std::chrono::nanoseconds>(5ms) .count(), 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::nanoseconds(30ms).count(), std::chrono::nanoseconds(40ms).count(), std::chrono::nanoseconds(60ms).count()}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::nanoseconds(52ms).count(), std::chrono::nanoseconds(56ms).count(), std::chrono::nanoseconds(60ms).count()}); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(40ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); mFrameTimeline->addSurfaceFrame(surfaceFrame1); presentFence1->signalForTest(std::chrono::nanoseconds(65ms).count()); mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1); EXPECT_EQ(surfaceFrame1->getJankType(), JankType::PredictionError); } TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) { Fps refreshRate = Fps::fromPeriodNsecs(std::chrono::nanoseconds(32ms).count()); EXPECT_CALL(*mTimeStats, incrementJankyFrames( TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne, sLayerNameOne, JankType::BufferStuffing | JankType::SurfaceFlingerScheduling, 0, 0, 0})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::nanoseconds(30ms).count(), std::chrono::nanoseconds(40ms).count(), std::chrono::nanoseconds(58ms).count()}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::nanoseconds(82ms).count(), std::chrono::nanoseconds(86ms).count(), std::chrono::nanoseconds(90ms).count()}); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(40ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(82ms).count(), refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented, /*previousLatchTime*/ std::chrono::nanoseconds(56ms).count()); mFrameTimeline->addSurfaceFrame(surfaceFrame1); presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count()); mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1); EXPECT_EQ(surfaceFrame1->getJankType(), JankType::BufferStuffing | JankType::SurfaceFlingerScheduling); } TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) { Fps refreshRate = Fps(11.0); Fps renderRate = Fps(30.0); Loading @@ -536,29 +607,22 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) { .count()})); auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE); int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(60ms).count()}); {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(), std::chrono::nanoseconds(60ms).count()}); int64_t sfToken1 = mTokenManager->generateTokenForPredictions( {std::chrono::duration_cast<std::chrono::nanoseconds>(82ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(86ms).count(), std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count()}); {std::chrono::nanoseconds(82ms).count(), std::chrono::nanoseconds(86ms).count(), std::chrono::nanoseconds(90ms).count()}); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne, sUidOne, sLayerNameOne, sLayerNameOne); surfaceFrame1->setAcquireFenceTime( std::chrono::duration_cast<std::chrono::nanoseconds>(45ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count(), refreshRate); surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(45ms).count()); mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); surfaceFrame1->setRenderRate(renderRate); mFrameTimeline->addSurfaceFrame(surfaceFrame1); presentFence1->signalForTest( std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count()); mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(86ms).count(), presentFence1); presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count()); mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1); EXPECT_EQ(surfaceFrame1->getJankType(), JankType::AppDeadlineMissed); } Loading
services/surfaceflinger/tests/unittests/TimeStatsTest.cpp +79 −67 File changed.Preview size limit exceeded, changes collapsed. Show changes