Wait for CPU idle between multiuser perf test iterations.
Bug: 342399089
Bug: 340812874
Test: atest UserLifecycleTests
Flag: None
Change-Id: I91579d8af35b4a7df76d6bc1bcfad328c107d7c2
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java
index 515ddc8..a4128a3 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkRunner.java
@@ -19,13 +19,16 @@
import android.os.Bundle;
import android.os.SystemClock;
import android.perftests.utils.ShellHelper;
+import android.util.Log;
import java.util.ArrayList;
+import java.util.concurrent.TimeoutException;
// Based on //platform/frameworks/base/apct-tests/perftests/utils/BenchmarkState.java
public class BenchmarkRunner {
-
- private static final long COOL_OFF_PERIOD_MS = 1000;
+ private static final String TAG = BenchmarkRunner.class.getSimpleName();
+ private static final int TIMEOUT_IN_SECONDS = 45;
+ private static final int CPU_IDLE_THRESHOLD_PERCENTAGE = 90;
private static final int NUM_ITERATIONS = 4;
@@ -79,8 +82,7 @@
}
private void prepareForNextRun() {
- SystemClock.sleep(COOL_OFF_PERIOD_MS);
- ShellHelper.runShellCommand("am wait-for-broadcast-idle --flush-broadcast-loopers");
+ waitCoolDownPeriod();
mStartTimeNs = System.nanoTime();
mPausedDurationNs = 0;
}
@@ -102,7 +104,7 @@
* to avoid unnecessary waiting.
*/
public void resumeTiming() {
- ShellHelper.runShellCommand("am wait-for-broadcast-idle --flush-broadcast-loopers");
+ waitCoolDownPeriod();
resumeTimer();
}
@@ -162,4 +164,58 @@
}
return null;
}
+
+ /** Waits for the CPU cores and the broadcast queue to be idle. */
+ public void waitCoolDownPeriod() {
+ waitForCpuIdle();
+ waitForBroadcastIdle();
+ }
+
+ private void waitForBroadcastIdle() {
+ try {
+ ShellHelper.runShellCommandWithTimeout(
+ "am wait-for-broadcast-idle --flush-broadcast-loopers", TIMEOUT_IN_SECONDS);
+ } catch (TimeoutException e) {
+ Log.e(TAG, "Ending waitForBroadcastIdle because it didn't finish in "
+ + TIMEOUT_IN_SECONDS + " seconds", e);
+ }
+ }
+
+ private void waitForCpuIdle() {
+ int count = 0;
+ int idleCpuPercentage;
+ while (count++ < TIMEOUT_IN_SECONDS) {
+ idleCpuPercentage = getIdleCpuPercentage();
+ Log.d(TAG, "Waiting for CPU idle #" + count + "=" + idleCpuPercentage + "%");
+ if (idleCpuPercentage > CPU_IDLE_THRESHOLD_PERCENTAGE) {
+ return;
+ }
+ SystemClock.sleep(1000);
+ }
+ Log.e(TAG, "Ending waitForCpuIdle because it didn't finish in "
+ + TIMEOUT_IN_SECONDS + " seconds");
+ }
+
+ private int getIdleCpuPercentage() {
+ String output = ShellHelper.runShellCommand("top -m 1 -n 1");
+
+ String[] tokens = output.split("\\s+");
+
+ float totalCpu = -1;
+ float idleCpu = -1;
+ for (String token : tokens) {
+ if (token.contains("%cpu")) {
+ totalCpu = Float.parseFloat(token.split("%")[0]);
+ } else if (token.contains("%idle")) {
+ idleCpu = Float.parseFloat(token.split("%")[0]);
+ }
+ }
+
+ if (totalCpu < 0 || idleCpu < 0) {
+ Log.e(TAG, "Could not get idle cpu percentage, output=" + output);
+ return -1;
+ }
+
+ return (int) (100 * idleCpu / totalCpu);
+ }
}
\ No newline at end of file
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
index 762e2af..98ab0c2 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/UserLifecycleTests.java
@@ -188,21 +188,6 @@
}
}
- /** Tests creating a new user, with wait times between iterations. */
- @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
- public void createUser_realistic() throws RemoteException {
- while (mRunner.keepRunning()) {
- Log.i(TAG, "Starting timer");
- final int userId = createUserNoFlags();
-
- mRunner.pauseTiming();
- Log.i(TAG, "Stopping timer");
- removeUser(userId);
- waitCoolDownPeriod();
- mRunner.resumeTimingForNextIteration();
- }
- }
-
/** Tests creating and starting a new user. */
@Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void createAndStartUser() throws RemoteException {
@@ -239,7 +224,6 @@
mRunner.pauseTiming();
Log.d(TAG, "Stopping timer");
removeUser(userId);
- waitCoolDownPeriod();
mRunner.resumeTimingForNextIteration();
}
}
@@ -254,7 +238,6 @@
mRunner.pauseTiming();
final int userId = createUserNoFlags();
- waitForBroadcastIdle();
runThenWaitForBroadcasts(userId, () -> {
mRunner.resumeTiming();
Log.i(TAG, "Starting timer");
@@ -309,9 +292,6 @@
preStartUser(userId, numberOfIterationsToSkip);
- waitForBroadcastIdle();
- waitCoolDownPeriod();
-
runThenWaitForBroadcasts(userId, () -> {
mRunner.resumeTiming();
Log.i(TAG, "Starting timer");
@@ -353,9 +333,6 @@
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
- waitForBroadcastIdle();
- waitCoolDownPeriod();
-
runThenWaitForBroadcasts(userId, () -> {
mRunner.resumeTiming();
Log.i(TAG, "Starting timer");
@@ -420,7 +397,6 @@
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
- waitCoolDownPeriod();
mRunner.resumeTiming();
Log.i(TAG, "Starting timer");
@@ -454,7 +430,6 @@
mRunner.pauseTiming();
Log.d(TAG, "Stopping timer");
removeUser(userId);
- waitCoolDownPeriod();
mRunner.resumeTimingForNextIteration();
}
}
@@ -466,6 +441,7 @@
mRunner.pauseTiming();
final int startUser = mAm.getCurrentUser();
final int userId = createUserNoFlags();
+
mRunner.resumeTiming();
Log.i(TAG, "Starting timer");
@@ -479,27 +455,6 @@
}
}
- /** Tests switching to an uninitialized user with wait times between iterations. */
- @Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
- public void switchUser_realistic() throws Exception {
- while (mRunner.keepRunning()) {
- mRunner.pauseTiming();
- final int startUser = ActivityManager.getCurrentUser();
- final int userId = createUserNoFlags();
- waitCoolDownPeriod();
- Log.d(TAG, "Starting timer");
- mRunner.resumeTiming();
-
- switchUser(userId);
-
- mRunner.pauseTiming();
- Log.d(TAG, "Stopping timer");
- switchUserNoCheck(startUser);
- removeUser(userId);
- mRunner.resumeTimingForNextIteration();
- }
- }
-
/** Tests switching to a previously-started, but no-longer-running, user. */
@Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void switchUser_stopped() throws RemoteException {
@@ -507,6 +462,7 @@
mRunner.pauseTiming();
final int startUser = mAm.getCurrentUser();
final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ true);
+
mRunner.resumeTiming();
Log.i(TAG, "Starting timer");
@@ -536,7 +492,6 @@
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
- waitCoolDownPeriod();
Log.d(TAG, "Starting timer");
mRunner.resumeTiming();
@@ -562,7 +517,6 @@
/* useStaticWallpaper */true);
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
- waitCoolDownPeriod();
Log.d(TAG, "Starting timer");
mRunner.resumeTiming();
@@ -606,7 +560,6 @@
final int testUser = initializeNewUserAndSwitchBack(/* stopNewUser */ false);
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
- waitCoolDownPeriod();
Log.d(TAG, "Starting timer");
mRunner.resumeTiming();
@@ -614,7 +567,6 @@
mRunner.pauseTiming();
Log.d(TAG, "Stopping timer");
- waitForBroadcastIdle();
switchUserNoCheck(startUser);
mRunner.resumeTimingForNextIteration();
}
@@ -631,7 +583,6 @@
/* useStaticWallpaper */ true);
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
- waitCoolDownPeriod();
Log.d(TAG, "Starting timer");
mRunner.resumeTiming();
@@ -639,7 +590,6 @@
mRunner.pauseTiming();
Log.d(TAG, "Stopping timer");
- waitForBroadcastIdle();
switchUserNoCheck(startUser);
mRunner.resumeTimingForNextIteration();
}
@@ -675,13 +625,11 @@
@Test(timeout = TIMEOUT_MAX_TEST_TIME_MS)
public void stopUser_realistic() throws RemoteException {
final int userId = createUserNoFlags();
- waitCoolDownPeriod();
while (mRunner.keepRunning()) {
mRunner.pauseTiming();
runThenWaitForBroadcasts(userId, ()-> {
mIam.startUserInBackground(userId);
}, Intent.ACTION_USER_STARTED, Intent.ACTION_MEDIA_MOUNTED);
- waitCoolDownPeriod();
Log.d(TAG, "Starting timer");
mRunner.resumeTiming();
@@ -703,7 +651,7 @@
final int startUser = mAm.getCurrentUser();
final int userId = createUserNoFlags();
- waitForBroadcastIdle();
+ mRunner.waitCoolDownPeriod();
mUserSwitchWaiter.runThenWaitUntilBootCompleted(userId, () -> {
mRunner.resumeTiming();
Log.i(TAG, "Starting timer");
@@ -726,7 +674,7 @@
final int startUser = ActivityManager.getCurrentUser();
final int userId = createUserNoFlags();
- waitCoolDownPeriod();
+ mRunner.waitCoolDownPeriod();
mUserSwitchWaiter.runThenWaitUntilBootCompleted(userId, () -> {
mRunner.resumeTiming();
Log.d(TAG, "Starting timer");
@@ -752,7 +700,7 @@
switchUser(userId);
}, Intent.ACTION_MEDIA_MOUNTED);
- waitForBroadcastIdle();
+ mRunner.waitCoolDownPeriod();
mUserSwitchWaiter.runThenWaitUntilSwitchCompleted(startUser, () -> {
runThenWaitForBroadcasts(userId, () -> {
mRunner.resumeTiming();
@@ -781,7 +729,7 @@
switchUser(userId);
}, Intent.ACTION_MEDIA_MOUNTED);
- waitCoolDownPeriod();
+ mRunner.waitCoolDownPeriod();
mUserSwitchWaiter.runThenWaitUntilSwitchCompleted(startUser, () -> {
runThenWaitForBroadcasts(userId, () -> {
mRunner.resumeTiming();
@@ -827,7 +775,6 @@
Log.d(TAG, "Stopping timer");
attestTrue("Failed creating profile " + userId, mUm.isManagedProfile(userId));
removeUser(userId);
- waitCoolDownPeriod();
mRunner.resumeTimingForNextIteration();
}
}
@@ -868,7 +815,6 @@
mRunner.pauseTiming();
Log.d(TAG, "Stopping timer");
removeUser(userId);
- waitCoolDownPeriod();
mRunner.resumeTimingForNextIteration();
}
}
@@ -913,7 +859,6 @@
mRunner.pauseTiming();
Log.d(TAG, "Stopping timer");
- waitCoolDownPeriod();
mRunner.resumeTimingForNextIteration();
}
removeUser(userId);
@@ -965,7 +910,6 @@
mRunner.pauseTiming();
Log.d(TAG, "Stopping timer");
removeUser(userId);
- waitCoolDownPeriod();
mRunner.resumeTimingForNextIteration();
}
}
@@ -1030,7 +974,6 @@
mRunner.pauseTiming();
Log.d(TAG, "Stopping timer");
removeUser(userId);
- waitCoolDownPeriod();
mRunner.resumeTimingForNextIteration();
}
}
@@ -1071,7 +1014,6 @@
mRunner.pauseTiming();
Log.d(TAG, "Stopping timer");
removeUser(userId);
- waitCoolDownPeriod();
mRunner.resumeTimingForNextIteration();
}
}
@@ -1124,7 +1066,6 @@
mRunner.pauseTiming();
Log.d(TAG, "Stopping timer");
removeUser(userId);
- waitCoolDownPeriod();
mRunner.resumeTimingForNextIteration();
}
}
@@ -1164,7 +1105,6 @@
runThenWaitForBroadcasts(userId, () -> {
startUserInBackgroundAndWaitForUnlock(userId);
}, Intent.ACTION_MEDIA_MOUNTED);
- waitCoolDownPeriod();
mRunner.resumeTiming();
Log.d(TAG, "Starting timer");
@@ -1280,6 +1220,7 @@
* If lack of success should fail the test, use {@link #switchUser(int)} instead.
*/
private boolean switchUserNoCheck(int userId) throws RemoteException {
+ mRunner.waitCoolDownPeriod();
final boolean[] success = {true};
mUserSwitchWaiter.runThenWaitUntilSwitchCompleted(userId, () -> {
mAm.switchUser(userId);
@@ -1296,7 +1237,7 @@
*/
private void stopUserAfterWaitingForBroadcastIdle(int userId)
throws RemoteException {
- waitForBroadcastIdle();
+ mRunner.waitCoolDownPeriod();
stopUser(userId);
}
@@ -1438,6 +1379,8 @@
*/
private void runThenWaitForBroadcasts(int userId, FunctionalUtils.ThrowingRunnable runnable,
String... actions) {
+ mRunner.waitCoolDownPeriod();
+
final String unreceivedAction =
mBroadcastWaiter.runThenWaitForBroadcasts(userId, runnable, actions);
@@ -1538,28 +1481,4 @@
assertEquals("", ShellHelper.runShellCommand("setprop " + name + " " + value));
return TextUtils.firstNotEmpty(oldValue, "invalid");
}
-
- private void waitForBroadcastIdle() {
- try {
- ShellHelper.runShellCommandWithTimeout(
- "am wait-for-broadcast-idle --flush-broadcast-loopers", TIMEOUT_IN_SECOND);
- } catch (TimeoutException e) {
- Log.e(TAG, "Ending waitForBroadcastIdle because it is taking too long", e);
- }
- }
-
- private void sleep(long ms) {
- try {
- Thread.sleep(ms);
- } catch (InterruptedException e) {
- // Ignore
- }
- }
-
- private void waitCoolDownPeriod() {
- // Heuristic value based on local tests. Stability increased compared to no waiting.
- final int tenSeconds = 1000 * 10;
- waitForBroadcastIdle();
- sleep(tenSeconds);
- }
}