SF: use FenceTime when possible
Fence::getSignalTime is calling a system call everytime,
where FenceTime caches the signal time.
This shows reduction in simpleperf for the main thread
2.23% -> 1.25%
Test: simpleperf for PIP + Notification shade expansion
Bug: 184378996
Change-Id: I182db2ddfcb7fdbde758f5d87357a16e60c1bb07
diff --git a/libs/ui/FenceTime.cpp b/libs/ui/FenceTime.cpp
index bdfe04b..538c1d2 100644
--- a/libs/ui/FenceTime.cpp
+++ b/libs/ui/FenceTime.cpp
@@ -97,6 +97,34 @@
return mState != State::INVALID;
}
+status_t FenceTime::wait(int timeout) {
+ // See if we already have a cached value we can return.
+ nsecs_t signalTime = mSignalTime.load(std::memory_order_relaxed);
+ if (signalTime != Fence::SIGNAL_TIME_PENDING) {
+ return NO_ERROR;
+ }
+
+ // Hold a reference to the fence on the stack in case the class'
+ // reference is removed by another thread. This prevents the
+ // fence from being destroyed until the end of this method, where
+ // we conveniently do not have the lock held.
+ sp<Fence> fence;
+ {
+ // With the lock acquired this time, see if we have the cached
+ // value or if we need to poll the fence.
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mFence.get()) {
+ // Another thread set the signal time just before we added the
+ // reference to mFence.
+ return NO_ERROR;
+ }
+ fence = mFence;
+ }
+
+ // Make the system call without the lock held.
+ return fence->wait(timeout);
+}
+
nsecs_t FenceTime::getSignalTime() {
// See if we already have a cached value we can return.
nsecs_t signalTime = mSignalTime.load(std::memory_order_relaxed);
diff --git a/libs/ui/include/ui/FenceTime.h b/libs/ui/include/ui/FenceTime.h
index ecba7f7..ac75f43 100644
--- a/libs/ui/include/ui/FenceTime.h
+++ b/libs/ui/include/ui/FenceTime.h
@@ -112,6 +112,13 @@
// Returns a snapshot of the FenceTime in its current state.
Snapshot getSnapshot() const;
+ // wait waits for up to timeout milliseconds for the fence to signal. If
+ // the fence signals then NO_ERROR is returned. If the timeout expires
+ // before the fence signals then -ETIME is returned. A timeout of
+ // TIMEOUT_NEVER may be used to indicate that the call should wait
+ // indefinitely for the fence to signal.
+ status_t wait(int timeout);
+
void signalForTest(nsecs_t signalTime);
private:
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index a974dc4..d6becbf 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -432,10 +432,12 @@
}
bool BufferStateLayer::setAcquireFence(const sp<Fence>& fence) {
- // The acquire fences of BufferStateLayers have already signaled before they are set
- mCallbackHandleAcquireTime = fence->getSignalTime();
-
mCurrentState.acquireFence = fence;
+ mCurrentState.acquireFenceTime = std::make_unique<FenceTime>(fence);
+
+ // The acquire fences of BufferStateLayers have already signaled before they are set
+ mCallbackHandleAcquireTime = mCurrentState.acquireFenceTime->getSignalTime();
+
mCurrentState.modified = true;
setTransactionFlags(eTransactionNeeded);
return true;
@@ -691,7 +693,8 @@
// bufferSurfaceFrame could be seen here if a pending state was applied successfully and we
// are processing the next state.
addSurfaceFramePresentedForBuffer(bufferSurfaceFrame,
- mDrawingState.acquireFence->getSignalTime(), latchTime);
+ mDrawingState.acquireFenceTime->getSignalTime(),
+ latchTime);
}
mCurrentStateModified = false;
diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp
index 8ad805b..178c531 100644
--- a/services/surfaceflinger/FrameTracker.cpp
+++ b/services/surfaceflinger/FrameTracker.cpp
@@ -62,10 +62,9 @@
mFrameRecords[mOffset].actualPresentTime = presentTime;
}
-void FrameTracker::setActualPresentFence(
- std::shared_ptr<FenceTime>&& readyFence) {
+void FrameTracker::setActualPresentFence(const std::shared_ptr<FenceTime>& readyFence) {
Mutex::Autolock lock(mMutex);
- mFrameRecords[mOffset].actualPresentFence = std::move(readyFence);
+ mFrameRecords[mOffset].actualPresentFence = readyFence;
mNumFences++;
}
diff --git a/services/surfaceflinger/FrameTracker.h b/services/surfaceflinger/FrameTracker.h
index 35382be..bc412ae 100644
--- a/services/surfaceflinger/FrameTracker.h
+++ b/services/surfaceflinger/FrameTracker.h
@@ -66,7 +66,7 @@
// setActualPresentFence sets the fence that is used to get the time
// at which the current frame became visible to the user.
- void setActualPresentFence(std::shared_ptr<FenceTime>&& fence);
+ void setActualPresentFence(const std::shared_ptr<FenceTime>& fence);
// setDisplayRefreshPeriod sets the display refresh period in nanoseconds.
// This is used to compute frame presentation duration statistics relative
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index b5410fe..dbd6b32 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -116,7 +116,8 @@
mCurrentState.bufferTransform = 0;
mCurrentState.transformToDisplayInverse = false;
mCurrentState.crop.makeInvalid();
- mCurrentState.acquireFence = new Fence(-1);
+ mCurrentState.acquireFence = sp<Fence>::make(-1);
+ mCurrentState.acquireFenceTime = std::make_shared<FenceTime>(mCurrentState.acquireFence);
mCurrentState.dataspace = ui::Dataspace::UNKNOWN;
mCurrentState.hdrMetadata.validTypes = 0;
mCurrentState.surfaceDamageRegion = Region::INVALID_REGION;
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 421a107..3f7a75f 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -261,6 +261,7 @@
sp<GraphicBuffer> buffer;
client_cache_t clientCacheId;
sp<Fence> acquireFence;
+ std::shared_ptr<FenceTime> acquireFenceTime;
HdrMetadata hdrMetadata;
Region surfaceDamageRegion;
int32_t api;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 84b4b23..a9c82d0 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1661,7 +1661,7 @@
}));
}
-sp<Fence> SurfaceFlinger::previousFrameFence() {
+SurfaceFlinger::FenceWithFenceTime SurfaceFlinger::previousFrameFence() {
// We are storing the last 2 present fences. If sf's phase offset is to be
// woken up before the actual vsync but targeting the next vsync, we need to check
// fence N-2
@@ -1671,9 +1671,9 @@
bool SurfaceFlinger::previousFramePending(int graceTimeMs) {
ATRACE_CALL();
- const sp<Fence>& fence = previousFrameFence();
+ const std::shared_ptr<FenceTime>& fence = previousFrameFence().fenceTime;
- if (fence == Fence::NO_FENCE) {
+ if (fence == FenceTime::NO_FENCE) {
return false;
}
@@ -1684,9 +1684,9 @@
}
nsecs_t SurfaceFlinger::previousFramePresentTime() {
- const sp<Fence>& fence = previousFrameFence();
+ const std::shared_ptr<FenceTime>& fence = previousFrameFence().fenceTime;
- if (fence == Fence::NO_FENCE) {
+ if (fence == FenceTime::NO_FENCE) {
return Fence::SIGNAL_TIME_INVALID;
}
@@ -2117,16 +2117,17 @@
getBE().mDisplayTimeline.updateSignalTimes();
mPreviousPresentFences[1] = mPreviousPresentFences[0];
- mPreviousPresentFences[0] =
+ mPreviousPresentFences[0].fence =
display ? getHwComposer().getPresentFence(display->getPhysicalId()) : Fence::NO_FENCE;
- auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFences[0]);
- getBE().mDisplayTimeline.push(presentFenceTime);
+ mPreviousPresentFences[0].fenceTime =
+ std::make_shared<FenceTime>(mPreviousPresentFences[0].fence);
+
+ getBE().mDisplayTimeline.push(mPreviousPresentFences[0].fenceTime);
// Set presentation information before calling Layer::releasePendingBuffer, such that jank
// information from previous' frame classification is already available when sending jank info
// to clients, so they get jank classification as early as possible.
- mFrameTimeline->setSfPresent(systemTime(),
- std::make_shared<FenceTime>(mPreviousPresentFences[0]),
+ mFrameTimeline->setSfPresent(systemTime(), mPreviousPresentFences[0].fenceTime,
glCompositionDoneFenceTime != FenceTime::NO_FENCE);
nsecs_t dequeueReadyTime = systemTime();
@@ -2140,7 +2141,7 @@
// be sampled a little later than when we started doing work for this frame,
// but that should be okay since updateCompositorTiming has snapping logic.
updateCompositorTiming(stats, mCompositionEngine->getLastFrameRefreshTimestamp(),
- presentFenceTime);
+ mPreviousPresentFences[0].fenceTime);
CompositorTiming compositorTiming;
{
std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
@@ -2148,8 +2149,9 @@
}
mDrawingState.traverse([&](Layer* layer) {
- const bool frameLatched = layer->onPostComposition(display, glCompositionDoneFenceTime,
- presentFenceTime, compositorTiming);
+ const bool frameLatched =
+ layer->onPostComposition(display, glCompositionDoneFenceTime,
+ mPreviousPresentFences[0].fenceTime, compositorTiming);
if (frameLatched) {
recordBufferingStats(layer->getName(), layer->getOccupancyHistory(false));
}
@@ -2162,12 +2164,12 @@
}
}
- mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0]);
+ mTransactionCallbackInvoker.addPresentFence(mPreviousPresentFences[0].fence);
mTransactionCallbackInvoker.sendCallbacks();
if (display && display->isPrimary() && display->getPowerMode() == hal::PowerMode::ON &&
- presentFenceTime->isValid()) {
- mScheduler->addPresentFence(presentFenceTime);
+ mPreviousPresentFences[0].fenceTime->isValid()) {
+ mScheduler->addPresentFence(mPreviousPresentFences[0].fenceTime);
}
const bool isDisplayConnected =
@@ -2182,9 +2184,8 @@
if (mAnimCompositionPending) {
mAnimCompositionPending = false;
- if (presentFenceTime->isValid()) {
- mAnimFrameTracker.setActualPresentFence(
- std::move(presentFenceTime));
+ if (mPreviousPresentFences[0].fenceTime->isValid()) {
+ mAnimFrameTracker.setActualPresentFence(mPreviousPresentFences[0].fenceTime);
} else if (isDisplayConnected) {
// The HWC doesn't support present fences, so use the refresh
// timestamp instead.
@@ -2203,7 +2204,7 @@
mTimeStats->incrementClientCompositionReusedFrames();
}
- mTimeStats->setPresentFenceGlobal(presentFenceTime);
+ mTimeStats->setPresentFenceGlobal(mPreviousPresentFences[0].fenceTime);
const size_t sfConnections = mScheduler->getEventThreadConnectionCount(mSfConnectionHandle);
const size_t appConnections = mScheduler->getEventThreadConnectionCount(mAppConnectionHandle);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index c57b180..c4c9ce3 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1013,9 +1013,14 @@
bool isDisplayModeAllowed(DisplayModeId) const REQUIRES(mStateLock);
+ struct FenceWithFenceTime {
+ sp<Fence> fence = Fence::NO_FENCE;
+ std::shared_ptr<FenceTime> fenceTime = FenceTime::NO_FENCE;
+ };
+
// Gets the fence for the previous frame.
// Must be called on the main thread.
- sp<Fence> previousFrameFence();
+ FenceWithFenceTime previousFrameFence();
// Whether the previous frame has not yet been presented to the display.
// If graceTimeMs is positive, this method waits for at most the provided
@@ -1193,7 +1198,7 @@
std::unordered_set<sp<Layer>, ISurfaceComposer::SpHash<Layer>> mLayersWithQueuedFrames;
// Tracks layers that need to update a display's dirty region.
std::vector<sp<Layer>> mLayersPendingRefresh;
- std::array<sp<Fence>, 2> mPreviousPresentFences = {Fence::NO_FENCE, Fence::NO_FENCE};
+ std::array<FenceWithFenceTime, 2> mPreviousPresentFences;
// True if in the previous frame at least one layer was composed via the GPU.
bool mHadClientComposition = false;
// True if in the previous frame at least one layer was composed via HW Composer.