Add a --startup-profile flag to the D8 CLI
Bug: b/245880650
Change-Id: I5ce88574ecd435b63e459be570252fe47d099da7
diff --git a/src/main/java/com/android/tools/r8/D8CommandParser.java b/src/main/java/com/android/tools/r8/D8CommandParser.java
index c85fe0d..0336de9 100644
--- a/src/main/java/com/android/tools/r8/D8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/D8CommandParser.java
@@ -5,6 +5,7 @@
import static com.android.tools.r8.ParseFlagInfoImpl.flag1;
+import com.android.tools.r8.experimental.startup.StartupProfileProviderUtils;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
import com.android.tools.r8.utils.ExceptionDiagnostic;
@@ -24,6 +25,8 @@
public class D8CommandParser extends BaseCompilerCommandParser<D8Command, D8Command.Builder> {
+ static final String STARTUP_PROFILE_FLAG = "--startup-profile";
+
private static final Set<String> OPTIONS_WITH_PARAMETER =
ImmutableSet.of(
"--output",
@@ -37,7 +40,8 @@
"--main-dex-list-output",
"--desugared-lib",
"--desugared-lib-pg-conf-output",
- THREAD_COUNT_FLAG);
+ THREAD_COUNT_FLAG,
+ STARTUP_PROFILE_FLAG);
public static List<ParseFlagInfo> getFlags() {
return ImmutableList.<ParseFlagInfo>builder()
@@ -79,6 +83,7 @@
.add(ParseFlagInfoImpl.getThreadCount())
.add(ParseFlagInfoImpl.getMapDiagnostics())
.add(ParseFlagInfoImpl.getAndroidPlatformBuild())
+ .add(ParseFlagInfoImpl.getStartupProfile())
.add(ParseFlagInfoImpl.getVersion("d8"))
.add(ParseFlagInfoImpl.getHelp())
.build();
@@ -305,6 +310,10 @@
builder.setDesugaredLibraryKeepRuleConsumer(consumer);
} else if (arg.equals("--android-platform-build")) {
builder.setAndroidPlatformBuild(true);
+ } else if (arg.equals(STARTUP_PROFILE_FLAG)) {
+ Path startupProfilePath = Paths.get(nextArg);
+ builder.addStartupProfileProviders(
+ StartupProfileProviderUtils.createFromHumanReadableArtProfile(startupProfilePath));
} else if (arg.startsWith("--")) {
if (tryParseAssertionArgument(builder, arg, origin)) {
continue;
diff --git a/src/main/java/com/android/tools/r8/ParseFlagInfoImpl.java b/src/main/java/com/android/tools/r8/ParseFlagInfoImpl.java
index af8d407..595a0b0 100644
--- a/src/main/java/com/android/tools/r8/ParseFlagInfoImpl.java
+++ b/src/main/java/com/android/tools/r8/ParseFlagInfoImpl.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.BaseCompilerCommandParser.MAP_DIAGNOSTICS;
import static com.android.tools.r8.BaseCompilerCommandParser.MIN_API_FLAG;
import static com.android.tools.r8.BaseCompilerCommandParser.THREAD_COUNT_FLAG;
+import static com.android.tools.r8.D8CommandParser.STARTUP_PROFILE_FLAG;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.google.common.collect.ImmutableList;
@@ -163,6 +164,10 @@
"is assumed to be the version specified by --min-api.");
}
+ public static ParseFlagInfoImpl getStartupProfile() {
+ return flag1(STARTUP_PROFILE_FLAG, "<file>", "Startup profile <file> to use for dex layout.");
+ }
+
public static ParseFlagInfoImpl flag0(String flag, String... help) {
return flag(flag, Collections.emptyList(), Arrays.asList(help));
}
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfileProviderUtils.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfileProviderUtils.java
index 0eef997..a4b0f5e 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfileProviderUtils.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfileProviderUtils.java
@@ -4,16 +4,14 @@
package com.android.tools.r8.experimental.startup;
+import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
+
import com.android.tools.r8.experimental.startup.profile.StartupItem;
import com.android.tools.r8.experimental.startup.profile.StartupProfile;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
import com.android.tools.r8.profile.art.ArtProfileBuilderUtils.SyntheticToSyntheticContextGeneralization;
-import com.android.tools.r8.profile.art.ArtProfileClassRuleInfo;
-import com.android.tools.r8.profile.art.ArtProfileMethodRuleInfo;
-import com.android.tools.r8.profile.art.ArtProfileRulePredicate;
-import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.profile.art.HumanReadableArtProfileParserBuilder;
import com.android.tools.r8.startup.StartupProfileBuilder;
import com.android.tools.r8.startup.StartupProfileProvider;
import com.android.tools.r8.startup.diagnostic.MissingStartupProfileItemsDiagnostic;
@@ -22,33 +20,23 @@
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Path;
+import java.util.function.Consumer;
public class StartupProfileProviderUtils {
public static StartupProfileProvider createFromHumanReadableArtProfile(Path path) {
+ return createFromHumanReadableArtProfile(path, emptyConsumer());
+ }
+
+ public static StartupProfileProvider createFromHumanReadableArtProfile(
+ Path path, Consumer<HumanReadableArtProfileParserBuilder> parserBuilderConsumer) {
return new StartupProfileProvider() {
@Override
public void getStartupProfile(StartupProfileBuilder startupProfileBuilder) {
try {
startupProfileBuilder.addHumanReadableArtProfile(
- new UTF8TextInputStream(path),
- profileParserBuilder ->
- profileParserBuilder.setRulePredicate(
- new ArtProfileRulePredicate() {
- @Override
- public boolean testClassRule(
- ClassReference classReference, ArtProfileClassRuleInfo classRuleInfo) {
- return false;
- }
-
- @Override
- public boolean testMethodRule(
- MethodReference methodReference,
- ArtProfileMethodRuleInfo methodRuleInfo) {
- return methodRuleInfo.isStartup();
- }
- }));
+ new UTF8TextInputStream(path), parserBuilderConsumer);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
diff --git a/src/test/java/com/android/tools/r8/D8CommandTest.java b/src/test/java/com/android/tools/r8/D8CommandTest.java
index e33cb93..a90db2a 100644
--- a/src/test/java/com/android/tools/r8/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/D8CommandTest.java
@@ -21,9 +21,15 @@
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.dex.Marker.Tool;
+import com.android.tools.r8.experimental.startup.profile.StartupItem;
+import com.android.tools.r8.experimental.startup.profile.StartupMethod;
+import com.android.tools.r8.experimental.startup.profile.StartupProfile;
import com.android.tools.r8.origin.EmbeddedOrigin;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.profile.art.ArtProfileBuilderUtils.SyntheticToSyntheticContextGeneralization;
import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.startup.StartupProfileProvider;
+import com.android.tools.r8.startup.diagnostic.MissingStartupProfileItemsDiagnostic;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.FileUtils;
@@ -773,6 +779,60 @@
assertTrue(parse("--android-platform-build").getAndroidPlatformBuild());
}
+ @Test
+ public void startupProfileFlagAbsentTest() throws Exception {
+ assertTrue(parse().getStartupProfileProviders().isEmpty());
+ }
+
+ @Test
+ public void startupProfileFlagPresentTest() throws Exception {
+ // Create a simple profile.
+ Path profile = temp.newFile("profile.txt").toPath();
+ String profileRule = "Lfoo/bar/Baz;->qux()V";
+ FileUtils.writeTextFile(profile, profileRule);
+
+ // Pass the profile on the command line.
+ List<StartupProfileProvider> startupProfileProviders =
+ parse("--startup-profile", profile.toString()).getStartupProfileProviders();
+ assertEquals(1, startupProfileProviders.size());
+
+ // Construct the internal profile representation using the provider.
+ InternalOptions options = new InternalOptions();
+ MissingStartupProfileItemsDiagnostic.Builder missingStartupProfileItemsDiagnosticBuilder =
+ MissingStartupProfileItemsDiagnostic.Builder.nop();
+ StartupProfileProvider startupProfileProvider = startupProfileProviders.get(0);
+ SyntheticToSyntheticContextGeneralization syntheticToSyntheticContextGeneralization =
+ SyntheticToSyntheticContextGeneralization.createForD8();
+ StartupProfile.Builder startupProfileBuilder =
+ StartupProfile.builder(
+ options,
+ missingStartupProfileItemsDiagnosticBuilder,
+ startupProfileProvider,
+ syntheticToSyntheticContextGeneralization);
+ startupProfileProvider.getStartupProfile(startupProfileBuilder);
+
+ // Verify we found the same rule.
+ StartupProfile startupProfile = startupProfileBuilder.build();
+ Collection<StartupItem> startupItems = startupProfile.getStartupItems();
+ assertEquals(1, startupItems.size());
+ StartupItem startupItem = startupItems.iterator().next();
+ assertTrue(startupItem.isStartupMethod());
+ StartupMethod startupMethod = startupItem.asStartupMethod();
+ assertEquals(profileRule, startupMethod.getReference().toSmaliString());
+ }
+
+ @Test
+ public void startupProfileFlagMissingParameterTest() {
+ String expectedErrorContains = "Missing parameter for --startup-profile.";
+ try {
+ DiagnosticsChecker.checkErrorsContains(
+ expectedErrorContains, handler -> parse(handler, "--startup-profile"));
+ fail("Expected failure");
+ } catch (CompilationFailedException e) {
+ // Expected.
+ }
+ }
+
@Override
String[] requiredArgsForTest() {
return new String[0];