Loading services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +5 −15 Original line number Diff line number Diff line Loading @@ -730,9 +730,11 @@ namespace impl { int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) { ATRACE_CALL(); std::scoped_lock lock(mMutex); while (mPredictions.size() >= kMaxTokens) { mPredictions.erase(mPredictions.begin()); } const int64_t assignedToken = mCurrentToken++; mPredictions[assignedToken] = {systemTime(), predictions}; flushTokens(systemTime()); mPredictions[assignedToken] = predictions; return assignedToken; } Loading @@ -740,23 +742,11 @@ std::optional<TimelineItem> TokenManager::getPredictionsForToken(int64_t token) std::scoped_lock lock(mMutex); auto predictionsIterator = mPredictions.find(token); if (predictionsIterator != mPredictions.end()) { return predictionsIterator->second.predictions; return predictionsIterator->second; } return {}; } void TokenManager::flushTokens(nsecs_t flushTime) { for (auto it = mPredictions.begin(); it != mPredictions.end();) { if (flushTime - it->second.timestamp >= kMaxRetentionTime) { it = mPredictions.erase(it); } else { // Tokens are ordered by time. If i'th token is within the retention time, then the // i+1'th token will also be within retention time. break; } } } FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid, JankClassificationThresholds thresholds) : mMaxDisplayFrames(kDefaultMaxDisplayFrames), Loading services/surfaceflinger/FrameTimeline/FrameTimeline.h +2 −8 Original line number Diff line number Diff line Loading @@ -92,11 +92,6 @@ struct TimelineItem { bool operator!=(const TimelineItem& other) const { return !(*this == other); } }; struct TokenManagerPrediction { nsecs_t timestamp = 0; TimelineItem predictions; }; struct JankClassificationThresholds { // The various thresholds for App and SF. If the actual timestamp falls within the threshold // compared to prediction, we treat it as on time. Loading Loading @@ -334,11 +329,10 @@ private: void flushTokens(nsecs_t flushTime) REQUIRES(mMutex); std::map<int64_t, TokenManagerPrediction> mPredictions GUARDED_BY(mMutex); std::map<int64_t, TimelineItem> mPredictions GUARDED_BY(mMutex); int64_t mCurrentToken GUARDED_BY(mMutex); mutable std::mutex mMutex; static constexpr nsecs_t kMaxRetentionTime = std::chrono::duration_cast<std::chrono::nanoseconds>(120ms).count(); static constexpr size_t kMaxTokens = 500; }; class FrameTimeline : public android::frametimeline::FrameTimeline { Loading services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +14 −13 Original line number Diff line number Diff line Loading @@ -73,7 +73,7 @@ public: mTokenManager = &mFrameTimeline->mTokenManager; mTraceCookieCounter = &mFrameTimeline->mTraceCookieCounter; maxDisplayFrames = &mFrameTimeline->mMaxDisplayFrames; maxTokenRetentionTime = mTokenManager->kMaxRetentionTime; maxTokens = mTokenManager->kMaxTokens; } // Each tracing session can be used for a single block of Start -> Stop. Loading Loading @@ -111,9 +111,11 @@ public: mFrameTimeline->setSfPresent(2500, presentFence1); } void flushTokens(nsecs_t flushTime) { std::lock_guard<std::mutex> lock(mTokenManager->mMutex); mTokenManager->flushTokens(flushTime); void flushTokens() { for (size_t i = 0; i < maxTokens; i++) { mTokenManager->generateTokenForPredictions({}); } EXPECT_EQ(getPredictions().size(), maxTokens); } SurfaceFrame& getSurfaceFrame(size_t displayFrameIdx, size_t surfaceFrameIdx) { Loading @@ -132,7 +134,7 @@ public: a.presentTime == b.presentTime; } const std::map<int64_t, TokenManagerPrediction>& getPredictions() const { const std::map<int64_t, TimelineItem>& getPredictions() const { return mTokenManager->mPredictions; } Loading @@ -155,7 +157,7 @@ public: TraceCookieCounter* mTraceCookieCounter; FenceToFenceTimeMap fenceFactory; uint32_t* maxDisplayFrames; nsecs_t maxTokenRetentionTime; size_t maxTokens; static constexpr pid_t kSurfaceFlingerPid = 666; static constexpr nsecs_t kPresentThreshold = std::chrono::nanoseconds(2ns).count(); static constexpr nsecs_t kDeadlineThreshold = std::chrono::nanoseconds(2ns).count(); Loading @@ -177,12 +179,11 @@ static constexpr int32_t sLayerIdTwo = 2; TEST_F(FrameTimelineTest, tokenManagerRemovesStalePredictions) { int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0}); EXPECT_EQ(getPredictions().size(), 1u); flushTokens(systemTime() + maxTokenRetentionTime); flushTokens(); int64_t token2 = mTokenManager->generateTokenForPredictions({10, 20, 30}); std::optional<TimelineItem> predictions = mTokenManager->getPredictionsForToken(token1); // token1 should have expired EXPECT_EQ(getPredictions().size(), 1u); EXPECT_EQ(predictions.has_value(), false); predictions = mTokenManager->getPredictionsForToken(token2); Loading Loading @@ -212,7 +213,7 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_noToken) { TEST_F(FrameTimelineTest, createSurfaceFrameForToken_expiredToken) { int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0}); flushTokens(systemTime() + maxTokenRetentionTime); flushTokens(); auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, Loading Loading @@ -707,7 +708,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_displayFramePredictionExpiredPres sLayerNameOne, /*isBuffer*/ true); surfaceFrame1->setAcquireFenceTime(45); // Trigger a prediction expiry flushTokens(systemTime() + maxTokenRetentionTime); flushTokens(); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); Loading Loading @@ -1065,7 +1066,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_predictionExpiredDoesNotTraceExpecte tracingSession->StartBlocking(); int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({10, 25, 30}); // Flush the token so that it would expire flushTokens(systemTime() + maxTokenRetentionTime); flushTokens(); // Set up the display frame mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11)); Loading Loading @@ -1283,7 +1284,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDoesNotTraceExpecte mTokenManager->generateTokenForPredictions({appStartTime, appEndTime, appPresentTime}); // Flush the token so that it would expire flushTokens(systemTime() + maxTokenRetentionTime); flushTokens(); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, Loading Loading @@ -1359,7 +1360,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDroppedFramesTraced mTokenManager->generateTokenForPredictions({appStartTime, appEndTime, appPresentTime}); // Flush the token so that it would expire flushTokens(systemTime() + maxTokenRetentionTime); flushTokens(); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, Loading Loading
services/surfaceflinger/FrameTimeline/FrameTimeline.cpp +5 −15 Original line number Diff line number Diff line Loading @@ -730,9 +730,11 @@ namespace impl { int64_t TokenManager::generateTokenForPredictions(TimelineItem&& predictions) { ATRACE_CALL(); std::scoped_lock lock(mMutex); while (mPredictions.size() >= kMaxTokens) { mPredictions.erase(mPredictions.begin()); } const int64_t assignedToken = mCurrentToken++; mPredictions[assignedToken] = {systemTime(), predictions}; flushTokens(systemTime()); mPredictions[assignedToken] = predictions; return assignedToken; } Loading @@ -740,23 +742,11 @@ std::optional<TimelineItem> TokenManager::getPredictionsForToken(int64_t token) std::scoped_lock lock(mMutex); auto predictionsIterator = mPredictions.find(token); if (predictionsIterator != mPredictions.end()) { return predictionsIterator->second.predictions; return predictionsIterator->second; } return {}; } void TokenManager::flushTokens(nsecs_t flushTime) { for (auto it = mPredictions.begin(); it != mPredictions.end();) { if (flushTime - it->second.timestamp >= kMaxRetentionTime) { it = mPredictions.erase(it); } else { // Tokens are ordered by time. If i'th token is within the retention time, then the // i+1'th token will also be within retention time. break; } } } FrameTimeline::FrameTimeline(std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid, JankClassificationThresholds thresholds) : mMaxDisplayFrames(kDefaultMaxDisplayFrames), Loading
services/surfaceflinger/FrameTimeline/FrameTimeline.h +2 −8 Original line number Diff line number Diff line Loading @@ -92,11 +92,6 @@ struct TimelineItem { bool operator!=(const TimelineItem& other) const { return !(*this == other); } }; struct TokenManagerPrediction { nsecs_t timestamp = 0; TimelineItem predictions; }; struct JankClassificationThresholds { // The various thresholds for App and SF. If the actual timestamp falls within the threshold // compared to prediction, we treat it as on time. Loading Loading @@ -334,11 +329,10 @@ private: void flushTokens(nsecs_t flushTime) REQUIRES(mMutex); std::map<int64_t, TokenManagerPrediction> mPredictions GUARDED_BY(mMutex); std::map<int64_t, TimelineItem> mPredictions GUARDED_BY(mMutex); int64_t mCurrentToken GUARDED_BY(mMutex); mutable std::mutex mMutex; static constexpr nsecs_t kMaxRetentionTime = std::chrono::duration_cast<std::chrono::nanoseconds>(120ms).count(); static constexpr size_t kMaxTokens = 500; }; class FrameTimeline : public android::frametimeline::FrameTimeline { Loading
services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp +14 −13 Original line number Diff line number Diff line Loading @@ -73,7 +73,7 @@ public: mTokenManager = &mFrameTimeline->mTokenManager; mTraceCookieCounter = &mFrameTimeline->mTraceCookieCounter; maxDisplayFrames = &mFrameTimeline->mMaxDisplayFrames; maxTokenRetentionTime = mTokenManager->kMaxRetentionTime; maxTokens = mTokenManager->kMaxTokens; } // Each tracing session can be used for a single block of Start -> Stop. Loading Loading @@ -111,9 +111,11 @@ public: mFrameTimeline->setSfPresent(2500, presentFence1); } void flushTokens(nsecs_t flushTime) { std::lock_guard<std::mutex> lock(mTokenManager->mMutex); mTokenManager->flushTokens(flushTime); void flushTokens() { for (size_t i = 0; i < maxTokens; i++) { mTokenManager->generateTokenForPredictions({}); } EXPECT_EQ(getPredictions().size(), maxTokens); } SurfaceFrame& getSurfaceFrame(size_t displayFrameIdx, size_t surfaceFrameIdx) { Loading @@ -132,7 +134,7 @@ public: a.presentTime == b.presentTime; } const std::map<int64_t, TokenManagerPrediction>& getPredictions() const { const std::map<int64_t, TimelineItem>& getPredictions() const { return mTokenManager->mPredictions; } Loading @@ -155,7 +157,7 @@ public: TraceCookieCounter* mTraceCookieCounter; FenceToFenceTimeMap fenceFactory; uint32_t* maxDisplayFrames; nsecs_t maxTokenRetentionTime; size_t maxTokens; static constexpr pid_t kSurfaceFlingerPid = 666; static constexpr nsecs_t kPresentThreshold = std::chrono::nanoseconds(2ns).count(); static constexpr nsecs_t kDeadlineThreshold = std::chrono::nanoseconds(2ns).count(); Loading @@ -177,12 +179,11 @@ static constexpr int32_t sLayerIdTwo = 2; TEST_F(FrameTimelineTest, tokenManagerRemovesStalePredictions) { int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0}); EXPECT_EQ(getPredictions().size(), 1u); flushTokens(systemTime() + maxTokenRetentionTime); flushTokens(); int64_t token2 = mTokenManager->generateTokenForPredictions({10, 20, 30}); std::optional<TimelineItem> predictions = mTokenManager->getPredictionsForToken(token1); // token1 should have expired EXPECT_EQ(getPredictions().size(), 1u); EXPECT_EQ(predictions.has_value(), false); predictions = mTokenManager->getPredictionsForToken(token2); Loading Loading @@ -212,7 +213,7 @@ TEST_F(FrameTimelineTest, createSurfaceFrameForToken_noToken) { TEST_F(FrameTimelineTest, createSurfaceFrameForToken_expiredToken) { int64_t token1 = mTokenManager->generateTokenForPredictions({0, 0, 0}); flushTokens(systemTime() + maxTokenRetentionTime); flushTokens(); auto surfaceFrame = mFrameTimeline->createSurfaceFrameForToken({token1, sInputEventId}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, sLayerNameOne, Loading Loading @@ -707,7 +708,7 @@ TEST_F(FrameTimelineTest, presentFenceSignaled_displayFramePredictionExpiredPres sLayerNameOne, /*isBuffer*/ true); surfaceFrame1->setAcquireFenceTime(45); // Trigger a prediction expiry flushTokens(systemTime() + maxTokenRetentionTime); flushTokens(); mFrameTimeline->setSfWakeUp(sfToken1, 52, refreshRate); surfaceFrame1->setPresentState(SurfaceFrame::PresentState::Presented); Loading Loading @@ -1065,7 +1066,7 @@ TEST_F(FrameTimelineTest, traceDisplayFrame_predictionExpiredDoesNotTraceExpecte tracingSession->StartBlocking(); int64_t displayFrameToken1 = mTokenManager->generateTokenForPredictions({10, 25, 30}); // Flush the token so that it would expire flushTokens(systemTime() + maxTokenRetentionTime); flushTokens(); // Set up the display frame mFrameTimeline->setSfWakeUp(displayFrameToken1, 20, Fps::fromPeriodNsecs(11)); Loading Loading @@ -1283,7 +1284,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDoesNotTraceExpecte mTokenManager->generateTokenForPredictions({appStartTime, appEndTime, appPresentTime}); // Flush the token so that it would expire flushTokens(systemTime() + maxTokenRetentionTime); flushTokens(); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, Loading Loading @@ -1359,7 +1360,7 @@ TEST_F(FrameTimelineTest, traceSurfaceFrame_predictionExpiredDroppedFramesTraced mTokenManager->generateTokenForPredictions({appStartTime, appEndTime, appPresentTime}); // Flush the token so that it would expire flushTokens(systemTime() + maxTokenRetentionTime); flushTokens(); auto surfaceFrame1 = mFrameTimeline->createSurfaceFrameForToken({surfaceFrameToken, /*inputEventId*/ 0}, sPidOne, sUidOne, sLayerIdOne, sLayerNameOne, Loading