Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ba6adf66 authored by John Reck's avatar John Reck
Browse files

Initial attempt at jank-tracking stat collection

Is a bit naive, perhaps overly aggressive, but sorta works

Change-Id: I01a774e00dbe681439c02557d9728ae43c45ce50
parent 004a46eb
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -1101,7 +1101,7 @@ public final class ActivityThread {
        @Override
        public void dumpGfxInfo(FileDescriptor fd, String[] args) {
            dumpGraphicsInfo(fd);
            WindowManagerGlobal.getInstance().dumpGfxInfo(fd);
            WindowManagerGlobal.getInstance().dumpGfxInfo(fd, args);
        }

        private void dumpDatabaseInfo(FileDescriptor fd, String[] args) {
+20 −0
Original line number Diff line number Diff line
@@ -140,6 +140,19 @@ public final class Choreographer {
    private long mLastFrameTimeNanos;
    private long mFrameIntervalNanos;

    /**
     * Contains information about the current frame for jank-tracking,
     * mainly timings of key events along with a bit of metadata about
     * view tree state
     *
     * TODO: Is there a better home for this? Currently Choreographer
     * is the only one with CALLBACK_ANIMATION start time, hence why this
     * resides here.
     *
     * @hide
     */
    FrameInfo mFrameInfo = new FrameInfo();

    /**
     * Callback type: Input callback.  Runs first.
     * @hide
@@ -513,6 +526,7 @@ public final class Choreographer {
                return; // no work to do
            }

            long intendedFrameTimeNanos = frameTimeNanos;
            startNanos = System.nanoTime();
            final long jitterNanos = startNanos - frameTimeNanos;
            if (jitterNanos >= mFrameIntervalNanos) {
@@ -541,12 +555,18 @@ public final class Choreographer {
                return;
            }

            mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
            mFrameScheduled = false;
            mLastFrameTimeNanos = frameTimeNanos;
        }

        mFrameInfo.markInputHandlingStart();
        doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);

        mFrameInfo.markAnimationsStart();
        doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);

        mFrameInfo.markPerformTraversalsStart();
        doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);

        if (DEBUG) {
+118 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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.
 */

package android.view;

import android.annotation.IntDef;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Class that contains all the timing information for the current frame. This
 * is used in conjunction with the hardware renderer to provide
 * continous-monitoring jank events
 *
 * All times in nanoseconds from CLOCK_MONOTONIC/System.nanoTime()
 *
 * To minimize overhead from System.nanoTime() calls we infer durations of
 * things by knowing the ordering of the events. For example, to know how
 * long layout & measure took it's displayListRecordStart - performTraversalsStart.
 *
 * These constants must be kept in sync with FrameInfo.h in libhwui and are
 * used for indexing into AttachInfo's mFrameInfo long[], which is intended
 * to be quick to pass down to native via JNI, hence a pre-packed format
 *
 * @hide
 */
final class FrameInfo {

    long[] mFrameInfo = new long[9];

    // Various flags set to provide extra metadata about the current frame
    private static final int FLAGS = 0;

    // Is this the first-draw following a window layout?
    public static final long FLAG_WINDOW_LAYOUT_CHANGED = 1;

    @IntDef(flag = true, value = {
            FLAG_WINDOW_LAYOUT_CHANGED })
    @Retention(RetentionPolicy.SOURCE)
    public @interface FrameInfoFlags {}

    // The intended vsync time, unadjusted by jitter
    private static final int INTENDED_VSYNC = 1;

    // Jitter-adjusted vsync time, this is what was used as input into the
    // animation & drawing system
    private static final int VSYNC = 2;

    // The time of the oldest input event
    private static final int OLDEST_INPUT_EVENT = 3;

    // The time of the newest input event
    private static final int NEWEST_INPUT_EVENT = 4;

    // When input event handling started
    private static final int HANDLE_INPUT_START = 5;

    // When animation evaluations started
    private static final int ANIMATION_START = 6;

    // When ViewRootImpl#performTraversals() started
    private static final int PERFORM_TRAVERSALS_START = 7;

    // When View:draw() started
    private static final int DRAW_START = 8;

    public void setVsync(long intendedVsync, long usedVsync) {
        mFrameInfo[INTENDED_VSYNC] = intendedVsync;
        mFrameInfo[VSYNC] = usedVsync;
        mFrameInfo[OLDEST_INPUT_EVENT] = Long.MAX_VALUE;
        mFrameInfo[NEWEST_INPUT_EVENT] = 0;
        mFrameInfo[FLAGS] = 0;
    }

    public void updateInputEventTime(long inputEventTime, long inputEventOldestTime) {
        if (inputEventOldestTime < mFrameInfo[OLDEST_INPUT_EVENT]) {
            mFrameInfo[OLDEST_INPUT_EVENT] = inputEventOldestTime;
        }
        if (inputEventTime > mFrameInfo[NEWEST_INPUT_EVENT]) {
            mFrameInfo[NEWEST_INPUT_EVENT] = inputEventTime;
        }
    }

    public void markInputHandlingStart() {
        mFrameInfo[HANDLE_INPUT_START] = System.nanoTime();
    }

    public void markAnimationsStart() {
        mFrameInfo[ANIMATION_START] = System.nanoTime();
    }

    public void markPerformTraversalsStart() {
        mFrameInfo[PERFORM_TRAVERSALS_START] = System.nanoTime();
    }

    public void markDrawStart() {
        mFrameInfo[DRAW_START] = System.nanoTime();
    }

    public void addFlags(@FrameInfoFlags long flags) {
        mFrameInfo[FLAGS] |= flags;
    }

}
+1 −1
Original line number Diff line number Diff line
@@ -278,7 +278,7 @@ public abstract class HardwareRenderer {
    /**
     * Outputs extra debugging information in the specified file descriptor.
     */
    abstract void dumpGfxInfo(PrintWriter pw, FileDescriptor fd);
    abstract void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args);

    /**
     * Loads system properties used by the renderer. This method is invoked
+36 −41
Original line number Diff line number Diff line
@@ -16,8 +16,7 @@

package android.view;

import com.android.internal.R;

import android.annotation.IntDef;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -27,16 +26,18 @@ import android.graphics.drawable.Drawable;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.os.Trace;
import android.util.Log;
import android.util.LongSparseArray;
import android.util.TimeUtils;
import android.view.Surface.OutOfResourcesException;
import android.view.View.AttachInfo;

import com.android.internal.R;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashSet;

@@ -74,6 +75,14 @@ public class ThreadedRenderer extends HardwareRenderer {
        PROFILE_PROPERTY_VISUALIZE_BARS,
    };

    private static final int FLAG_DUMP_FRAMESTATS   = 1 << 0;
    private static final int FLAG_DUMP_RESET        = 1 << 1;

    @IntDef(flag = true, value = {
            FLAG_DUMP_FRAMESTATS, FLAG_DUMP_RESET })
    @Retention(RetentionPolicy.SOURCE)
    public @interface DumpFlags {}

    // Size of the rendered content.
    private int mWidth, mHeight;

@@ -93,12 +102,12 @@ public class ThreadedRenderer extends HardwareRenderer {
    private final float mLightRadius;
    private final int mAmbientShadowAlpha;
    private final int mSpotShadowAlpha;
    private final float mDensity;

    private long mNativeProxy;
    private boolean mInitialized = false;
    private RenderNode mRootNode;
    private Choreographer mChoreographer;
    private boolean mProfilingEnabled;
    private boolean mRootNodeNeedsUpdate;

    ThreadedRenderer(Context context, boolean translucent) {
@@ -110,6 +119,7 @@ public class ThreadedRenderer extends HardwareRenderer {
                (int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f);
        mSpotShadowAlpha = (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f);
        a.recycle();
        mDensity = context.getResources().getDisplayMetrics().density;

        long rootNodePtr = nCreateRootRenderNode();
        mRootNode = RenderNode.adopt(rootNodePtr);
@@ -214,7 +224,7 @@ public class ThreadedRenderer extends HardwareRenderer {
        mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight);
        nSetup(mNativeProxy, mSurfaceWidth, mSurfaceHeight,
                lightX, mLightY, mLightZ, mLightRadius,
                mAmbientShadowAlpha, mSpotShadowAlpha);
                mAmbientShadowAlpha, mSpotShadowAlpha, mDensity);
    }

    @Override
@@ -233,32 +243,25 @@ public class ThreadedRenderer extends HardwareRenderer {
    }

    @Override
    void dumpGfxInfo(PrintWriter pw, FileDescriptor fd) {
    void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args) {
        pw.flush();
        nDumpProfileInfo(mNativeProxy, fd);
        int flags = 0;
        for (int i = 0; i < args.length; i++) {
            switch (args[i]) {
                case "framestats":
                    flags |= FLAG_DUMP_FRAMESTATS;
                    break;
                case "reset":
                    flags |= FLAG_DUMP_RESET;
                    break;
            }

    private static int search(String[] values, String value) {
        for (int i = 0; i < values.length; i++) {
            if (values[i].equals(value)) return i;
        }
        return -1;
    }

    private static boolean checkIfProfilingRequested() {
        String profiling = SystemProperties.get(HardwareRenderer.PROFILE_PROPERTY);
        int graphType = search(VISUALIZERS, profiling);
        return (graphType >= 0) || Boolean.parseBoolean(profiling);
        nDumpProfileInfo(mNativeProxy, fd, flags);
    }

    @Override
    boolean loadSystemProperties() {
        boolean changed = nLoadSystemProperties(mNativeProxy);
        boolean wantProfiling = checkIfProfilingRequested();
        if (wantProfiling != mProfilingEnabled) {
            mProfilingEnabled = wantProfiling;
            changed = true;
        }
        if (changed) {
            invalidateRoot();
        }
@@ -307,20 +310,12 @@ public class ThreadedRenderer extends HardwareRenderer {
    @Override
    void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
        attachInfo.mIgnoreDirtyState = true;
        long frameTimeNanos = mChoreographer.getFrameTimeNanos();
        attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;

        long recordDuration = 0;
        if (mProfilingEnabled) {
            recordDuration = System.nanoTime();
        }
        final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer;
        choreographer.mFrameInfo.markDrawStart();

        updateRootDisplayList(view, callbacks);

        if (mProfilingEnabled) {
            recordDuration = System.nanoTime() - recordDuration;
        }

        attachInfo.mIgnoreDirtyState = false;

        // register animating rendernodes which started animating prior to renderer
@@ -337,8 +332,8 @@ public class ThreadedRenderer extends HardwareRenderer {
            attachInfo.mPendingAnimatingRenderNodes = null;
        }

        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
                recordDuration, view.getResources().getDisplayMetrics().density);
        final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
        if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
            setEnabled(false);
            attachInfo.mViewRootImpl.mSurface.release();
@@ -500,10 +495,9 @@ public class ThreadedRenderer extends HardwareRenderer {
    private static native boolean nPauseSurface(long nativeProxy, Surface window);
    private static native void nSetup(long nativeProxy, int width, int height,
            float lightX, float lightY, float lightZ, float lightRadius,
            int ambientShadowAlpha, int spotShadowAlpha);
            int ambientShadowAlpha, int spotShadowAlpha, float density);
    private static native void nSetOpaque(long nativeProxy, boolean opaque);
    private static native int nSyncAndDrawFrame(long nativeProxy,
            long frameTimeNanos, long recordDuration, float density);
    private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
    private static native void nDestroy(long nativeProxy);
    private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);

@@ -523,5 +517,6 @@ public class ThreadedRenderer extends HardwareRenderer {
    private static native void nStopDrawing(long nativeProxy);
    private static native void nNotifyFramePending(long nativeProxy);

    private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd);
    private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd,
            @DumpFlags int dumpFlags);
}
Loading