diff options
author | Nicolas Geoffray <ngeoffray@google.com> | 2018-02-12 21:21:20 +0000 |
---|---|---|
committer | Nicolas Geoffray <ngeoffray@google.com> | 2018-02-15 10:44:17 +0000 |
commit | e7a566f2fb6701d7fd32ca0c983dbe9364a90ca1 (patch) | |
tree | 9e98a378a9809f4232082e49f358d261760e13dc /tests | |
parent | 90f285ba517995f391494279d12a7cdb4bd024c2 (diff) |
Add more ways to run AppLaunch.
1) Pass a list of compiler filters.
2) Pass an option to output cpu cycles and major faults from app.
bug: 73091359
Test: adb shell "am instrument -e drop_cache true -e compiler_filters \"speed-profile|verify|quicken\" -e simpleperf_app true -e apps com.google.android.apps.maps^Maps -e launch_directory /data/local/tmp -w com.android.tests.applaunch com.android.tests.applaunch/android.test.InstrumentationTestRunner"
Test:
adb shell "am instrument -e drop_cache true -e simpleperf_cmd \"simpleperf stat -a\" -e apps com.google.android.apps.maps^Maps -e launch_directory /data/local/tmp -w com.android.tests.applaunch com.android.tests.applaunch/android.test.InstrumentationTestRunner"
com.android.tests.applaunch.AppLaunch:INSTRUMENTATION_STATUS: Maps=1488,1850,1973,1972,1929,1947,1968,1771,2006,1912,
INSTRUMENTATION_STATUS_CODE: 0
.
Test results for InstrumentationTestRunner=.
Time: 88.636
OK (1 test)
Change-Id: I61fea8c124107cbd7234f69358078780ab74c4b6
Diffstat (limited to 'tests')
-rw-r--r-- | tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java | 371 |
1 files changed, 251 insertions, 120 deletions
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java index 063060f166dc..228f9bbddcd1 100644 --- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java +++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java @@ -65,6 +65,7 @@ public class AppLaunch extends InstrumentationTestCase { private static final int JOIN_TIMEOUT = 10000; private static final String TAG = AppLaunch.class.getSimpleName(); + // optional parameter: comma separated list of required account types before proceeding // with the app launch private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts"; @@ -73,32 +74,36 @@ public class AppLaunch extends InstrumentationTestCase { private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations"; private static final String KEY_LAUNCH_ORDER = "launch_order"; private static final String KEY_DROP_CACHE = "drop_cache"; - private static final String KEY_SIMULATE_MAINTANANCE = "simulate_maintanance"; - private static final String KEY_SIMPLEPPERF_CMD = "simpleperf_cmd"; + private static final String KEY_SIMPLEPERF_CMD = "simpleperf_cmd"; + private static final String KEY_SIMPLEPERF_APP = "simpleperf_app"; private static final String KEY_TRACE_ITERATIONS = "trace_iterations"; private static final String KEY_LAUNCH_DIRECTORY = "launch_directory"; private static final String KEY_TRACE_DIRECTORY = "trace_directory"; private static final String KEY_TRACE_CATEGORY = "trace_categories"; private static final String KEY_TRACE_BUFFERSIZE = "trace_bufferSize"; private static final String KEY_TRACE_DUMPINTERVAL = "tracedump_interval"; + private static final String KEY_COMPILER_FILTERS = "compiler_filters"; + + private static final String SIMPLEPERF_APP_CMD = + "simpleperf --log fatal stat --csv -e cpu-cycles,major-faults --app %s & %s"; private static final String WEARABLE_ACTION_GOOGLE = "com.google.android.wearable.action.GOOGLE"; - private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 5000; //5s to allow app to idle - private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; //750ms idle for non initial launches - private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 5000; //5s between launching apps + private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 5000; // 5s to allow app to idle + private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; // 750ms idle for non initial launches + private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 5000; // 5s between launching apps 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"; - private static final String DEFAULT_TRACE_CATEGORIES = "sched,freq,gfx,view,dalvik,webview," - + "input,wm,disk,am,wm"; + private static final String DEFAULT_TRACE_CATEGORIES = + "sched,freq,gfx,view,dalvik,webview,input,wm,disk,am,wm"; private static final String DEFAULT_TRACE_BUFFER_SIZE = "20000"; private static final String DEFAULT_TRACE_DUMP_INTERVAL = "10"; - private static final String TRIAL_LAUNCH = "TRAIL_LAUNCH"; + private static final String TRIAL_LAUNCH = "TRIAL_LAUNCH"; 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"; private static final String SUCCESS_MESSAGE = "Status: ok"; - private static final String PROFILE_COMPILE_SUCCESS = "Success"; + private static final String COMPILE_SUCCESS = "Success"; private static final String THIS_TIME = "ThisTime:"; private static final String LAUNCH_ITERATION = "LAUNCH_ITERATION - %d"; private static final String TRACE_ITERATION = "TRACE_ITERATION-%d"; @@ -106,14 +111,15 @@ public class AppLaunch extends InstrumentationTestCase { private static final String TRACE_ITERATION_PREFIX = "TRACE_ITERATION"; private static final String LAUNCH_ORDER_CYCLIC = "cyclic"; private static final String LAUNCH_ORDER_SEQUENTIAL = "sequential"; - private static final String SPEED_PROFILE_CMD = "cmd package compile -f -m speed-profile %s"; - - + private static final String COMPILE_CMD = "cmd package compile -f -m %s %s"; + private static final String SPEED_PROFILE_FILTER = "speed-profile"; + private static final String VERIFY_FILTER = "verify"; + private static final String LAUNCH_SCRIPT_NAME = "appLaunch"; private Map<String, Intent> mNameToIntent; private List<LaunchOrder> mLaunchOrderList = new ArrayList<LaunchOrder>(); private Map<String, String> mNameToResultKey; - private Map<String, List<Long>> mNameToLaunchTime; + private Map<String, Map<String, List<AppLaunchResult>>> mNameToLaunchTime; private IActivityManager mAm; private String mSimplePerfCmd = null; private String mLaunchOrder = null; @@ -123,12 +129,10 @@ public class AppLaunch extends InstrumentationTestCase { private String mTraceDirectoryStr = null; private Bundle mResult = new Bundle(); private Set<String> mRequiredAccounts; - private boolean mTrailLaunch = true; - private File mFile = null; - private FileOutputStream mOutputStream = null; + private boolean mTrialLaunch = false; private BufferedWriter mBufferedWriter = null; - private boolean mSimulateMaintanance = false; - + private boolean mSimplePerfAppOnly = false; + private String[] mCompilerFilters = null; @Override protected void setUp() throws Exception { @@ -142,6 +146,16 @@ public class AppLaunch extends InstrumentationTestCase { super.tearDown(); } + private void addLaunchResult(LaunchOrder launch, AppLaunchResult result) { + mNameToLaunchTime.get(launch.getApp()).get(launch.getCompilerFilter()).add(result); + } + + private boolean hasFailureOnFirstLaunch(LaunchOrder launch) { + List<AppLaunchResult> results = + mNameToLaunchTime.get(launch.getApp()).get(launch.getCompilerFilter()); + return (results.size() > 0) && (results.get(0).mLaunchTime < 0); + } + public void testMeasureStartUpTime() throws RemoteException, NameNotFoundException, IOException, InterruptedException { InstrumentationTestRunner instrumentation = @@ -149,11 +163,6 @@ public class AppLaunch extends InstrumentationTestCase { Bundle args = instrumentation.getArguments(); mAm = ActivityManager.getService(); String launchDirectory = args.getString(KEY_LAUNCH_DIRECTORY); - mTraceDirectoryStr = args.getString(KEY_TRACE_DIRECTORY); - mDropCache = Boolean.parseBoolean(args.getString(KEY_DROP_CACHE)); - mSimplePerfCmd = args.getString(KEY_SIMPLEPPERF_CMD); - mLaunchOrder = args.getString(KEY_LAUNCH_ORDER, LAUNCH_ORDER_CYCLIC); - mSimulateMaintanance = Boolean.parseBoolean(args.getString(KEY_SIMULATE_MAINTANANCE)); createMappings(); parseArgs(args); @@ -171,13 +180,14 @@ public class AppLaunch extends InstrumentationTestCase { try { File launchSubDir = new File(launchRootDir, LAUNCH_SUB_DIRECTORY); + if (!launchSubDir.exists() && !launchSubDir.mkdirs()) { throw new IOException("Unable to create the lauch file sub directory"); } - mFile = new File(launchSubDir, LAUNCH_FILE); - mOutputStream = new FileOutputStream(mFile); + File file = new File(launchSubDir, LAUNCH_FILE); + FileOutputStream outputStream = new FileOutputStream(file); mBufferedWriter = new BufferedWriter(new OutputStreamWriter( - mOutputStream)); + outputStream)); // Root directory for trace file during the launches File rootTrace = null; @@ -217,70 +227,67 @@ public class AppLaunch extends InstrumentationTestCase { setLaunchOrder(); for (LaunchOrder launch : mLaunchOrderList) { + dropCache(); // App launch times for trial launch will not be used for final // launch time calculations. if (launch.getLaunchReason().equals(TRIAL_LAUNCH)) { // In the "applaunch.txt" file, trail launches is referenced using // "TRIAL_LAUNCH" - long launchTime = startApp(launch.getApp(), true, launch.getLaunchReason()); - if (launchTime < 0) { - List<Long> appLaunchList = new ArrayList<Long>(); - appLaunchList.add(-1L); - mNameToLaunchTime.put(launch.getApp(), appLaunchList); + String appPkgName = mNameToIntent.get(launch.getApp()) + .getComponent().getPackageName(); + if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) { + assertTrue(String.format("Not able to compile the app : %s", appPkgName), + compileApp(VERIFY_FILTER, appPkgName)); + } else if (launch.getCompilerFilter() != null) { + assertTrue(String.format("Not able to compile the app : %s", appPkgName), + compileApp(launch.getCompilerFilter(), appPkgName)); + } + // We only need to run a trial for the speed-profile filter, but we always + // run one for "applaunch.txt" consistency. + AppLaunchResult launchResult = + startApp(launch.getApp(), true, 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; } sleep(INITIAL_LAUNCH_IDLE_TIMEOUT); - closeApp(launch.getApp(), true); - dropCache(); - if (mSimulateMaintanance) { - String appPkgName = mNameToIntent.get(launch.getApp()) - .getComponent().getPackageName(); - assertTrue(String.format("Not able to speed profile the app : %s", - appPkgName), profileCompileApp(appPkgName)); + if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) { + // Send SIGUSR1 to force dumping a profile. + String sendSignalCommand = + String.format("killall -s SIGUSR1 %s", appPkgName); + getInstrumentation().getUiAutomation().executeShellCommand( + sendSignalCommand); + assertTrue(String.format("Not able to compile the app : %s", appPkgName), + compileApp(launch.getCompilerFilter(), appPkgName)); } - sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT); } // App launch times used for final calculation - if (launch.getLaunchReason().contains(LAUNCH_ITERATION_PREFIX)) { - long launchTime = -1; - if (null != mNameToLaunchTime.get(launch.getApp())) { - long firstLaunchTime = mNameToLaunchTime.get(launch.getApp()).get(0); - if (firstLaunchTime < 0) { - // skip if the app has failures while launched first - continue; - } + else if (launch.getLaunchReason().contains(LAUNCH_ITERATION_PREFIX)) { + AppLaunchResult launchResults = null; + if (hasFailureOnFirstLaunch(launch)) { + // skip if the app has failures while launched first + continue; } // In the "applaunch.txt" file app launches are referenced using // "LAUNCH_ITERATION - ITERATION NUM" - launchTime = startApp(launch.getApp(), true, launch.getLaunchReason()); - if (launchTime < 0) { + launchResults = startApp(launch.getApp(), true, launch.getLaunchReason()); + if (launchResults.mLaunchTime < 0) { + addLaunchResult(launch, new AppLaunchResult()); // if it fails once, skip the rest of the launches - List<Long> appLaunchList = new ArrayList<Long>(); - appLaunchList.add(-1L); - mNameToLaunchTime.put(launch.getApp(), appLaunchList); continue; } else { - if (null != mNameToLaunchTime.get(launch.getApp())) { - mNameToLaunchTime.get(launch.getApp()).add(launchTime); - } else { - List<Long> appLaunchList = new ArrayList<Long>(); - appLaunchList.add(launchTime); - mNameToLaunchTime.put(launch.getApp(), appLaunchList); - } + addLaunchResult(launch, launchResults); } sleep(POST_LAUNCH_IDLE_TIMEOUT); - closeApp(launch.getApp(), true); - dropCache(); - sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT); } // App launch times for trace launch will not be used for final // launch time calculations. - if (launch.getLaunchReason().contains(TRACE_ITERATION_PREFIX)) { + else if (launch.getLaunchReason().contains(TRACE_ITERATION_PREFIX)) { AtraceLogger atraceLogger = AtraceLogger .getAtraceLoggerInstance(getInstrumentation()); // Start the trace @@ -293,11 +300,10 @@ public class AppLaunch extends InstrumentationTestCase { } finally { // Stop the trace atraceLogger.atraceStop(); - closeApp(launch.getApp(), true); - dropCache(); - sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT); } } + closeApp(launch.getApp(), true); + sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT); } } finally { if (null != mBufferedWriter) { @@ -306,29 +312,45 @@ public class AppLaunch extends InstrumentationTestCase { } for (String app : mNameToResultKey.keySet()) { - StringBuilder launchTimes = new StringBuilder(); - for (Long launch : mNameToLaunchTime.get(app)) { - launchTimes.append(launch); - launchTimes.append(","); + for (String compilerFilter : mCompilerFilters) { + StringBuilder launchTimes = new StringBuilder(); + StringBuilder cpuCycles = new StringBuilder(); + StringBuilder majorFaults = new StringBuilder(); + for (AppLaunchResult result : mNameToLaunchTime.get(app).get(compilerFilter)) { + launchTimes.append(result.mLaunchTime); + launchTimes.append(","); + if (mSimplePerfAppOnly) { + cpuCycles.append(result.mCpuCycles); + cpuCycles.append(","); + majorFaults.append(result.mMajorFaults); + majorFaults.append(","); + } + } + String filterName = (compilerFilter == null) ? "" : ("-" + compilerFilter); + mResult.putString(mNameToResultKey.get(app) + filterName, launchTimes.toString()); + if (mSimplePerfAppOnly) { + mResult.putString(mNameToResultKey.get(app) + filterName + "-cpuCycles", + cpuCycles.toString()); + mResult.putString(mNameToResultKey.get(app) + filterName + "-majorFaults", + majorFaults.toString()); + } } - mResult.putString(mNameToResultKey.get(app), launchTimes.toString()); } instrumentation.sendStatus(0, mResult); } /** - * Compile the app package using speed compile command and return true or false + * Compile the app package using compilerFilter and return true or false * based on status of the compilation command. */ - private boolean profileCompileApp(String appPkgName) throws IOException { - Log.i(TAG, "Starting to speed profile " + appPkgName); + private boolean compileApp(String compilerFilter, String appPkgName) throws IOException { try (ParcelFileDescriptor result = getInstrumentation().getUiAutomation(). - executeShellCommand(String.format(SPEED_PROFILE_CMD, appPkgName)); + executeShellCommand(String.format(COMPILE_CMD, compilerFilter, appPkgName)); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader( new FileInputStream(result.getFileDescriptor())))) { String line; while ((line = bufferedReader.readLine()) != null) { - if (line.contains(PROFILE_COMPILE_SUCCESS)) { + if (line.contains(COMPILE_SUCCESS)) { return true; } } @@ -344,38 +366,42 @@ public class AppLaunch extends InstrumentationTestCase { */ private void setLaunchOrder() { if (LAUNCH_ORDER_CYCLIC.equalsIgnoreCase(mLaunchOrder)) { - if (mTrailLaunch) { - for (String app : mNameToResultKey.keySet()) { - mLaunchOrderList.add(new LaunchOrder(app, TRIAL_LAUNCH)); - } - } - for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) { - for (String app : mNameToResultKey.keySet()) { - mLaunchOrderList.add(new LaunchOrder(app, - String.format(LAUNCH_ITERATION, launchCount))); - } - } - if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) { - for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) { + for (String compilerFilter : mCompilerFilters) { + if (mTrialLaunch) { for (String app : mNameToResultKey.keySet()) { - mLaunchOrderList.add(new LaunchOrder(app, - String.format(TRACE_ITERATION, traceCount))); + mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH)); } } - } - } else if (LAUNCH_ORDER_SEQUENTIAL.equalsIgnoreCase(mLaunchOrder)) { - for (String app : mNameToResultKey.keySet()) { - if (mTrailLaunch) { - mLaunchOrderList.add(new LaunchOrder(app, TRIAL_LAUNCH)); - } for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) { - mLaunchOrderList.add(new LaunchOrder(app, - String.format(LAUNCH_ITERATION, launchCount))); + for (String app : mNameToResultKey.keySet()) { + mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, + String.format(LAUNCH_ITERATION, launchCount))); + } } if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) { for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) { - mLaunchOrderList.add(new LaunchOrder(app, - String.format(TRACE_ITERATION, traceCount))); + for (String app : mNameToResultKey.keySet()) { + mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, + String.format(TRACE_ITERATION, traceCount))); + } + } + } + } + } else if (LAUNCH_ORDER_SEQUENTIAL.equalsIgnoreCase(mLaunchOrder)) { + for (String compilerFilter : mCompilerFilters) { + for (String app : mNameToResultKey.keySet()) { + if (mTrialLaunch) { + mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH)); + } + for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) { + mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, + String.format(LAUNCH_ITERATION, launchCount))); + } + if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) { + for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) { + mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, + String.format(TRACE_ITERATION, traceCount))); + } } } } @@ -385,7 +411,7 @@ public class AppLaunch extends InstrumentationTestCase { } private void dropCache() { - if (true == mDropCache) { + if (mDropCache) { assertNotNull("Issue in dropping the cache", getInstrumentation().getUiAutomation() .executeShellCommand(DROP_CACHE_SCRIPT)); @@ -394,7 +420,7 @@ public class AppLaunch extends InstrumentationTestCase { private void parseArgs(Bundle args) { mNameToResultKey = new LinkedHashMap<String, String>(); - mNameToLaunchTime = new HashMap<String, List<Long>>(); + mNameToLaunchTime = new HashMap<>(); String launchIterations = args.getString(KEY_LAUNCH_ITERATIONS); if (launchIterations != null) { mLaunchIterations = Integer.parseInt(launchIterations); @@ -421,7 +447,38 @@ public class AppLaunch extends InstrumentationTestCase { mRequiredAccounts.add(accountType); } } - mTrailLaunch = "true".equals(args.getString(KEY_TRIAL_LAUNCH)); + + String compilerFilterList = args.getString(KEY_COMPILER_FILTERS); + if (compilerFilterList != null) { + // If a compiler filter is passed, we make a trial launch to force compilation + // of the apps. + mTrialLaunch = true; + mCompilerFilters = compilerFilterList.split("\\|"); + } else { + // Just pass a null compiler filter to use the current state of the app. + mCompilerFilters = new String[1]; + } + + // Pre-populate the results map to avoid null checks. + for (String app : mNameToLaunchTime.keySet()) { + HashMap<String, List<AppLaunchResult>> map = new HashMap<>(); + mNameToLaunchTime.put(app, map); + for (String compilerFilter : mCompilerFilters) { + map.put(compilerFilter, new ArrayList<>()); + } + } + + mTraceDirectoryStr = args.getString(KEY_TRACE_DIRECTORY); + mDropCache = Boolean.parseBoolean(args.getString(KEY_DROP_CACHE)); + mSimplePerfCmd = args.getString(KEY_SIMPLEPERF_CMD); + mLaunchOrder = args.getString(KEY_LAUNCH_ORDER, LAUNCH_ORDER_CYCLIC); + mSimplePerfAppOnly = Boolean.parseBoolean(args.getString(KEY_SIMPLEPERF_APP)); + mTrialLaunch = mTrialLaunch || Boolean.parseBoolean(args.getString(KEY_TRIAL_LAUNCH)); + + if (mSimplePerfCmd != null && mSimplePerfAppOnly) { + Log.w(TAG, String.format("Passing both %s and %s is not supported, ignoring %s", + KEY_SIMPLEPERF_CMD, KEY_SIMPLEPERF_APP)); + } } private boolean hasLeanback(Context context) { @@ -465,17 +522,17 @@ public class AppLaunch extends InstrumentationTestCase { } } - private long startApp(String appName, boolean forceStopBeforeLaunch, String launchReason) - throws NameNotFoundException, RemoteException { + private AppLaunchResult startApp(String appName, boolean forceStopBeforeLaunch, + String launchReason) throws NameNotFoundException, RemoteException { Log.i(TAG, "Starting " + appName); Intent startIntent = mNameToIntent.get(appName); if (startIntent == null) { Log.w(TAG, "App does not exist: " + appName); mResult.putString(mNameToResultKey.get(appName), "App does not exist"); - return -1L; + return new AppLaunchResult(); } - AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch , + AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch, launchReason); Thread t = new Thread(runnable); t.start(); @@ -569,10 +626,12 @@ public class AppLaunch extends InstrumentationTestCase { private class LaunchOrder { private String mApp; + private String mCompilerFilter; private String mLaunchReason; - LaunchOrder(String app,String launchReason){ + LaunchOrder(String app, String compilerFilter, String launchReason){ mApp = app; + mCompilerFilter = compilerFilter; mLaunchReason = launchReason; } @@ -584,6 +643,10 @@ public class AppLaunch extends InstrumentationTestCase { mApp = app; } + public String getCompilerFilter() { + return mCompilerFilter; + } + public String getLaunchReason() { return mLaunchReason; } @@ -593,9 +656,31 @@ public class AppLaunch extends InstrumentationTestCase { } } + private class AppLaunchResult { + long mLaunchTime; + long mCpuCycles; + long mMajorFaults; + + AppLaunchResult() { + mLaunchTime = -1L; + mCpuCycles = -1L; + mMajorFaults = -1L; + } + + AppLaunchResult(String launchTime, String cpuCycles, String majorFaults) { + try { + mLaunchTime = Long.parseLong(launchTime, 10); + mCpuCycles = Long.parseLong(cpuCycles, 10); + mMajorFaults = Long.parseLong(majorFaults, 10); + } catch (NumberFormatException e) { + Log.e(TAG, "Error parsing result", e); + } + } + } + private class AppLaunchRunnable implements Runnable { private Intent mLaunchIntent; - private Long mResult; + private AppLaunchResult mLaunchResult; private boolean mForceStopBeforeLaunch; private String mLaunchReason; @@ -604,14 +689,15 @@ public class AppLaunch extends InstrumentationTestCase { mLaunchIntent = intent; mForceStopBeforeLaunch = forceStopBeforeLaunch; mLaunchReason = launchReason; - mResult = -1L; + mLaunchResult = new AppLaunchResult(); } - public Long getResult() { - return mResult; + public AppLaunchResult getResult() { + return mLaunchResult; } public void run() { + File launchFile = null; try { String packageName = mLaunchIntent.getComponent().getPackageName(); String componentName = mLaunchIntent.getComponent().flattenToShortString(); @@ -619,17 +705,38 @@ public class AppLaunch extends InstrumentationTestCase { mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT); } String launchCmd = String.format("%s %s", APP_LAUNCH_CMD, componentName); - if (null != mSimplePerfCmd) { + if (mSimplePerfAppOnly) { + try { + // executeShellCommand cannot handle shell specific actions, like '&'. + // Therefore, we create a file containing the command and make that + // the command to launch. + launchFile = File.createTempFile(LAUNCH_SCRIPT_NAME, ".sh"); + launchFile.setExecutable(true); + try (FileOutputStream stream = new FileOutputStream(launchFile); + BufferedWriter writer = + new BufferedWriter(new OutputStreamWriter(stream))) { + String cmd = String.format(SIMPLEPERF_APP_CMD, packageName, launchCmd); + writer.write(cmd); + } + launchCmd = launchFile.getAbsolutePath(); + } catch (IOException e) { + Log.w(TAG, "Error writing the launch command", e); + return; + } + } else if (null != mSimplePerfCmd) { launchCmd = String.format("%s %s", mSimplePerfCmd, launchCmd); } Log.v(TAG, "Final launch cmd:" + launchCmd); ParcelFileDescriptor parcelDesc = getInstrumentation().getUiAutomation() .executeShellCommand(launchCmd); - mResult = Long.parseLong(parseLaunchTimeAndWrite(parcelDesc, String.format - ("App Launch :%s %s", - componentName, mLaunchReason)), 10); + mLaunchResult = parseLaunchTimeAndWrite(parcelDesc, String.format + ("App Launch :%s %s", componentName, mLaunchReason)); } catch (RemoteException e) { Log.w(TAG, "Error launching app", e); + } finally { + if (launchFile != null) { + launchFile.delete(); + } } } @@ -639,12 +746,14 @@ public class AppLaunch extends InstrumentationTestCase { * @param parcelDesc * @return */ - private String parseLaunchTimeAndWrite(ParcelFileDescriptor parcelDesc, String headerInfo) { + private AppLaunchResult parseLaunchTimeAndWrite(ParcelFileDescriptor parcelDesc, + String headerInfo) { String launchTime = "-1"; + String cpuCycles = "-1"; + String majorFaults = "-1"; boolean launchSuccess = false; try { InputStream inputStream = new FileInputStream(parcelDesc.getFileDescriptor()); - StringBuilder appLaunchOuput = new StringBuilder(); /* SAMPLE OUTPUT : Starting: Intent { cmp=com.google.android.calculator/com.android.calculator2.Calculator } Status: ok @@ -653,6 +762,11 @@ public class AppLaunch extends InstrumentationTestCase { TotalTime: 357 WaitTime: 377 Complete*/ + /* WITH SIMPLEPERF : + Performance counter statistics, + 6595722690,cpu-cycles,4.511040,GHz,(100%), + 0,major-faults,0.000,/sec,(100%), + Total test time,1.462129,seconds,*/ BufferedReader bufferedReader = new BufferedReader(new InputStreamReader( inputStream)); String line = null; @@ -669,6 +783,23 @@ public class AppLaunch extends InstrumentationTestCase { String launchSplit[] = line.split(":"); launchTime = launchSplit[1].trim(); } + + if (mSimplePerfAppOnly) { + // Parse simpleperf output. + if (lineCount == 9) { + if (!line.contains("cpu-cycles")) { + Log.e(TAG, "Error in simpleperf output"); + } else { + cpuCycles = line.split(",")[0].trim(); + } + } else if (lineCount == 10) { + if (!line.contains("major-faults")) { + Log.e(TAG, "Error in simpleperf output"); + } else { + majorFaults = line.split(",")[0].trim(); + } + } + } mBufferedWriter.write(line); mBufferedWriter.newLine(); lineCount++; @@ -678,7 +809,7 @@ public class AppLaunch extends InstrumentationTestCase { } catch (IOException e) { Log.w(TAG, "Error writing the launch file", e); } - return launchTime; + return new AppLaunchResult(launchTime, cpuCycles, majorFaults); } } |