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

Commit 9410c197 authored by Pascal Muetschard's avatar Pascal Muetschard
Browse files

Include the display refresh rate in the jank data.

Bug: b/261839034
Test: manual, atest com.android.internal.jank
Change-Id: I411ee2bf205a3cb71e17ca0597a2ee87e7747ba7
parent 73b6d7ab
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -436,13 +436,16 @@ public final class SurfaceControl implements Parcelable {
        // Jank due to unknown reasons.
        public static final int UNKNOWN = 0x80;

        public JankData(long frameVsyncId, @JankType int jankType) {
        public JankData(long frameVsyncId, @JankType int jankType, long frameIntervalNs) {
            this.frameVsyncId = frameVsyncId;
            this.jankType = jankType;
            this.frameIntervalNs = frameIntervalNs;

        }

        public final long frameVsyncId;
        public final @JankType int jankType;
        public final long frameIntervalNs;
    }

    /**
+86 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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 com.android.internal.jank;

import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_REFRESH_RATE__UNKNOWN_REFRESH_RATE;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_REFRESH_RATE__VARIABLE_REFRESH_RATE;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_REFRESH_RATE__RR_30_HZ;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_REFRESH_RATE__RR_60_HZ;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_REFRESH_RATE__RR_90_HZ;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_REFRESH_RATE__RR_120_HZ;
import static com.android.internal.util.FrameworkStatsLog.UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_REFRESH_RATE__RR_240_HZ;

import android.annotation.IntDef;

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

/**
 * Display refresh rate related functionality.
 * @hide
 */
public class DisplayRefreshRate {
    public static final int UNKNOWN_REFRESH_RATE =
            UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_REFRESH_RATE__UNKNOWN_REFRESH_RATE;
    public static final int VARIABLE_REFRESH_RATE =
            UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_REFRESH_RATE__VARIABLE_REFRESH_RATE;
    public static final int REFRESH_RATE_30_HZ =
            UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_REFRESH_RATE__RR_30_HZ;
    public static final int REFRESH_RATE_60_HZ =
            UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_REFRESH_RATE__RR_60_HZ;
    public static final int REFRESH_RATE_90_HZ =
            UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_REFRESH_RATE__RR_90_HZ;
    public static final int REFRESH_RATE_120_HZ =
            UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_REFRESH_RATE__RR_120_HZ;
    public static final int REFRESH_RATE_240_HZ =
            UIINTERACTION_FRAME_INFO_REPORTED__DISPLAY_REFRESH_RATE__RR_240_HZ;

    /** @hide */
    @IntDef({
        UNKNOWN_REFRESH_RATE,
        VARIABLE_REFRESH_RATE,
        REFRESH_RATE_30_HZ,
        REFRESH_RATE_60_HZ,
        REFRESH_RATE_90_HZ,
        REFRESH_RATE_120_HZ,
        REFRESH_RATE_240_HZ,
    })
    @Retention(RetentionPolicy.SOURCE)
    public @interface RefreshRate {
    }

    private DisplayRefreshRate() {
    }

    /**
     * Computes the display refresh rate based off the frame interval.
     */
    @RefreshRate
    public static int getRefreshRate(long frameIntervalNs) {
        long rate = Math.round(1e9 / frameIntervalNs);
        if (rate < 50) {
            return REFRESH_RATE_30_HZ;
        } else if (rate < 80) {
            return REFRESH_RATE_60_HZ;
        } else if (rate < 110) {
            return REFRESH_RATE_90_HZ;
        } else if (rate < 180) {
            return REFRESH_RATE_120_HZ;
        } else {
            return REFRESH_RATE_240_HZ;
        }
    }
}
+23 −8
Original line number Diff line number Diff line
@@ -24,6 +24,8 @@ import static android.view.SurfaceControl.JankData.JANK_SURFACEFLINGER_GPU_DEADL
import static android.view.SurfaceControl.JankData.PREDICTION_ERROR;
import static android.view.SurfaceControl.JankData.SURFACE_FLINGER_SCHEDULING;

import static com.android.internal.jank.DisplayRefreshRate.UNKNOWN_REFRESH_RATE;
import static com.android.internal.jank.DisplayRefreshRate.VARIABLE_REFRESH_RATE;
import static com.android.internal.jank.InteractionJankMonitor.ACTION_SESSION_CANCEL;
import static com.android.internal.jank.InteractionJankMonitor.ACTION_SESSION_END;
import static com.android.internal.jank.InteractionJankMonitor.EXECUTOR_TASK_TIMEOUT;
@@ -49,6 +51,7 @@ import android.view.ViewRootImpl;
import android.view.WindowCallbacks;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.jank.DisplayRefreshRate.RefreshRate;
import com.android.internal.jank.InteractionJankMonitor.Configuration;
import com.android.internal.jank.InteractionJankMonitor.Session;
import com.android.internal.util.FrameworkStatsLog;
@@ -132,26 +135,30 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
        boolean hwuiCallbackFired;
        boolean surfaceControlCallbackFired;
        @JankType int jankType;
        @RefreshRate int refreshRate;

        static JankInfo createFromHwuiCallback(long frameVsyncId, long totalDurationNanos,
                boolean isFirstFrame) {
            return new JankInfo(frameVsyncId, true, false, JANK_NONE, totalDurationNanos,
                    isFirstFrame);
            return new JankInfo(frameVsyncId, true, false, JANK_NONE, UNKNOWN_REFRESH_RATE,
                    totalDurationNanos, isFirstFrame);
        }

        static JankInfo createFromSurfaceControlCallback(long frameVsyncId,
                @JankType int jankType) {
            return new JankInfo(frameVsyncId, false, true, jankType, 0, false /* isFirstFrame */);
                @JankType int jankType, @RefreshRate int refreshRate) {
            return new JankInfo(
                    frameVsyncId, false, true, jankType, refreshRate, 0, false /* isFirstFrame */);
        }

        private JankInfo(long frameVsyncId, boolean hwuiCallbackFired,
                boolean surfaceControlCallbackFired, @JankType int jankType,
                @RefreshRate int refreshRate,
                long totalDurationNanos, boolean isFirstFrame) {
            this.frameVsyncId = frameVsyncId;
            this.hwuiCallbackFired = hwuiCallbackFired;
            this.surfaceControlCallbackFired = surfaceControlCallbackFired;
            this.totalDurationNanos = totalDurationNanos;
            this.jankType = jankType;
            this.refreshRate = refreshRate;
            this.totalDurationNanos = totalDurationNanos;
            this.isFirstFrame = isFirstFrame;
        }

@@ -468,14 +475,16 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
                if (!isInRange(jankStat.frameVsyncId)) {
                    continue;
                }
                int refreshRate = DisplayRefreshRate.getRefreshRate(jankStat.frameIntervalNs);
                JankInfo info = findJankInfo(jankStat.frameVsyncId);
                if (info != null) {
                    info.surfaceControlCallbackFired = true;
                    info.jankType = jankStat.jankType;
                    info.refreshRate = refreshRate;
                } else {
                    mJankInfos.put((int) jankStat.frameVsyncId,
                            JankInfo.createFromSurfaceControlCallback(
                                    jankStat.frameVsyncId, jankStat.jankType));
                                    jankStat.frameVsyncId, jankStat.jankType, refreshRate));
                }
            }
            processJankInfos();
