am ccdc6a6a: Merge "New debugging tool in adb shell dumpsys gfxinfo"

* commit 'ccdc6a6accdc898ade946b6aada6f15f45192b98':
  New debugging tool in adb shell dumpsys gfxinfo
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 9e8a228..1932c7f 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -39,6 +39,7 @@
 import javax.microedition.khronos.opengles.GL;
 
 import java.io.File;
+import java.io.PrintWriter;
 
 import static javax.microedition.khronos.egl.EGL10.*;
 
@@ -84,13 +85,27 @@
     static final String DISABLE_VSYNC_PROPERTY = "hwui.disable_vsync";
 
     /**
+     * System property used to enable or disable hardware rendering profiling.
+     * The default value of this property is assumed to be false.
+     * 
+     * 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:
+     * "true", to enable profiling
+     * "false", to disable profiling
+     */
+    static final String PROFILE_PROPERTY = "hwui.profile";
+
+    /**
      * System property used to debug EGL configuration choice.
      * 
      * Possible values:
      * "choice", print the chosen configuration only
      * "all", print all possible configurations
      */
-    static final String PRINT_CONFIG_PROPERTY = "hwui.print_config";    
+    static final String PRINT_CONFIG_PROPERTY = "hwui.print_config";
 
     /**
      * Turn on to draw dirty regions every other frame.
@@ -112,6 +127,16 @@
      */
     public static boolean sSystemRendererDisabled = false;
 
+    /**
+     * Number of frames to profile.
+     */
+    private static final int PROFILE_MAX_FRAMES = 64;
+
+    /**
+     * Number of floats per profiled frame.
+     */
+    private static final int PROFILE_FRAME_DATA_COUNT = 3;
+
     private boolean mEnabled;
     private boolean mRequested = true;
 
