Emit build speed and threads in metadata
Bug: b/367558466
Change-Id: Iec25f5f9305dc286b96827e0a5e33c253c7087fc
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 8fccc8d..ae6a649 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -328,7 +328,8 @@
reportSyntheticInformation(appView);
if (options.isGeneratingClassFiles()) {
- new CfApplicationWriter(appView, marker).write(options.getClassFileConsumer(), inputApp);
+ new CfApplicationWriter(appView, marker)
+ .write(options.getClassFileConsumer(), executor, inputApp);
} else {
ApplicationWriter.create(appView, marker).write(executor, inputApp);
}
diff --git a/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java b/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
index 4b2ab5a..f0445dd 100644
--- a/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
+++ b/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
@@ -135,7 +135,7 @@
} else {
assert options.isGeneratingClassFiles();
new CfApplicationWriter(appView, options.getMarker())
- .write(options.getClassFileConsumer(), app);
+ .write(options.getClassFileConsumer(), executorService, app);
}
} catch (ExecutionException e) {
throw unwrapExecutionException(e);
diff --git a/src/main/java/com/android/tools/r8/L8.java b/src/main/java/com/android/tools/r8/L8.java
index 1c1e64c..f744a67 100644
--- a/src/main/java/com/android/tools/r8/L8.java
+++ b/src/main/java/com/android/tools/r8/L8.java
@@ -149,7 +149,8 @@
appView));
new GenericSignatureRewriter(appView).run(appView.appInfo().classes(), executor);
- new CfApplicationWriter(appView, options.getMarker()).write(options.getClassFileConsumer());
+ new CfApplicationWriter(appView, options.getMarker())
+ .write(options.getClassFileConsumer(), executor);
options.printWarnings();
} catch (ExecutionException e) {
throw unwrapExecutionException(e);
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 93926dd..46f11fd 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -222,7 +222,8 @@
Marker marker = options.getMarker();
assert marker != null;
if (options.isGeneratingClassFiles()) {
- new CfApplicationWriter(appView, marker).write(options.getClassFileConsumer(), inputApp);
+ new CfApplicationWriter(appView, marker)
+ .write(options.getClassFileConsumer(), executorService, inputApp);
} else {
ApplicationWriter.create(appView, marker).write(executorService, inputApp);
}
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index b6c9ae4..52ae388 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -739,6 +739,7 @@
}
private R8Command makeR8Command() {
+ long created = System.nanoTime();
Reporter reporter = getReporter();
DexItemFactory factory = new DexItemFactory();
List<ProguardConfigurationRule> mainDexKeepRules =
@@ -839,7 +840,8 @@
resourceShrinkerConfiguration,
keepSpecifications,
buildMetadataConsumer,
- partialCompilationConfiguration);
+ partialCompilationConfiguration,
+ created);
if (inputDependencyGraphConsumer != null) {
inputDependencyGraphConsumer.finished();
@@ -1062,6 +1064,7 @@
private final ResourceShrinkerConfiguration resourceShrinkerConfiguration;
private final Consumer<? super R8BuildMetadata> buildMetadataConsumer;
private final R8PartialCompilationConfiguration partialCompilationConfiguration;
+ private final long created;
/** Get a new {@link R8Command.Builder}. */
public static Builder builder() {
@@ -1162,7 +1165,8 @@
ResourceShrinkerConfiguration resourceShrinkerConfiguration,
List<KeepSpecificationSource> keepSpecifications,
Consumer<? super R8BuildMetadata> buildMetadataConsumer,
- R8PartialCompilationConfiguration partialCompilationConfiguration) {
+ R8PartialCompilationConfiguration partialCompilationConfiguration,
+ long created) {
super(
inputApp,
mode,
@@ -1213,6 +1217,7 @@
this.resourceShrinkerConfiguration = resourceShrinkerConfiguration;
this.buildMetadataConsumer = buildMetadataConsumer;
this.partialCompilationConfiguration = partialCompilationConfiguration;
+ this.created = created;
}
private R8Command(boolean printHelp, boolean printVersion) {
@@ -1243,6 +1248,7 @@
resourceShrinkerConfiguration = null;
buildMetadataConsumer = null;
partialCompilationConfiguration = null;
+ created = -1;
}
public DexItemFactory getDexItemFactory() {
@@ -1267,6 +1273,7 @@
@Override
InternalOptions getInternalOptions() {
InternalOptions internal = new InternalOptions(getMode(), proguardConfiguration, getReporter());
+ internal.created = created;
assert !internal.testing.allowOutlinerInterfaceArrayArguments; // Only allow in tests.
internal.programConsumer = getProgramConsumer();
internal.setMinApiLevel(AndroidApiLevel.getAndroidApiLevel(getMinApiLevel()));
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index 9554f4e..c1b8ee6 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -452,7 +452,7 @@
options.reporter.failIfPendingErrors();
// Supply info to all additional resource consumers.
if (!(programConsumer instanceof ConvertedCfFiles)) {
- supplyAdditionalConsumers(appView, virtualFiles);
+ supplyAdditionalConsumers(appView, executorService, virtualFiles);
}
} finally {
timing.end();
@@ -655,7 +655,8 @@
}
@SuppressWarnings("DefaultCharset")
- public static void supplyAdditionalConsumers(AppView<?> appView, List<VirtualFile> virtualFiles) {
+ public static void supplyAdditionalConsumers(
+ AppView<?> appView, ExecutorService executorService, List<VirtualFile> virtualFiles) {
InternalOptions options = appView.options();
Reporter reporter = options.reporter;
appView.getArtProfileCollection().supplyConsumers(appView);
@@ -711,7 +712,7 @@
if (options.r8BuildMetadataConsumer != null) {
assert appView.hasClassHierarchy();
options.r8BuildMetadataConsumer.accept(
- BuildMetadataFactory.create(appView.withClassHierarchy(), virtualFiles));
+ BuildMetadataFactory.create(appView.withClassHierarchy(), executorService, virtualFiles));
}
}
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
index 20de02a..6ccbf71 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -66,6 +66,7 @@
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
+import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
import java.util.function.Predicate;
import org.objectweb.asm.AnnotationVisitor;
@@ -113,15 +114,16 @@
return appView.getNamingLens();
}
- public void write(ClassFileConsumer consumer) {
+ public void write(ClassFileConsumer consumer, ExecutorService executorService) {
assert !options.hasMappingFileSupport();
- write(consumer, null);
+ write(consumer, executorService, null);
}
- public void write(ClassFileConsumer consumer, AndroidApp inputApp) {
+ public void write(
+ ClassFileConsumer consumer, ExecutorService executorService, AndroidApp inputApp) {
application.timing.begin("CfApplicationWriter.write");
try {
- writeApplication(inputApp, consumer);
+ writeApplication(inputApp, consumer, executorService);
} finally {
application.timing.end();
}
@@ -138,7 +140,8 @@
return true;
}
- private void writeApplication(AndroidApp inputApp, ClassFileConsumer consumer) {
+ private void writeApplication(
+ AndroidApp inputApp, ClassFileConsumer consumer, ExecutorService executorService) {
ProguardMapId proguardMapId = null;
if (options.hasMappingFileSupport()) {
assert marker.isPresent();
@@ -187,7 +190,7 @@
}
globalsConsumer.finished(appView);
}
- ApplicationWriter.supplyAdditionalConsumers(appView, Collections.emptyList());
+ ApplicationWriter.supplyAdditionalConsumers(appView, executorService, Collections.emptyList());
}
private void writeClassCatchingErrors(
diff --git a/src/main/java/com/android/tools/r8/metadata/R8BuildMetadata.java b/src/main/java/com/android/tools/r8/metadata/R8BuildMetadata.java
index c3f13b0..096f514 100644
--- a/src/main/java/com/android/tools/r8/metadata/R8BuildMetadata.java
+++ b/src/main/java/com/android/tools/r8/metadata/R8BuildMetadata.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.metadata.impl.R8ApiModelingOptionsImpl;
import com.android.tools.r8.metadata.impl.R8BaselineProfileRewritingOptionsImpl;
import com.android.tools.r8.metadata.impl.R8BuildMetadataImpl;
+import com.android.tools.r8.metadata.impl.R8CompilationInfoImpl;
import com.android.tools.r8.metadata.impl.R8KeepAttributesOptionsImpl;
import com.android.tools.r8.metadata.impl.R8LibraryDesugaringOptionsImpl;
import com.android.tools.r8.metadata.impl.R8OptionsImpl;
@@ -28,6 +29,7 @@
.registerTypeAdapter(
R8BaselineProfileRewritingOptions.class,
deserializeTo(R8BaselineProfileRewritingOptionsImpl.class))
+ .registerTypeAdapter(R8CompilationInfo.class, deserializeTo(R8CompilationInfoImpl.class))
.registerTypeAdapter(
R8KeepAttributesOptions.class, deserializeTo(R8KeepAttributesOptionsImpl.class))
.registerTypeAdapter(
@@ -53,6 +55,8 @@
*/
R8BaselineProfileRewritingOptions getBaselineProfileRewritingOptions();
+ R8CompilationInfo getCompilationInfo();
+
/**
* @return null if not compiling to dex.
*/
diff --git a/src/main/java/com/android/tools/r8/metadata/R8CompilationInfo.java b/src/main/java/com/android/tools/r8/metadata/R8CompilationInfo.java
new file mode 100644
index 0000000..2bc4a6a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/metadata/R8CompilationInfo.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2024, 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.metadata;
+
+import com.android.tools.r8.keepanno.annotations.KeepForApi;
+
+@KeepForApi
+public interface R8CompilationInfo {
+
+ long getBuildTime();
+
+ long getNumberOfThreads();
+}
diff --git a/src/main/java/com/android/tools/r8/metadata/impl/BuildMetadataFactory.java b/src/main/java/com/android/tools/r8/metadata/impl/BuildMetadataFactory.java
index 69e906c..31a76a8 100644
--- a/src/main/java/com/android/tools/r8/metadata/impl/BuildMetadataFactory.java
+++ b/src/main/java/com/android/tools/r8/metadata/impl/BuildMetadataFactory.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.metadata.R8BuildMetadata;
import com.android.tools.r8.utils.InternalOptions;
import java.util.List;
+import java.util.concurrent.ExecutorService;
public class BuildMetadataFactory {
@@ -23,11 +24,14 @@
}
public static R8BuildMetadata create(
- AppView<? extends AppInfoWithClassHierarchy> appView, List<VirtualFile> virtualFiles) {
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ ExecutorService executorService,
+ List<VirtualFile> virtualFiles) {
InternalOptions options = appView.options();
return R8BuildMetadataImpl.builder()
.setOptions(new R8OptionsImpl(options))
.setBaselineProfileRewritingOptions(R8BaselineProfileRewritingOptionsImpl.create(options))
+ .setCompilationInfo(R8CompilationInfoImpl.create(executorService, options))
.applyIf(options.isGeneratingDex(), builder -> builder.setDexChecksums(virtualFiles))
.setResourceOptimizationOptions(R8ResourceOptimizationOptionsImpl.create(options))
.setStartupOptimizationOptions(
diff --git a/src/main/java/com/android/tools/r8/metadata/impl/R8BuildMetadataImpl.java b/src/main/java/com/android/tools/r8/metadata/impl/R8BuildMetadataImpl.java
index 47d97b5..daf5193 100644
--- a/src/main/java/com/android/tools/r8/metadata/impl/R8BuildMetadataImpl.java
+++ b/src/main/java/com/android/tools/r8/metadata/impl/R8BuildMetadataImpl.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.keepanno.annotations.UsedByReflection;
import com.android.tools.r8.metadata.R8BaselineProfileRewritingOptions;
import com.android.tools.r8.metadata.R8BuildMetadata;
+import com.android.tools.r8.metadata.R8CompilationInfo;
import com.android.tools.r8.metadata.R8Options;
import com.android.tools.r8.metadata.R8ResourceOptimizationOptions;
import com.android.tools.r8.metadata.R8StartupOptimizationOptions;
@@ -41,6 +42,10 @@
private final R8BaselineProfileRewritingOptions baselineProfileRewritingOptions;
@Expose
+ @SerializedName("compilationInfo")
+ private final R8CompilationInfo compilationInfo;
+
+ @Expose
@SerializedName("dexChecksums")
private final List<String> dexChecksums;
@@ -59,12 +64,14 @@
public R8BuildMetadataImpl(
R8Options options,
R8BaselineProfileRewritingOptions baselineProfileRewritingOptions,
+ R8CompilationInfo compilationInfo,
List<String> dexChecksums,
R8ResourceOptimizationOptions resourceOptimizationOptions,
R8StartupOptimizationOptions startupOptimizationOptions,
String version) {
this.options = options;
this.baselineProfileRewritingOptions = baselineProfileRewritingOptions;
+ this.compilationInfo = compilationInfo;
this.dexChecksums = dexChecksums;
this.resourceOptimizationOptions = resourceOptimizationOptions;
this.startupOptimizationOptions = startupOptimizationOptions;
@@ -86,6 +93,11 @@
}
@Override
+ public R8CompilationInfo getCompilationInfo() {
+ return compilationInfo;
+ }
+
+ @Override
public List<String> getDexChecksums() {
return dexChecksums;
}
@@ -114,6 +126,7 @@
private R8Options options;
private R8BaselineProfileRewritingOptions baselineProfileRewritingOptions;
+ private R8CompilationInfo compilationInfo;
private List<String> dexChecksums;
private R8ResourceOptimizationOptions resourceOptimizationOptions;
private R8StartupOptimizationOptions startupOptimizationOptions;
@@ -137,6 +150,11 @@
return this;
}
+ public Builder setCompilationInfo(R8CompilationInfo compilationInfo) {
+ this.compilationInfo = compilationInfo;
+ return this;
+ }
+
public Builder setDexChecksums(List<VirtualFile> virtualFiles) {
this.dexChecksums =
virtualFiles.stream()
@@ -167,6 +185,7 @@
return new R8BuildMetadataImpl(
options,
baselineProfileRewritingOptions,
+ compilationInfo,
dexChecksums,
resourceOptimizationOptions,
startupOptimizationOptions,
diff --git a/src/main/java/com/android/tools/r8/metadata/impl/R8CompilationInfoImpl.java b/src/main/java/com/android/tools/r8/metadata/impl/R8CompilationInfoImpl.java
new file mode 100644
index 0000000..e68225d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/metadata/impl/R8CompilationInfoImpl.java
@@ -0,0 +1,56 @@
+// Copyright (c) 2024, 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.metadata.impl;
+
+import com.android.tools.r8.keepanno.annotations.AnnotationPattern;
+import com.android.tools.r8.keepanno.annotations.FieldAccessFlags;
+import com.android.tools.r8.keepanno.annotations.KeepConstraint;
+import com.android.tools.r8.keepanno.annotations.KeepItemKind;
+import com.android.tools.r8.keepanno.annotations.UsedByReflection;
+import com.android.tools.r8.metadata.R8CompilationInfo;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ThreadUtils;
+import com.google.gson.annotations.Expose;
+import com.google.gson.annotations.SerializedName;
+import java.util.concurrent.ExecutorService;
+
+@UsedByReflection(
+ description = "Keep and preserve @SerializedName for correct (de)serialization",
+ constraints = {KeepConstraint.LOOKUP},
+ constrainAnnotations = @AnnotationPattern(constant = SerializedName.class),
+ kind = KeepItemKind.CLASS_AND_FIELDS,
+ fieldAccess = {FieldAccessFlags.PRIVATE},
+ fieldAnnotatedByClassConstant = SerializedName.class)
+public class R8CompilationInfoImpl implements R8CompilationInfo {
+
+ @Expose
+ @SerializedName("buildTime")
+ private final long buildTime;
+
+ @Expose
+ @SerializedName("numberOfThreads")
+ private final long numberOfThreads;
+
+ private R8CompilationInfoImpl(long buildTime, int numberOfThreads) {
+ this.buildTime = buildTime;
+ this.numberOfThreads = numberOfThreads;
+ }
+
+ public static R8CompilationInfoImpl create(
+ ExecutorService executorService, InternalOptions options) {
+ assert options.created > 0;
+ long buildTime = System.nanoTime() - options.created;
+ return new R8CompilationInfoImpl(buildTime, ThreadUtils.getNumberOfThreads(executorService));
+ }
+
+ @Override
+ public long getBuildTime() {
+ return buildTime;
+ }
+
+ @Override
+ public long getNumberOfThreads() {
+ return numberOfThreads;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/relocator/Relocator.java b/src/main/java/com/android/tools/r8/relocator/Relocator.java
index a0824ca..d74a6e9 100644
--- a/src/main/java/com/android/tools/r8/relocator/Relocator.java
+++ b/src/main/java/com/android/tools/r8/relocator/Relocator.java
@@ -81,7 +81,8 @@
appView.setAppServices(AppServices.builder(appView).build());
appView.setNamingLens(command.getMapping().compute(appView));
new GenericSignatureRewriter(appView).run(appInfo.classes(), executor);
- new CfApplicationWriter(appView, new Marker(Tool.Relocator)).write(command.getConsumer());
+ new CfApplicationWriter(appView, new Marker(Tool.Relocator))
+ .write(command.getConsumer(), executor);
options.printWarnings();
} catch (ExecutionException e) {
throw unwrapExecutionException(e);
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 763198e..ad6845e 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -241,6 +241,7 @@
return proguardConfiguration;
}
+ public long created = -1;
private final ProguardConfiguration proguardConfiguration;
public final Reporter reporter;