From e8696a40e09b24b634214684d18526187b316a2f Mon Sep 17 00:00:00 2001 From: Jamie Gennis Date: Sun, 15 Jan 2012 18:54:57 -0800 Subject: [PATCH 1/2] hack up frame latency measurement Change-Id: I6d9a466a23285304f0e229a5649815636ab5d6af --- opengl/libs/EGL/eglApi.cpp | 20 +++++++++++++++ services/surfaceflinger/Layer.cpp | 29 ++++++++++++++++++++++ services/surfaceflinger/Layer.h | 5 ++++ services/surfaceflinger/LayerBase.h | 4 ++- services/surfaceflinger/SurfaceFlinger.cpp | 6 +++++ 5 files changed, 63 insertions(+), 1 deletion(-) diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp index 664f2582d..8b37da56c 100644 --- a/opengl/libs/EGL/eglApi.cpp +++ b/opengl/libs/EGL/eglApi.cpp @@ -477,6 +477,26 @@ EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface surface, return result; } +void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) { + clearError(); + + egl_display_t const * const dp = validate_display(dpy); + if (!dp) { + return; + } + + SurfaceRef _s(dp, surface); + if (!_s.get()) { + setError(EGL_BAD_SURFACE, EGL_FALSE); + return; + } + + int64_t timestamp = systemTime(SYSTEM_TIME_MONOTONIC); + + egl_surface_t const * const s = get_surface(surface); + native_window_set_buffers_timestamp(s->win.get(), timestamp); +} + // ---------------------------------------------------------------------------- // Contexts // ---------------------------------------------------------------------------- diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index d4c4b1f93..51efdc26e 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -63,6 +63,22 @@ Layer::Layer(SurfaceFlinger* flinger, { mCurrentCrop.makeInvalid(); glGenTextures(1, &mTextureName); + + mFrameLatencyNeeded = false; + mFrameLatencyOffset = 0; + for (int i = 0; i < 128; i++) { + mFrameLatencies[i] = 0; + } +} + +void Layer::onLayerDisplayed() { + if (mFrameLatencyNeeded) { + int64_t now = systemTime(SYSTEM_TIME_MONOTONIC); + mFrameLatencies[mFrameLatencyOffset] = now - + mSurfaceTexture->getTimestamp(); + mFrameLatencyOffset = (mFrameLatencyOffset + 1) % 128; + mFrameLatencyNeeded = false; + } } void Layer::onFirstRef() @@ -408,6 +424,7 @@ void Layer::lockPageFlip(bool& recomputeVisibleRegions) // update the active buffer mActiveBuffer = mSurfaceTexture->getCurrentBuffer(); + mFrameLatencyNeeded = true; const Rect crop(mSurfaceTexture->getCurrentCrop()); const uint32_t transform(mSurfaceTexture->getCurrentTransform()); @@ -538,6 +555,18 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const result.append(buffer); + const int64_t* l = mFrameLatencies; + int o = mFrameLatencyOffset; + for (int i = 0; i < 128; i += 8) { + snprintf(buffer, SIZE, + " " + "% 12lld % 12lld % 12lld % 12lld " + "% 12lld % 12lld % 12lld % 12lld\n", + l[(o+i+0)%128], l[(o+i+1)%128], l[(o+i+2)%128], l[(o+i+3)%128], + l[(o+i+4)%128], l[(o+i+5)%128], l[(o+i+6)%128], l[(o+i+7)%128]); + result.append(buffer); + } + if (mSurfaceTexture != 0) { mSurfaceTexture->dump(result, " ", buffer, SIZE); } diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 2b9471b01..9686259db 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -78,6 +78,8 @@ public: // LayerBaseClient interface virtual wp getSurfaceTextureBinder() const; + virtual void onLayerDisplayed(); + // only for debugging inline const sp& getActiveBuffer() const { return mActiveBuffer; } @@ -110,6 +112,9 @@ private: uint32_t mCurrentTransform; uint32_t mCurrentScalingMode; bool mCurrentOpacity; + bool mFrameLatencyNeeded; + int mFrameLatencyOffset; + int64_t mFrameLatencies[128]; // constants PixelFormat mFormat; diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h index 7f6214510..0c1b228bf 100644 --- a/services/surfaceflinger/LayerBase.h +++ b/services/surfaceflinger/LayerBase.h @@ -205,7 +205,9 @@ public: /** called with the state lock when the surface is removed from the * current list */ virtual void onRemoved() { }; - + + virtual void onLayerDisplayed() { }; + /** always call base class first */ virtual void dump(String8& result, char* scratch, size_t size) const; virtual void shortDump(String8& result, char* scratch, size_t size) const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index af474022d..b2952017c 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -445,6 +445,12 @@ void SurfaceFlinger::postFramebuffer() const nsecs_t now = systemTime(); mDebugInSwapBuffers = now; hw.flip(mSwapRegion); + + size_t numLayers = mVisibleLayersSortedByZ.size(); + for (size_t i = 0; i < numLayers; i++) { + mVisibleLayersSortedByZ[i]->onLayerDisplayed(); + } + mLastSwapBufferTime = systemTime() - now; mDebugInSwapBuffers = 0; mSwapRegion.clear(); From 82d7ab6c7e0cf971e515134ccf072682dd1a2cdb Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 19 Jan 2012 18:34:40 -0800 Subject: [PATCH 2/2] improve SurfaceFlinger dumpsys It is now possible to say: dumpsys SurfaceFlinger --latency to print latency information about all windows dumpsys SurfaceFlinger --latency window-name to print the latency stats of the specified window for instance: dumpsys SurfaceFlinger --latency SurfaceView The data consists of one line containing global stats, followed by 128 lines of tab separated timestamps in nanosecond. The first line currently contains the refresh period in nanosecond. Each 128 following line contains 3 timestamps, of respectively the app draw time, the vsync timestamp just prior the call to set and the timestamp of the call to set. Change-Id: Ib6b6da1d7e2e6ba49c282bdbc0b56a7dc203343a --- .../DisplayHardware/DisplayHardware.cpp | 15 +- .../DisplayHardware/DisplayHardware.h | 5 +- services/surfaceflinger/EventThread.cpp | 2 +- services/surfaceflinger/Layer.cpp | 48 ++-- services/surfaceflinger/Layer.h | 14 +- services/surfaceflinger/LayerBase.cpp | 6 + services/surfaceflinger/LayerBase.h | 1 + services/surfaceflinger/SurfaceFlinger.cpp | 252 ++++++++++-------- services/surfaceflinger/SurfaceFlinger.h | 3 + 9 files changed, 209 insertions(+), 137 deletions(-) diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp index 438a6daf3..986aec576 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp @@ -350,15 +350,28 @@ uint32_t DisplayHardware::getPageFlipCount() const { } // this needs to be thread safe -nsecs_t DisplayHardware::waitForVSync() const { +nsecs_t DisplayHardware::waitForRefresh() const { nsecs_t timestamp; if (mVSync.wait(×tamp) < 0) { // vsync not supported! usleep( getDelayToNextVSyncUs(×tamp) ); } + mLastHwVSync = timestamp; // FIXME: Not thread safe return timestamp; } +nsecs_t DisplayHardware::getRefreshTimestamp() const { + // this returns the last refresh timestamp. + // if the last one is not available, we estimate it based on + // the refresh period and whatever closest timestamp we have. + nsecs_t now = systemTime(); + return now - ((now - mLastHwVSync) % mRefreshPeriod); +} + +nsecs_t DisplayHardware::getRefreshPeriod() const { + return mRefreshPeriod; +} + int32_t DisplayHardware::getDelayToNextVSyncUs(nsecs_t* timestamp) const { Mutex::Autolock _l(mFakeVSyncMutex); const nsecs_t period = mRefreshPeriod; diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h index 77da272bb..02be4dcba 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h @@ -76,7 +76,9 @@ public: uint32_t getMaxViewportDims() const; // waits for the next vsync and returns the timestamp of when it happened - nsecs_t waitForVSync() const; + nsecs_t waitForRefresh() const; + nsecs_t getRefreshPeriod() const; + nsecs_t getRefreshTimestamp() const; uint32_t getPageFlipCount() const; EGLDisplay getEGLDisplay() const { return mDisplay; } @@ -119,6 +121,7 @@ private: mutable Mutex mFakeVSyncMutex; mutable nsecs_t mNextFakeVSync; nsecs_t mRefreshPeriod; + mutable nsecs_t mLastHwVSync; HWComposer* mHwc; diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp index 80ab5195c..6796d7dee 100644 --- a/services/surfaceflinger/EventThread.cpp +++ b/services/surfaceflinger/EventThread.cpp @@ -129,7 +129,7 @@ bool EventThread::threadLoop() { // at least one listener requested VSYNC mLock.unlock(); - timestamp = mHw.waitForVSync(); + timestamp = mHw.waitForRefresh(); mLock.lock(); mDeliveredEvents++; diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index 51efdc26e..a29428142 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -38,6 +38,7 @@ #include "Layer.h" #include "SurfaceFlinger.h" #include "SurfaceTextureLayer.h" +#include #define DEBUG_RESIZE 0 @@ -54,6 +55,8 @@ Layer::Layer(SurfaceFlinger* flinger, mCurrentTransform(0), mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), mCurrentOpacity(true), + mFrameLatencyNeeded(false), + mFrameLatencyOffset(0), mFormat(PIXEL_FORMAT_NONE), mGLExtensions(GLExtensions::getInstance()), mOpaqueLayer(true), @@ -63,19 +66,14 @@ Layer::Layer(SurfaceFlinger* flinger, { mCurrentCrop.makeInvalid(); glGenTextures(1, &mTextureName); - - mFrameLatencyNeeded = false; - mFrameLatencyOffset = 0; - for (int i = 0; i < 128; i++) { - mFrameLatencies[i] = 0; - } } void Layer::onLayerDisplayed() { if (mFrameLatencyNeeded) { - int64_t now = systemTime(SYSTEM_TIME_MONOTONIC); - mFrameLatencies[mFrameLatencyOffset] = now - - mSurfaceTexture->getTimestamp(); + const DisplayHardware& hw(graphicPlane(0).displayHardware()); + mFrameStats[mFrameLatencyOffset].timestamp = mSurfaceTexture->getTimestamp(); + mFrameStats[mFrameLatencyOffset].set = systemTime(); + mFrameStats[mFrameLatencyOffset].vsync = hw.getRefreshTimestamp(); mFrameLatencyOffset = (mFrameLatencyOffset + 1) % 128; mFrameLatencyNeeded = false; } @@ -555,23 +553,33 @@ void Layer::dump(String8& result, char* buffer, size_t SIZE) const result.append(buffer); - const int64_t* l = mFrameLatencies; - int o = mFrameLatencyOffset; - for (int i = 0; i < 128; i += 8) { - snprintf(buffer, SIZE, - " " - "% 12lld % 12lld % 12lld % 12lld " - "% 12lld % 12lld % 12lld % 12lld\n", - l[(o+i+0)%128], l[(o+i+1)%128], l[(o+i+2)%128], l[(o+i+3)%128], - l[(o+i+4)%128], l[(o+i+5)%128], l[(o+i+6)%128], l[(o+i+7)%128]); - result.append(buffer); - } + LayerBase::dumpStats(result, buffer, SIZE); if (mSurfaceTexture != 0) { mSurfaceTexture->dump(result, " ", buffer, SIZE); } } +void Layer::dumpStats(String8& result, char* buffer, size_t SIZE) const +{ + LayerBaseClient::dumpStats(result, buffer, SIZE); + const size_t o = mFrameLatencyOffset; + const DisplayHardware& hw(graphicPlane(0).displayHardware()); + const nsecs_t period = hw.getRefreshPeriod(); + result.appendFormat("%lld\n", period); + for (size_t i=0 ; i<128 ; i++) { + const size_t index = (o+i) % 128; + const nsecs_t time_app = mFrameStats[index].timestamp; + const nsecs_t time_set = mFrameStats[index].set; + const nsecs_t time_vsync = mFrameStats[index].vsync; + result.appendFormat("%lld\t%lld\t%lld\n", + time_app, + time_vsync, + time_set); + } + result.append("\n"); +} + uint32_t Layer::getEffectiveUsage(uint32_t usage) const { // TODO: should we do something special if mSecure is set? diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h index 9686259db..b3fa5e739 100644 --- a/services/surfaceflinger/Layer.h +++ b/services/surfaceflinger/Layer.h @@ -34,6 +34,7 @@ #include "LayerBase.h" #include "SurfaceTextureLayer.h" #include "Transform.h" +#include namespace android { @@ -86,6 +87,7 @@ public: protected: virtual void onFirstRef(); virtual void dump(String8& result, char* scratch, size_t size) const; + virtual void dumpStats(String8& result, char* buffer, size_t SIZE) const; private: friend class SurfaceTextureLayer; @@ -114,7 +116,14 @@ private: bool mCurrentOpacity; bool mFrameLatencyNeeded; int mFrameLatencyOffset; - int64_t mFrameLatencies[128]; + struct Statistics { + Statistics() : timestamp(0), set(0), vsync(0) { } + nsecs_t timestamp; // buffer timestamp + nsecs_t set; // buffer displayed timestamp + nsecs_t vsync; // vsync immediately before set + }; + // protected by mLock + Statistics mFrameStats[128]; // constants PixelFormat mFormat; @@ -126,9 +135,6 @@ private: bool mSecure; // no screenshots bool mProtectedByApp; // application requires protected path to external sink Region mPostedDirtyRegion; - - // binder thread, transaction thread - mutable Mutex mLock; }; // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp index 37879f1a4..1e2c4cb54 100644 --- a/services/surfaceflinger/LayerBase.cpp +++ b/services/surfaceflinger/LayerBase.cpp @@ -471,6 +471,9 @@ void LayerBase::drawWithOpenGL(const Region& clip) const void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const { const Layer::State& s(drawingState()); + s.transparentRegion.dump(result, "transparentRegion"); + transparentRegionScreen.dump(result, "transparentRegionScreen"); + visibleRegionScreen.dump(result, "visibleRegionScreen"); snprintf(buffer, SIZE, "+ %s %p (%s)\n" " " @@ -491,6 +494,9 @@ void LayerBase::shortDump(String8& result, char* scratch, size_t size) const LayerBase::dump(result, scratch, size); } +void LayerBase::dumpStats(String8& result, char* scratch, size_t SIZE) const +{ +} // --------------------------------------------------------------------------- diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h index 0c1b228bf..03d2cc6a8 100644 --- a/services/surfaceflinger/LayerBase.h +++ b/services/surfaceflinger/LayerBase.h @@ -211,6 +211,7 @@ public: /** always call base class first */ virtual void dump(String8& result, char* scratch, size_t size) const; virtual void shortDump(String8& result, char* scratch, size_t size) const; + virtual void dumpStats(String8& result, char* buffer, size_t SIZE) const; enum { // flags for doTransaction() diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index b2952017c..883b642ca 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -431,7 +431,7 @@ bool SurfaceFlinger::threadLoop() } else { // pretend we did the post hw.compositionComplete(); - hw.waitForVSync(); + hw.waitForRefresh(); } return true; } @@ -1469,14 +1469,6 @@ status_t SurfaceFlinger::dump(int fd, const Vector& args) IPCThreadState::self()->getCallingUid()); result.append(buffer); } else { - - // figure out if we're stuck somewhere - const nsecs_t now = systemTime(); - const nsecs_t inSwapBuffers(mDebugInSwapBuffers); - const nsecs_t inTransaction(mDebugInTransaction); - nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0; - nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0; - // Try to get the main lock, but don't insist if we can't // (this would indicate SF is stuck, but we want to be able to // print something in dumpsys). @@ -1492,111 +1484,20 @@ status_t SurfaceFlinger::dump(int fd, const Vector& args) result.append(buffer); } - /* - * Dump the visible layer list - */ - const LayerVector& currentLayers = mCurrentState.layersSortedByZ; - const size_t count = currentLayers.size(); - snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count); - result.append(buffer); - for (size_t i=0 ; i& layer(currentLayers[i]); - layer->dump(result, buffer, SIZE); - const Layer::State& s(layer->drawingState()); - s.transparentRegion.dump(result, "transparentRegion"); - layer->transparentRegionScreen.dump(result, "transparentRegionScreen"); - layer->visibleRegionScreen.dump(result, "visibleRegionScreen"); + bool dumpAll = true; + size_t index = 0; + if (args.size()) { + dumpAll = false; + if (args[index] == String16("--latency")) { + index++; + dumpStatsLocked(args, index, result, buffer, SIZE); + } } - /* - * Dump the layers in the purgatory - */ - - const size_t purgatorySize = mLayerPurgatory.size(); - snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize); - result.append(buffer); - for (size_t i=0 ; i& layer(mLayerPurgatory.itemAt(i)); - layer->shortDump(result, buffer, SIZE); + if (dumpAll) { + dumpAllLocked(result, buffer, SIZE); } - /* - * Dump SurfaceFlinger global state - */ - - snprintf(buffer, SIZE, "SurfaceFlinger global state:\n"); - result.append(buffer); - - const GLExtensions& extensions(GLExtensions::getInstance()); - snprintf(buffer, SIZE, "GLES: %s, %s, %s\n", - extensions.getVendor(), - extensions.getRenderer(), - extensions.getVersion()); - result.append(buffer); - - snprintf(buffer, SIZE, "EGL : %s\n", - eglQueryString(graphicPlane(0).getEGLDisplay(), - EGL_VERSION_HW_ANDROID)); - result.append(buffer); - - snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension()); - result.append(buffer); - - mWormholeRegion.dump(result, "WormholeRegion"); - const DisplayHardware& hw(graphicPlane(0).displayHardware()); - snprintf(buffer, SIZE, - " orientation=%d, canDraw=%d\n", - mCurrentState.orientation, hw.canDraw()); - result.append(buffer); - snprintf(buffer, SIZE, - " last eglSwapBuffers() time: %f us\n" - " last transaction time : %f us\n" - " refresh-rate : %f fps\n" - " x-dpi : %f\n" - " y-dpi : %f\n", - mLastSwapBufferTime/1000.0, - mLastTransactionTime/1000.0, - hw.getRefreshRate(), - hw.getDpiX(), - hw.getDpiY()); - result.append(buffer); - - if (inSwapBuffersDuration || !locked) { - snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n", - inSwapBuffersDuration/1000.0); - result.append(buffer); - } - - if (inTransactionDuration || !locked) { - snprintf(buffer, SIZE, " transaction time: %f us\n", - inTransactionDuration/1000.0); - result.append(buffer); - } - - /* - * VSYNC state - */ - mEventThread->dump(result, buffer, SIZE); - - /* - * Dump HWComposer state - */ - HWComposer& hwc(hw.getHwComposer()); - snprintf(buffer, SIZE, "h/w composer state:\n"); - result.append(buffer); - snprintf(buffer, SIZE, " h/w composer %s and %s\n", - hwc.initCheck()==NO_ERROR ? "present" : "not present", - (mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled"); - result.append(buffer); - hwc.dump(result, buffer, SIZE, mVisibleLayersSortedByZ); - - /* - * Dump gralloc state - */ - const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); - alloc.dump(result); - hw.dump(result); - if (locked) { mStateLock.unlock(); } @@ -1605,6 +1506,137 @@ status_t SurfaceFlinger::dump(int fd, const Vector& args) return NO_ERROR; } +void SurfaceFlinger::dumpStatsLocked(const Vector& args, size_t& index, + String8& result, char* buffer, size_t SIZE) const +{ + String8 name; + if (index < args.size()) { + name = String8(args[index]); + index++; + } + + const LayerVector& currentLayers = mCurrentState.layersSortedByZ; + const size_t count = currentLayers.size(); + for (size_t i=0 ; i& 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); + } + } +} + +void SurfaceFlinger::dumpAllLocked( + String8& result, char* buffer, size_t SIZE) const +{ + // figure out if we're stuck somewhere + const nsecs_t now = systemTime(); + const nsecs_t inSwapBuffers(mDebugInSwapBuffers); + const nsecs_t inTransaction(mDebugInTransaction); + nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0; + nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0; + + /* + * Dump the visible layer list + */ + const LayerVector& currentLayers = mCurrentState.layersSortedByZ; + const size_t count = currentLayers.size(); + snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count); + result.append(buffer); + for (size_t i=0 ; i& layer(currentLayers[i]); + layer->dump(result, buffer, SIZE); + } + + /* + * Dump the layers in the purgatory + */ + + const size_t purgatorySize = mLayerPurgatory.size(); + snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize); + result.append(buffer); + for (size_t i=0 ; i& layer(mLayerPurgatory.itemAt(i)); + layer->shortDump(result, buffer, SIZE); + } + + /* + * Dump SurfaceFlinger global state + */ + + snprintf(buffer, SIZE, "SurfaceFlinger global state:\n"); + result.append(buffer); + + const GLExtensions& extensions(GLExtensions::getInstance()); + snprintf(buffer, SIZE, "GLES: %s, %s, %s\n", + extensions.getVendor(), + extensions.getRenderer(), + extensions.getVersion()); + result.append(buffer); + + snprintf(buffer, SIZE, "EGL : %s\n", + eglQueryString(graphicPlane(0).getEGLDisplay(), + EGL_VERSION_HW_ANDROID)); + result.append(buffer); + + snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension()); + result.append(buffer); + + mWormholeRegion.dump(result, "WormholeRegion"); + const DisplayHardware& hw(graphicPlane(0).displayHardware()); + snprintf(buffer, SIZE, + " orientation=%d, canDraw=%d\n", + mCurrentState.orientation, hw.canDraw()); + result.append(buffer); + snprintf(buffer, SIZE, + " last eglSwapBuffers() time: %f us\n" + " last transaction time : %f us\n" + " refresh-rate : %f fps\n" + " x-dpi : %f\n" + " y-dpi : %f\n", + mLastSwapBufferTime/1000.0, + mLastTransactionTime/1000.0, + hw.getRefreshRate(), + hw.getDpiX(), + hw.getDpiY()); + result.append(buffer); + + snprintf(buffer, SIZE, " eglSwapBuffers time: %f us\n", + inSwapBuffersDuration/1000.0); + result.append(buffer); + + snprintf(buffer, SIZE, " transaction time: %f us\n", + inTransactionDuration/1000.0); + result.append(buffer); + + /* + * VSYNC state + */ + mEventThread->dump(result, buffer, SIZE); + + /* + * Dump HWComposer state + */ + HWComposer& hwc(hw.getHwComposer()); + snprintf(buffer, SIZE, "h/w composer state:\n"); + result.append(buffer); + snprintf(buffer, SIZE, " h/w composer %s and %s\n", + hwc.initCheck()==NO_ERROR ? "present" : "not present", + (mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled"); + result.append(buffer); + hwc.dump(result, buffer, SIZE, mVisibleLayersSortedByZ); + + /* + * Dump gralloc state + */ + const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get()); + alloc.dump(result); + hw.dump(result); +} + status_t SurfaceFlinger::onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 7f6c90ca0..c976e5a00 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -337,6 +337,9 @@ private: void debugFlashRegions(); void drawWormhole() const; + void dumpStatsLocked(const Vector& args, size_t& index, + String8& result, char* buffer, size_t SIZE) const; + void dumpAllLocked(String8& result, char* buffer, size_t SIZE) const; mutable MessageQueue mEventQueue;