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

Commit 7d3306a0 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add performance test of add/remove window"

parents 56b61987 54a86c68
Loading
Loading
Loading
Loading
+3 −11
Original line number Diff line number Diff line
@@ -39,7 +39,6 @@ import android.widget.LinearLayout;
import androidx.test.filters.LargeTest;
import androidx.test.rule.ActivityTestRule;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -51,9 +50,7 @@ import java.util.function.IntSupplier;

@RunWith(Parameterized.class)
@LargeTest
public class RelayoutPerfTest {
    private static final IWindowSession sSession = WindowManagerGlobal.getWindowSession();

public class RelayoutPerfTest extends WindowManagerPerfTestBase {
    private int mIteration;

    @Rule
@@ -85,12 +82,6 @@ public class RelayoutPerfTest {
        });
    }

    @Before
    public void setUp() {
        getInstrumentation().getUiAutomation().executeShellCommand("input keyevent KEYCODE_WAKEUP");
        getInstrumentation().getUiAutomation().executeShellCommand("wm dismiss-keyguard");
    }

    @Test
    public void testRelayout() throws Throwable {
        final Activity activity = mActivityRule.getActivity();
@@ -154,8 +145,9 @@ public class RelayoutPerfTest {
        }

        void runBenchmark(BenchmarkState state) throws RemoteException {
            final IWindowSession session = WindowManagerGlobal.getWindowSession();
            while (state.keepRunning()) {
                sSession.relayout(mWindow, mSeq, mParams, mWidth, mHeight,
                session.relayout(mWindow, mSeq, mParams, mWidth, mHeight,
                        mViewVisibility.getAsInt(), mFlags, mFrameNumber, mOutFrame,
                        mOutOverscanInsets, mOutContentInsets, mOutVisibleInsets, mOutStableInsets,
                        mOutOutsets, mOutBackDropFrame, mOutDisplayCutout, mOutMergedConfiguration,
+108 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.wm;

import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;

import android.graphics.Rect;
import android.os.RemoteException;
import android.os.SystemClock;
import android.perftests.utils.ManualBenchmarkState;
import android.perftests.utils.ManualBenchmarkState.ManualBenchmarkTest;
import android.perftests.utils.PerfManualStatusReporter;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.IWindowSession;
import android.view.InputChannel;
import android.view.InsetsState;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;

import androidx.test.filters.LargeTest;

import com.android.internal.view.BaseIWindow;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;

@LargeTest
public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase {
    @Rule
    public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter();

    @BeforeClass
    public static void setUpClass() {
        // Get the permission to use most window types.
        sUiAutomation.adoptShellPermissionIdentity();
    }

    @AfterClass
    public static void tearDownClass() {
        sUiAutomation.dropShellPermissionIdentity();
    }

    @Test
    @ManualBenchmarkTest(warmupDurationNs = WARMUP_DURATION, targetTestDurationNs = TEST_DURATION)
    public void testAddRemoveWindow() throws Throwable {
        new TestWindow().runBenchmark(mPerfStatusReporter.getBenchmarkState());
    }

    private static class TestWindow extends BaseIWindow {
        final WindowManager.LayoutParams mLayoutParams = new WindowManager.LayoutParams();
        final Rect mOutFrame = new Rect();
        final Rect mOutContentInsets = new Rect();
        final Rect mOutStableInsets = new Rect();
        final Rect mOutOutsets = new Rect();
        final DisplayCutout.ParcelableWrapper mOutDisplayCutout =
                new DisplayCutout.ParcelableWrapper();
        final InsetsState mOutInsetsState = new InsetsState();

        TestWindow() {
            mLayoutParams.setTitle(TestWindow.class.getName());
            mLayoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
            // Simulate as common phone window.
            mLayoutParams.flags = FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR;
        }

        void runBenchmark(ManualBenchmarkState state) throws RemoteException {
            final IWindowSession session = WindowManagerGlobal.getWindowSession();
            long elapsedTimeNs = 0;
            while (state.keepRunning(elapsedTimeNs)) {
                // InputChannel cannot be reused.
                final InputChannel inputChannel = new InputChannel();

                long startTime = SystemClock.elapsedRealtimeNanos();
                session.addToDisplay(this, mSeq, mLayoutParams, View.VISIBLE,
                        Display.DEFAULT_DISPLAY, mOutFrame, mOutContentInsets, mOutStableInsets,
                        mOutOutsets, mOutDisplayCutout, inputChannel, mOutInsetsState);
                final long elapsedTimeNsOfAdd = SystemClock.elapsedRealtimeNanos() - startTime;
                state.addExtraResult("add", elapsedTimeNsOfAdd);

                startTime = SystemClock.elapsedRealtimeNanos();
                session.remove(this);
                final long elapsedTimeNsOfRemove = SystemClock.elapsedRealtimeNanos() - startTime;
                state.addExtraResult("remove", elapsedTimeNsOfRemove);

                elapsedTimeNs = elapsedTimeNsOfAdd + elapsedTimeNsOfRemove;
            }
        }
    }
}
+37 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.wm;

import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;

import android.app.UiAutomation;

import org.junit.Before;

public class WindowManagerPerfTestBase {
    static final UiAutomation sUiAutomation = getInstrumentation().getUiAutomation();
    static final long NANOS_PER_S = 1000L * 1000 * 1000;
    static final long WARMUP_DURATION = 1 * NANOS_PER_S;
    static final long TEST_DURATION = 5 * NANOS_PER_S;

    @Before
    public void setUp() {
        // In order to be closer to the real use case.
        sUiAutomation.executeShellCommand("input keyevent KEYCODE_WAKEUP");
        sUiAutomation.executeShellCommand("wm dismiss-keyguard");
    }
}
+82 −19
Original line number Diff line number Diff line
@@ -19,8 +19,13 @@ package android.perftests.utils;
import android.app.Activity;
import android.app.Instrumentation;
import android.os.Bundle;
import android.util.ArrayMap;
import android.util.Log;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;

@@ -71,6 +76,8 @@ public final class ManualBenchmarkState {

    private int mState = NOT_STARTED;  // Current benchmark state.

    private long mWarmupDurationNs = WARMUP_DURATION_NS;
    private long mTargetTestDurationNs = TARGET_TEST_DURATION_NS;
    private long mWarmupStartTime = 0;
    private int mWarmupIterations = 0;

@@ -79,12 +86,30 @@ public final class ManualBenchmarkState {
    // Individual duration in nano seconds.
    private ArrayList<Long> mResults = new ArrayList<>();

    /** @see #addExtraResult(String, long) */
    private ArrayMap<String, ArrayList<Long>> mExtraResults;

    // Statistics. These values will be filled when the benchmark has finished.
    // The computation needs double precision, but long int is fine for final reporting.
    private Stats mStats;

    void configure(ManualBenchmarkTest testAnnotation) {
        if (testAnnotation == null) {
            return;
        }

        final long warmupDurationNs = testAnnotation.warmupDurationNs();
        if (warmupDurationNs >= 0) {
            mWarmupDurationNs = warmupDurationNs;
        }
        final long targetTestDurationNs = testAnnotation.targetTestDurationNs();
        if (targetTestDurationNs >= 0) {
            mTargetTestDurationNs = targetTestDurationNs;
        }
    }

    private void beginBenchmark(long warmupDuration, int iterations) {
        mMaxIterations = (int) (TARGET_TEST_DURATION_NS / (warmupDuration / iterations));
        mMaxIterations = (int) (mTargetTestDurationNs / (warmupDuration / iterations));
        mMaxIterations = Math.min(MAX_TEST_ITERATIONS,
                Math.max(mMaxIterations, MIN_TEST_ITERATIONS));
        mState = RUNNING;
@@ -108,7 +133,7 @@ public final class ManualBenchmarkState {
                final long timeSinceStartingWarmup = System.nanoTime() - mWarmupStartTime;
                ++mWarmupIterations;
                if (mWarmupIterations >= WARMUP_MIN_ITERATIONS
                        && timeSinceStartingWarmup >= WARMUP_DURATION_NS) {
                        && timeSinceStartingWarmup >= mWarmupDurationNs) {
                    beginBenchmark(timeSinceStartingWarmup, mWarmupIterations);
                }
                return true;
@@ -129,31 +154,69 @@ public final class ManualBenchmarkState {
        }
    }

    private String summaryLine() {
        final StringBuilder sb = new StringBuilder();
    /**
     * Adds additional result while this benchmark is running. It is used when a sequence of
     * operations is executed consecutively, the duration of each operation can also be recorded.
     */
    public void addExtraResult(String key, long duration) {
        if (mState != RUNNING) {
            return;
        }
        if (mExtraResults == null) {
            mExtraResults = new ArrayMap<>();
        }
        mExtraResults.computeIfAbsent(key, k -> new ArrayList<>()).add(duration);
    }

    private static String summaryLine(String key, Stats stats, ArrayList<Long> results) {
        final StringBuilder sb = new StringBuilder(key);
        sb.append(" Summary: ");
        sb.append("median=").append(mStats.getMedian()).append("ns, ");
        sb.append("mean=").append(mStats.getMean()).append("ns, ");
        sb.append("min=").append(mStats.getMin()).append("ns, ");
        sb.append("max=").append(mStats.getMax()).append("ns, ");
        sb.append("sigma=").append(mStats.getStandardDeviation()).append(", ");
        sb.append("iteration=").append(mResults.size()).append(", ");
        sb.append("values=").append(mResults.toString());
        sb.append("median=").append(stats.getMedian()).append("ns, ");
        sb.append("mean=").append(stats.getMean()).append("ns, ");
        sb.append("min=").append(stats.getMin()).append("ns, ");
        sb.append("max=").append(stats.getMax()).append("ns, ");
        sb.append("sigma=").append(stats.getStandardDeviation()).append(", ");
        sb.append("iteration=").append(results.size()).append(", ");
        sb.append("values=");
        if (results.size() > 100) {
            sb.append(results.subList(0, 100)).append(" ...");
        } else {
            sb.append(results);
        }
        return sb.toString();
    }

    private static void fillStatus(Bundle status, String key, Stats stats) {
        status.putLong(key + "_median", stats.getMedian());
        status.putLong(key + "_mean", (long) stats.getMean());
        status.putLong(key + "_percentile90", stats.getPercentile90());
        status.putLong(key + "_percentile95", stats.getPercentile95());
        status.putLong(key + "_stddev", (long) stats.getStandardDeviation());
    }

    public void sendFullStatusReport(Instrumentation instrumentation, String key) {
        if (mState != FINISHED) {
            throw new IllegalStateException("The benchmark hasn't finished");
        }
        Log.i(TAG, key + summaryLine());
        Log.i(TAG, summaryLine(key, mStats, mResults));
        final Bundle status = new Bundle();
        status.putLong(key + "_median", mStats.getMedian());
        status.putLong(key + "_mean", (long) mStats.getMean());
        status.putLong(key + "_percentile90", mStats.getPercentile90());
        status.putLong(key + "_percentile95", mStats.getPercentile95());
        status.putLong(key + "_stddev", (long) mStats.getStandardDeviation());
        instrumentation.sendStatus(Activity.RESULT_OK, status);
        fillStatus(status, key, mStats);
        if (mExtraResults != null) {
            for (int i = 0; i < mExtraResults.size(); i++) {
                final String subKey = key + "_" + mExtraResults.keyAt(i);
                final Stats stats = new Stats(mExtraResults.valueAt(i));
                Log.i(TAG, summaryLine(subKey, mStats, mResults));
                fillStatus(status, subKey, stats);
            }
        }
        instrumentation.sendStatus(Activity.RESULT_OK, status);
    }

    /** The annotation to customize the test, e.g. the duration of warm-up and target test. */
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ManualBenchmarkTest {
        long warmupDurationNs() default -1;
        long targetTestDurationNs() default -1;
    }
}
+4 −4
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@

package android.perftests.utils;

import androidx.test.InstrumentationRegistry;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;

import org.junit.rules.TestRule;
import org.junit.runner.Description;
@@ -59,15 +59,15 @@ public class PerfManualStatusReporter implements TestRule {

    @Override
    public Statement apply(Statement base, Description description) {
        mState.configure(description.getAnnotation(ManualBenchmarkState.ManualBenchmarkTest.class));

        return new Statement() {
            @Override
            public void evaluate() throws Throwable {
                base.evaluate();

                mState.sendFullStatusReport(InstrumentationRegistry.getInstrumentation(),
                        description.getMethodName());
                mState.sendFullStatusReport(getInstrumentation(), description.getMethodName());
            }
        };
    }
}