diff options
author | Igor Murashkin <iam@google.com> | 2020-03-13 10:44:14 -0700 |
---|---|---|
committer | Igor Murashkin <iam@google.com> | 2020-03-13 10:44:14 -0700 |
commit | 52c9a36d79e551ebf3be29ca34ac249ab039d2d6 (patch) | |
tree | fef4db9729638fa455387ad14153f554657e94c1 /tests/AppLaunch/src | |
parent | a132d3b5e2d23771dfdcbcf107692aa8131ef0e5 (diff) |
AppLaunch: Update to support iorap compilations on go/perfmaster
Use the new 'iorap_trial_launch' boolean flag to use iorap.
When iorap is enabled, it adds 3 extra trial launches to collect
perfetto traces and then compile it into an iorap prefetch file.
Test: am instrument -w -r -e iorap_trial_launch true -e \
trace_iterations 2 -e debug false -e apps "Calculator^Calculator" -e \
launch_directory /sdcard -e compiler_filters 'speed-profile' -e \
trial_launch true -e trace_directory sdcard -e log false -e drop_cache \
true -e required_accounts com.google -e timeout_msec 300000 -e \
launch_order CYCLIC -e launch_iterations 5 \
com.android.tests.applaunch/android.test.InstrumentationTestRunner
Bug: 150880186
Change-Id: Ibc0a39e04dd671aa3d6fa5fca086251e622a5235
Diffstat (limited to 'tests/AppLaunch/src')
-rw-r--r-- | tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java | 257 |
1 files changed, 247 insertions, 10 deletions
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java index da45d9a258bd..2f9a1c8ade0d 100644 --- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java +++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java @@ -71,6 +71,7 @@ public class AppLaunch extends InstrumentationTestCase { // with the app launch private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts"; private static final String KEY_APPS = "apps"; + private static final String KEY_IORAP_TRIAL_LAUNCH = "iorap_trial_launch"; private static final String KEY_TRIAL_LAUNCH = "trial_launch"; private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations"; private static final String KEY_LAUNCH_ORDER = "launch_order"; @@ -98,6 +99,9 @@ public class AppLaunch extends InstrumentationTestCase { private static final int BEFORE_KILL_APP_SLEEP_TIMEOUT = 1000; // 1s before killing private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 3000; // 3s between launching apps private static final int PROFILE_SAVE_SLEEP_TIMEOUT = 1000; // Allow 1s for the profile to save + private static final int IORAP_TRACE_DURATION_TIMEOUT = 7000; // Allow 7s for trace to complete. + private static final int IORAP_TRIAL_LAUNCH_ITERATIONS = 3; // min 3 launches to merge traces. + private static final int IORAP_COMPILE_CMD_TIMEOUT = 600; // in seconds: 10 minutes private static final String LAUNCH_SUB_DIRECTORY = "launch_logs"; private static final String LAUNCH_FILE = "applaunch.txt"; private static final String TRACE_SUB_DIRECTORY = "atrace_logs"; @@ -106,6 +110,9 @@ public class AppLaunch extends InstrumentationTestCase { private static final String DEFAULT_TRACE_BUFFER_SIZE = "20000"; private static final String DEFAULT_TRACE_DUMP_INTERVAL = "10"; private static final String TRIAL_LAUNCH = "TRIAL_LAUNCH"; + private static final String IORAP_TRIAL_LAUNCH = "IORAP_TRIAL_LAUNCH"; + private static final String IORAP_TRIAL_LAUNCH_FIRST = "IORAP_TRIAL_LAUNCH_FIRST"; + private static final String IORAP_TRIAL_LAUNCH_LAST = "IORAP_TRIAL_LAUNCH_LAST"; private static final String DELIMITER = ","; private static final String DROP_CACHE_SCRIPT = "/data/local/tmp/dropCache.sh"; private static final String APP_LAUNCH_CMD = "am start -W -n"; @@ -119,6 +126,10 @@ public class AppLaunch extends InstrumentationTestCase { private static final String LAUNCH_ORDER_CYCLIC = "cyclic"; private static final String LAUNCH_ORDER_SEQUENTIAL = "sequential"; private static final String COMPILE_CMD = "cmd package compile -f -m %s %s"; + private static final String IORAP_COMPILE_CMD = "cmd jobscheduler run -f android 283673059"; + private static final String IORAP_MAINTENANCE_CMD = + "iorap.cmd.maintenance --purge-package %s /data/misc/iorapd/sqlite.db"; + private static final String IORAP_DUMPSYS_CMD = "dumpsys iorapd"; private static final String SPEED_PROFILE_FILTER = "speed-profile"; private static final String VERIFY_FILTER = "verify"; private static final String LAUNCH_SCRIPT_NAME = "appLaunch"; @@ -138,6 +149,7 @@ public class AppLaunch extends InstrumentationTestCase { private Bundle mResult = new Bundle(); private Set<String> mRequiredAccounts; private boolean mTrialLaunch = false; + private boolean mIorapTrialLaunch = false; private BufferedWriter mBufferedWriter = null; private boolean mSimplePerfAppOnly = false; private String[] mCompilerFilters = null; @@ -145,6 +157,13 @@ public class AppLaunch extends InstrumentationTestCase { private boolean mCycleCleanUp = false; private boolean mTraceAll = false; private boolean mIterationCycle = false; + + enum IorapStatus { + UNDEFINED, + ENABLED, + DISABLED + } + private IorapStatus mIorapStatus = IorapStatus.UNDEFINED; private long mCycleTime = 0; private StringBuilder mCycleTimes = new StringBuilder(); @@ -243,7 +262,10 @@ public class AppLaunch extends InstrumentationTestCase { setLaunchOrder(); for (LaunchOrder launch : mLaunchOrderList) { - dropCache(); + toggleIorapStatus(launch.getIorapEnabled()); + dropCache(/*override*/false); + + Log.v(TAG, "Launch reason: " + launch.getLaunchReason()); // App launch times for trial launch will not be used for final // launch time calculations. @@ -289,6 +311,43 @@ public class AppLaunch extends InstrumentationTestCase { compileApp(launch.getCompilerFilter(), appPkgName)); } } + else if (launch.getLaunchReason().startsWith(IORAP_TRIAL_LAUNCH)) { + mIterationCycle = false; + + // In the "applaunch.txt" file, iorap-trial launches is referenced using + // "IORAP_TRIAL_LAUNCH" or "IORAP_TRIAL_LAUNCH_LAST" + Intent startIntent = mNameToIntent.get(launch.getApp()); + if (startIntent == null) { + Log.w(TAG, "App does not exist: " + launch.getApp()); + mResult.putString(mNameToResultKey.get(launch.getApp()), + "App does not exist"); + continue; + } + String appPkgName = startIntent.getComponent().getPackageName(); + + if (launch.getLaunchReason().equals(IORAP_TRIAL_LAUNCH_FIRST)) { + // delete any iorap-traces associated with this package. + purgeIorapPackage(appPkgName); + } + dropCache(/*override*/true); // iorap-trial runs must have drop cache. + + AppLaunchResult launchResult = + startApp(launch.getApp(), launch.getLaunchReason()); + if (launchResult.mLaunchTime < 0) { + addLaunchResult(launch, new AppLaunchResult()); + // simply pass the app if launch isn't successful + // error should have already been logged by startApp + continue; + } + // wait for slightly more than 5s (iorapd.perfetto.trace_duration_ms) for the trace buffers to complete. + sleep(IORAP_TRACE_DURATION_TIMEOUT); + + if (launch.getLaunchReason().equals(IORAP_TRIAL_LAUNCH_LAST)) { + // run the iorap job scheduler and wait for iorap to compile fully. + assertTrue(String.format("Not able to iorap-compile the app : %s", appPkgName), + compileAppForIorap(appPkgName)); + } + } // App launch times used for final calculation else if (launch.getLaunchReason().contains(LAUNCH_ITERATION_PREFIX)) { @@ -440,6 +499,74 @@ public class AppLaunch extends InstrumentationTestCase { } /** + * Compile the app package using compilerFilter and return true or false + * based on status of the compilation command. + */ + private boolean compileAppForIorap(String appPkgName) throws IOException { + getInstrumentation().getUiAutomation(). + executeShellCommand(IORAP_COMPILE_CMD); + + for (int i = 0; i < IORAP_COMPILE_CMD_TIMEOUT; ++i) { + IorapCompilationStatus status = waitForIorapCompiled(appPkgName); + if (status == IorapCompilationStatus.COMPLETE) { + return true; + } else if (status == IorapCompilationStatus.INSUFFICIENT_TRACES) { + return false; + } // else INCOMPLETE. keep asking iorapd if it's done yet. + sleep(1000); + } + + return false; + } + + enum IorapCompilationStatus { + INCOMPLETE, + COMPLETE, + INSUFFICIENT_TRACES, + } + private IorapCompilationStatus waitForIorapCompiled(String appPkgName) throws IOException { + try (ParcelFileDescriptor result = getInstrumentation().getUiAutomation(). + executeShellCommand(IORAP_DUMPSYS_CMD); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader( + new FileInputStream(result.getFileDescriptor())))) { + String line; + String prevLine = ""; + while ((line = bufferedReader.readLine()) != null) { + // Match the indented VersionedComponentName string. + // " com.google.android.deskclock/com.android.deskclock.DeskClock@62000712" + // Note: spaces are meaningful here. + if (prevLine.contains(" " + appPkgName) && prevLine.contains("@")) { + // pre-requisite: + // Compiled Status: Raw traces pending compilation (3) + if (line.contains("Compiled Status: Usable compiled trace")) { + return IorapCompilationStatus.COMPLETE; + } else if (line.contains("Compiled Status: ") && + line.contains("more traces for compilation")) { + // Compiled Status: Need 1 more traces for compilation + // No amount of waiting will help here because there were + // insufficient traces made. + return IorapCompilationStatus.INSUFFICIENT_TRACES; + } + } + + prevLine = line; + } + return IorapCompilationStatus.INCOMPLETE; + } + } + + private String makeReasonForIorapTrialLaunch(int launchCount) { + String reason = IORAP_TRIAL_LAUNCH; + if (launchCount == 0) { + reason = IORAP_TRIAL_LAUNCH_FIRST; + } + if (launchCount == IORAP_TRIAL_LAUNCH_ITERATIONS - 1) { + reason = IORAP_TRIAL_LAUNCH_LAST; + } + return reason; + } + + /** * If launch order is "cyclic" then apps will be launched one after the * other for each iteration count. * If launch order is "sequential" then each app will be launched for given number @@ -450,20 +577,31 @@ public class AppLaunch extends InstrumentationTestCase { for (String compilerFilter : mCompilerFilters) { if (mTrialLaunch) { for (String app : mNameToResultKey.keySet()) { - mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH)); + mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH, /*iorapEnabled*/false)); + } + } + if (mIorapTrialLaunch) { + for (int launchCount = 0; launchCount < IORAP_TRIAL_LAUNCH_ITERATIONS; ++launchCount) { + for (String app : mNameToResultKey.keySet()) { + String reason = makeReasonForIorapTrialLaunch(launchCount); + mLaunchOrderList.add( + new LaunchOrder(app, compilerFilter, + reason, + /*iorapEnabled*/true)); + } } } for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) { for (String app : mNameToResultKey.keySet()) { mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, - String.format(LAUNCH_ITERATION, launchCount))); + String.format(LAUNCH_ITERATION, launchCount), mIorapTrialLaunch)); } } if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) { for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) { for (String app : mNameToResultKey.keySet()) { mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, - String.format(TRACE_ITERATION, traceCount))); + String.format(TRACE_ITERATION, traceCount), mIorapTrialLaunch)); } } } @@ -472,16 +610,25 @@ public class AppLaunch extends InstrumentationTestCase { for (String compilerFilter : mCompilerFilters) { for (String app : mNameToResultKey.keySet()) { if (mTrialLaunch) { - mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH)); + mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH, /*iorapEnabled*/false)); + } + if (mIorapTrialLaunch) { + for (int launchCount = 0; launchCount < IORAP_TRIAL_LAUNCH_ITERATIONS; ++launchCount) { + String reason = makeReasonForIorapTrialLaunch(launchCount); + mLaunchOrderList.add( + new LaunchOrder(app, compilerFilter, + reason, + /*iorapEnabled*/true)); + } } for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) { mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, - String.format(LAUNCH_ITERATION, launchCount))); + String.format(LAUNCH_ITERATION, launchCount), mIorapTrialLaunch)); } if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) { for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) { mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, - String.format(TRACE_ITERATION, traceCount))); + String.format(TRACE_ITERATION, traceCount), mIorapTrialLaunch)); } } } @@ -491,14 +638,92 @@ public class AppLaunch extends InstrumentationTestCase { } } - private void dropCache() { - if (mDropCache) { + private void dropCache(boolean override) { + if (mDropCache || override) { assertNotNull("Issue in dropping the cache", getInstrumentation().getUiAutomation() .executeShellCommand(DROP_CACHE_SCRIPT)); } } + // [[ $(adb shell whoami) == "root" ]] + private boolean checkIfRoot() throws IOException { + String total = ""; + try (ParcelFileDescriptor result = getInstrumentation().getUiAutomation(). + executeShellCommand("whoami"); + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader( + new FileInputStream(result.getFileDescriptor())))) { + String line; + while ((line = bufferedReader.readLine()) != null) { + total = total + line; + } + } + return total.contains("root"); + } + + // Delete all db rows and files associated with a package in iorapd. + // Effectively deletes any raw or compiled trace files, unoptimizing the package in iorap. + private void purgeIorapPackage(String packageName) { + try { + if (!checkIfRoot()) { + throw new AssertionError("must be root to toggle iorapd; try adb root?"); + } + } catch (IOException e) { + throw new AssertionError(e); + } + + getInstrumentation().getUiAutomation() + .executeShellCommand("stop iorapd"); + sleep(100); // give iorapd enough time to stop. + getInstrumentation().getUiAutomation() + .executeShellCommand(String.format(IORAP_MAINTENANCE_CMD, packageName)); + Log.v(TAG, "Executed: " + String.format(IORAP_MAINTENANCE_CMD, packageName)); + getInstrumentation().getUiAutomation() + .executeShellCommand("start iorapd"); + sleep(2000); // give iorapd enough time to start up. + } + + /** + * Toggle iorapd-based readahead and trace-collection. + * If iorapd is already enabled and enable is true, does nothing. + * If iorapd is already disabled and enable is false, does nothing. + */ + private void toggleIorapStatus(boolean enable) { + boolean currentlyEnabled = false; + Log.v(TAG, "toggleIorapStatus " + Boolean.toString(enable)); + + // Do nothing if we are already enabled or disabled. + if (mIorapStatus == IorapStatus.ENABLED && enable) { + return; + } else if (mIorapStatus == IorapStatus.DISABLED && !enable) { + return; + } + + try { + if (!checkIfRoot()) { + throw new AssertionError("must be root to toggle iorapd; try adb root?"); + } + } catch (IOException e) { + throw new AssertionError(e); + } + + getInstrumentation().getUiAutomation() + .executeShellCommand("stop iorapd"); + getInstrumentation().getUiAutomation() + .executeShellCommand(String.format("setprop iorapd.perfetto.enable %b", enable)); + getInstrumentation().getUiAutomation() + .executeShellCommand(String.format("setprop iorapd.readahead.enable %b", enable)); + getInstrumentation().getUiAutomation() + .executeShellCommand("start iorapd"); + sleep(2000); // give enough time for iorapd to start back up. + + if (enable) { + mIorapStatus = IorapStatus.ENABLED; + } else { + mIorapStatus = IorapStatus.DISABLED; + } + } + private void parseArgs(Bundle args) { mNameToResultKey = new LinkedHashMap<String, String>(); mNameToLaunchTime = new HashMap<>(); @@ -562,6 +787,8 @@ public class AppLaunch extends InstrumentationTestCase { mCycleCleanUp = Boolean.parseBoolean(args.getString(KEY_CYCLE_CLEAN)); mTraceAll = Boolean.parseBoolean(args.getString(KEY_TRACE_ALL)); mTrialLaunch = mTrialLaunch || Boolean.parseBoolean(args.getString(KEY_TRIAL_LAUNCH)); + mIorapTrialLaunch = mIorapTrialLaunch || + Boolean.parseBoolean(args.getString(KEY_IORAP_TRIAL_LAUNCH)); if (mSimplePerfCmd != null && mSimplePerfAppOnly) { Log.w(TAG, String.format("Passing both %s and %s is not supported, ignoring %s", @@ -740,11 +967,13 @@ public class AppLaunch extends InstrumentationTestCase { private String mApp; private String mCompilerFilter; private String mLaunchReason; + private boolean mIorapEnabled; - LaunchOrder(String app, String compilerFilter, String launchReason){ + LaunchOrder(String app, String compilerFilter, String launchReason, boolean iorapEnabled) { mApp = app; mCompilerFilter = compilerFilter; mLaunchReason = launchReason; + mIorapEnabled = iorapEnabled; } public String getApp() { @@ -766,6 +995,14 @@ public class AppLaunch extends InstrumentationTestCase { public void setLaunchReason(String launchReason) { mLaunchReason = launchReason; } + + public void setIorapEnabled(boolean iorapEnabled) { + mIorapEnabled = iorapEnabled; + } + + public boolean getIorapEnabled() { + return mIorapEnabled; + } } private class AppLaunchResult { |