Enable concurrent parsing in trace references
This makes the following improvements to trace references:
* Create an ExecutorService for reading the app concurrently
* Implement the new API for async parsing in the ProgramResourceProviders used by trace references
Bug: b/448130900
Change-Id: Ide3a22dbc841f5fb322b71d87367285eeede5345
diff --git a/src/main/java/com/android/tools/r8/tracereferences/TraceReferences.java b/src/main/java/com/android/tools/r8/tracereferences/TraceReferences.java
index 9d0ef51..ade3e8b 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/TraceReferences.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/TraceReferences.java
@@ -24,11 +24,13 @@
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.timing.Timing;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
+import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
@KeepForApi
@@ -38,6 +40,11 @@
runForTesting(command, command.getInternalOptions());
}
+ public static void run(TraceReferencesCommand command, ExecutorService executorService)
+ throws CompilationFailedException {
+ runForTesting(command, command.getInternalOptions(), executorService);
+ }
+
private static void forEachDescriptor(ProgramResourceProvider provider, Consumer<String> consumer)
throws ResourceException, IOException {
for (ProgramResource programResource : provider.getProgramResources()) {
@@ -63,11 +70,18 @@
static void runForTesting(TraceReferencesCommand command, InternalOptions options)
throws CompilationFailedException {
- ExceptionUtils.withCompilationHandler(
- command.getReporter(), () -> runInternal(command, options));
+ runForTesting(command, options, ThreadUtils.getExecutorService(options));
}
- static void runInternal(TraceReferencesCommand command, InternalOptions options)
+ static void runForTesting(
+ TraceReferencesCommand command, InternalOptions options, ExecutorService executorService)
+ throws CompilationFailedException {
+ ExceptionUtils.withCompilationHandler(
+ command.getReporter(), () -> runInternal(command, options, executorService));
+ }
+
+ static void runInternal(
+ TraceReferencesCommand command, InternalOptions options, ExecutorService executorService)
throws IOException, ResourceException {
AndroidApp.Builder builder = AndroidApp.builder();
command.getLibrary().forEach(builder::addLibraryResourceProvider);
@@ -84,7 +98,7 @@
AppView.createForTracer(
AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(
new ApplicationReader(builder.build(), options, Timing.empty())
- .readDirectSingleThreaded(),
+ .readDirect(executorService),
ClassToFeatureSplitMap.createEmptyClassToFeatureSplitMap(),
MainDexInfo.none(),
GlobalSyntheticsStrategy.forSingleOutputMode()));
diff --git a/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesCommand.java b/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesCommand.java
index 429b912..462e396 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesCommand.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/TraceReferencesCommand.java
@@ -39,6 +39,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Set;
+import java.util.function.Consumer;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
@@ -214,15 +215,20 @@
public ProgramResource getProgramResource(String descriptor) {
return descriptor.equals(this.descriptor) ? programResource : null;
}
+
+ @Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) {
+ consumer.accept(programResource);
+ }
}
- private ClassFileResourceProvider singleClassFileClassFileResourceProvider(Path file)
+ private static ClassFileResourceProvider singleClassFileClassFileResourceProvider(Path file)
throws IOException {
return new SingleClassClassFileResourceProvider(
new PathOrigin(file), Files.readAllBytes(file));
}
- private ProgramResourceProvider singleClassFileProgramResourceProvider(Path file)
+ private static ProgramResourceProvider singleClassFileProgramResourceProvider(Path file)
throws IOException {
byte[] bytes = Files.readAllBytes(file);
String descriptor = extractClassDescriptor(bytes);
@@ -230,9 +236,33 @@
@Override
public Collection<ProgramResource> getProgramResources() {
- return ImmutableList.of(
- ProgramResource.fromBytes(
- new PathOrigin(file), Kind.CF, bytes, ImmutableSet.of(descriptor)));
+ return Collections.singletonList(createProgramResource());
+ }
+
+ @Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) {
+ consumer.accept(createProgramResource());
+ }
+
+ private ProgramResource createProgramResource() {
+ return ProgramResource.fromBytes(
+ new PathOrigin(file), Kind.CF, bytes, ImmutableSet.of(descriptor));
+ }
+ };
+ }
+
+ private static ProgramResourceProvider singleDexFileProgramResourceProvider(Path file) {
+ ProgramResource programResource = ProgramResource.fromFile(Kind.DEX, file);
+ return new ProgramResourceProvider() {
+
+ @Override
+ public Collection<ProgramResource> getProgramResources() {
+ return Collections.singletonList(programResource);
+ }
+
+ @Override
+ public void getProgramResources(Consumer<ProgramResource> consumer) {
+ consumer.accept(programResource);
}
};
}
@@ -277,15 +307,7 @@
error(new ExceptionDiagnostic(e));
}
} else if (isDexFile(file)) {
- traceSourceBuilder.add(
- new ProgramResourceProvider() {
- ProgramResource dexResource = ProgramResource.fromFile(Kind.DEX, file);
-
- @Override
- public Collection<ProgramResource> getProgramResources() {
- return Collections.singletonList(dexResource);
- }
- });
+ traceSourceBuilder.add(singleDexFileProgramResourceProvider(file));
} else {
error(new StringDiagnostic("Unsupported source file type", new PathOrigin(file)));
}