diff options
author | John Reck <jreck@google.com> | 2015-05-12 07:17:50 -0700 |
---|---|---|
committer | John Reck <jreck@google.com> | 2015-05-12 11:02:07 -0700 |
commit | 4c9e59d03c2bca38001225b79d01740b8999adfb (patch) | |
tree | 140ff328b9966bdd974a7868c631eebdc1fea76f | |
parent | 4bd4121d584e16c700ba08828c675b7f906ff331 (diff) | |
download | frameworks_base-4c9e59d03c2bca38001225b79d01740b8999adfb.zip frameworks_base-4c9e59d03c2bca38001225b79d01740b8999adfb.tar.gz frameworks_base-4c9e59d03c2bca38001225b79d01740b8999adfb.tar.bz2 |
Unify DrawProfiler/JankStats
Bug: 20822400
Change-Id: I24345c3120440bfce14e8cbe7e880b39f10b744a
-rw-r--r-- | libs/hwui/Android.common.mk | 2 | ||||
-rw-r--r-- | libs/hwui/FrameInfoVisualizer.cpp (renamed from libs/hwui/DrawProfiler.cpp) | 111 | ||||
-rw-r--r-- | libs/hwui/FrameInfoVisualizer.h (renamed from libs/hwui/DrawProfiler.h) | 67 | ||||
-rw-r--r-- | libs/hwui/Properties.h | 14 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.cpp | 8 | ||||
-rw-r--r-- | libs/hwui/renderthread/CanvasContext.h | 10 | ||||
-rw-r--r-- | libs/hwui/renderthread/DrawFrameTask.cpp | 2 | ||||
-rw-r--r-- | libs/hwui/utils/RingBuffer.h | 2 |
8 files changed, 90 insertions, 126 deletions
diff --git a/libs/hwui/Android.common.mk b/libs/hwui/Android.common.mk index 8a4e609..3e76656 100644 --- a/libs/hwui/Android.common.mk +++ b/libs/hwui/Android.common.mk @@ -40,11 +40,11 @@ LOCAL_SRC_FILES := \ DisplayList.cpp \ DisplayListCanvas.cpp \ Dither.cpp \ - DrawProfiler.cpp \ Extensions.cpp \ FboCache.cpp \ FontRenderer.cpp \ FrameInfo.cpp \ + FrameInfoVisualizer.cpp \ GammaFontRenderer.cpp \ GlopBuilder.cpp \ GradientCache.cpp \ diff --git a/libs/hwui/DrawProfiler.cpp b/libs/hwui/FrameInfoVisualizer.cpp index 7addef9..0411742 100644 --- a/libs/hwui/DrawProfiler.cpp +++ b/libs/hwui/FrameInfoVisualizer.cpp @@ -13,19 +13,15 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "DrawProfiler.h" - -#include <cutils/compiler.h> +#include "FrameInfoVisualizer.h" #include "OpenGLRenderer.h" -#define DEFAULT_MAX_FRAMES 128 +#include <cutils/compiler.h> #define RETURN_IF_PROFILING_DISABLED() if (CC_LIKELY(mType == ProfileType::None)) return #define RETURN_IF_DISABLED() if (CC_LIKELY(mType == ProfileType::None && !mShowDirtyRegions)) return -#define NANOS_TO_MILLIS_FLOAT(nanos) ((nanos) * 0.000001f) - #define PROFILE_DRAW_WIDTH 3 #define PROFILE_DRAW_THRESHOLD_STROKE_WIDTH 2 #define PROFILE_DRAW_DP_PER_MS 7 @@ -55,15 +51,16 @@ static int dpToPx(int dp, float density) { return (int) (dp * density + 0.5f); } -DrawProfiler::DrawProfiler() { +FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source) + : mFrameSource(source) { setDensity(1); } -DrawProfiler::~DrawProfiler() { +FrameInfoVisualizer::~FrameInfoVisualizer() { destroyData(); } -void DrawProfiler::setDensity(float density) { +void FrameInfoVisualizer::setDensity(float density) { if (CC_UNLIKELY(mDensity != density)) { mDensity = density; mVerticalUnit = dpToPx(PROFILE_DRAW_DP_PER_MS, density); @@ -72,35 +69,7 @@ void DrawProfiler::setDensity(float density) { } } -void DrawProfiler::startFrame(nsecs_t recordDurationNanos) { - RETURN_IF_PROFILING_DISABLED(); - mData[mCurrentFrame].record = NANOS_TO_MILLIS_FLOAT(recordDurationNanos); - mPreviousTime = systemTime(CLOCK_MONOTONIC); -} - -void DrawProfiler::markPlaybackStart() { - RETURN_IF_PROFILING_DISABLED(); - nsecs_t now = systemTime(CLOCK_MONOTONIC); - mData[mCurrentFrame].prepare = NANOS_TO_MILLIS_FLOAT(now - mPreviousTime); - mPreviousTime = now; -} - -void DrawProfiler::markPlaybackEnd() { - RETURN_IF_PROFILING_DISABLED(); - nsecs_t now = systemTime(CLOCK_MONOTONIC); - mData[mCurrentFrame].playback = NANOS_TO_MILLIS_FLOAT(now - mPreviousTime); - mPreviousTime = now; -} - -void DrawProfiler::finishFrame() { - RETURN_IF_PROFILING_DISABLED(); - nsecs_t now = systemTime(CLOCK_MONOTONIC); - mData[mCurrentFrame].swapBuffers = NANOS_TO_MILLIS_FLOAT(now - mPreviousTime); - mPreviousTime = now; - mCurrentFrame = (mCurrentFrame + 1) % mDataSize; -} - -void DrawProfiler::unionDirty(SkRect* dirty) { +void FrameInfoVisualizer::unionDirty(SkRect* dirty) { RETURN_IF_DISABLED(); // Not worth worrying about minimizing the dirty region for debugging, so just // dirty the entire viewport. @@ -110,7 +79,7 @@ void DrawProfiler::unionDirty(SkRect* dirty) { } } -void DrawProfiler::draw(OpenGLRenderer* canvas) { +void FrameInfoVisualizer::draw(OpenGLRenderer* canvas) { RETURN_IF_DISABLED(); if (mShowDirtyRegions) { @@ -131,27 +100,21 @@ void DrawProfiler::draw(OpenGLRenderer* canvas) { } } -void DrawProfiler::createData() { - if (mData) return; +void FrameInfoVisualizer::createData() { + if (mRects.get()) return; - mDataSize = property_get_int32(PROPERTY_PROFILE_MAXFRAMES, DEFAULT_MAX_FRAMES); - if (mDataSize <= 0) mDataSize = 1; - if (mDataSize > 4096) mDataSize = 4096; // Reasonable maximum - mData = (FrameTimingData*) calloc(mDataSize, sizeof(FrameTimingData)); - mRects = new float*[NUM_ELEMENTS]; + mRects.reset(new float*[mFrameSource.capacity()]); for (int i = 0; i < NUM_ELEMENTS; i++) { // 4 floats per rect - mRects[i] = (float*) calloc(mDataSize, 4 * sizeof(float)); + mRects.get()[i] = (float*) calloc(mFrameSource.capacity(), 4 * sizeof(float)); } - mCurrentFrame = 0; } -void DrawProfiler::destroyData() { - delete mData; - mData = nullptr; +void FrameInfoVisualizer::destroyData() { + mRects.reset(nullptr); } -void DrawProfiler::addRect(Rect& r, float data, float* shapeOutput) { +void FrameInfoVisualizer::addRect(Rect& r, float data, float* shapeOutput) { r.top = r.bottom - (data * mVerticalUnit); shapeOutput[0] = r.left; shapeOutput[1] = r.top; @@ -160,40 +123,40 @@ void DrawProfiler::addRect(Rect& r, float data, float* shapeOutput) { r.bottom = r.top; } -void DrawProfiler::prepareShapes(const int baseline) { +void FrameInfoVisualizer::prepareShapes(const int baseline) { Rect r; r.right = mHorizontalUnit; - for (int i = 0; i < mDataSize; i++) { + for (size_t i = 0; i < mFrameSource.size(); i++) { const int shapeIndex = i * 4; r.bottom = baseline; - addRect(r, mData[i].record, mRects[RECORD_INDEX] + shapeIndex); - addRect(r, mData[i].prepare, mRects[PREPARE_INDEX] + shapeIndex); - addRect(r, mData[i].playback, mRects[PLAYBACK_INDEX] + shapeIndex); - addRect(r, mData[i].swapBuffers, mRects[SWAPBUFFERS_INDEX] + shapeIndex); + addRect(r, recordDuration(i), mRects.get()[RECORD_INDEX] + shapeIndex); + addRect(r, prepareDuration(i), mRects.get()[PREPARE_INDEX] + shapeIndex); + addRect(r, issueDrawDuration(i), mRects.get()[PLAYBACK_INDEX] + shapeIndex); + addRect(r, swapBuffersDuration(i), mRects.get()[SWAPBUFFERS_INDEX] + shapeIndex); r.translate(mHorizontalUnit, 0); } } -void DrawProfiler::drawGraph(OpenGLRenderer* canvas) { +void FrameInfoVisualizer::drawGraph(OpenGLRenderer* canvas) { SkPaint paint; for (int i = 0; i < NUM_ELEMENTS; i++) { paint.setColor(ELEMENT_COLORS[i]); - canvas->drawRects(mRects[i], mDataSize * 4, &paint); + canvas->drawRects(mRects.get()[i], mFrameSource.capacity() * 4, &paint); } } -void DrawProfiler::drawCurrentFrame(OpenGLRenderer* canvas) { +void FrameInfoVisualizer::drawCurrentFrame(OpenGLRenderer* canvas) { // This draws a solid rect over the entirety of the current frame's shape // To do so we use the bottom of mRects[0] and the top of mRects[NUM_ELEMENTS-1] // which will therefore fully overlap the previously drawn rects SkPaint paint; paint.setColor(CURRENT_FRAME_COLOR); - const int i = mCurrentFrame * 4; - canvas->drawRect(mRects[0][i], mRects[NUM_ELEMENTS-1][i+1], mRects[0][i+2], - mRects[0][i+3], &paint); + const int i = (mFrameSource.size() - 1) * 4; + canvas->drawRect(mRects.get()[0][i], mRects.get()[NUM_ELEMENTS-1][i+1], + mRects.get()[0][i+2], mRects.get()[0][i+3], &paint); } -void DrawProfiler::drawThreshold(OpenGLRenderer* canvas) { +void FrameInfoVisualizer::drawThreshold(OpenGLRenderer* canvas) { SkPaint paint; paint.setColor(THRESHOLD_COLOR); paint.setStrokeWidth(mThresholdStroke); @@ -205,7 +168,7 @@ void DrawProfiler::drawThreshold(OpenGLRenderer* canvas) { canvas->drawLines(pts, 4, &paint); } -bool DrawProfiler::consumeProperties() { +bool FrameInfoVisualizer::consumeProperties() { bool changed = false; ProfileType newType = Properties::getProfileType(); if (newType != mType) { @@ -226,29 +189,25 @@ bool DrawProfiler::consumeProperties() { return changed; } -void DrawProfiler::dumpData(int fd) { +void FrameInfoVisualizer::dumpData(int fd) { RETURN_IF_PROFILING_DISABLED(); // This method logs the last N frames (where N is <= mDataSize) since the // last call to dumpData(). In other words if there's a dumpData(), draw frame, // dumpData(), the last dumpData() should only log 1 frame. - const FrameTimingData emptyData = {0, 0, 0, 0}; - FILE *file = fdopen(fd, "a"); fprintf(file, "\n\tDraw\tPrepare\tProcess\tExecute\n"); - for (int frameOffset = 1; frameOffset <= mDataSize; frameOffset++) { - int i = (mCurrentFrame + frameOffset) % mDataSize; - if (!memcmp(mData + i, &emptyData, sizeof(FrameTimingData))) { + for (size_t i = 0; i < mFrameSource.size(); i++) { + if (mFrameSource[i][FrameInfoIndex::kIntendedVsync] <= mLastFrameLogged) { continue; } + mLastFrameLogged = mFrameSource[i][FrameInfoIndex::kIntendedVsync]; fprintf(file, "\t%3.2f\t%3.2f\t%3.2f\t%3.2f\n", - mData[i].record, mData[i].prepare, mData[i].playback, mData[i].swapBuffers); + recordDuration(i), prepareDuration(i), + issueDrawDuration(i), swapBuffersDuration(i)); } - // reset the buffer - memset(mData, 0, sizeof(FrameTimingData) * mDataSize); - mCurrentFrame = 0; fflush(file); } diff --git a/libs/hwui/DrawProfiler.h b/libs/hwui/FrameInfoVisualizer.h index ef6101c..f62e34d 100644 --- a/libs/hwui/DrawProfiler.h +++ b/libs/hwui/FrameInfoVisualizer.h @@ -16,42 +16,41 @@ #ifndef DRAWPROFILER_H #define DRAWPROFILER_H +#include "FrameInfo.h" #include "Properties.h" #include "Rect.h" +#include "utils/RingBuffer.h" #include <utils/Timers.h> +#include <memory> + namespace android { namespace uirenderer { class OpenGLRenderer; -class DrawProfiler { +// TODO: This is a bit awkward as it needs to match the thing in CanvasContext +// A better abstraction here would be nice but iterators are painful +// and RingBuffer having the size baked into the template is also painful +// But making DrawProfiler also be templated is ALSO painful +// At least this is a compile failure if this doesn't match, so there's that. +typedef RingBuffer<FrameInfo, 120> FrameInfoSource; + +class FrameInfoVisualizer { public: - DrawProfiler(); - ~DrawProfiler(); + FrameInfoVisualizer(FrameInfoSource& source); + ~FrameInfoVisualizer(); bool consumeProperties(); void setDensity(float density); - void startFrame(nsecs_t recordDurationNanos = 0); - void markPlaybackStart(); - void markPlaybackEnd(); - void finishFrame(); - void unionDirty(SkRect* dirty); void draw(OpenGLRenderer* canvas); void dumpData(int fd); private: - typedef struct { - float record; - float prepare; - float playback; - float swapBuffers; - } FrameTimingData; - void createData(); void destroyData(); @@ -61,14 +60,39 @@ private: void drawCurrentFrame(OpenGLRenderer* canvas); void drawThreshold(OpenGLRenderer* canvas); + static inline float duration(nsecs_t start, nsecs_t end) { + float duration = ((end - start) * 0.000001f); + return duration > 0.0f ? duration : 0.0f; + } + + inline float recordDuration(size_t index) { + return duration( + mFrameSource[index][FrameInfoIndex::kIntendedVsync], + mFrameSource[index][FrameInfoIndex::kSyncStart]); + } + + inline float prepareDuration(size_t index) { + return duration( + mFrameSource[index][FrameInfoIndex::kSyncStart], + mFrameSource[index][FrameInfoIndex::kIssueDrawCommandsStart]); + } + + inline float issueDrawDuration(size_t index) { + return duration( + mFrameSource[index][FrameInfoIndex::kIssueDrawCommandsStart], + mFrameSource[index][FrameInfoIndex::kSwapBuffers]); + } + + inline float swapBuffersDuration(size_t index) { + return duration( + mFrameSource[index][FrameInfoIndex::kSwapBuffers], + mFrameSource[index][FrameInfoIndex::kFrameCompleted]); + } + ProfileType mType = ProfileType::None; float mDensity = 0; - FrameTimingData* mData = nullptr; - int mDataSize = 0; - - int mCurrentFrame = -1; - nsecs_t mPreviousTime = 0; + FrameInfoSource& mFrameSource; int mVerticalUnit = 0; int mHorizontalUnit = 0; @@ -81,11 +105,12 @@ private: * OpenGLRenderer:drawRects() that makes up all the FrameTimingData:record * information. */ - float** mRects = nullptr; + std::unique_ptr<float*> mRects; bool mShowDirtyRegions = false; SkRect mDirtyRegion; bool mFlashToggle = false; + nsecs_t mLastFrameLogged = 0; }; } /* namespace uirenderer */ diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index cb5560f..e34444a 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -109,20 +109,6 @@ enum DebugLevel { #define PROPERTY_PROFILE_VISUALIZE_BARS "visual_bars" /** - * System property used to specify the number of frames to be used - * when doing hardware rendering profiling. - * The default value of this property is #PROFILE_MAX_FRAMES. - * - * When profiling is enabled, the adb shell dumpsys gfxinfo command will - * output extra information about the time taken to execute by the last - * frames. - * - * Possible values: - * "60", to set the limit of frames to 60 - */ -#define PROPERTY_PROFILE_MAXFRAMES "debug.hwui.profile.maxframes" - -/** * Used to enable/disable non-rectangular clipping debugging. * * The accepted values are: diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index 733e5e0..6d7dcf1 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -46,7 +46,8 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, , mOpaque(!translucent) , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord())) , mRootRenderNode(rootRenderNode) - , mJankTracker(thread.timeLord().frameIntervalNanos()) { + , mJankTracker(thread.timeLord().frameIntervalNanos()) + , mProfiler(mFrames) { mRenderThread.renderState().registerCanvasContext(this); mProfiler.setDensity(mRenderThread.mainDisplayInfo().density); } @@ -218,7 +219,6 @@ void CanvasContext::draw() { return; } - profiler().markPlaybackStart(); mCurrentFrameInfo->markIssueDrawCommandsStart(); EGLint width, height; @@ -251,8 +251,6 @@ void CanvasContext::draw() { bool drew = mCanvas->finish(); - profiler().markPlaybackEnd(); - // Even if we decided to cancel the frame, from the perspective of jank // metrics the frame was swapped at this point mCurrentFrameInfo->markSwapBuffers(); @@ -267,7 +265,6 @@ void CanvasContext::draw() { mCurrentFrameInfo->markFrameCompleted(); mJankTracker.addFrame(*mCurrentFrameInfo); mRenderThread.jankTracker().addFrame(*mCurrentFrameInfo); - profiler().finishFrame(); } // Called by choreographer to do an RT-driven animation @@ -278,7 +275,6 @@ void CanvasContext::doFrame() { ATRACE_CALL(); - profiler().startFrame(); int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE]; UiFrameInfoBuilder(frameInfo) .addFlag(FrameInfoFlags::kRTAnimation) diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index 8163b0f..8d54304 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -18,9 +18,9 @@ #define CANVASCONTEXT_H_ #include "DamageAccumulator.h" -#include "DrawProfiler.h" #include "IContextFactory.h" #include "FrameInfo.h" +#include "FrameInfoVisualizer.h" #include "RenderNode.h" #include "utils/RingBuffer.h" #include "renderthread/RenderTask.h" @@ -103,7 +103,7 @@ public: void stopDrawing(); void notifyFramePending(); - DrawProfiler& profiler() { return mProfiler; } + FrameInfoVisualizer& profiler() { return mProfiler; } void dumpFrames(int fd); void resetFrameStats(); @@ -140,12 +140,12 @@ private: const sp<RenderNode> mRootRenderNode; - DrawProfiler mProfiler; FrameInfo* mCurrentFrameInfo = nullptr; - // Ring buffer large enough for 1 second worth of frames - RingBuffer<FrameInfo, 60> mFrames; + // Ring buffer large enough for 2 seconds worth of frames + RingBuffer<FrameInfo, 120> mFrames; std::string mName; JankTracker mJankTracker; + FrameInfoVisualizer mProfiler; std::set<RenderNode*> mPrefetechedLayers; }; diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp index 35391b2..83af4ae 100644 --- a/libs/hwui/renderthread/DrawFrameTask.cpp +++ b/libs/hwui/renderthread/DrawFrameTask.cpp @@ -83,8 +83,6 @@ void DrawFrameTask::postAndWait() { void DrawFrameTask::run() { ATRACE_NAME("DrawFrame"); - mContext->profiler().startFrame(); - bool canUnblockUiThread; bool canDrawThisFrame; { diff --git a/libs/hwui/utils/RingBuffer.h b/libs/hwui/utils/RingBuffer.h index fc9aec0..6d0a06b 100644 --- a/libs/hwui/utils/RingBuffer.h +++ b/libs/hwui/utils/RingBuffer.h @@ -31,7 +31,7 @@ public: RingBuffer() {} ~RingBuffer() {} - size_t capacity() { return SIZE; } + constexpr size_t capacity() { return SIZE; } size_t size() { return mCount; } T& next() { |