Fix speed-profile compilation in rules.
Bug: b/169651233
Test: CompilationFilterRuleTest
Change-Id: I01bd675f7263087b1847096f4ae280464a5f629c
diff --git a/libraries/health/rules/src/android/platform/test/rule/CompilationFilterRule.java b/libraries/health/rules/src/android/platform/test/rule/CompilationFilterRule.java
index 092aa8d..1316fe9 100644
--- a/libraries/health/rules/src/android/platform/test/rule/CompilationFilterRule.java
+++ b/libraries/health/rules/src/android/platform/test/rule/CompilationFilterRule.java
@@ -18,6 +18,7 @@
import static java.util.stream.Collectors.joining;
+import android.os.SystemClock;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
@@ -26,16 +27,23 @@
import org.junit.runner.Description;
import org.junit.runners.model.InitializationError;
+import java.util.HashSet;
+import java.util.Set;
+
/** This rule compiles the applications with the specified filter, or skips if unspecified. */
public class CompilationFilterRule extends TestWatcher {
//
private static final String LOG_TAG = CompilationFilterRule.class.getSimpleName();
// Compilation constants
@VisibleForTesting static final String COMPILE_CMD_FORMAT = "cmd package compile -f -m %s %s";
+ @VisibleForTesting static final String DUMP_PROFILE_CMD = "killall -s SIGUSR1 %s";
private static final ImmutableList<String> COMPILE_FILTER_LIST =
ImmutableList.of("speed", "speed-profile", "quicken", "verify");
+ @VisibleForTesting static final String SPEED_PROFILE_FILTER = "speed-profile";
+ private static final String PROFILE_SAVE_TIMEOUT = "profile-save-timeout";
@VisibleForTesting static final String COMPILE_FILTER_OPTION = "compilation-filter";
@VisibleForTesting static final String COMPILE_SUCCESS = "Success";
+ private static Set<String> mCompiledTests = new HashSet<>();
private final String[] mApplications;
@@ -48,9 +56,12 @@
}
@Override
- protected void starting(Description description) {
+ protected void finished(Description description) {
// Identify the filter option to use.
String filter = getArguments().getString(COMPILE_FILTER_OPTION);
+ // Default speed profile save timeout set to 5 secs.
+ long profileSaveTimeout = Integer
+ .parseInt(getArguments().getString(PROFILE_SAVE_TIMEOUT, "5000"));
if (filter == null) {
// No option provided, default to a no-op.
Log.d(LOG_TAG, "Skipping complation because filter option is unset.");
@@ -61,13 +72,38 @@
String.format(
"Unknown compiler filter: %s, not part of %s", filter, filterOptions));
}
- // Compile each application in sequence.
- for (String app : mApplications) {
- String response = executeShellCommand(String.format(COMPILE_CMD_FORMAT, filter, app));
- if (!response.contains(COMPILE_SUCCESS)) {
- Log.d(LOG_TAG, String.format("Received response: %s", response));
- throw new RuntimeException(String.format("Failed to compile %s.", app));
+ // Profile varies based on the test even for the same app. Tracking the test id to make
+ // sure the test compiled once after the first iteration of the test.
+ String testId = description.getDisplayName();
+ if (!mCompiledTests.contains(testId)) {
+ for (String app : mApplications) {
+ // For speed profile compilation, ART team recommended to wait for 5 secs when app
+ // is in the foreground, dump the profile, wait for another 5 secs before
+ // speed-profile compilation.
+ if (filter.equalsIgnoreCase(SPEED_PROFILE_FILTER)) {
+ SystemClock.sleep(profileSaveTimeout);
+ // Send SIGUSR1 to force dumping a profile.
+ String response = executeShellCommand(String.format(DUMP_PROFILE_CMD, app));
+ if (!response.isEmpty()) {
+ Log.d(LOG_TAG,
+ String.format("Received dump profile cmd response: %s", response));
+ throw new RuntimeException(
+ String.format("Failed to dump profile %s.", app));
+ }
+ // killall is async, wait few seconds to let the app save the profile.
+ SystemClock.sleep(profileSaveTimeout);
+ }
+ String response = executeShellCommand(
+ String.format(COMPILE_CMD_FORMAT, filter, app));
+ if (!response.contains(COMPILE_SUCCESS)) {
+ Log.d(LOG_TAG, String.format("Received compile cmd response: %s", response));
+ throw new RuntimeException(String.format("Failed to compile %s.", app));
+ } else {
+ mCompiledTests.add(testId);
+ }
}
+ } else {
+ Log.d(LOG_TAG, String.format("Test %s already compiled", testId));
}
}
}
diff --git a/libraries/health/rules/tests/src/android/platform/test/rule/CompilationFilterRuleTest.java b/libraries/health/rules/tests/src/android/platform/test/rule/CompilationFilterRuleTest.java
index 42a444d..974c032 100644
--- a/libraries/health/rules/tests/src/android/platform/test/rule/CompilationFilterRuleTest.java
+++ b/libraries/health/rules/tests/src/android/platform/test/rule/CompilationFilterRuleTest.java
@@ -49,8 +49,8 @@
public void testAppToCompile_badFilterThrows() throws Throwable {
Bundle badFilterBundle = new Bundle();
badFilterBundle.putString(CompilationFilterRule.COMPILE_FILTER_OPTION, "bad-option");
- TestableCompilationFilterRule rule =
- new TestableCompilationFilterRule(badFilterBundle, "example.package");
+ TestableCompilationFilterRule rule = new TestableCompilationFilterRule(badFilterBundle,
+ "example.package");
try {
rule.apply(rule.getTestStatement(), TEST_DESC).evaluate();
fail("An exception should have been thrown about bad filter, but wasn't.");
@@ -58,19 +58,19 @@
}
}
- /** Tests that this rule will compile one app before the test, if supplied. */
+ /** Tests that this rule will compile one app after the test, if supplied. */
@Test
public void testAppToCompile_failCompilationThrows() throws Throwable {
- Bundle badFilterBundle = new Bundle();
- badFilterBundle.putString(CompilationFilterRule.COMPILE_FILTER_OPTION, "speed");
- TestableCompilationFilterRule rule =
- new TestableCompilationFilterRule(badFilterBundle, "example.package") {
- @Override
- protected String executeShellCommand(String cmd) {
- super.executeShellCommand(cmd);
- return "Error";
- }
- };
+ Bundle filterBundle = new Bundle();
+ filterBundle.putString(CompilationFilterRule.COMPILE_FILTER_OPTION, "speed");
+ TestableCompilationFilterRule rule = new TestableCompilationFilterRule(filterBundle,
+ "example.package") {
+ @Override
+ protected String executeShellCommand(String cmd) {
+ super.executeShellCommand(cmd);
+ return "Error";
+ }
+ };
try {
rule.apply(rule.getTestStatement(), TEST_DESC).evaluate();
fail("An exception should have been thrown about compilation failure, but wasn't.");
@@ -78,48 +78,81 @@
}
}
- /** Tests that this rule will compile one app before the test, if supplied. */
+ /** Tests that this rule will compile one app after the test, if supplied. */
@Test
public void testOneAppToCompile() throws Throwable {
- Bundle badFilterBundle = new Bundle();
- badFilterBundle.putString(CompilationFilterRule.COMPILE_FILTER_OPTION, "speed");
- TestableCompilationFilterRule rule =
- new TestableCompilationFilterRule(badFilterBundle, "example.package") {
- @Override
- protected String executeShellCommand(String cmd) {
- super.executeShellCommand(cmd);
- return CompilationFilterRule.COMPILE_SUCCESS;
- }
- };
- rule.apply(rule.getTestStatement(), TEST_DESC).evaluate();
- String compileCmd =
- String.format(CompilationFilterRule.COMPILE_CMD_FORMAT, "speed", "example.package");
- assertThat(rule.getOperations()).containsExactly(compileCmd, "test").inOrder();
+ Bundle filterBundle = new Bundle();
+ filterBundle.putString(CompilationFilterRule.COMPILE_FILTER_OPTION, "speed");
+ TestableCompilationFilterRule rule = new TestableCompilationFilterRule(filterBundle,
+ "example.package") {
+ @Override
+ protected String executeShellCommand(String cmd) {
+ super.executeShellCommand(cmd);
+ return CompilationFilterRule.COMPILE_SUCCESS;
+ }
+ };
+ rule.apply(rule.getTestStatement(), Description.createTestDescription("clzz", "mthd1"))
+ .evaluate();
+ String compileCmd = String.format(CompilationFilterRule.COMPILE_CMD_FORMAT, "speed",
+ "example.package");
+ assertThat(rule.getOperations()).containsExactly("test", compileCmd)
+ .inOrder();
}
- /** Tests that this rule will compile multiple apps before the test, if supplied. */
+ /** Tests that this rule will compile multiple apps after the test, if supplied. */
@Test
public void testMultipleAppsToCompile() throws Throwable {
- Bundle badFilterBundle = new Bundle();
- badFilterBundle.putString(CompilationFilterRule.COMPILE_FILTER_OPTION, "speed");
- TestableCompilationFilterRule rule =
- new TestableCompilationFilterRule(
- badFilterBundle, "example.package1", "example.package2") {
- @Override
- protected String executeShellCommand(String cmd) {
- super.executeShellCommand(cmd);
- return CompilationFilterRule.COMPILE_SUCCESS;
- }
- };
- rule.apply(rule.getTestStatement(), TEST_DESC).evaluate();
- String compileCmd1 =
- String.format(
- CompilationFilterRule.COMPILE_CMD_FORMAT, "speed", "example.package1");
- String compileCmd2 =
- String.format(
- CompilationFilterRule.COMPILE_CMD_FORMAT, "speed", "example.package2");
+ Bundle filterBundle = new Bundle();
+ filterBundle.putString(CompilationFilterRule.COMPILE_FILTER_OPTION, "speed");
+ TestableCompilationFilterRule rule = new TestableCompilationFilterRule(filterBundle,
+ "example.package1", "example.package2") {
+ @Override
+ protected String executeShellCommand(String cmd) {
+ super.executeShellCommand(cmd);
+ return CompilationFilterRule.COMPILE_SUCCESS;
+ }
+ };
+ rule.apply(rule.getTestStatement(), Description.createTestDescription("clzz", "mthd2"))
+ .evaluate();
+ String compileCmd1 = String.format(
+ CompilationFilterRule.COMPILE_CMD_FORMAT, "speed", "example.package1");
+ String compileCmd2 = String.format(
+ CompilationFilterRule.COMPILE_CMD_FORMAT, "speed", "example.package2");
assertThat(rule.getOperations())
- .containsExactly(compileCmd1, compileCmd2, "test")
+ .containsExactly("test", compileCmd1, compileCmd2)
+ .inOrder();
+ }
+
+ /** Tests that this rule will speed profile compile multiple apps after the test,
+ * if supplied. */
+ @Test
+ public void testMultipleAppsToCompileInSpeedProfile() throws Throwable {
+ Bundle filterBundle = new Bundle();
+ filterBundle.putString(CompilationFilterRule.COMPILE_FILTER_OPTION,
+ CompilationFilterRule.SPEED_PROFILE_FILTER);
+ TestableCompilationFilterRule rule = new TestableCompilationFilterRule(filterBundle,
+ "example.package1", "example.package2") {
+ @Override
+ protected String executeShellCommand(String cmd) {
+ super.executeShellCommand(cmd);
+ if (cmd.contains("killall -s SIGUSR1")) {
+ return "";
+ }
+ return CompilationFilterRule.COMPILE_SUCCESS;
+ }
+ };
+ rule.apply(rule.getTestStatement(), Description.createTestDescription("clzz", "mthd3"))
+ .evaluate();
+ String dumpCmd1 = String.format(CompilationFilterRule.DUMP_PROFILE_CMD,
+ "example.package1");
+ String compileCmd1 = String.format(CompilationFilterRule.COMPILE_CMD_FORMAT,
+ CompilationFilterRule.SPEED_PROFILE_FILTER, "example.package1");
+ String dumpCmd2 = String.format(CompilationFilterRule.DUMP_PROFILE_CMD,
+ "example.package2");
+ String compileCmd2 = String.format(CompilationFilterRule.COMPILE_CMD_FORMAT,
+ CompilationFilterRule.SPEED_PROFILE_FILTER, "example.package2");
+ assertThat(rule.getOperations())
+ .containsExactly("test", dumpCmd1, compileCmd1, dumpCmd2, compileCmd2)
.inOrder();
}