Add instruction size, dex segments and oat size to benchmark data
Change-Id: If553dc37b77760cea1ea8cae2602be3774d9e900
diff --git a/src/main/java/com/android/tools/r8/DexSegments.java b/src/main/java/com/android/tools/r8/DexSegments.java
index fafce61..b6ca92d 100644
--- a/src/main/java/com/android/tools/r8/DexSegments.java
+++ b/src/main/java/com/android/tools/r8/DexSegments.java
@@ -140,38 +140,20 @@
}
}
- public static Map<Integer, SegmentInfo> run(Command command)
+ public static Int2ReferenceMap<SegmentInfo> run(Command command)
throws IOException, ResourceException {
if (command.isPrintHelp()) {
System.out.println(Command.USAGE_MESSAGE);
return null;
}
- AndroidApp app = command.getInputApp();
+ return run(command.getInputApp());
+ }
+ public static Int2ReferenceMap<SegmentInfo> run(AndroidApp app)
+ throws IOException, ResourceException {
Int2ReferenceMap<SegmentInfo> result = new Int2ReferenceLinkedOpenHashMap<>();
- // Fill the results with all benchmark items otherwise golem may report missing benchmarks.
- int[] benchmarks =
- new int[] {
- Constants.TYPE_ENCODED_ARRAY_ITEM,
- Constants.TYPE_HEADER_ITEM,
- Constants.TYPE_DEBUG_INFO_ITEM,
- Constants.TYPE_FIELD_ID_ITEM,
- Constants.TYPE_ANNOTATION_SET_REF_LIST,
- Constants.TYPE_STRING_ID_ITEM,
- Constants.TYPE_MAP_LIST,
- Constants.TYPE_PROTO_ID_ITEM,
- Constants.TYPE_METHOD_ID_ITEM,
- Constants.TYPE_TYPE_ID_ITEM,
- Constants.TYPE_STRING_DATA_ITEM,
- Constants.TYPE_CLASS_DATA_ITEM,
- Constants.TYPE_TYPE_LIST,
- Constants.TYPE_ANNOTATIONS_DIRECTORY_ITEM,
- Constants.TYPE_ANNOTATION_ITEM,
- Constants.TYPE_ANNOTATION_SET_ITEM,
- Constants.TYPE_CLASS_DEF_ITEM
- };
- for (int benchmark : benchmarks) {
- result.computeIfAbsent(benchmark, (key) -> new SegmentInfo());
+ for (int benchmark : DexSection.getConstants()) {
+ result.put(benchmark, new SegmentInfo());
}
try (Closer closer = Closer.create()) {
for (ProgramResource resource : app.computeAllProgramResources()) {
@@ -179,7 +161,8 @@
for (DexSection dexSection :
DexParser.parseMapFrom(
closer.register(resource.getByteStream()), resource.getOrigin())) {
- SegmentInfo info = result.computeIfAbsent(dexSection.type, (key) -> new SegmentInfo());
+ assert result.containsKey(dexSection.type) : dexSection.typeName();
+ SegmentInfo info = result.get(dexSection.type);
info.increment(dexSection.length, dexSection.size());
}
}
diff --git a/src/main/java/com/android/tools/r8/dex/DexSection.java b/src/main/java/com/android/tools/r8/dex/DexSection.java
index 39a01b2..79b20bc 100644
--- a/src/main/java/com/android/tools/r8/dex/DexSection.java
+++ b/src/main/java/com/android/tools/r8/dex/DexSection.java
@@ -20,6 +20,29 @@
this.end = -1;
}
+ public static int[] getConstants() {
+ return new int[] {
+ Constants.TYPE_ENCODED_ARRAY_ITEM,
+ Constants.TYPE_HEADER_ITEM,
+ Constants.TYPE_DEBUG_INFO_ITEM,
+ Constants.TYPE_FIELD_ID_ITEM,
+ Constants.TYPE_ANNOTATION_SET_REF_LIST,
+ Constants.TYPE_STRING_ID_ITEM,
+ Constants.TYPE_MAP_LIST,
+ Constants.TYPE_PROTO_ID_ITEM,
+ Constants.TYPE_METHOD_ID_ITEM,
+ Constants.TYPE_TYPE_ID_ITEM,
+ Constants.TYPE_STRING_DATA_ITEM,
+ Constants.TYPE_CLASS_DATA_ITEM,
+ Constants.TYPE_TYPE_LIST,
+ Constants.TYPE_ANNOTATIONS_DIRECTORY_ITEM,
+ Constants.TYPE_ANNOTATION_ITEM,
+ Constants.TYPE_ANNOTATION_SET_ITEM,
+ Constants.TYPE_CLASS_DEF_ITEM,
+ Constants.TYPE_CODE_ITEM
+ };
+ }
+
void setEnd(int end) {
this.end = end;
}
diff --git a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkConfig.java b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkConfig.java
index 0eab29b..bff9585 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkConfig.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkConfig.java
@@ -168,8 +168,23 @@
return this;
}
- public Builder measureComposableCodeSize() {
- metrics.add(BenchmarkMetric.ComposableCodeSize);
+ public Builder measureInstructionCodeSize() {
+ metrics.add(BenchmarkMetric.InstructionCodeSize);
+ return this;
+ }
+
+ public Builder measureComposableInstructionCodeSize() {
+ metrics.add(BenchmarkMetric.ComposableInstructionCodeSize);
+ return this;
+ }
+
+ public Builder measureDexSegmentsCodeSize() {
+ metrics.add(BenchmarkMetric.DexSegmentsCodeSize);
+ return this;
+ }
+
+ public Builder measureDex2OatCodeSize() {
+ metrics.add(BenchmarkMetric.Dex2OatCodeSize);
return this;
}
@@ -248,7 +263,7 @@
}
public boolean containsComposableCodeSizeMetric() {
- return containsMetric(BenchmarkMetric.ComposableCodeSize);
+ return containsMetric(BenchmarkMetric.ComposableInstructionCodeSize);
}
public BenchmarkIdentifier getIdentifier() {
diff --git a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsCollection.java b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsCollection.java
index 8fc8508..dc841ba 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsCollection.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsCollection.java
@@ -3,7 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.benchmarks;
+import com.android.tools.r8.DexSegments.SegmentInfo;
import com.android.tools.r8.errors.Unimplemented;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
@@ -23,24 +25,40 @@
@Override
public void addRuntimeResult(long result) {
- throw new BenchmarkConfigError(
- "Unexpected attempt to add a result to a the root of a benchmark with sub-benchmarks");
+ throw error();
}
@Override
public void addCodeSizeResult(long result) {
- throw new BenchmarkConfigError(
- "Unexpected attempt to add a result to a the root of a benchmark with sub-benchmarks");
+ throw error();
}
@Override
- public void addComposableCodeSizeResult(long result) {
- throw new BenchmarkConfigError(
- "Unexpected attempt to add a result to a the root of a benchmark with sub-benchmarks");
+ public void addInstructionCodeSizeResult(long result) {
+ throw error();
+ }
+
+ @Override
+ public void addComposableInstructionCodeSizeResult(long result) {
+ throw error();
+ }
+
+ @Override
+ public void addDexSegmentsSizeResult(Int2ReferenceMap<SegmentInfo> result) {
+ throw error();
+ }
+
+ @Override
+ public void addDex2OatSizeResult(long result) {
+ throw error();
}
@Override
public void addResourceSizeResult(long result) {
+ throw error();
+ }
+
+ private BenchmarkConfigError error() {
throw new BenchmarkConfigError(
"Unexpected attempt to add a result to a the root of a benchmark with sub-benchmarks");
}
diff --git a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsSingle.java b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsSingle.java
index ad6b1b3..93b6efb 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsSingle.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsSingle.java
@@ -3,12 +3,19 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.benchmarks;
+import com.android.tools.r8.DexSegments.SegmentInfo;
+import com.android.tools.r8.dex.DexSection;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongList;
import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
import java.util.Set;
+import java.util.function.IntToLongFunction;
import java.util.function.LongConsumer;
public class BenchmarkResultsSingle implements BenchmarkResults {
@@ -16,8 +23,13 @@
private final String name;
private final Set<BenchmarkMetric> metrics;
private final LongList runtimeResults = new LongArrayList();
+
+ // Consider using LongSet to eliminate duplicate results for size.
private final LongList codeSizeResults = new LongArrayList();
- private final LongList composableCodeSizeResults = new LongArrayList();
+ private final LongList instructionCodeSizeResults = new LongArrayList();
+ private final LongList composableInstructionCodeSizeResults = new LongArrayList();
+ private final LongList dex2OatSizeResult = new LongArrayList();
+ private final List<Int2ReferenceMap<SegmentInfo>> dexSegmentsSizeResults = new ArrayList<>();
public BenchmarkResultsSingle(String name, Set<BenchmarkMetric> metrics) {
this.name = name;
@@ -32,8 +44,8 @@
return codeSizeResults;
}
- public LongList getComposableCodeSizeResults() {
- return composableCodeSizeResults;
+ public LongList getComposableInstructionCodeSizeResults() {
+ return composableInstructionCodeSizeResults;
}
public LongList getRuntimeResults() {
@@ -53,12 +65,37 @@
}
@Override
- public void addComposableCodeSizeResult(long result) {
+ public void addInstructionCodeSizeResult(long result) {
verifyMetric(
- BenchmarkMetric.ComposableCodeSize,
- metrics.contains(BenchmarkMetric.ComposableCodeSize),
+ BenchmarkMetric.InstructionCodeSize,
+ metrics.contains(BenchmarkMetric.InstructionCodeSize),
true);
- composableCodeSizeResults.add(result);
+ instructionCodeSizeResults.add(result);
+ }
+
+ @Override
+ public void addComposableInstructionCodeSizeResult(long result) {
+ verifyMetric(
+ BenchmarkMetric.ComposableInstructionCodeSize,
+ metrics.contains(BenchmarkMetric.ComposableInstructionCodeSize),
+ true);
+ composableInstructionCodeSizeResults.add(result);
+ }
+
+ @Override
+ public void addDexSegmentsSizeResult(Int2ReferenceMap<SegmentInfo> result) {
+ verifyMetric(
+ BenchmarkMetric.DexSegmentsCodeSize,
+ metrics.contains(BenchmarkMetric.DexSegmentsCodeSize),
+ true);
+ dexSegmentsSizeResults.add(result);
+ }
+
+ @Override
+ public void addDex2OatSizeResult(long result) {
+ verifyMetric(
+ BenchmarkMetric.Dex2OatCodeSize, metrics.contains(BenchmarkMetric.Dex2OatCodeSize), true);
+ dex2OatSizeResult.add(result);
}
@Override
@@ -91,12 +128,24 @@
!runtimeResults.isEmpty());
verifyMetric(
BenchmarkMetric.CodeSize,
- metrics.contains(BenchmarkMetric.CodeSize),
+ isBenchmarkingCodeSize() && metrics.contains(BenchmarkMetric.CodeSize),
!codeSizeResults.isEmpty());
verifyMetric(
- BenchmarkMetric.ComposableCodeSize,
- metrics.contains(BenchmarkMetric.ComposableCodeSize),
- !composableCodeSizeResults.isEmpty());
+ BenchmarkMetric.InstructionCodeSize,
+ isBenchmarkingCodeSize() && metrics.contains(BenchmarkMetric.InstructionCodeSize),
+ !instructionCodeSizeResults.isEmpty());
+ verifyMetric(
+ BenchmarkMetric.ComposableInstructionCodeSize,
+ isBenchmarkingCodeSize() && metrics.contains(BenchmarkMetric.ComposableInstructionCodeSize),
+ !composableInstructionCodeSizeResults.isEmpty());
+ verifyMetric(
+ BenchmarkMetric.DexSegmentsCodeSize,
+ isBenchmarkingCodeSize() && metrics.contains(BenchmarkMetric.DexSegmentsCodeSize),
+ !dexSegmentsSizeResults.isEmpty());
+ verifyMetric(
+ BenchmarkMetric.Dex2OatCodeSize,
+ isBenchmarkingCodeSize() && metrics.contains(BenchmarkMetric.Dex2OatCodeSize),
+ !dex2OatSizeResult.isEmpty());
}
private void printRunTime(long duration) {
@@ -105,12 +154,29 @@
}
private void printCodeSize(long bytes) {
- System.out.println(BenchmarkResults.prettyMetric(name, BenchmarkMetric.CodeSize, "" + bytes));
+ System.out.println(BenchmarkResults.prettyMetric(name, BenchmarkMetric.CodeSize, bytes));
}
- private void printComposableCodeSize(long bytes) {
+ private void printInstructionCodeSize(long bytes) {
System.out.println(
- BenchmarkResults.prettyMetric(name, BenchmarkMetric.ComposableCodeSize, "" + bytes));
+ BenchmarkResults.prettyMetric(name, BenchmarkMetric.InstructionCodeSize, bytes));
+ }
+
+ private void printComposableInstructionCodeSize(long bytes) {
+ System.out.println(
+ BenchmarkResults.prettyMetric(name, BenchmarkMetric.ComposableInstructionCodeSize, bytes));
+ }
+
+ private void printDexSegmentSize(int section, long bytes) {
+ System.out.println(
+ BenchmarkResults.prettyMetric(
+ name,
+ BenchmarkMetric.DexSegmentsCodeSize + ", " + DexSection.typeName(section),
+ bytes));
+ }
+
+ private void printDex2OatSize(long bytes) {
+ System.out.println(BenchmarkResults.prettyMetric(name, BenchmarkMetric.Dex2OatCodeSize, bytes));
}
@Override
@@ -123,23 +189,45 @@
}
printCodeSizeResults(codeSizeResults, failOnCodeSizeDifferences, this::printCodeSize);
printCodeSizeResults(
- composableCodeSizeResults, failOnCodeSizeDifferences, this::printComposableCodeSize);
+ instructionCodeSizeResults, failOnCodeSizeDifferences, this::printInstructionCodeSize);
+ printCodeSizeResults(
+ composableInstructionCodeSizeResults,
+ failOnCodeSizeDifferences,
+ this::printComposableInstructionCodeSize);
+ for (int section : DexSection.getConstants()) {
+ printCodeSizeResults(
+ dexSegmentsSizeResults,
+ i -> dexSegmentsSizeResults.get(i).get(section).getSegmentSize(),
+ failOnCodeSizeDifferences,
+ result -> printDexSegmentSize(section, result));
+ }
+ printCodeSizeResults(dex2OatSizeResult, failOnCodeSizeDifferences, this::printDex2OatSize);
}
private static void printCodeSizeResults(
LongList codeSizeResults, boolean failOnCodeSizeDifferences, LongConsumer printer) {
- if (!codeSizeResults.isEmpty()) {
- long size = codeSizeResults.getLong(0);
- if (failOnCodeSizeDifferences) {
- for (int i = 1; i < codeSizeResults.size(); i++) {
- if (size != codeSizeResults.getLong(i)) {
- throw new RuntimeException(
- "Unexpected code size difference: " + size + " and " + codeSizeResults.getLong(i));
- }
+ printCodeSizeResults(
+ codeSizeResults, codeSizeResults::getLong, failOnCodeSizeDifferences, printer);
+ }
+
+ private static void printCodeSizeResults(
+ Collection<?> codeSizeResults,
+ IntToLongFunction getter,
+ boolean failOnCodeSizeDifferences,
+ LongConsumer printer) {
+ if (codeSizeResults.isEmpty()) {
+ return;
+ }
+ long size = getter.applyAsLong(0);
+ if (failOnCodeSizeDifferences) {
+ for (int i = 1; i < codeSizeResults.size(); i++) {
+ if (size != getter.applyAsLong(i)) {
+ throw new RuntimeException(
+ "Unexpected code size difference: " + size + " and " + getter.applyAsLong(i));
}
}
- printer.accept(size);
}
+ printer.accept(size);
}
@Override
diff --git a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsSingleAdapter.java b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsSingleAdapter.java
index 68d6fb8..416594b 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsSingleAdapter.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsSingleAdapter.java
@@ -22,9 +22,10 @@
(codeSizeResult, iteration) -> {
JsonObject resultObject = new JsonObject();
resultObject.addProperty("code_size", codeSizeResult);
- if (!result.getComposableCodeSizeResults().isEmpty()) {
+ if (!result.getComposableInstructionCodeSizeResults().isEmpty()) {
resultObject.addProperty(
- "composable_code_size", result.getComposableCodeSizeResults().getLong(iteration));
+ "composable_code_size",
+ result.getComposableInstructionCodeSizeResults().getLong(iteration));
}
resultObject.addProperty("runtime", result.getRuntimeResults().getLong(iteration));
resultsArray.add(resultObject);
diff --git a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsWarmup.java b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsWarmup.java
index 19c1de8..4f16cc4 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsWarmup.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsWarmup.java
@@ -3,7 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.benchmarks;
+import com.android.tools.r8.DexSegments.SegmentInfo;
import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.errors.Unreachable;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongList;
import java.io.PrintStream;
@@ -13,7 +16,6 @@
private final String name;
private final LongList runtimeResults = new LongArrayList();
private long codeSizeResult = -1;
- private long composableCodeSizeResult = -1;
private long resourceSizeResult = -1;
public BenchmarkResultsWarmup(String name) {
@@ -37,17 +39,27 @@
}
@Override
- public void addComposableCodeSizeResult(long result) {
- if (composableCodeSizeResult == -1) {
- composableCodeSizeResult = result;
- }
- if (composableCodeSizeResult != result) {
- throw new RuntimeException(
- "Unexpected Composable code size difference: "
- + result
- + " and "
- + composableCodeSizeResult);
- }
+ public void addInstructionCodeSizeResult(long result) {
+ throw addSizeResultError();
+ }
+
+ @Override
+ public void addComposableInstructionCodeSizeResult(long result) {
+ throw addSizeResultError();
+ }
+
+ @Override
+ public void addDexSegmentsSizeResult(Int2ReferenceMap<SegmentInfo> result) {
+ throw addSizeResultError();
+ }
+
+ @Override
+ public void addDex2OatSizeResult(long result) {
+ throw addSizeResultError();
+ }
+
+ private Unreachable addSizeResultError() {
+ throw new Unreachable("Unexpected attempt to add size result for warmup run");
}
@Override
@@ -68,6 +80,11 @@
}
@Override
+ public boolean isBenchmarkingCodeSize() {
+ return false;
+ }
+
+ @Override
public void printResults(ResultMode mode, boolean failOnCodeSizeDifferences) {
if (runtimeResults.isEmpty()) {
throw new BenchmarkConfigError("Expected runtime results for warmup run");
diff --git a/src/test/java/com/android/tools/r8/benchmarks/appdumps/AppDumpBenchmarkBuilder.java b/src/test/java/com/android/tools/r8/benchmarks/appdumps/AppDumpBenchmarkBuilder.java
index 09934bc..1ba1fd0 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/appdumps/AppDumpBenchmarkBuilder.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/appdumps/AppDumpBenchmarkBuilder.java
@@ -118,7 +118,10 @@
.addDependency(dumpDependency)
.measureRunTime()
.measureCodeSize()
- .measureComposableCodeSize()
+ .measureInstructionCodeSize()
+ .measureComposableInstructionCodeSize()
+ .measureDexSegmentsCodeSize()
+ .measureDex2OatCodeSize()
.setTimeout(10, TimeUnit.MINUTES)
.build();
}
@@ -306,7 +309,9 @@
r ->
r.benchmarkCompile(results)
.benchmarkCodeSize(results)
- .benchmarkComposableCodeSize(results));
+ .benchmarkInstructionCodeSize(results)
+ .benchmarkDexSegmentsCodeSize(results)
+ .benchmarkDex2OatCodeSize(results));
});
}
diff --git a/src/test/testbase/java/com/android/tools/r8/Dex2OatTestRunResult.java b/src/test/testbase/java/com/android/tools/r8/Dex2OatTestRunResult.java
index 13ae71f..6b89f23 100644
--- a/src/test/testbase/java/com/android/tools/r8/Dex2OatTestRunResult.java
+++ b/src/test/testbase/java/com/android/tools/r8/Dex2OatTestRunResult.java
@@ -8,14 +8,20 @@
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.AndroidApp;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
import org.hamcrest.CoreMatchers;
import org.hamcrest.Matcher;
public class Dex2OatTestRunResult extends SingleTestRunResult<Dex2OatTestRunResult> {
+ private final Path oat;
+
public Dex2OatTestRunResult(
- AndroidApp app, TestRuntime runtime, ProcessResult result, TestState state) {
+ AndroidApp app, Path oat, TestRuntime runtime, ProcessResult result, TestState state) {
super(app, runtime, result, state);
+ this.oat = oat;
}
@Override
@@ -44,13 +50,7 @@
return self();
}
- public Dex2OatTestRunResult assertVerificationErrors() {
- assertSuccess();
- Matcher<? super String> matcher = CoreMatchers.containsString("Verification error");
- assertThat(
- errorMessage("Run dex2oat did not produce verification errors.", matcher.toString()),
- getStdErr(),
- matcher);
- return self();
+ public long getOatSizeOrDefault(long defaultValue) throws IOException {
+ return Files.exists(oat) ? Files.size(oat) : defaultValue;
}
}
diff --git a/src/test/testbase/java/com/android/tools/r8/R8TestCompileResult.java b/src/test/testbase/java/com/android/tools/r8/R8TestCompileResult.java
index 3ff7487..6bd6774 100644
--- a/src/test/testbase/java/com/android/tools/r8/R8TestCompileResult.java
+++ b/src/test/testbase/java/com/android/tools/r8/R8TestCompileResult.java
@@ -8,13 +8,17 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import com.android.tools.r8.TestRuntime.DexRuntime;
+import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.androidresources.AndroidResourceTestingUtils;
import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.ResourceTableInspector;
import com.android.tools.r8.benchmarks.BenchmarkResults;
+import com.android.tools.r8.benchmarks.InstructionCodeSizeResult;
import com.android.tools.r8.dexsplitter.SplitterTestBase.SplitRunner;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.metadata.R8BuildMetadata;
import com.android.tools.r8.profile.art.model.ExternalArtProfile;
import com.android.tools.r8.profile.art.utils.ArtProfileInspector;
@@ -314,34 +318,63 @@
@Override
public R8TestCompileResult benchmarkCodeSize(BenchmarkResults results)
throws IOException, ResourceException {
- int applicationSizeWithFeatures =
- AndroidApp.builder(app).addProgramFiles(features).build().applicationSize();
- results.addCodeSizeResult(applicationSizeWithFeatures);
+ if (results.isBenchmarkingCodeSize()) {
+ int applicationSizeWithFeatures =
+ AndroidApp.builder(app).addProgramFiles(features).build().applicationSize();
+ results.addCodeSizeResult(applicationSizeWithFeatures);
+ }
return self();
}
@Override
- public R8TestCompileResult benchmarkComposableCodeSize(BenchmarkResults results)
+ public R8TestCompileResult benchmarkInstructionCodeSize(BenchmarkResults results)
throws IOException {
- int composableCodeSize = getComposableCodeSize(inspector());
- for (Path feature : features) {
- composableCodeSize += getComposableCodeSize(featureInspector(feature));
+ if (results.isBenchmarkingCodeSize()) {
+ InstructionCodeSizeResult result = getComposableCodeSize(inspector());
+ for (Path feature : features) {
+ result.add(getComposableCodeSize(featureInspector(feature)));
+ }
+ results.addInstructionCodeSizeResult(result.instructionCodeSize);
+ results.addComposableInstructionCodeSizeResult(result.composableInstructionCodeSize);
}
- results.addComposableCodeSizeResult(composableCodeSize);
return self();
}
- private int getComposableCodeSize(CodeInspector inspector) {
+ private InstructionCodeSizeResult getComposableCodeSize(CodeInspector inspector) {
DexType composableType =
inspector.getFactory().createType("Landroidx/compose/runtime/Composable;");
- int composableCodeSize = 0;
+ InstructionCodeSizeResult result = new InstructionCodeSizeResult();
for (FoundClassSubject classSubject : inspector.allClasses()) {
- for (ProgramMethod method : classSubject.getDexProgramClass().directProgramMethods()) {
- if (method.getAnnotations().hasAnnotation(composableType)) {
- composableCodeSize += method.getDefinition().getCode().asDexCode().codeSizeInBytes();
+ DexProgramClass clazz = classSubject.getDexProgramClass();
+ for (DexEncodedMethod method : clazz.methods(DexEncodedMethod::hasCode)) {
+ int instructionCodeSize = method.getCode().asDexCode().codeSizeInBytes();
+ result.instructionCodeSize += instructionCodeSize;
+ if (method.annotations().hasAnnotation(composableType)) {
+ result.composableInstructionCodeSize += instructionCodeSize;
}
}
}
- return composableCodeSize;
+ return result;
+ }
+
+ @Override
+ public R8TestCompileResult benchmarkDexSegmentsCodeSize(BenchmarkResults results)
+ throws IOException, ResourceException {
+ if (results.isBenchmarkingCodeSize()) {
+ AndroidApp appWithFeatures =
+ features.isEmpty() ? app : AndroidApp.builder(app).addProgramFiles(features).build();
+ results.addDexSegmentsSizeResult(DexSegments.run(appWithFeatures));
+ }
+ return self();
+ }
+
+ @Override
+ public R8TestCompileResult benchmarkDex2OatCodeSize(BenchmarkResults results) throws IOException {
+ if (results.isBenchmarkingCodeSize()) {
+ Dex2OatTestRunResult dex2OatTestRunResult =
+ runDex2Oat(new DexRuntime(DexVm.Version.LATEST_DEX2OAT));
+ results.addDex2OatSizeResult(dex2OatTestRunResult.getOatSizeOrDefault(0));
+ }
+ return self();
}
}
diff --git a/src/test/testbase/java/com/android/tools/r8/TestCompileResult.java b/src/test/testbase/java/com/android/tools/r8/TestCompileResult.java
index 1f50960..80cf267 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestCompileResult.java
@@ -715,7 +715,7 @@
Path oatFile = tmp.resolve("out.oat");
app.writeToZipForTesting(jarFile, OutputMode.DexIndexed);
return new Dex2OatTestRunResult(
- app, runtime, ToolHelper.runDex2OatRaw(jarFile, oatFile, vm), state);
+ app, oatFile, runtime, ToolHelper.runDex2OatRaw(jarFile, oatFile, vm), state);
}
public CR benchmarkCodeSize(BenchmarkResults results) throws IOException, ResourceException {
@@ -723,7 +723,17 @@
return self();
}
- public CR benchmarkComposableCodeSize(BenchmarkResults results)
+ public CR benchmarkInstructionCodeSize(BenchmarkResults results)
+ throws IOException, ResourceException {
+ throw new Unimplemented();
+ }
+
+ public CR benchmarkDexSegmentsCodeSize(BenchmarkResults results)
+ throws IOException, ResourceException {
+ throw new Unimplemented();
+ }
+
+ public CR benchmarkDex2OatCodeSize(BenchmarkResults results)
throws IOException, ResourceException {
throw new Unimplemented();
}
diff --git a/src/test/testbase/java/com/android/tools/r8/ToolHelper.java b/src/test/testbase/java/com/android/tools/r8/ToolHelper.java
index 2061f8f..92b7774 100644
--- a/src/test/testbase/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/testbase/java/com/android/tools/r8/ToolHelper.java
@@ -388,6 +388,8 @@
// TODO(b/204855476): Rename to DEFAULT alias once the checked in VM is removed.
public static final Version NEW_DEFAULT = DEFAULT;
+ public static final Version LATEST_DEX2OAT = V12_0_0;
+
Version(String shortName) {
this.shortName = shortName;
}
diff --git a/src/test/testbase/java/com/android/tools/r8/benchmarks/BenchmarkMetric.java b/src/test/testbase/java/com/android/tools/r8/benchmarks/BenchmarkMetric.java
index abf93ce..11ffbcd 100644
--- a/src/test/testbase/java/com/android/tools/r8/benchmarks/BenchmarkMetric.java
+++ b/src/test/testbase/java/com/android/tools/r8/benchmarks/BenchmarkMetric.java
@@ -6,7 +6,10 @@
public enum BenchmarkMetric {
RunTimeRaw,
CodeSize,
- ComposableCodeSize,
+ InstructionCodeSize,
+ ComposableInstructionCodeSize,
+ DexSegmentsCodeSize,
+ Dex2OatCodeSize,
StartupTime;
public String getDartType() {
diff --git a/src/test/testbase/java/com/android/tools/r8/benchmarks/BenchmarkResults.java b/src/test/testbase/java/com/android/tools/r8/benchmarks/BenchmarkResults.java
index a925368..6f8d5b6 100644
--- a/src/test/testbase/java/com/android/tools/r8/benchmarks/BenchmarkResults.java
+++ b/src/test/testbase/java/com/android/tools/r8/benchmarks/BenchmarkResults.java
@@ -3,17 +3,26 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.benchmarks;
+import com.android.tools.r8.DexSegments.SegmentInfo;
import com.android.tools.r8.utils.StringUtils;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import java.io.PrintStream;
public interface BenchmarkResults {
+
// Append a runtime result. This may be summed or averaged depending on the benchmark set up.
void addRuntimeResult(long result);
// Append a code size result. This is always assumed to be identical if called multiple times.
void addCodeSizeResult(long result);
- void addComposableCodeSizeResult(long result);
+ void addInstructionCodeSizeResult(long result);
+
+ void addComposableInstructionCodeSizeResult(long result);
+
+ void addDexSegmentsSizeResult(Int2ReferenceMap<SegmentInfo> result);
+
+ void addDex2OatSizeResult(long result);
// Append a resource size result. This is always assumed to be identical if called multiple times.
void addResourceSizeResult(long result);
@@ -22,6 +31,10 @@
// This will throw if called on a benchmark without sub-benchmarks.
BenchmarkResults getSubResults(String name);
+ default boolean isBenchmarkingCodeSize() {
+ return true;
+ }
+
void printResults(ResultMode resultMode, boolean failOnCodeSizeDifferences);
void writeResults(PrintStream out);
@@ -30,8 +43,20 @@
return "" + (nanoTime / 1000000) + " ms";
}
+ static String prettyMetric(String name, BenchmarkMetric metric, long value) {
+ return prettyMetric(name, metric.name(), Long.toString(value));
+ }
+
static String prettyMetric(String name, BenchmarkMetric metric, String value) {
- return name + "(" + metric.name() + "): " + value;
+ return prettyMetric(name, metric.name(), value);
+ }
+
+ static String prettyMetric(String name, String metricName, long value) {
+ return prettyMetric(name, metricName, Long.toString(value));
+ }
+
+ static String prettyMetric(String name, String metricName, String value) {
+ return name + "(" + metricName + "): " + value;
}
enum ResultMode {
diff --git a/src/test/testbase/java/com/android/tools/r8/benchmarks/InstructionCodeSizeResult.java b/src/test/testbase/java/com/android/tools/r8/benchmarks/InstructionCodeSizeResult.java
new file mode 100644
index 0000000..20af572
--- /dev/null
+++ b/src/test/testbase/java/com/android/tools/r8/benchmarks/InstructionCodeSizeResult.java
@@ -0,0 +1,15 @@
+// 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.benchmarks;
+
+public class InstructionCodeSizeResult {
+
+ public long instructionCodeSize;
+ public long composableInstructionCodeSize;
+
+ public void add(InstructionCodeSizeResult result) {
+ instructionCodeSize += result.instructionCodeSize;
+ composableInstructionCodeSize += result.composableInstructionCodeSize;
+ }
+}