API for passing a human-readable ART profile as a startup profile
Change-Id: I5ea336d3551c91be6fb4c10fbb69231d16166c96
diff --git a/src/main/java/com/android/tools/r8/TextInputStream.java b/src/main/java/com/android/tools/r8/TextInputStream.java
new file mode 100644
index 0000000..433df09
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/TextInputStream.java
@@ -0,0 +1,16 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8;
+
+import java.io.InputStream;
+import java.nio.charset.Charset;
+
+@Keep
+public interface TextInputStream {
+
+ InputStream getInputStream();
+
+ Charset getCharset();
+}
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfile.java b/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfile.java
index a0d6204..44918e0 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfile.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/profile/StartupProfile.java
@@ -4,7 +4,10 @@
package com.android.tools.r8.experimental.startup.profile;
+import com.android.tools.r8.TextInputStream;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.startup.HumanReadableARTProfileParserBuilder;
import com.android.tools.r8.startup.StartupClassBuilder;
import com.android.tools.r8.startup.StartupMethodBuilder;
import com.android.tools.r8.startup.StartupProfileBuilder;
@@ -100,6 +103,13 @@
return addStartupItem(syntheticStartupMethodBuilder.build());
}
+ @Override
+ public StartupProfileBuilder addHumanReadableARTProfile(
+ TextInputStream textInputStream,
+ Consumer<HumanReadableARTProfileParserBuilder> parserBuilderConsumer) {
+ throw new Unimplemented();
+ }
+
private Builder addStartupItem(StartupItem startupItem) {
this.startupItemsBuilder.add(startupItem);
return this;
diff --git a/src/main/java/com/android/tools/r8/startup/ARTProfileClassRuleInfo.java b/src/main/java/com/android/tools/r8/startup/ARTProfileClassRuleInfo.java
new file mode 100644
index 0000000..59b089c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/startup/ARTProfileClassRuleInfo.java
@@ -0,0 +1,10 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.startup;
+
+import com.android.tools.r8.Keep;
+
+@Keep
+public interface ARTProfileClassRuleInfo {}
diff --git a/src/main/java/com/android/tools/r8/startup/ARTProfileMethodRuleInfo.java b/src/main/java/com/android/tools/r8/startup/ARTProfileMethodRuleInfo.java
new file mode 100644
index 0000000..02bb118
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/startup/ARTProfileMethodRuleInfo.java
@@ -0,0 +1,20 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.startup;
+
+import com.android.tools.r8.Keep;
+
+@Keep
+public interface ARTProfileMethodRuleInfo {
+
+ /** Returns true if this method rule method rule is flagged as hot ('H'). */
+ boolean isHot();
+
+ /** Returns true if this method rule method rule is flagged as startup ('S'). */
+ boolean isStartup();
+
+ /** Returns true if this method rule method rule is flagged as post-startup ('P'). */
+ boolean isPostStartup();
+}
diff --git a/src/main/java/com/android/tools/r8/startup/ARTProfileRulePredicate.java b/src/main/java/com/android/tools/r8/startup/ARTProfileRulePredicate.java
new file mode 100644
index 0000000..b99ca35
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/startup/ARTProfileRulePredicate.java
@@ -0,0 +1,17 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.startup;
+
+import com.android.tools.r8.Keep;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.MethodReference;
+
+@Keep
+public interface ARTProfileRulePredicate {
+
+ boolean testClassRule(ClassReference classReference, ARTProfileClassRuleInfo classRuleInfo);
+
+ boolean testMethodRule(MethodReference methodReference, ARTProfileMethodRuleInfo methodRuleInfo);
+}
diff --git a/src/main/java/com/android/tools/r8/startup/HumanReadableARTProfileParserBuilder.java b/src/main/java/com/android/tools/r8/startup/HumanReadableARTProfileParserBuilder.java
new file mode 100644
index 0000000..6f54ccc
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/startup/HumanReadableARTProfileParserBuilder.java
@@ -0,0 +1,24 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.startup;
+
+import com.android.tools.r8.Keep;
+
+/**
+ * A builder for configuring a parser for the human-readable ART profile format.
+ *
+ * @see <a href="https://developer.android.com/topic/performance/baselineprofiles">ART Baseline
+ * Profiles</a>
+ */
+@Keep
+public interface HumanReadableARTProfileParserBuilder {
+
+ /**
+ * Only include rules from the ART profile that satisfies the given {@param rulePredicate}.
+ *
+ * <p>By default, all rules from the ART profile are included.
+ */
+ HumanReadableARTProfileParserBuilder setRulePredicate(ARTProfileRulePredicate rulePredicate);
+}
diff --git a/src/main/java/com/android/tools/r8/startup/StartupProfileBuilder.java b/src/main/java/com/android/tools/r8/startup/StartupProfileBuilder.java
index d3626a1..85e3f15 100644
--- a/src/main/java/com/android/tools/r8/startup/StartupProfileBuilder.java
+++ b/src/main/java/com/android/tools/r8/startup/StartupProfileBuilder.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.startup;
import com.android.tools.r8.Keep;
+import com.android.tools.r8.TextInputStream;
import java.util.function.Consumer;
/** Interface for providing a startup profile to the compiler. */
@@ -40,4 +41,15 @@
*/
StartupProfileBuilder addSyntheticStartupMethod(
Consumer<SyntheticStartupMethodBuilder> syntheticStartupMethodBuilderConsumer);
+
+ /**
+ * Adds the rules from the given human-readable ART profile to the startup profile and then closes
+ * the stream.
+ *
+ * @see <a href="https://developer.android.com/topic/performance/baselineprofiles">ART Baseline
+ * Profiles</a>
+ */
+ StartupProfileBuilder addHumanReadableARTProfile(
+ TextInputStream textInputStream,
+ Consumer<HumanReadableARTProfileParserBuilder> parserBuilderConsumer);
}
diff --git a/src/test/java/com/android/tools/r8/compilerapi/startupprofile/StartupProfileApiTest.java b/src/test/java/com/android/tools/r8/compilerapi/startupprofile/StartupProfileApiTest.java
index b6572fc..2ea14dc 100644
--- a/src/test/java/com/android/tools/r8/compilerapi/startupprofile/StartupProfileApiTest.java
+++ b/src/test/java/com/android/tools/r8/compilerapi/startupprofile/StartupProfileApiTest.java
@@ -5,7 +5,10 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.D8;
import com.android.tools.r8.D8Command;
import com.android.tools.r8.DexIndexedConsumer;
@@ -16,14 +19,24 @@
import com.android.tools.r8.compilerapi.CompilerApiTest;
import com.android.tools.r8.compilerapi.CompilerApiTestRunner;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.startup.ARTProfileClassRuleInfo;
+import com.android.tools.r8.startup.ARTProfileMethodRuleInfo;
+import com.android.tools.r8.startup.ARTProfileRulePredicate;
import com.android.tools.r8.startup.StartupProfileBuilder;
import com.android.tools.r8.startup.StartupProfileProvider;
import com.android.tools.r8.utils.ThrowingConsumer;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
import java.nio.file.Path;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.List;
import java.util.function.BiConsumer;
import org.junit.Test;
@@ -40,7 +53,7 @@
return ApiTest.class;
}
- @Test
+ @Test(expected = CompilationFailedException.class)
public void testD8ArrayApi() throws Exception {
ApiTest test = new ApiTest(ApiTest.PARAMETERS);
runTest(
@@ -49,7 +62,7 @@
test.runD8(ApiTest::addStartupProfileProviderUsingArrayApi, programConsumer));
}
- @Test
+ @Test(expected = CompilationFailedException.class)
public void testD8CollectionApi() throws Exception {
ApiTest test = new ApiTest(ApiTest.PARAMETERS);
runTest(
@@ -58,7 +71,7 @@
test.runD8(ApiTest::addStartupProfileProviderUsingCollectionApi, programConsumer));
}
- @Test
+ @Test(expected = CompilationFailedException.class)
public void testR8ArrayApi() throws Exception {
ApiTest test = new ApiTest(ApiTest.PARAMETERS);
runTest(
@@ -67,7 +80,7 @@
test.runR8(ApiTest::addStartupProfileProviderUsingArrayApi, programConsumer));
}
- @Test
+ @Test(expected = CompilationFailedException.class)
public void testR8CollectionApi() throws Exception {
ApiTest test = new ApiTest(ApiTest.PARAMETERS);
runTest(
@@ -98,9 +111,36 @@
@Override
public void getStartupProfile(StartupProfileBuilder startupProfileBuilder) {
- startupProfileBuilder.addStartupClass(
- startupClassBuilder ->
- startupClassBuilder.setClassReference(Reference.classFromClass(getMockClass())));
+ // Create human-readable ART startup profile.
+ ClassReference mockClassReference = Reference.classFromClass(getMockClass());
+ ClosableByteArrayInputStream inputStream =
+ new ClosableByteArrayInputStream(mockClassReference.getDescriptor().getBytes());
+
+ // Create parser and parse ART profile.
+ List<ClassReference> seenClasses = new ArrayList<>();
+ startupProfileBuilder.addHumanReadableARTProfile(
+ new InputStreamReader(inputStream),
+ parserBuilder ->
+ parserBuilder.setRulePredicate(
+ new ARTProfileRulePredicate() {
+ @Override
+ public boolean testClassRule(
+ ClassReference reference, ARTProfileClassRuleInfo classRuleInfo) {
+ seenClasses.add(reference);
+ return true;
+ }
+
+ @Override
+ public boolean testMethodRule(
+ MethodReference reference, ARTProfileMethodRuleInfo methodRuleInfo) {
+ return true;
+ }
+ }));
+
+ // Verify rule predicate has been used and input stream is closed.
+ assertEquals(1, seenClasses.size());
+ assertEquals(mockClassReference, seenClasses.get(0));
+ assertTrue(inputStream.isClosed());
}
@Override
@@ -142,7 +182,7 @@
R8.run(commandBuilder.build());
}
- @Test
+ @Test(expected = CompilationFailedException.class)
public void testD8ArrayApi() throws Exception {
runD8(ApiTest::addStartupProfileProviderUsingArrayApi, DexIndexedConsumer.emptyConsumer());
}
@@ -154,7 +194,7 @@
commandBuilder.addStartupProfileProviders(startupProfileProviders);
}
- @Test
+ @Test(expected = CompilationFailedException.class)
public void testD8CollectionApi() throws Exception {
runD8(
ApiTest::addStartupProfileProviderUsingCollectionApi, DexIndexedConsumer.emptyConsumer());
@@ -167,7 +207,7 @@
commandBuilder.addStartupProfileProviders(startupProfileProviders);
}
- @Test
+ @Test(expected = CompilationFailedException.class)
public void testR8ArrayApi() throws Exception {
runR8(ApiTest::addStartupProfileProviderUsingArrayApi, DexIndexedConsumer.emptyConsumer());
}
@@ -179,7 +219,7 @@
commandBuilder.addStartupProfileProviders(startupProfileProviders);
}
- @Test
+ @Test(expected = CompilationFailedException.class)
public void testR8CollectionApi() throws Exception {
runR8(
ApiTest::addStartupProfileProviderUsingCollectionApi, DexIndexedConsumer.emptyConsumer());
@@ -191,5 +231,24 @@
Collections.singleton(startupProfileProvider);
commandBuilder.addStartupProfileProviders(startupProfileProviders);
}
+
+ private static class ClosableByteArrayInputStream extends ByteArrayInputStream {
+
+ private boolean closed;
+
+ public ClosableByteArrayInputStream(byte[] buf) {
+ super(buf);
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ closed = true;
+ }
+
+ public boolean isClosed() {
+ return closed;
+ }
+ }
}
}
diff --git a/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java b/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java
index a9ca8c5..988d188 100644
--- a/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java
+++ b/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java
@@ -13,10 +13,13 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TextInputStream;
import com.android.tools.r8.ThrowableConsumer;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.experimental.startup.instrumentation.StartupInstrumentationOptions;
import com.android.tools.r8.experimental.startup.profile.StartupProfileParser;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.startup.HumanReadableARTProfileParserBuilder;
import com.android.tools.r8.startup.StartupClassBuilder;
import com.android.tools.r8.startup.StartupMethodBuilder;
import com.android.tools.r8.startup.StartupProfileBuilder;
@@ -80,6 +83,13 @@
startupItemConsumer.accept(syntheticStartupMethodBuilder.build());
return this;
}
+
+ @Override
+ public StartupProfileBuilder addHumanReadableARTProfile(
+ TextInputStream textInputStream,
+ Consumer<HumanReadableARTProfileParserBuilder> parserBuilderConsumer) {
+ throw new Unimplemented();
+ }
};
}
diff --git a/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1 b/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
index 4753c76..f85515d 100644
--- a/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
+++ b/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
@@ -1 +1 @@
-46ac3bedbdba8732e48d13fcc94967f43ae1d91b
\ No newline at end of file
+c750aa168121238836d3ef622949611f3d97f66a
\ No newline at end of file