@@ -592,6 +601,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
        int missedSfFramesCount = 0;
        int maxSuccessiveMissedFramesCount = 0;
        int successiveMissedFramesCount = 0;
        @RefreshRate int refreshRate = UNKNOWN_REFRESH_RATE;

        for (int i = 0; i < mJankInfos.size(); i++) {
            JankInfo info = mJankInfos.valueAt(i);
@@ -627,6 +637,10 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
                            maxSuccessiveMissedFramesCount, successiveMissedFramesCount);
                    successiveMissedFramesCount = 0;
                }
                if (info.refreshRate != UNKNOWN_REFRESH_RATE && info.refreshRate != refreshRate) {
                    refreshRate = (refreshRate == UNKNOWN_REFRESH_RATE)
                            ? info.refreshRate : VARIABLE_REFRESH_RATE;
                }
                // TODO (b/174755489): Early latch currently gets fired way too often, so we have
                // to ignore it for now.
                if (!mSurfaceOnly && !info.hwuiCallbackFired) {
@@ -669,6 +683,7 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
            mStatsLog.write(
                    FrameworkStatsLog.UI_INTERACTION_FRAME_INFO_REPORTED,
                    mDisplayId,
                    refreshRate,
                    mSession.getStatsdInteractionType(),
                    totalFramesCount,
                    missedFramesCount,
@@ -866,10 +881,10 @@ public class FrameTracker extends SurfaceControl.OnJankDataListener
        }

        /** {@see FrameworkStatsLog#write) */
        public void write(int code, int displayId,
        public void write(int code, int displayId, @RefreshRate int refreshRate,
                int arg1, long arg2, long arg3, long arg4, long arg5, long arg6, long arg7) {
            FrameworkStatsLog.write(code, arg1, arg2, arg3, arg4, arg5, arg6, arg7,
                    mDisplayResolutionTracker.getResolution(displayId));
                    mDisplayResolutionTracker.getResolution(displayId), refreshRate);
        }
    }

