Loading apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java 0 → 100644 +276 −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.perftests.utils.ManualBenchmarkState.STATS_REPORT_COEFFICIENT_VAR; import static android.perftests.utils.ManualBenchmarkState.STATS_REPORT_ITERATION; import static android.perftests.utils.ManualBenchmarkState.STATS_REPORT_MEAN; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static org.hamcrest.core.AnyOf.anyOf; import static org.hamcrest.core.Is.is; import android.app.Activity; import android.app.ActivityTaskManager; import android.app.IActivityTaskManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; 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.perftests.utils.StubActivity; import android.util.Pair; import android.view.IRecentsAnimationController; import android.view.IRecentsAnimationRunner; import android.view.RemoteAnimationTarget; import android.view.WindowManager; import androidx.test.filters.LargeTest; import androidx.test.rule.ActivityTestRule; import androidx.test.runner.lifecycle.ActivityLifecycleCallback; import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; import androidx.test.runner.lifecycle.Stage; import org.junit.After; import org.junit.AfterClass; import org.junit.Assume; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @RunWith(Parameterized.class) @LargeTest public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase { private static Intent sRecentsIntent; @Rule public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter(); @Rule public final ActivityTestRule<StubActivity> mActivityRule = new ActivityTestRule<>( StubActivity.class, false /* initialTouchMode */, false /* launchActivity */); private long mMeasuredTimeNs; private LifecycleListener mLifecycleListener; @Parameterized.Parameter(0) public int intervalBetweenOperations; @Parameterized.Parameters(name = "interval{0}ms") public static Collection<Object[]> getParameters() { return Arrays.asList(new Object[][] { { 0 }, { 100 }, { 300 }, }); } @BeforeClass public static void setUpClass() { // Get the permission to invoke startRecentsActivity. sUiAutomation.adoptShellPermissionIdentity(); final Context context = getInstrumentation().getContext(); final PackageManager pm = context.getPackageManager(); final ComponentName defaultHome = pm.getHomeActivities(new ArrayList<>()); try { final ComponentName recentsComponent = ComponentName.unflattenFromString(context.getResources().getString( com.android.internal.R.string.config_recentsComponentName)); final int enabledState = pm.getComponentEnabledSetting(recentsComponent); Assume.assumeThat(enabledState, anyOf( is(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT), is(PackageManager.COMPONENT_ENABLED_STATE_ENABLED))); final boolean homeIsRecents = recentsComponent.getPackageName().equals(defaultHome.getPackageName()); sRecentsIntent = new Intent().setComponent(homeIsRecents ? defaultHome : recentsComponent); } catch (Exception e) { Assume.assumeNoException(e); } } @AfterClass public static void tearDownClass() { sUiAutomation.dropShellPermissionIdentity(); } @Before @Override public void setUp() { super.setUp(); final Activity testActivity = mActivityRule.launchActivity(null /* intent */); try { mActivityRule.runOnUiThread(() -> testActivity.getWindow() .addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)); } catch (Throwable ignored) { } mLifecycleListener = new LifecycleListener(testActivity); ActivityLifecycleMonitorRegistry.getInstance().addLifecycleCallback(mLifecycleListener); } @After public void tearDown() { ActivityLifecycleMonitorRegistry.getInstance().removeLifecycleCallback(mLifecycleListener); } /** Simulate the timing of touch. */ private void makeInterval() { SystemClock.sleep(intervalBetweenOperations); } /** * <pre> * Steps: * (1) Start recents activity (only make it visible). * (2) Finish animation, take turns to execute (a), (b). * (a) Move recents activity to top. * ({@link com.android.server.wm.RecentsAnimationController#REORDER_MOVE_TO_TOP}) * Move test app to top by startActivityFromRecents. * (b) Cancel (it is similar to swipe a little distance and give up to enter recents). * ({@link com.android.server.wm.RecentsAnimationController#REORDER_MOVE_TO_ORIGINAL_POSITION}) * (3) Loop (1). * </pre> */ @Test @ManualBenchmarkTest( warmupDurationNs = TIME_1_S_IN_NS, targetTestDurationNs = TIME_5_S_IN_NS, statsReportFlags = STATS_REPORT_ITERATION | STATS_REPORT_MEAN | STATS_REPORT_COEFFICIENT_VAR) public void testRecentsAnimation() throws Throwable { final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState(); final IActivityTaskManager atm = ActivityTaskManager.getService(); final ArrayList<Pair<String, Boolean>> finishCases = new ArrayList<>(); // Real launch the recents activity. finishCases.add(new Pair<>("finishMoveToTop", true)); // Return to the original top. finishCases.add(new Pair<>("finishCancel", false)); // Ensure startRecentsActivity won't be called before finishing the animation. final Semaphore recentsSemaphore = new Semaphore(1); final int testActivityTaskId = mActivityRule.getActivity().getTaskId(); final IRecentsAnimationRunner.Stub anim = new IRecentsAnimationRunner.Stub() { int mIteration; @Override public void onAnimationStart(IRecentsAnimationController controller, RemoteAnimationTarget[] apps, Rect homeContentInsets, Rect minimizedHomeBounds) throws RemoteException { final Pair<String, Boolean> finishCase = finishCases.get(mIteration++ % 2); final boolean moveRecentsToTop = finishCase.second; makeInterval(); long startTime = SystemClock.elapsedRealtimeNanos(); controller.finish(moveRecentsToTop, false /* sendUserLeaveHint */); final long elapsedTimeNsOfFinish = SystemClock.elapsedRealtimeNanos() - startTime; mMeasuredTimeNs += elapsedTimeNsOfFinish; state.addExtraResult(finishCase.first, elapsedTimeNsOfFinish); if (moveRecentsToTop) { mLifecycleListener.waitForIdleSync(Stage.STOPPED); startTime = SystemClock.elapsedRealtimeNanos(); atm.startActivityFromRecents(testActivityTaskId, null /* options */); final long elapsedTimeNs = SystemClock.elapsedRealtimeNanos() - startTime; mMeasuredTimeNs += elapsedTimeNs; state.addExtraResult("startFromRecents", elapsedTimeNs); mLifecycleListener.waitForIdleSync(Stage.RESUMED); } makeInterval(); recentsSemaphore.release(); } @Override public void onAnimationCanceled(boolean deferredWithScreenshot) throws RemoteException { Assume.assumeNoException( new AssertionError("onAnimationCanceled should not be called")); } }; while (state.keepRunning(mMeasuredTimeNs)) { Assume.assumeTrue(recentsSemaphore.tryAcquire(TIME_5_S_IN_NS, TimeUnit.NANOSECONDS)); final long startTime = SystemClock.elapsedRealtimeNanos(); atm.startRecentsActivity(sRecentsIntent, null /* unused */, anim); final long elapsedTimeNsOfStart = SystemClock.elapsedRealtimeNanos() - startTime; mMeasuredTimeNs += elapsedTimeNsOfStart; state.addExtraResult("start", elapsedTimeNsOfStart); } // Ensure the last round of animation callback is done. recentsSemaphore.tryAcquire(TIME_5_S_IN_NS, TimeUnit.NANOSECONDS); recentsSemaphore.release(); } private static class LifecycleListener implements ActivityLifecycleCallback { private final Activity mTargetActivity; private Stage mWaitingStage; private Stage mReceivedStage; LifecycleListener(Activity activity) { mTargetActivity = activity; } void waitForIdleSync(Stage state) { synchronized (this) { if (state != mReceivedStage) { mWaitingStage = state; try { wait(TimeUnit.NANOSECONDS.toMillis(TIME_5_S_IN_NS)); } catch (InterruptedException impossible) { } } mWaitingStage = mReceivedStage = null; } getInstrumentation().waitForIdleSync(); } @Override public void onActivityLifecycleChanged(Activity activity, Stage stage) { if (mTargetActivity != activity) { return; } synchronized (this) { mReceivedStage = stage; if (mWaitingStage == mReceivedStage) { notifyAll(); } } } } } apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -60,7 +60,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase { } @Test @ManualBenchmarkTest(warmupDurationNs = WARMUP_DURATION, targetTestDurationNs = TEST_DURATION) @ManualBenchmarkTest(warmupDurationNs = TIME_1_S_IN_NS, targetTestDurationNs = TIME_5_S_IN_NS) public void testAddRemoveWindow() throws Throwable { new TestWindow().runBenchmark(mPerfStatusReporter.getBenchmarkState()); } Loading apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java +2 −2 Original line number Diff line number Diff line Loading @@ -25,8 +25,8 @@ 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; static final long TIME_1_S_IN_NS = 1 * NANOS_PER_S; static final long TIME_5_S_IN_NS = 5 * NANOS_PER_S; @Before public void setUp() { Loading apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java +67 −8 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.perftests.utils; import android.annotation.IntDef; import android.app.Activity; import android.app.Instrumentation; import android.os.Bundle; Loading Loading @@ -58,6 +59,28 @@ import java.util.concurrent.TimeUnit; public final class ManualBenchmarkState { private static final String TAG = ManualBenchmarkState.class.getSimpleName(); @IntDef(prefix = {"STATS_REPORT"}, value = { STATS_REPORT_MEDIAN, STATS_REPORT_MEAN, STATS_REPORT_MIN, STATS_REPORT_MAX, STATS_REPORT_PERCENTILE90, STATS_REPORT_PERCENTILE95, STATS_REPORT_STDDEV, STATS_REPORT_ITERATION, }) public @interface StatsReport {} public static final int STATS_REPORT_MEDIAN = 0x00000001; public static final int STATS_REPORT_MEAN = 0x00000002; public static final int STATS_REPORT_MIN = 0x00000004; public static final int STATS_REPORT_MAX = 0x00000008; public static final int STATS_REPORT_PERCENTILE90 = 0x00000010; public static final int STATS_REPORT_PERCENTILE95 = 0x00000020; public static final int STATS_REPORT_STDDEV = 0x00000040; public static final int STATS_REPORT_COEFFICIENT_VAR = 0x00000080; public static final int STATS_REPORT_ITERATION = 0x00000100; // TODO: Tune these values. // warm-up for duration private static final long WARMUP_DURATION_NS = TimeUnit.SECONDS.toNanos(5); Loading Loading @@ -93,6 +116,13 @@ public final class ManualBenchmarkState { // The computation needs double precision, but long int is fine for final reporting. private Stats mStats; private int mStatsReportFlags = STATS_REPORT_MEDIAN | STATS_REPORT_MEAN | STATS_REPORT_PERCENTILE90 | STATS_REPORT_PERCENTILE95 | STATS_REPORT_STDDEV; private boolean shouldReport(int statsReportFlag) { return (mStatsReportFlags & statsReportFlag) != 0; } void configure(ManualBenchmarkTest testAnnotation) { if (testAnnotation == null) { return; Loading @@ -106,6 +136,10 @@ public final class ManualBenchmarkState { if (targetTestDurationNs >= 0) { mTargetTestDurationNs = targetTestDurationNs; } final int statsReportFlags = testAnnotation.statsReportFlags(); if (statsReportFlags >= 0) { mStatsReportFlags = statsReportFlags; } } private void beginBenchmark(long warmupDuration, int iterations) { Loading Loading @@ -186,12 +220,35 @@ public final class ManualBenchmarkState { return sb.toString(); } private static void fillStatus(Bundle status, String key, Stats stats) { private void fillStatus(Bundle status, String key, Stats stats) { if (shouldReport(STATS_REPORT_ITERATION)) { status.putLong(key + "_iteration", stats.getSize()); } if (shouldReport(STATS_REPORT_MEDIAN)) { status.putLong(key + "_median", stats.getMedian()); status.putLong(key + "_mean", (long) stats.getMean()); } if (shouldReport(STATS_REPORT_MEAN)) { status.putLong(key + "_mean", Math.round(stats.getMean())); } if (shouldReport(STATS_REPORT_MIN)) { status.putLong(key + "_min", stats.getMin()); } if (shouldReport(STATS_REPORT_MAX)) { status.putLong(key + "_max", stats.getMax()); } if (shouldReport(STATS_REPORT_PERCENTILE90)) { status.putLong(key + "_percentile90", stats.getPercentile90()); } if (shouldReport(STATS_REPORT_PERCENTILE95)) { status.putLong(key + "_percentile95", stats.getPercentile95()); status.putLong(key + "_stddev", (long) stats.getStandardDeviation()); } if (shouldReport(STATS_REPORT_STDDEV)) { status.putLong(key + "_stddev", Math.round(stats.getStandardDeviation())); } if (shouldReport(STATS_REPORT_COEFFICIENT_VAR)) { status.putLong(key + "_cv", Math.round((100 * stats.getStandardDeviation() / stats.getMean()))); } } public void sendFullStatusReport(Instrumentation instrumentation, String key) { Loading @@ -204,8 +261,9 @@ public final class ManualBenchmarkState { 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)); final ArrayList<Long> results = mExtraResults.valueAt(i); final Stats stats = new Stats(results); Log.i(TAG, summaryLine(subKey, stats, results)); fillStatus(status, subKey, stats); } } Loading @@ -218,5 +276,6 @@ public final class ManualBenchmarkState { public @interface ManualBenchmarkTest { long warmupDurationNs() default -1; long targetTestDurationNs() default -1; @StatsReport int statsReportFlags() default -1; } } apct-tests/perftests/utils/src/android/perftests/utils/Stats.java +6 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import java.util.List; public class Stats { private long mMedian, mMin, mMax, mPercentile90, mPercentile95; private double mMean, mStandardDeviation; private final int mSize; /* Calculate stats in constructor. */ public Stats(List<Long> values) { Loading @@ -35,6 +36,7 @@ public class Stats { Collections.sort(values); mSize = size; mMin = values.get(0); mMax = values.get(values.size() - 1); Loading @@ -56,6 +58,10 @@ public class Stats { mStandardDeviation = Math.sqrt(mStandardDeviation / (double) (size - 1)); } public int getSize() { return mSize; } public double getMean() { return mMean; } Loading Loading
apct-tests/perftests/core/src/android/wm/RecentsAnimationPerfTest.java 0 → 100644 +276 −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.perftests.utils.ManualBenchmarkState.STATS_REPORT_COEFFICIENT_VAR; import static android.perftests.utils.ManualBenchmarkState.STATS_REPORT_ITERATION; import static android.perftests.utils.ManualBenchmarkState.STATS_REPORT_MEAN; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; import static org.hamcrest.core.AnyOf.anyOf; import static org.hamcrest.core.Is.is; import android.app.Activity; import android.app.ActivityTaskManager; import android.app.IActivityTaskManager; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; 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.perftests.utils.StubActivity; import android.util.Pair; import android.view.IRecentsAnimationController; import android.view.IRecentsAnimationRunner; import android.view.RemoteAnimationTarget; import android.view.WindowManager; import androidx.test.filters.LargeTest; import androidx.test.rule.ActivityTestRule; import androidx.test.runner.lifecycle.ActivityLifecycleCallback; import androidx.test.runner.lifecycle.ActivityLifecycleMonitorRegistry; import androidx.test.runner.lifecycle.Stage; import org.junit.After; import org.junit.AfterClass; import org.junit.Assume; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @RunWith(Parameterized.class) @LargeTest public class RecentsAnimationPerfTest extends WindowManagerPerfTestBase { private static Intent sRecentsIntent; @Rule public final PerfManualStatusReporter mPerfStatusReporter = new PerfManualStatusReporter(); @Rule public final ActivityTestRule<StubActivity> mActivityRule = new ActivityTestRule<>( StubActivity.class, false /* initialTouchMode */, false /* launchActivity */); private long mMeasuredTimeNs; private LifecycleListener mLifecycleListener; @Parameterized.Parameter(0) public int intervalBetweenOperations; @Parameterized.Parameters(name = "interval{0}ms") public static Collection<Object[]> getParameters() { return Arrays.asList(new Object[][] { { 0 }, { 100 }, { 300 }, }); } @BeforeClass public static void setUpClass() { // Get the permission to invoke startRecentsActivity. sUiAutomation.adoptShellPermissionIdentity(); final Context context = getInstrumentation().getContext(); final PackageManager pm = context.getPackageManager(); final ComponentName defaultHome = pm.getHomeActivities(new ArrayList<>()); try { final ComponentName recentsComponent = ComponentName.unflattenFromString(context.getResources().getString( com.android.internal.R.string.config_recentsComponentName)); final int enabledState = pm.getComponentEnabledSetting(recentsComponent); Assume.assumeThat(enabledState, anyOf( is(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT), is(PackageManager.COMPONENT_ENABLED_STATE_ENABLED))); final boolean homeIsRecents = recentsComponent.getPackageName().equals(defaultHome.getPackageName()); sRecentsIntent = new Intent().setComponent(homeIsRecents ? defaultHome : recentsComponent); } catch (Exception e) { Assume.assumeNoException(e); } } @AfterClass public static void tearDownClass() { sUiAutomation.dropShellPermissionIdentity(); } @Before @Override public void setUp() { super.setUp(); final Activity testActivity = mActivityRule.launchActivity(null /* intent */); try { mActivityRule.runOnUiThread(() -> testActivity.getWindow() .addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)); } catch (Throwable ignored) { } mLifecycleListener = new LifecycleListener(testActivity); ActivityLifecycleMonitorRegistry.getInstance().addLifecycleCallback(mLifecycleListener); } @After public void tearDown() { ActivityLifecycleMonitorRegistry.getInstance().removeLifecycleCallback(mLifecycleListener); } /** Simulate the timing of touch. */ private void makeInterval() { SystemClock.sleep(intervalBetweenOperations); } /** * <pre> * Steps: * (1) Start recents activity (only make it visible). * (2) Finish animation, take turns to execute (a), (b). * (a) Move recents activity to top. * ({@link com.android.server.wm.RecentsAnimationController#REORDER_MOVE_TO_TOP}) * Move test app to top by startActivityFromRecents. * (b) Cancel (it is similar to swipe a little distance and give up to enter recents). * ({@link com.android.server.wm.RecentsAnimationController#REORDER_MOVE_TO_ORIGINAL_POSITION}) * (3) Loop (1). * </pre> */ @Test @ManualBenchmarkTest( warmupDurationNs = TIME_1_S_IN_NS, targetTestDurationNs = TIME_5_S_IN_NS, statsReportFlags = STATS_REPORT_ITERATION | STATS_REPORT_MEAN | STATS_REPORT_COEFFICIENT_VAR) public void testRecentsAnimation() throws Throwable { final ManualBenchmarkState state = mPerfStatusReporter.getBenchmarkState(); final IActivityTaskManager atm = ActivityTaskManager.getService(); final ArrayList<Pair<String, Boolean>> finishCases = new ArrayList<>(); // Real launch the recents activity. finishCases.add(new Pair<>("finishMoveToTop", true)); // Return to the original top. finishCases.add(new Pair<>("finishCancel", false)); // Ensure startRecentsActivity won't be called before finishing the animation. final Semaphore recentsSemaphore = new Semaphore(1); final int testActivityTaskId = mActivityRule.getActivity().getTaskId(); final IRecentsAnimationRunner.Stub anim = new IRecentsAnimationRunner.Stub() { int mIteration; @Override public void onAnimationStart(IRecentsAnimationController controller, RemoteAnimationTarget[] apps, Rect homeContentInsets, Rect minimizedHomeBounds) throws RemoteException { final Pair<String, Boolean> finishCase = finishCases.get(mIteration++ % 2); final boolean moveRecentsToTop = finishCase.second; makeInterval(); long startTime = SystemClock.elapsedRealtimeNanos(); controller.finish(moveRecentsToTop, false /* sendUserLeaveHint */); final long elapsedTimeNsOfFinish = SystemClock.elapsedRealtimeNanos() - startTime; mMeasuredTimeNs += elapsedTimeNsOfFinish; state.addExtraResult(finishCase.first, elapsedTimeNsOfFinish); if (moveRecentsToTop) { mLifecycleListener.waitForIdleSync(Stage.STOPPED); startTime = SystemClock.elapsedRealtimeNanos(); atm.startActivityFromRecents(testActivityTaskId, null /* options */); final long elapsedTimeNs = SystemClock.elapsedRealtimeNanos() - startTime; mMeasuredTimeNs += elapsedTimeNs; state.addExtraResult("startFromRecents", elapsedTimeNs); mLifecycleListener.waitForIdleSync(Stage.RESUMED); } makeInterval(); recentsSemaphore.release(); } @Override public void onAnimationCanceled(boolean deferredWithScreenshot) throws RemoteException { Assume.assumeNoException( new AssertionError("onAnimationCanceled should not be called")); } }; while (state.keepRunning(mMeasuredTimeNs)) { Assume.assumeTrue(recentsSemaphore.tryAcquire(TIME_5_S_IN_NS, TimeUnit.NANOSECONDS)); final long startTime = SystemClock.elapsedRealtimeNanos(); atm.startRecentsActivity(sRecentsIntent, null /* unused */, anim); final long elapsedTimeNsOfStart = SystemClock.elapsedRealtimeNanos() - startTime; mMeasuredTimeNs += elapsedTimeNsOfStart; state.addExtraResult("start", elapsedTimeNsOfStart); } // Ensure the last round of animation callback is done. recentsSemaphore.tryAcquire(TIME_5_S_IN_NS, TimeUnit.NANOSECONDS); recentsSemaphore.release(); } private static class LifecycleListener implements ActivityLifecycleCallback { private final Activity mTargetActivity; private Stage mWaitingStage; private Stage mReceivedStage; LifecycleListener(Activity activity) { mTargetActivity = activity; } void waitForIdleSync(Stage state) { synchronized (this) { if (state != mReceivedStage) { mWaitingStage = state; try { wait(TimeUnit.NANOSECONDS.toMillis(TIME_5_S_IN_NS)); } catch (InterruptedException impossible) { } } mWaitingStage = mReceivedStage = null; } getInstrumentation().waitForIdleSync(); } @Override public void onActivityLifecycleChanged(Activity activity, Stage stage) { if (mTargetActivity != activity) { return; } synchronized (this) { mReceivedStage = stage; if (mWaitingStage == mReceivedStage) { notifyAll(); } } } } }
apct-tests/perftests/core/src/android/wm/WindowAddRemovePerfTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -60,7 +60,7 @@ public class WindowAddRemovePerfTest extends WindowManagerPerfTestBase { } @Test @ManualBenchmarkTest(warmupDurationNs = WARMUP_DURATION, targetTestDurationNs = TEST_DURATION) @ManualBenchmarkTest(warmupDurationNs = TIME_1_S_IN_NS, targetTestDurationNs = TIME_5_S_IN_NS) public void testAddRemoveWindow() throws Throwable { new TestWindow().runBenchmark(mPerfStatusReporter.getBenchmarkState()); } Loading
apct-tests/perftests/core/src/android/wm/WindowManagerPerfTestBase.java +2 −2 Original line number Diff line number Diff line Loading @@ -25,8 +25,8 @@ 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; static final long TIME_1_S_IN_NS = 1 * NANOS_PER_S; static final long TIME_5_S_IN_NS = 5 * NANOS_PER_S; @Before public void setUp() { Loading
apct-tests/perftests/utils/src/android/perftests/utils/ManualBenchmarkState.java +67 −8 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.perftests.utils; import android.annotation.IntDef; import android.app.Activity; import android.app.Instrumentation; import android.os.Bundle; Loading Loading @@ -58,6 +59,28 @@ import java.util.concurrent.TimeUnit; public final class ManualBenchmarkState { private static final String TAG = ManualBenchmarkState.class.getSimpleName(); @IntDef(prefix = {"STATS_REPORT"}, value = { STATS_REPORT_MEDIAN, STATS_REPORT_MEAN, STATS_REPORT_MIN, STATS_REPORT_MAX, STATS_REPORT_PERCENTILE90, STATS_REPORT_PERCENTILE95, STATS_REPORT_STDDEV, STATS_REPORT_ITERATION, }) public @interface StatsReport {} public static final int STATS_REPORT_MEDIAN = 0x00000001; public static final int STATS_REPORT_MEAN = 0x00000002; public static final int STATS_REPORT_MIN = 0x00000004; public static final int STATS_REPORT_MAX = 0x00000008; public static final int STATS_REPORT_PERCENTILE90 = 0x00000010; public static final int STATS_REPORT_PERCENTILE95 = 0x00000020; public static final int STATS_REPORT_STDDEV = 0x00000040; public static final int STATS_REPORT_COEFFICIENT_VAR = 0x00000080; public static final int STATS_REPORT_ITERATION = 0x00000100; // TODO: Tune these values. // warm-up for duration private static final long WARMUP_DURATION_NS = TimeUnit.SECONDS.toNanos(5); Loading Loading @@ -93,6 +116,13 @@ public final class ManualBenchmarkState { // The computation needs double precision, but long int is fine for final reporting. private Stats mStats; private int mStatsReportFlags = STATS_REPORT_MEDIAN | STATS_REPORT_MEAN | STATS_REPORT_PERCENTILE90 | STATS_REPORT_PERCENTILE95 | STATS_REPORT_STDDEV; private boolean shouldReport(int statsReportFlag) { return (mStatsReportFlags & statsReportFlag) != 0; } void configure(ManualBenchmarkTest testAnnotation) { if (testAnnotation == null) { return; Loading @@ -106,6 +136,10 @@ public final class ManualBenchmarkState { if (targetTestDurationNs >= 0) { mTargetTestDurationNs = targetTestDurationNs; } final int statsReportFlags = testAnnotation.statsReportFlags(); if (statsReportFlags >= 0) { mStatsReportFlags = statsReportFlags; } } private void beginBenchmark(long warmupDuration, int iterations) { Loading Loading @@ -186,12 +220,35 @@ public final class ManualBenchmarkState { return sb.toString(); } private static void fillStatus(Bundle status, String key, Stats stats) { private void fillStatus(Bundle status, String key, Stats stats) { if (shouldReport(STATS_REPORT_ITERATION)) { status.putLong(key + "_iteration", stats.getSize()); } if (shouldReport(STATS_REPORT_MEDIAN)) { status.putLong(key + "_median", stats.getMedian()); status.putLong(key + "_mean", (long) stats.getMean()); } if (shouldReport(STATS_REPORT_MEAN)) { status.putLong(key + "_mean", Math.round(stats.getMean())); } if (shouldReport(STATS_REPORT_MIN)) { status.putLong(key + "_min", stats.getMin()); } if (shouldReport(STATS_REPORT_MAX)) { status.putLong(key + "_max", stats.getMax()); } if (shouldReport(STATS_REPORT_PERCENTILE90)) { status.putLong(key + "_percentile90", stats.getPercentile90()); } if (shouldReport(STATS_REPORT_PERCENTILE95)) { status.putLong(key + "_percentile95", stats.getPercentile95()); status.putLong(key + "_stddev", (long) stats.getStandardDeviation()); } if (shouldReport(STATS_REPORT_STDDEV)) { status.putLong(key + "_stddev", Math.round(stats.getStandardDeviation())); } if (shouldReport(STATS_REPORT_COEFFICIENT_VAR)) { status.putLong(key + "_cv", Math.round((100 * stats.getStandardDeviation() / stats.getMean()))); } } public void sendFullStatusReport(Instrumentation instrumentation, String key) { Loading @@ -204,8 +261,9 @@ public final class ManualBenchmarkState { 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)); final ArrayList<Long> results = mExtraResults.valueAt(i); final Stats stats = new Stats(results); Log.i(TAG, summaryLine(subKey, stats, results)); fillStatus(status, subKey, stats); } } Loading @@ -218,5 +276,6 @@ public final class ManualBenchmarkState { public @interface ManualBenchmarkTest { long warmupDurationNs() default -1; long targetTestDurationNs() default -1; @StatsReport int statsReportFlags() default -1; } }
apct-tests/perftests/utils/src/android/perftests/utils/Stats.java +6 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ import java.util.List; public class Stats { private long mMedian, mMin, mMax, mPercentile90, mPercentile95; private double mMean, mStandardDeviation; private final int mSize; /* Calculate stats in constructor. */ public Stats(List<Long> values) { Loading @@ -35,6 +36,7 @@ public class Stats { Collections.sort(values); mSize = size; mMin = values.get(0); mMax = values.get(values.size() - 1); Loading @@ -56,6 +58,10 @@ public class Stats { mStandardDeviation = Math.sqrt(mStandardDeviation / (double) (size - 1)); } public int getSize() { return mSize; } public double getMean() { return mMean; } Loading