Merge "Unify DrawProfiler/JankStats" into mnc-dev
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 @@
     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.h b/libs/hwui/DrawProfiler.h
deleted file mode 100644
index ef6101c..0000000
--- a/libs/hwui/DrawProfiler.h
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef DRAWPROFILER_H
-#define DRAWPROFILER_H
-
-#include "Properties.h"
-#include "Rect.h"
-
-#include <utils/Timers.h>
-
-namespace android {
-namespace uirenderer {
-
-class OpenGLRenderer;
-
-class DrawProfiler {
-public:
-    DrawProfiler();
-    ~DrawProfiler();
-
-    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();
-
-    void addRect(Rect& r, float data, float* shapeOutput);
-    void prepareShapes(const int baseline);
-    void drawGraph(OpenGLRenderer* canvas);
-    void drawCurrentFrame(OpenGLRenderer* canvas);
-    void drawThreshold(OpenGLRenderer* canvas);
-
-    ProfileType mType = ProfileType::None;
-    float mDensity = 0;
-
-    FrameTimingData* mData = nullptr;
-    int mDataSize = 0;
-
-    int mCurrentFrame = -1;
-    nsecs_t mPreviousTime = 0;
-
-    int mVerticalUnit = 0;
-    int mHorizontalUnit = 0;
-    int mThresholdStroke = 0;
-
-    /*
-     * mRects represents an array of rect shapes, divided into NUM_ELEMENTS
-     * groups such that each group is drawn with the same paint.
-     * For example mRects[0] is the array of rect floats suitable for
-     * OpenGLRenderer:drawRects() that makes up all the FrameTimingData:record
-     * information.
-     */
-    float** mRects = nullptr;
-
-    bool mShowDirtyRegions = false;
-    SkRect mDirtyRegion;
-    bool mFlashToggle = false;
-};
-
-} /* namespace uirenderer */
-} /* namespace android */
-
-#endif /* DRAWPROFILER_H */
diff --git a/libs/hwui/DrawProfiler.cpp b/libs/hwui/FrameInfoVisualizer.cpp
similarity index 60%
rename from libs/hwui/DrawProfiler.cpp
rename to 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 @@
     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::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::draw(OpenGLRenderer* canvas) {
+void FrameInfoVisualizer::draw(OpenGLRenderer* canvas) {
     RETURN_IF_DISABLED();
 
     if (mShowDirtyRegions) {
@@ -131,27 +100,21 @@
     }
 }
 
-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 @@
     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 @@
     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 @@
     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/FrameInfoVisualizer.h b/libs/hwui/FrameInfoVisualizer.h
new file mode 100644
index 0000000..f62e34d
--- /dev/null
+++ b/libs/hwui/FrameInfoVisualizer.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#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;
+
+// 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:
+    FrameInfoVisualizer(FrameInfoSource& source);
+    ~FrameInfoVisualizer();
+
+    bool consumeProperties();
+    void setDensity(float density);
+
+    void unionDirty(SkRect* dirty);
+    void draw(OpenGLRenderer* canvas);
+
+    void dumpData(int fd);
+
+private:
+    void createData();
+    void destroyData();
+
+    void addRect(Rect& r, float data, float* shapeOutput);
+    void prepareShapes(const int baseline);
+    void drawGraph(OpenGLRenderer* canvas);
+    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;
+
+    FrameInfoSource& mFrameSource;
+
+    int mVerticalUnit = 0;
+    int mHorizontalUnit = 0;
+    int mThresholdStroke = 0;
+
+    /*
+     * mRects represents an array of rect shapes, divided into NUM_ELEMENTS
+     * groups such that each group is drawn with the same paint.
+     * For example mRects[0] is the array of rect floats suitable for
+     * OpenGLRenderer:drawRects() that makes up all the FrameTimingData:record
+     * information.
+     */
+    std::unique_ptr<float*> mRects;
+
+    bool mShowDirtyRegions = false;
+    SkRect mDirtyRegion;
+    bool mFlashToggle = false;
+    nsecs_t mLastFrameLogged = 0;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* DRAWPROFILER_H */
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index e993f74..26d8bf7 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -109,20 +109,6 @@
 #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 @@
         , 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 @@
         return;
     }
 
-    profiler().markPlaybackStart();
     mCurrentFrameInfo->markIssueDrawCommandsStart();
 
     EGLint width, height;
@@ -251,8 +251,6 @@
 
     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 @@
     mCurrentFrameInfo->markFrameCompleted();
     mJankTracker.addFrame(*mCurrentFrameInfo);
     mRenderThread.jankTracker().addFrame(*mCurrentFrameInfo);
-    profiler().finishFrame();
 }
 
 // Called by choreographer to do an RT-driven animation
@@ -278,7 +275,6 @@
 
     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 @@
     void stopDrawing();
     void notifyFramePending();
 
-    DrawProfiler& profiler() { return mProfiler; }
+    FrameInfoVisualizer& profiler() { return mProfiler; }
 
     void dumpFrames(int fd);
     void resetFrameStats();
@@ -140,12 +140,12 @@
 
     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::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 @@
     RingBuffer() {}
     ~RingBuffer() {}
 
-    size_t capacity() { return SIZE; }
+    constexpr size_t capacity() { return SIZE; }
     size_t size() { return mCount; }
 
     T& next() {