SurfaceFlinger: add win anim frame time tracking
This change makes the 'dumpsys SurfaceFlinger --latency' command with no extra
args dump the frame timestamp data for the most recent frames that
SurfaceFlinger generated that included window animation transaction changes.
Change-Id: I8bded1ea08a4cddefef0aa955401052bb9107c90
diff --git a/services/surfaceflinger/FrameTracker.cpp b/services/surfaceflinger/FrameTracker.cpp
index 5c66ff9..9b55d44 100644
--- a/services/surfaceflinger/FrameTracker.cpp
+++ b/services/surfaceflinger/FrameTracker.cpp
@@ -31,28 +31,34 @@
}
void FrameTracker::setDesiredPresentTime(nsecs_t presentTime) {
+ Mutex::Autolock lock(mMutex);
mFrameRecords[mOffset].desiredPresentTime = presentTime;
}
void FrameTracker::setFrameReadyTime(nsecs_t readyTime) {
+ Mutex::Autolock lock(mMutex);
mFrameRecords[mOffset].frameReadyTime = readyTime;
}
void FrameTracker::setFrameReadyFence(const sp<Fence>& readyFence) {
+ Mutex::Autolock lock(mMutex);
mFrameRecords[mOffset].frameReadyFence = readyFence;
mNumFences++;
}
void FrameTracker::setActualPresentTime(nsecs_t presentTime) {
+ Mutex::Autolock lock(mMutex);
mFrameRecords[mOffset].actualPresentTime = presentTime;
}
void FrameTracker::setActualPresentFence(const sp<Fence>& readyFence) {
+ Mutex::Autolock lock(mMutex);
mFrameRecords[mOffset].actualPresentFence = readyFence;
mNumFences++;
}
void FrameTracker::advanceFrame() {
+ Mutex::Autolock lock(mMutex);
mOffset = (mOffset+1) % NUM_FRAME_RECORDS;
mFrameRecords[mOffset].desiredPresentTime = INT64_MAX;
mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
@@ -74,10 +80,11 @@
// Clean up the signaled fences to keep the number of open fence FDs in
// this process reasonable.
- processFences();
+ processFencesLocked();
}
void FrameTracker::clear() {
+ Mutex::Autolock lock(mMutex);
for (size_t i = 0; i < NUM_FRAME_RECORDS; i++) {
mFrameRecords[i].desiredPresentTime = 0;
mFrameRecords[i].frameReadyTime = 0;
@@ -86,9 +93,12 @@
mFrameRecords[i].actualPresentFence.clear();
}
mNumFences = 0;
+ mFrameRecords[mOffset].desiredPresentTime = INT64_MAX;
+ mFrameRecords[mOffset].frameReadyTime = INT64_MAX;
+ mFrameRecords[mOffset].actualPresentTime = INT64_MAX;
}
-void FrameTracker::processFences() const {
+void FrameTracker::processFencesLocked() const {
FrameRecord* records = const_cast<FrameRecord*>(mFrameRecords);
int& numFences = const_cast<int&>(mNumFences);
@@ -116,7 +126,8 @@
}
void FrameTracker::dump(String8& result) const {
- processFences();
+ Mutex::Autolock lock(mMutex);
+ processFencesLocked();
const size_t o = mOffset;
for (size_t i = 1; i < NUM_FRAME_RECORDS; i++) {
diff --git a/services/surfaceflinger/FrameTracker.h b/services/surfaceflinger/FrameTracker.h
index e8a8c48..3d122c4 100644
--- a/services/surfaceflinger/FrameTracker.h
+++ b/services/surfaceflinger/FrameTracker.h
@@ -19,6 +19,7 @@
#include <stddef.h>
+#include <utils/Mutex.h>
#include <utils/Timers.h>
#include <utils/RefBase.h>
@@ -96,7 +97,7 @@
// This method is const because although it modifies the frame records it
// does so in such a way that the information represented should not
// change. This allows it to be called from the dump method.
- void processFences() const;
+ void processFencesLocked() const;
// mFrameRecords is the circular buffer storing the tracked data for each
// frame.
@@ -113,6 +114,9 @@
// The number of fences is tracked so that the run time of processFences
// doesn't grow with NUM_FRAME_RECORDS.
int mNumFences;
+
+ // mMutex is used to protect access to all member variables.
+ mutable Mutex mMutex;
};
}
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 0cc03e1..1feb9de 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -757,9 +757,6 @@
void Layer::dumpStats(String8& result, char* buffer, size_t SIZE) const
{
LayerBaseClient::dumpStats(result, buffer, SIZE);
- const nsecs_t period =
- mFlinger->getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
- result.appendFormat("%lld\n", period);
mFrameTracker.dump(result);
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index ef829ed..a82767b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -129,6 +129,7 @@
// thread-safe
volatile int32_t mQueuedFrames;
+ FrameTracker mFrameTracker;
// main thread
sp<GraphicBuffer> mActiveBuffer;
@@ -138,7 +139,6 @@
bool mCurrentOpacity;
bool mRefreshPending;
bool mFrameLatencyNeeded;
- FrameTracker mFrameTracker;
// constants
PixelFormat mFormat;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1fa3b8f..caabf1d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -93,6 +93,7 @@
mBootTime(systemTime()),
mVisibleRegionsDirty(false),
mHwWorkListDirty(false),
+ mAnimCompositionPending(false),
mDebugRegion(0),
mDebugDDMS(0),
mDebugDisableHWC(0),
@@ -885,6 +886,22 @@
for (size_t i=0 ; i<count ; i++) {
currentLayers[i]->onPostComposition();
}
+
+ if (mAnimCompositionPending) {
+ mAnimCompositionPending = false;
+
+ const HWComposer& hwc = getHwComposer();
+ sp<Fence> presentFence = hwc.getDisplayFence(HWC_DISPLAY_PRIMARY);
+ if (presentFence != NULL) {
+ mAnimFrameTracker.setActualPresentFence(presentFence);
+ } else {
+ // The HWC doesn't support present fences, so use the refresh
+ // timestamp instead.
+ nsecs_t presentTime = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
+ mAnimFrameTracker.setActualPresentTime(presentTime);
+ }
+ mAnimFrameTracker.advanceFrame();
+ }
}
void SurfaceFlinger::rebuildLayerStacks() {
@@ -1301,6 +1318,10 @@
mLayersPendingRemoval.clear();
}
+ // If this transaction is part of a window animation then the next frame
+ // we composite should be considered an animation as well.
+ mAnimCompositionPending = mAnimTransactionPending;
+
mDrawingState = mCurrentState;
mTransactionPending = false;
mAnimTransactionPending = false;
@@ -2264,22 +2285,26 @@
index++;
}
- const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
- const size_t count = currentLayers.size();
- for (size_t i=0 ; i<count ; i++) {
- const sp<LayerBase>& layer(currentLayers[i]);
- if (name.isEmpty()) {
- snprintf(buffer, SIZE, "%s\n", layer->getName().string());
- result.append(buffer);
- }
- if (name.isEmpty() || (name == layer->getName())) {
- layer->dumpStats(result, buffer, SIZE);
+ const nsecs_t period =
+ getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
+ result.appendFormat("%lld\n", period);
+
+ if (name.isEmpty()) {
+ mAnimFrameTracker.dump(result);
+ } else {
+ const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+ const size_t count = currentLayers.size();
+ for (size_t i=0 ; i<count ; i++) {
+ const sp<LayerBase>& layer(currentLayers[i]);
+ if (name == layer->getName()) {
+ layer->dumpStats(result, buffer, SIZE);
+ }
}
}
}
void SurfaceFlinger::clearStatsLocked(const Vector<String16>& args, size_t& index,
- String8& result, char* buffer, size_t SIZE) const
+ String8& result, char* buffer, size_t SIZE)
{
String8 name;
if (index < args.size()) {
@@ -2295,6 +2320,8 @@
layer->clearStats();
}
}
+
+ mAnimFrameTracker.clear();
}
/*static*/ void SurfaceFlinger::appendSfConfigString(String8& result)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 65fea30..72dd652 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -45,8 +45,9 @@
#include <private/gui/LayerState.h>
#include "Barrier.h"
-#include "MessageQueue.h"
#include "DisplayDevice.h"
+#include "FrameTracker.h"
+#include "MessageQueue.h"
#include "DisplayHardware/HWComposer.h"
@@ -390,7 +391,7 @@
void dumpStatsLocked(const Vector<String16>& args, size_t& index,
String8& result, char* buffer, size_t SIZE) const;
void clearStatsLocked(const Vector<String16>& args, size_t& index,
- String8& result, char* buffer, size_t SIZE) const;
+ String8& result, char* buffer, size_t SIZE);
void dumpAllLocked(String8& result, char* buffer, size_t SIZE) const;
bool startDdmConnection();
static void appendSfConfigString(String8& result);
@@ -432,6 +433,7 @@
State mDrawingState;
bool mVisibleRegionsDirty;
bool mHwWorkListDirty;
+ bool mAnimCompositionPending;
// this may only be written from the main thread with mStateLock held
// it may be read from other threads with mStateLock held
@@ -451,6 +453,7 @@
// these are thread safe
mutable MessageQueue mEventQueue;
mutable Barrier mReadyToRunBarrier;
+ FrameTracker mAnimFrameTracker;
// protected by mDestroyedLayerLock;
mutable Mutex mDestroyedLayerLock;