+4 −4
Original line number Diff line number Diff line
@@ -1951,8 +1951,9 @@ public:
        jobjectArray jJankDataArray = env->NewObjectArray(jankData.size(),
                gJankDataClassInfo.clazz, nullptr);
        for (size_t i = 0; i < jankData.size(); i++) {
            jobject jJankData = env->NewObject(gJankDataClassInfo.clazz,
                    gJankDataClassInfo.ctor, jankData[i].frameVsyncId, jankData[i].jankType);
            jobject jJankData = env->NewObject(gJankDataClassInfo.clazz, gJankDataClassInfo.ctor,
                                               jankData[i].frameVsyncId, jankData[i].jankType,
                                               jankData[i].frameIntervalNs);
            env->SetObjectArrayElement(jJankDataArray, i, jJankData);
            env->DeleteLocalRef(jJankData);
        }
@@ -2523,8 +2524,7 @@ int register_android_view_SurfaceControl(JNIEnv* env)
    jclass jankDataClazz =
                FindClassOrDie(env, "android/view/SurfaceControl$JankData");
    gJankDataClassInfo.clazz = MakeGlobalRefOrDie(env, jankDataClazz);
    gJankDataClassInfo.ctor =
            GetMethodIDOrDie(env, gJankDataClassInfo.clazz, "<init>", "(JI)V");
    gJankDataClassInfo.ctor = GetMethodIDOrDie(env, gJankDataClassInfo.clazz, "<init>", "(JIJ)V");
    jclass onJankDataListenerClazz =
            FindClassOrDie(env, "android/view/SurfaceControl$OnJankDataListener");
    gJankDataListenerClassInfo.clazz = MakeGlobalRefOrDie(env, onJankDataListenerClazz);
+42 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 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 com.android.internal.jank;

import static com.android.internal.jank.DisplayRefreshRate.REFRESH_RATE_120_HZ;
import static com.android.internal.jank.DisplayRefreshRate.REFRESH_RATE_240_HZ;
import static com.android.internal.jank.DisplayRefreshRate.REFRESH_RATE_30_HZ;
import static com.android.internal.jank.DisplayRefreshRate.REFRESH_RATE_60_HZ;
import static com.android.internal.jank.DisplayRefreshRate.REFRESH_RATE_90_HZ;
import static com.android.internal.jank.DisplayRefreshRate.getRefreshRate;

import static com.google.common.truth.Truth.assertThat;

import androidx.test.filters.SmallTest;

import org.junit.Test;

@SmallTest
public class DisplayRefreshRateTest {
    @Test
    public void testRefreshRateMapping() {
        assertThat(getRefreshRate((long) 1e9 / 30)).isEqualTo(REFRESH_RATE_30_HZ);
        assertThat(getRefreshRate((long) 1e9 / 60)).isEqualTo(REFRESH_RATE_60_HZ);
        assertThat(getRefreshRate((long) 1e9 / 90)).isEqualTo(REFRESH_RATE_90_HZ);
        assertThat(getRefreshRate((long) 1e9 / 120)).isEqualTo(REFRESH_RATE_120_HZ);
        assertThat(getRefreshRate((long) 1e9 / 240)).isEqualTo(REFRESH_RATE_240_HZ);
    }
}
Loading