Fix SF jank classification
In a buffer stuffed state, there is no way the app frame will be
presented on time. It will be at least one vsync late even if the app
frame finished much earlier than expected. The current system wrongly
classifies this as SF Scheduling jank when in reality, the only jank is
that the app is now in a buffer stuffed state.
The other case can also happen, the app could have presented only one
vsync late in a stuffed scenario, but it could have spent some time
waiting on dequeue. To consider this case and give some room for the
app, we try to adjust the deadline within which the app should be ready
to be presented on the next vsync. This way, we can find frames that are
truly long in a buffer stuffed state.
Bug: 180423820
Test: libsurfaceflinger_unittest
Change-Id: I6ff35d018cfab1ef1e96d010165ed7bce013a98e
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 9a4e020..7e6141e 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -67,7 +67,7 @@
void SetUp() override {
mTimeStats = std::make_shared<mock::TimeStats>();
mFrameTimeline = std::make_unique<impl::FrameTimeline>(mTimeStats, kSurfaceFlingerPid,
- kTestThresholds);
+ kTestThresholds, kHwcDuration);
mFrameTimeline->registerDataSource();
mTokenManager = &mFrameTimeline->mTokenManager;
mTraceCookieCounter = &mFrameTimeline->mTraceCookieCounter;
@@ -162,6 +162,7 @@
static constexpr JankClassificationThresholds kTestThresholds{kPresentThreshold,
kDeadlineThreshold,
kStartThreshold};
+ static constexpr nsecs_t kHwcDuration = std::chrono::nanoseconds(3ns).count();
};
static const std::string sLayerNameOne = "layer1";
@@ -420,37 +421,29 @@
// Tests related to TimeStats
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsLongSfCpu) {
- Fps refreshRate = Fps(11);
+ Fps refreshRate = Fps::fromPeriodNsecs(11);
+ // Deadline delta is 2ms because, sf's adjusted deadline is 60 - composerTime(3) = 57ms.
EXPECT_CALL(*mTimeStats,
incrementJankyFrames(
TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
sLayerNameOne,
- JankType::SurfaceFlingerCpuDeadlineMissed,
- std::chrono::duration_cast<
- std::chrono::nanoseconds>(3ms)
- .count(),
- std::chrono::duration_cast<
- std::chrono::nanoseconds>(10ms)
- .count(),
+ JankType::SurfaceFlingerCpuDeadlineMissed, 2, 10,
0}));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
- {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).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()});
+ 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);
- mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
- surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(20ms).count());
+ mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
+ surfaceFrame1->setAcquireFenceTime(20);
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
- presentFence1->signalForTest(std::chrono::nanoseconds(70ms).count());
+ presentFence1->signalForTest(70);
- mFrameTimeline->setSfPresent(std::chrono::nanoseconds(59ms).count(), presentFence1);
+ mFrameTimeline->setSfPresent(59, presentFence1);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsDisplayMiss) {
@@ -458,186 +451,153 @@
EXPECT_CALL(*mTimeStats,
incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
sLayerNameOne, JankType::DisplayHAL,
- 0, 0, 0}));
+ -1, 0, 0}));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
- {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).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()});
+ 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);
- mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+ mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
- surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(20ms).count());
+ surfaceFrame1->setAcquireFenceTime(20);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
- presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count());
- mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1);
+ presentFence1->signalForTest(90);
+ mFrameTimeline->setSfPresent(56, presentFence1);
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::DisplayHAL);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
Fps refreshRate = Fps(11.0);
EXPECT_CALL(*mTimeStats,
- incrementJankyFrames(
- TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
- sLayerNameOne, JankType::AppDeadlineMissed, 0, 0,
- std::chrono::duration_cast<
- std::chrono::nanoseconds>(25ms)
- .count()}));
+ incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+ sLayerNameOne,
+ JankType::AppDeadlineMissed, -1, 0,
+ 25}));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
- {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(),
- std::chrono::nanoseconds(60ms).count()});
- int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
- {std::chrono::nanoseconds(82ms).count(), std::chrono::nanoseconds(86ms).count(),
- std::chrono::nanoseconds(90ms).count()});
+ int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90});
+
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerIdOne, sLayerNameOne,
sLayerNameOne);
- surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(45ms).count());
- mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+ surfaceFrame1->setAcquireFenceTime(45);
+ mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
- presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count());
- mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1);
+ presentFence1->signalForTest(90);
+ mFrameTimeline->setSfPresent(86, presentFence1);
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::AppDeadlineMissed);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfScheduling) {
- Fps refreshRate = Fps::fromPeriodNsecs(std::chrono::nanoseconds(32ms).count());
+ Fps refreshRate = Fps::fromPeriodNsecs(32);
EXPECT_CALL(*mTimeStats,
- incrementJankyFrames(
- TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
- sLayerNameOne,
- JankType::SurfaceFlingerScheduling, 0, 0,
- std::chrono::duration_cast<
- std::chrono::nanoseconds>(-10ms)
- .count()}));
+ incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+ sLayerNameOne,
+ JankType::SurfaceFlingerScheduling,
+ -1, 0, -10}));
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()});
+ int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({40, 60, 92});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerIdOne, sLayerNameOne,
sLayerNameOne);
- surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(50ms).count());
- mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+ surfaceFrame1->setAcquireFenceTime(50);
+ mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
- presentFence1->signalForTest(std::chrono::nanoseconds(60ms).count());
- mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1);
+ presentFence1->signalForTest(60);
+ mFrameTimeline->setSfPresent(56, presentFence1);
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::SurfaceFlingerScheduling);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsSfPredictionError) {
- Fps refreshRate = Fps(16.66f);
+ Fps refreshRate = Fps::fromPeriodNsecs(16);
EXPECT_CALL(*mTimeStats,
- incrementJankyFrames(
- TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
- sLayerNameOne, JankType::PredictionError, 0,
- std::chrono::duration_cast<
- std::chrono::nanoseconds>(5ms)
- .count(),
- 0}));
+ incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+ sLayerNameOne,
+ JankType::PredictionError, -1, 5,
+ 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()});
+ int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 60});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerIdOne, sLayerNameOne,
sLayerNameOne);
- surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(40ms).count());
- mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+ surfaceFrame1->setAcquireFenceTime(40);
+ mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
- presentFence1->signalForTest(std::chrono::nanoseconds(65ms).count());
- mFrameTimeline->setSfPresent(std::chrono::nanoseconds(56ms).count(), presentFence1);
+ presentFence1->signalForTest(65);
+ mFrameTimeline->setSfPresent(56, presentFence1);
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::PredictionError);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppBufferStuffing) {
- Fps refreshRate = Fps::fromPeriodNsecs(std::chrono::nanoseconds(32ms).count());
+ Fps refreshRate = Fps::fromPeriodNsecs(32);
EXPECT_CALL(*mTimeStats,
- incrementJankyFrames(
- TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
- sLayerNameOne,
- JankType::BufferStuffing |
- JankType::SurfaceFlingerScheduling,
- 0, 0, 0}));
+ incrementJankyFrames(TimeStats::JankyFramesInfo{refreshRate, std::nullopt, sUidOne,
+ sLayerNameOne,
+ JankType::BufferStuffing, -1, 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()});
+ int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({30, 40, 58});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90});
+
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerIdOne, sLayerNameOne,
sLayerNameOne);
- surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(40ms).count());
- mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(82ms).count(), refreshRate);
+ surfaceFrame1->setAcquireFenceTime(40);
+ mFrameTimeline->setSfWakeUp(sfToken1, 82, refreshRate);
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented,
- /*previousLatchTime*/
- std::chrono::nanoseconds(56ms).count());
+ /*previousLatchTime*/ 56);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
- presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count());
- mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1);
+ presentFence1->signalForTest(90);
+ mFrameTimeline->setSfPresent(86, presentFence1);
- EXPECT_EQ(surfaceFrame1->getJankType(),
- JankType::BufferStuffing | JankType::SurfaceFlingerScheduling);
+ EXPECT_EQ(surfaceFrame1->getJankType(), JankType::BufferStuffing);
}
TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMissWithRenderRate) {
- Fps refreshRate = Fps(11.0);
- Fps renderRate = Fps(30.0);
+ Fps refreshRate = Fps::fromPeriodNsecs(11);
+ Fps renderRate = Fps::fromPeriodNsecs(30);
EXPECT_CALL(*mTimeStats,
incrementJankyFrames(
TimeStats::JankyFramesInfo{refreshRate, renderRate, sUidOne, sLayerNameOne,
- JankType::AppDeadlineMissed, 0, 0,
- std::chrono::duration_cast<
- std::chrono::nanoseconds>(25ms)
- .count()}));
+ JankType::AppDeadlineMissed, -1, 0, 25}));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions(
- {std::chrono::nanoseconds(10ms).count(), std::chrono::nanoseconds(20ms).count(),
- std::chrono::nanoseconds(60ms).count()});
- int64_t sfToken1 = mTokenManager->generateTokenForPredictions(
- {std::chrono::nanoseconds(82ms).count(), std::chrono::nanoseconds(86ms).count(),
- std::chrono::nanoseconds(90ms).count()});
+ int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 60});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({82, 90, 90});
+
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerIdOne, sLayerNameOne,
sLayerNameOne);
- surfaceFrame1->setAcquireFenceTime(std::chrono::nanoseconds(45ms).count());
- mFrameTimeline->setSfWakeUp(sfToken1, std::chrono::nanoseconds(52ms).count(), refreshRate);
+ surfaceFrame1->setAcquireFenceTime(45);
+ mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate);
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
surfaceFrame1->setRenderRate(renderRate);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
- presentFence1->signalForTest(std::chrono::nanoseconds(90ms).count());
- mFrameTimeline->setSfPresent(std::chrono::nanoseconds(86ms).count(), presentFence1);
+ presentFence1->signalForTest(90);
+ mFrameTimeline->setSfPresent(86, presentFence1);
EXPECT_EQ(surfaceFrame1->getJankType(), JankType::AppDeadlineMissed);
}
@@ -893,7 +853,7 @@
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
tracingSession->StartBlocking();
- int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({10, 25, 30});
+ int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({10, 30, 30});
// Set up the display frame
mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11));
@@ -933,7 +893,7 @@
// Packet - 1 : FrameEnd (ExpectedDisplayFrame)
const auto& packet1 = packets[1];
ASSERT_TRUE(packet1.has_timestamp());
- EXPECT_EQ(packet1.timestamp(), 25u);
+ EXPECT_EQ(packet1.timestamp(), 30u);
ASSERT_TRUE(packet1.has_frame_timeline_event());
const auto& event1 = packet1.frame_timeline_event();
@@ -1179,12 +1139,9 @@
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
tracingSession->StartBlocking();
- constexpr nsecs_t appStartTime =
- std::chrono::duration_cast<std::chrono::nanoseconds>(10ms).count();
- constexpr nsecs_t appEndTime =
- std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count();
- constexpr nsecs_t appPresentTime =
- std::chrono::duration_cast<std::chrono::nanoseconds>(30ms).count();
+ constexpr nsecs_t appStartTime = std::chrono::nanoseconds(10ms).count();
+ constexpr nsecs_t appEndTime = std::chrono::nanoseconds(20ms).count();
+ constexpr nsecs_t appPresentTime = std::chrono::nanoseconds(30ms).count();
int64_t surfaceFrameToken =
mTokenManager->generateTokenForPredictions({appStartTime, appEndTime, appPresentTime});
@@ -1197,12 +1154,9 @@
surfaceFrame1->setActualQueueTime(appEndTime);
surfaceFrame1->setAcquireFenceTime(appEndTime);
- constexpr nsecs_t sfStartTime =
- std::chrono::duration_cast<std::chrono::nanoseconds>(20ms).count();
- constexpr nsecs_t sfEndTime =
- std::chrono::duration_cast<std::chrono::nanoseconds>(30ms).count();
- constexpr nsecs_t sfPresentTime =
- std::chrono::duration_cast<std::chrono::nanoseconds>(30ms).count();
+ constexpr nsecs_t sfStartTime = std::chrono::nanoseconds(20ms).count();
+ constexpr nsecs_t sfEndTime = std::chrono::nanoseconds(30ms).count();
+ constexpr nsecs_t sfPresentTime = std::chrono::nanoseconds(30ms).count();
int64_t displayFrameToken =
mTokenManager->generateTokenForPredictions({sfStartTime, sfEndTime, sfPresentTime});
@@ -1261,7 +1215,7 @@
EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
int64_t surfaceFrameToken = mTokenManager->generateTokenForPredictions({10, 20, 30});
- int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 30});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 30, 30});
auto surfaceFrame =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, sInputEventId}, sPidOne,
sUidOne, sLayerIdOne, sLayerNameOne,
@@ -1292,8 +1246,8 @@
TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishEarlyPresent) {
Fps vsyncRate = Fps::fromPeriodNsecs(11);
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
- int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 30, 40});
+ int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 70});
mFrameTimeline->setSfWakeUp(sfToken1, 22, vsyncRate);
mFrameTimeline->setSfPresent(26, presentFence1);
auto displayFrame = getDisplayFrame(0);
@@ -1331,8 +1285,8 @@
TEST_F(FrameTimelineTest, jankClassification_displayFrameOnTimeFinishLatePresent) {
Fps vsyncRate = Fps::fromPeriodNsecs(11);
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
- int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 30, 40});
+ int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 70});
mFrameTimeline->setSfWakeUp(sfToken1, 22, vsyncRate);
mFrameTimeline->setSfPresent(26, presentFence1);
auto displayFrame = getDisplayFrame(0);
@@ -1411,11 +1365,33 @@
EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerCpuDeadlineMissed);
}
+TEST_F(FrameTimelineTest, jankClassification_displayFrameLateStartLateFinishLatePresent) {
+ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
+ mFrameTimeline->setSfWakeUp(sfToken1, 26, Fps::fromPeriodNsecs(11));
+ mFrameTimeline->setSfPresent(36, presentFence1);
+ auto displayFrame = getDisplayFrame(0);
+ presentFence1->signalForTest(52);
+
+ // Fences haven't been flushed yet, so it should be 0
+ EXPECT_EQ(displayFrame->getActuals().presentTime, 0);
+
+ addEmptyDisplayFrame();
+ displayFrame = getDisplayFrame(0);
+
+ // Fences have flushed, so the present timestamps should be updated
+ EXPECT_EQ(displayFrame->getActuals().presentTime, 52);
+ EXPECT_EQ(displayFrame->getFrameStartMetadata(), FrameStartMetadata::LateStart);
+ EXPECT_EQ(displayFrame->getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+ EXPECT_EQ(displayFrame->getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+ EXPECT_EQ(displayFrame->getJankType(), JankType::SurfaceFlingerScheduling);
+}
+
TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishEarlyPresent) {
EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
- int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 30, 40});
+ int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 70});
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40});
int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70});
auto surfaceFrame1 =
@@ -1426,7 +1402,7 @@
mFrameTimeline->setSfWakeUp(sfToken1, 22, Fps::fromPeriodNsecs(11));
surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame1);
- mFrameTimeline->setSfPresent(26, presentFence1);
+ mFrameTimeline->setSfPresent(27, presentFence1);
auto displayFrame1 = getDisplayFrame(0);
auto& presentedSurfaceFrame1 = getSurfaceFrame(0, 0);
presentFence1->signalForTest(30);
@@ -1446,7 +1422,7 @@
mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame2);
- mFrameTimeline->setSfPresent(56, presentFence2);
+ mFrameTimeline->setSfPresent(57, presentFence2);
auto displayFrame2 = getDisplayFrame(1);
auto& presentedSurfaceFrame2 = getSurfaceFrame(1, 0);
@@ -1494,8 +1470,8 @@
TEST_F(FrameTimelineTest, jankClassification_surfaceFrameOnTimeFinishLatePresent) {
EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 26, 40});
- int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 56, 70});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({22, 30, 40});
+ int64_t sfToken2 = mTokenManager->generateTokenForPredictions({52, 60, 70});
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 40});
int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 70});
auto surfaceFrame1 =
@@ -1526,7 +1502,7 @@
mFrameTimeline->setSfWakeUp(sfToken2, 52, Fps::fromPeriodNsecs(11));
surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented);
mFrameTimeline->addSurfaceFrame(surfaceFrame2);
- mFrameTimeline->setSfPresent(56, presentFence2);
+ mFrameTimeline->setSfPresent(57, presentFence2);
auto displayFrame2 = getDisplayFrame(1);
auto& presentedSurfaceFrame2 = getSurfaceFrame(1, 0);
@@ -1575,7 +1551,7 @@
EXPECT_CALL(*mTimeStats, incrementJankyFrames(_));
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- int64_t sfToken1 = mTokenManager->generateTokenForPredictions({42, 46, 50});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({42, 50, 50});
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 26, 60});
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
@@ -1617,8 +1593,8 @@
EXPECT_CALL(*mTimeStats, incrementJankyFrames(_)).Times(2);
auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
- int64_t sfToken1 = mTokenManager->generateTokenForPredictions({32, 36, 40});
- int64_t sfToken2 = mTokenManager->generateTokenForPredictions({42, 46, 50});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({32, 40, 40});
+ int64_t sfToken2 = mTokenManager->generateTokenForPredictions({42, 50, 50});
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({5, 16, 30});
int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({25, 36, 50});
auto surfaceFrame1 =
@@ -1693,8 +1669,8 @@
int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
- int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 56, 60});
- int64_t sfToken2 = mTokenManager->generateTokenForPredictions({112, 116, 120});
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+ int64_t sfToken2 = mTokenManager->generateTokenForPredictions({112, 120, 120});
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
sUidOne, sLayerIdOne, sLayerNameOne,
@@ -1764,12 +1740,90 @@
JankType::AppDeadlineMissed | JankType::BufferStuffing);
}
+TEST_F(FrameTimelineTest, jankClassification_appDeadlineAdjustedForBufferStuffing) {
+ // Layer specific increment
+ EXPECT_CALL(*mTimeStats, incrementJankyFrames(_)).Times(2);
+ auto presentFence1 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ int64_t surfaceFrameToken1 = mTokenManager->generateTokenForPredictions({10, 20, 30});
+ int64_t surfaceFrameToken2 = mTokenManager->generateTokenForPredictions({40, 50, 60});
+
+ int64_t sfToken1 = mTokenManager->generateTokenForPredictions({52, 60, 60});
+ int64_t sfToken2 = mTokenManager->generateTokenForPredictions({82, 90, 90});
+ auto surfaceFrame1 =
+ mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken1, sInputEventId}, sPidOne,
+ sUidOne, sLayerIdOne, sLayerNameOne,
+ sLayerNameOne);
+ surfaceFrame1->setAcquireFenceTime(50);
+ mFrameTimeline->setSfWakeUp(sfToken1, 52, Fps::fromPeriodNsecs(30));
+ surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented);
+ mFrameTimeline->addSurfaceFrame(surfaceFrame1);
+ mFrameTimeline->setSfPresent(56, presentFence1);
+ auto displayFrame1 = getDisplayFrame(0);
+ auto& presentedSurfaceFrame1 = getSurfaceFrame(0, 0);
+ presentFence1->signalForTest(60);
+
+ // Fences for the first frame haven't been flushed yet, so it should be 0
+ EXPECT_EQ(displayFrame1->getActuals().presentTime, 0);
+ auto actuals1 = presentedSurfaceFrame1.getActuals();
+ EXPECT_EQ(actuals1.presentTime, 0);
+
+ // Trigger a flush by finalizing the next DisplayFrame
+ auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
+ auto surfaceFrame2 =
+ mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken2, sInputEventId}, sPidOne,
+ sUidOne, sLayerIdOne, sLayerNameOne,
+ sLayerNameOne);
+ surfaceFrame2->setAcquireFenceTime(80);
+ mFrameTimeline->setSfWakeUp(sfToken2, 82, Fps::fromPeriodNsecs(30));
+ // Setting previous latch time to 54, adjusted deadline will be 54 + vsyncTime(30) = 84
+ surfaceFrame2->setPresentState(SurfaceFrame::PresentState::Presented, 54);
+ mFrameTimeline->addSurfaceFrame(surfaceFrame2);
+ mFrameTimeline->setSfPresent(86, presentFence2);
+ auto displayFrame2 = getDisplayFrame(1);
+ auto& presentedSurfaceFrame2 = getSurfaceFrame(1, 0);
+ presentFence2->signalForTest(90);
+
+ // Fences for the first frame have flushed, so the present timestamps should be updated
+ EXPECT_EQ(displayFrame1->getActuals().presentTime, 60);
+ actuals1 = presentedSurfaceFrame1.getActuals();
+ EXPECT_EQ(actuals1.endTime, 50);
+ EXPECT_EQ(actuals1.presentTime, 60);
+
+ EXPECT_EQ(displayFrame1->getFramePresentMetadata(), FramePresentMetadata::OnTimePresent);
+ EXPECT_EQ(displayFrame1->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+ EXPECT_EQ(displayFrame1->getJankType(), JankType::None);
+
+ EXPECT_EQ(presentedSurfaceFrame1.getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+ EXPECT_EQ(presentedSurfaceFrame1.getFrameReadyMetadata(), FrameReadyMetadata::LateFinish);
+ EXPECT_EQ(presentedSurfaceFrame1.getJankType(), JankType::AppDeadlineMissed);
+
+ // Fences for the second frame haven't been flushed yet, so it should be 0
+ EXPECT_EQ(displayFrame2->getActuals().presentTime, 0);
+ auto actuals2 = presentedSurfaceFrame2.getActuals();
+ EXPECT_EQ(actuals2.presentTime, 0);
+
+ addEmptyDisplayFrame();
+
+ // Fences for the second frame have flushed, so the present timestamps should be updated
+ EXPECT_EQ(displayFrame2->getActuals().presentTime, 90);
+ actuals2 = presentedSurfaceFrame2.getActuals();
+ EXPECT_EQ(actuals2.presentTime, 90);
+
+ EXPECT_EQ(displayFrame2->getFramePresentMetadata(), FramePresentMetadata::OnTimePresent);
+ EXPECT_EQ(displayFrame2->getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+ EXPECT_EQ(displayFrame2->getJankType(), JankType::None);
+
+ EXPECT_EQ(presentedSurfaceFrame2.getFramePresentMetadata(), FramePresentMetadata::LatePresent);
+ EXPECT_EQ(presentedSurfaceFrame2.getFrameReadyMetadata(), FrameReadyMetadata::OnTimeFinish);
+ EXPECT_EQ(presentedSurfaceFrame2.getJankType(), JankType::BufferStuffing);
+}
+
TEST_F(FrameTimelineTest, computeFps_noLayerIds_returnsZero) {
EXPECT_EQ(mFrameTimeline->computeFps({}), 0.0f);
}
TEST_F(FrameTimelineTest, computeFps_singleDisplayFrame_returnsZero) {
- const auto oneHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count();
+ const auto oneHundredMs = std::chrono::nanoseconds(100ms).count();
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne,
@@ -1784,8 +1838,8 @@
}
TEST_F(FrameTimelineTest, computeFps_twoDisplayFrames_oneLayer) {
- const auto oneHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count();
- const auto twoHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(200ms).count();
+ const auto oneHundredMs = std::chrono::nanoseconds(100ms).count();
+ const auto twoHundredMs = std::chrono::nanoseconds(200ms).count();
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne,
sLayerIdOne, sLayerNameOne, sLayerNameOne);
@@ -1808,8 +1862,8 @@
}
TEST_F(FrameTimelineTest, computeFps_twoDisplayFrames_twoLayers) {
- const auto oneHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count();
- const auto twoHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(200ms).count();
+ const auto oneHundredMs = std::chrono::nanoseconds(100ms).count();
+ const auto twoHundredMs = std::chrono::nanoseconds(200ms).count();
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne,
sLayerIdOne, sLayerNameOne, sLayerNameOne);
@@ -1832,8 +1886,8 @@
}
TEST_F(FrameTimelineTest, computeFps_filtersOutLayers) {
- const auto oneHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count();
- const auto twoHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(200ms).count();
+ const auto oneHundredMs = std::chrono::nanoseconds(100ms).count();
+ const auto twoHundredMs = std::chrono::nanoseconds(200ms).count();
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne,
sLayerIdOne, sLayerNameOne, sLayerNameOne);
@@ -1856,11 +1910,11 @@
}
TEST_F(FrameTimelineTest, computeFps_averagesOverMultipleFrames) {
- const auto oneHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(100ms).count();
- const auto twoHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(200ms).count();
- const auto threeHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(300ms).count();
- const auto fiveHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(500ms).count();
- const auto sixHundredMs = std::chrono::duration_cast<std::chrono::nanoseconds>(600ms).count();
+ const auto oneHundredMs = std::chrono::nanoseconds(100ms).count();
+ const auto twoHundredMs = std::chrono::nanoseconds(200ms).count();
+ const auto threeHundredMs = std::chrono::nanoseconds(300ms).count();
+ const auto fiveHundredMs = std::chrono::nanoseconds(500ms).count();
+ const auto sixHundredMs = std::chrono::nanoseconds(600ms).count();
auto surfaceFrame1 =
mFrameTimeline->createSurfaceFrameForToken(FrameTimelineInfo(), sPidOne, sUidOne,
sLayerIdOne, sLayerNameOne, sLayerNameOne);