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

Commit 2355cb73 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "AppLaunch: Update to support iorap compilations on go/perfmaster" am:...

Merge "AppLaunch: Update to support iorap compilations on go/perfmaster" am: 94e52381 am: 954c3991

Change-Id: I82d8174e406cbff19a45fba789c2c6e57659d6d4
parents 20faafc4 954c3991
Loading
Loading
Loading
Loading
+247 −10
Original line number Diff line number Diff line
@@ -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)) {
@@ -439,6 +498,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.
@@ -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 {