@@ -226,6 +251,12 @@
     abstract HardwareCanvas getCanvas();
 
     /**
+     * Outputs extra debugging information in the specified file descriptor.
+     * @param pw
+     */
+    abstract void dumpGfxInfo(PrintWriter pw);
+    
+    /**
      * Sets the directory to use as a persistent storage for hardware rendering
      * resources.
      * 
@@ -439,6 +470,7 @@
         
         GL mGl;
         HardwareCanvas mCanvas;
+
         int mFrameCount;
         Paint mDebugPaint;
 
@@ -456,6 +488,10 @@
 
         final boolean mVsyncDisabled;
 
+        final boolean mProfileEnabled;
+        final float[] mProfileData;
+        int mProfileCurrentFrame = -PROFILE_FRAME_DATA_COUNT;
+
         final int mGlVersion;
         final boolean mTranslucent;
 
@@ -472,6 +508,34 @@
             if (mVsyncDisabled) {
                 Log.d(LOG_TAG, "Disabling v-sync");
             }
+
+            //noinspection PointlessBooleanExpression,ConstantConditions
+            if (!ViewDebug.DEBUG_LATENCY) {
+                final String profileProperty = SystemProperties.get(PROFILE_PROPERTY, "false");
+                mProfileEnabled = "true".equalsIgnoreCase(profileProperty);
+                if (mProfileEnabled) {
+                    Log.d(LOG_TAG, "Profiling hardware renderer");
+                }
+            } else {
+                mProfileEnabled = true;
+            }
+
+            if (mProfileEnabled) {
+                mProfileData = new float[PROFILE_MAX_FRAMES * PROFILE_FRAME_DATA_COUNT];
+            } else {
+                mProfileData = null;
+            }
+        }
+
+        @Override
+        void dumpGfxInfo(PrintWriter pw) {
+            if (mProfileEnabled) {
+                pw.printf("\n\tDraw\tProcess\tExecute\n");
+                for (int i = 0; i < mProfileData.length; i += PROFILE_FRAME_DATA_COUNT) {
+                    pw.printf("\t%3.2f\t%3.2f\t%3.2f\n", mProfileData[i], mProfileData[i + 1],
+                            mProfileData[i + 2]);
+                }
+            }
         }
 
         /**
@@ -860,34 +924,49 @@
                                 (view.mPrivateFlags & View.INVALIDATED) == View.INVALIDATED;
                         view.mPrivateFlags &= ~View.INVALIDATED;
 
-                        final long getDisplayListStartTime;
-                        if (ViewDebug.DEBUG_LATENCY) {
+                        long getDisplayListStartTime = 0;
+                        if (mProfileEnabled) {
+                            mProfileCurrentFrame += PROFILE_FRAME_DATA_COUNT;
+                            if (mProfileCurrentFrame >= mProfileData.length) {
+                                mProfileCurrentFrame = 0;
+                            }
+
                             getDisplayListStartTime = System.nanoTime();
                         }
 
                         DisplayList displayList = view.getDisplayList();
 
-                        if (ViewDebug.DEBUG_LATENCY) {
+                        if (mProfileEnabled) {
                             long now = System.nanoTime();
-                            Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- getDisplayList() took "
-                                    + ((now - getDisplayListStartTime) * 0.000001f) + "ms");
+                            float total = (now - getDisplayListStartTime) * 0.000001f;
+                            //noinspection PointlessArithmeticExpression
+                            mProfileData[mProfileCurrentFrame] = total;
+
+                            if (ViewDebug.DEBUG_LATENCY) {
+                                Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- getDisplayList() took " +
+                                        total + "ms");
+                            }
                         }
 
                         if (displayList != null) {
-                            final long drawDisplayListStartTime;
-                            if (ViewDebug.DEBUG_LATENCY) {
+                            long drawDisplayListStartTime = 0;
+                            if (mProfileEnabled) {
                                 drawDisplayListStartTime = System.nanoTime();
                             }
 
-                            boolean invalidateNeeded = canvas.drawDisplayList(
-                                    displayList, view.getWidth(),
-                                    view.getHeight(), mRedrawClip);
+                            boolean invalidateNeeded = canvas.drawDisplayList(displayList,
+                                    view.getWidth(), view.getHeight(), mRedrawClip);
 
-                            if (ViewDebug.DEBUG_LATENCY) {
+                            if (mProfileEnabled) {
                                 long now = System.nanoTime();
-                                Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- drawDisplayList() took "
-                                        + ((now - drawDisplayListStartTime) * 0.000001f)
-                                        + "ms, invalidateNeeded=" + invalidateNeeded + ".");
+                                float total = (now - drawDisplayListStartTime) * 0.000001f;
+                                mProfileData[mProfileCurrentFrame + 1] = total;
+
+                                if (ViewDebug.DEBUG_LATENCY) {
+                                    Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- drawDisplayList() took " +
+                                            total + "ms, invalidateNeeded=" +
+                                            invalidateNeeded + ".");
+                                }
                             }
 
                             if (invalidateNeeded) {
@@ -922,17 +1001,22 @@
 
                     attachInfo.mIgnoreDirtyState = false;
 
-                    final long eglSwapBuffersStartTime;
-                    if (ViewDebug.DEBUG_LATENCY) {
+                    long eglSwapBuffersStartTime = 0;
+                    if (mProfileEnabled) {
                         eglSwapBuffersStartTime = System.nanoTime();
                     }
 
                     sEgl.eglSwapBuffers(sEglDisplay, mEglSurface);
 
-                    if (ViewDebug.DEBUG_LATENCY) {
+                    if (mProfileEnabled) {
                         long now = System.nanoTime();
-                        Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- eglSwapBuffers() took "
-                                + ((now - eglSwapBuffersStartTime) * 0.000001f) + "ms");
+                        float total = (now - eglSwapBuffersStartTime) * 0.000001f;
+                        mProfileData[mProfileCurrentFrame + 2] = total;
+
+                        if (ViewDebug.DEBUG_LATENCY) {
+                            Log.d(ViewDebug.DEBUG_LATENCY_TAG, "- eglSwapBuffers() took " +
+                                    total + "ms");
+                        }
                     }
 
                     checkEglErrors();
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index 6bdc4e8..6dbdedb 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -480,9 +480,19 @@
         try {
             synchronized (this) {
                 if (mViews != null) {
-                    pw.println("View hierarchy:");
-
                     final int count = mViews.length;
+                    
+                    pw.println("Profile data in ms:");
+
+                    for (int i = 0; i < count; i++) {
+                        ViewRootImpl root = mRoots[i];
+                        HardwareRenderer renderer = root.getView().mAttachInfo.mHardwareRenderer;
+                        if (renderer != null) {
+                            renderer.dumpGfxInfo(pw);
+                        }
+                    }
+
+                    pw.println("\nView hierarchy:");
 
                     int viewsCount = 0;
                     int displayListsSize = 0;