More debug info data in ApkAnalyzer
This updates the apk analyzer to also output debug info stats (no debug
info count, embedded pc debug info count, event based debug info count)
for each rebuild.
This also includes the size of the debug info by running DexSegments.
Finally this adds another rebuild configuration which has a map output.
Change-Id: I32b5607f2f12fb687361b6342ae096d0cc0747fa
diff --git a/src/main/java/com/android/tools/r8/DexSegments.java b/src/main/java/com/android/tools/r8/DexSegments.java
index e2e6e01..8b9bb0b 100644
--- a/src/main/java/com/android/tools/r8/DexSegments.java
+++ b/src/main/java/com/android/tools/r8/DexSegments.java
@@ -17,7 +17,7 @@
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import java.io.IOException;
import java.nio.file.Paths;
-import java.util.Map;
+import java.util.function.BiConsumer;
public class DexSegments {
public static class Command extends BaseCommand {
@@ -105,7 +105,7 @@
throws IOException, CompilationFailedException, ResourceException {
Command.Builder builder = Command.parse(args);
Command cmd = builder.build();
- Map<Integer, SegmentInfo> result = run(cmd);
+ Result result = run(cmd);
if (result == null) {
return;
}
@@ -141,13 +141,11 @@
}
}
- public static Map<Integer, SegmentInfo> runForTesting(Command command)
- throws IOException, ResourceException {
+ public static Result runForTesting(Command command) throws IOException, ResourceException {
return run(command);
}
- public static Int2ReferenceMap<SegmentInfo> run(Command command)
- throws IOException, ResourceException {
+ public static Result run(Command command) throws IOException, ResourceException {
if (command.isPrintHelp()) {
System.out.println(Command.USAGE_MESSAGE);
return null;
@@ -155,13 +153,11 @@
return run(command.getInputApp());
}
- public static Map<Integer, SegmentInfo> runForTesting(AndroidApp app)
- throws IOException, ResourceException {
+ public static Result runForTesting(AndroidApp app) throws IOException, ResourceException {
return run(app);
}
- public static Int2ReferenceMap<SegmentInfo> run(AndroidApp app)
- throws IOException, ResourceException {
+ public static Result run(AndroidApp app) throws IOException, ResourceException {
Int2ReferenceMap<SegmentInfo> result = new Int2ReferenceLinkedOpenHashMap<>();
for (int benchmark : DexSection.getConstants()) {
result.put(benchmark, new SegmentInfo());
@@ -176,7 +172,28 @@
}
}
}
- return result;
+ return new Result(result);
+ }
+
+ public static class Result {
+
+ Int2ReferenceMap<SegmentInfo> segments;
+
+ Result(Int2ReferenceMap<SegmentInfo> segments) {
+ this.segments = segments;
+ }
+
+ public SegmentInfo get(int segment) {
+ return segments.get(segment);
+ }
+
+ public SegmentInfo getDebugInfo() {
+ return segments.get(Constants.TYPE_DEBUG_INFO_ITEM);
+ }
+
+ public void forEach(BiConsumer<? super Integer, ? super SegmentInfo> fn) {
+ segments.forEach(fn);
+ }
}
public static class SegmentInfo {
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 4cc859f..e7d4a66 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsCollection.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsCollection.java
@@ -3,9 +3,8 @@
// 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.DexSegments;
import com.android.tools.r8.utils.internal.exceptions.Unimplemented;
-import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -66,7 +65,7 @@
}
@Override
- public void addDexSegmentsSizeResult(Int2ReferenceMap<SegmentInfo> result) {
+ public void addDexSegmentsSizeResult(DexSegments.Result result) {
throw error();
}
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 e0ac1f4..96b3eca 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsSingle.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsSingle.java
@@ -6,12 +6,11 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.DexSegments.SegmentInfo;
+import com.android.tools.r8.DexSegments;
import com.android.tools.r8.dex.DexSection;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
-import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongList;
import java.io.IOException;
@@ -40,7 +39,7 @@
private final LongList instructionCodeSizeResults = new LongArrayList();
private final LongList composableInstructionCodeSizeResults = new LongArrayList();
private final LongList dex2OatSizeResults = new LongArrayList();
- private final List<Int2ReferenceMap<SegmentInfo>> dexSegmentsSizeResults = new ArrayList<>();
+ private final List<DexSegments.Result> dexSegmentsSizeResults = new ArrayList<>();
private final LongList resourceSizeResults = new LongArrayList();
public BenchmarkResultsSingle(String name, Set<BenchmarkMetric> metrics) {
@@ -64,7 +63,7 @@
return composableInstructionCodeSizeResults;
}
- public List<Int2ReferenceMap<SegmentInfo>> getDexSegmentsSizeResults() {
+ public List<DexSegments.Result> getDexSegmentsSizeResults() {
return dexSegmentsSizeResults;
}
@@ -155,7 +154,7 @@
}
@Override
- public void addDexSegmentsSizeResult(Int2ReferenceMap<SegmentInfo> result) {
+ public void addDexSegmentsSizeResult(DexSegments.Result result) {
verifyMetric(
BenchmarkMetric.DexSegmentsCodeSize,
metrics.contains(BenchmarkMetric.DexSegmentsCodeSize),
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 01ca4a6..ec68f19 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsWarmup.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsWarmup.java
@@ -5,10 +5,9 @@
import static org.junit.Assert.assertFalse;
-import com.android.tools.r8.DexSegments.SegmentInfo;
+import com.android.tools.r8.DexSegments;
import com.android.tools.r8.utils.internal.exceptions.Unimplemented;
import com.android.tools.r8.utils.internal.exceptions.Unreachable;
-import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongList;
import java.nio.file.Path;
@@ -87,7 +86,7 @@
}
@Override
- public void addDexSegmentsSizeResult(Int2ReferenceMap<SegmentInfo> result) {
+ public void addDexSegmentsSizeResult(DexSegments.Result result) {
throw addSizeResultError();
}
diff --git a/src/test/java/com/android/tools/r8/dex/DexCodeDeduppingTest.java b/src/test/java/com/android/tools/r8/dex/DexCodeDeduppingTest.java
index 90322ea..15d32af 100644
--- a/src/test/java/com/android/tools/r8/dex/DexCodeDeduppingTest.java
+++ b/src/test/java/com/android/tools/r8/dex/DexCodeDeduppingTest.java
@@ -25,7 +25,6 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -238,7 +237,7 @@
public SegmentInfo getCodeSegmentInfo(Path path)
throws CompilationFailedException, ResourceException, IOException {
Command.Builder builder = Command.builder().addProgramFiles(path);
- Map<Integer, SegmentInfo> segmentInfoMap = DexSegments.runForTesting(builder.build());
+ DexSegments.Result segmentInfoMap = DexSegments.runForTesting(builder.build());
return segmentInfoMap.get(Constants.TYPE_CODE_ITEM);
}
diff --git a/src/test/java/com/android/tools/r8/dex/DexCodeInvokeSuperDeduppingTest.java b/src/test/java/com/android/tools/r8/dex/DexCodeInvokeSuperDeduppingTest.java
index 41a3c6d..009e4ce 100644
--- a/src/test/java/com/android/tools/r8/dex/DexCodeInvokeSuperDeduppingTest.java
+++ b/src/test/java/com/android/tools/r8/dex/DexCodeInvokeSuperDeduppingTest.java
@@ -19,7 +19,6 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
-import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -98,7 +97,7 @@
public SegmentInfo getCodeSegmentInfo(Path path)
throws CompilationFailedException, ResourceException, IOException {
DexSegments.Command command = DexSegments.Command.builder().addProgramFiles(path).build();
- Map<Integer, SegmentInfo> segmentInfoMap = DexSegments.runForTesting(command);
+ DexSegments.Result segmentInfoMap = DexSegments.runForTesting(command);
return segmentInfoMap.get(Constants.TYPE_CODE_ITEM);
}
diff --git a/src/test/java8/naming/com/android/tools/r8/naming/sourcefile/StringPoolSizeWithLazyDexStringsTest.java b/src/test/java8/naming/com/android/tools/r8/naming/sourcefile/StringPoolSizeWithLazyDexStringsTest.java
index c9f17bc..a736a56 100644
--- a/src/test/java8/naming/com/android/tools/r8/naming/sourcefile/StringPoolSizeWithLazyDexStringsTest.java
+++ b/src/test/java8/naming/com/android/tools/r8/naming/sourcefile/StringPoolSizeWithLazyDexStringsTest.java
@@ -18,7 +18,6 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.internal.StringUtils;
-import java.util.Map;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -65,7 +64,7 @@
}
private void checkStringSegmentSize(R8TestCompileResult result) throws Exception {
- Map<Integer, SegmentInfo> segments =
+ DexSegments.Result segments =
DexSegments.runForTesting(Command.builder().addProgramFiles(result.writeToZip()).build());
SegmentInfo stringInfo = segments.get(Constants.TYPE_STRING_ID_ITEM);
assertEquals(8, stringInfo.getItemCount());
diff --git a/src/test/testbase/java/com/android/tools/r8/R8TestCompileResultBase.java b/src/test/testbase/java/com/android/tools/r8/R8TestCompileResultBase.java
index 383c52e..680602e 100644
--- a/src/test/testbase/java/com/android/tools/r8/R8TestCompileResultBase.java
+++ b/src/test/testbase/java/com/android/tools/r8/R8TestCompileResultBase.java
@@ -9,7 +9,6 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.DexSegments.SegmentInfo;
import com.android.tools.r8.TestRuntime.DexRuntime;
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.ProcessResult;
@@ -42,8 +41,6 @@
import com.android.tools.r8.utils.internal.ThrowingBiConsumer;
import com.android.tools.r8.utils.internal.ThrowingConsumer;
import com.microsoft.playwright.Page;
-import it.unimi.dsi.fastutil.ints.Int2ReferenceLinkedOpenHashMap;
-import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
@@ -426,12 +423,8 @@
return self();
}
- private Int2ReferenceMap<SegmentInfo> runDexSegments(AndroidApp app)
- throws IOException, ResourceException {
- Map<Integer, SegmentInfo> result = DexSegments.runForTesting(app);
- Int2ReferenceMap<SegmentInfo> rewrittenResult = new Int2ReferenceLinkedOpenHashMap<>();
- rewrittenResult.putAll(result);
- return rewrittenResult;
+ private DexSegments.Result runDexSegments(AndroidApp app) throws IOException, ResourceException {
+ return DexSegments.runForTesting(app);
}
@Override
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 9cd8404..8edfc1a 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,9 +3,8 @@
// 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.DexSegments;
import com.android.tools.r8.utils.internal.StringUtils;
-import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import java.io.IOException;
import java.nio.file.Path;
@@ -29,7 +28,7 @@
void addComposableInstructionCodeSizeResult(long result);
- void addDexSegmentsSizeResult(Int2ReferenceMap<SegmentInfo> result);
+ void addDexSegmentsSizeResult(DexSegments.Result result);
void addDex2OatSizeResult(long result);
diff --git a/src/tools/java/com/android/tools/r8/tools/apkanalyzer/ApkAnalyzer.java b/src/tools/java/com/android/tools/r8/tools/apkanalyzer/ApkAnalyzer.java
index 9de3e7a..ced33da 100644
--- a/src/tools/java/com/android/tools/r8/tools/apkanalyzer/ApkAnalyzer.java
+++ b/src/tools/java/com/android/tools/r8/tools/apkanalyzer/ApkAnalyzer.java
@@ -6,6 +6,10 @@
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.D8;
import com.android.tools.r8.D8Command;
+import com.android.tools.r8.DexIndexedConsumer;
+import com.android.tools.r8.DexSegments;
+import com.android.tools.r8.ResourceException;
+import com.android.tools.r8.StringConsumer;
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.DexParser;
@@ -14,8 +18,6 @@
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexCode;
-import com.android.tools.r8.graph.DexDebugInfo;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
@@ -27,7 +29,7 @@
import com.android.tools.r8.shaking.FilteredClassPath;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.DexIndexedSizeConsumer;
+import com.android.tools.r8.utils.AndroidAppConsumers;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.internal.BooleanUtils;
import com.android.tools.r8.utils.timing.Timing;
@@ -50,7 +52,7 @@
public class ApkAnalyzer {
- public static void main(String[] args) throws IOException {
+ public static void main(String[] args) throws IOException, ResourceException {
if (args.length < 1) {
System.err.println("Usage: ApkAnalyzer <apk-path> [--csv]");
System.exit(1);
@@ -90,19 +92,21 @@
}
}
- private static Integer rebuildApk(
+ private static RebuildDexStats rebuildDex(
Path apkPath,
DesugaredLibraryInfo desugaredLibraryInfo,
+ StringConsumer mapConsumer,
AndroidApiLevel minApiLevel,
Consumer<InternalOptions> optionsModification)
throws Exception {
- DexIndexedSizeConsumer sizeConsumer = new DexIndexedSizeConsumer();
+ AndroidAppConsumers sink = new AndroidAppConsumers();
D8Command.Builder builder =
D8Command.builder()
.setDisableDesugaring(true)
.setMinApiLevel(minApiLevel.getLevel(), minApiLevel.getMinor())
.setMode(CompilationMode.RELEASE)
- .setProgramConsumer(sizeConsumer);
+ .setProgramConsumer(sink.wrapDexIndexedConsumer(DexIndexedConsumer.emptyConsumer()))
+ .setProguardMapConsumer(mapConsumer);
try (ZipFile zipFile = new ZipFile(apkPath.toFile())) {
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
@@ -121,7 +125,11 @@
}
}
D8.ApkAnalyzerEntryPoint.run(builder.build(), optionsModification);
- return sizeConsumer.size();
+ AndroidApp output = sink.build();
+ return new RebuildDexStats(
+ output.applicationSize(),
+ DebugInfoStats.create(readApplication(output)),
+ DexSegments.run(output));
}
private static void printResult(ApkAnalyzerResult result) {
@@ -134,41 +142,27 @@
System.out.println("res_file_size_min=" + result.resSize.min);
System.out.println("res_file_size_max=" + result.resSize.max);
System.out.println("res_file_size_total=" + result.resSize.total);
- if (result.rebuildSize != null) {
- System.out.println("rebuild_size=" + result.rebuildSize);
- System.out.println(
- "rebuild_size_improvement="
- + getImprovementString(result.dexSize.total, result.rebuildSize));
+ result.debugInfoStats.printToStdout("base", result.dexSegments);
+ if (result.rebuildResult != null) {
+ result.rebuildResult.printToStdout("rebuild", result);
}
- if (result.rebuildDexOptSize != null) {
- System.out.println("rebuild_dex_opt_size=" + result.rebuildDexOptSize);
- System.out.println(
- "rebuild_dex_opt_size_improvement="
- + getImprovementString(result.dexSize.total, result.rebuildDexOptSize));
+ if (result.rebuildDexOptResult != null) {
+ result.rebuildDexOptResult.printToStdout("rebuild_dex_opt", result);
}
- if (result.rebuildReuseDistSize != null) {
- System.out.println("rebuild_reuse_dist_size=" + result.rebuildReuseDistSize);
- System.out.println(
- "rebuild_reuse_dist_size_improvement="
- + getImprovementString(result.dexSize.total, result.rebuildReuseDistSize));
+ if (result.rebuildMapOutResult != null) {
+ result.rebuildMapOutResult.printToStdout("rebuild_map_out", result);
}
- if (result.rebuildNoRefinementSize != null) {
- System.out.println("rebuild_no_refinement_size=" + result.rebuildNoRefinementSize);
- System.out.println(
- "rebuild_no_refinement_size_improvement="
- + getImprovementString(result.dexSize.total, result.rebuildNoRefinementSize));
+ if (result.rebuildReuseDistResult != null) {
+ result.rebuildReuseDistResult.printToStdout("rebuild_reuse_dist", result);
}
- if (result.rebuildContainerSize != null) {
- System.out.println("rebuild_container_size=" + result.rebuildContainerSize);
- System.out.println(
- "rebuild_container_size_improvement="
- + getImprovementString(result.dexSize.total, result.rebuildContainerSize));
+ if (result.rebuildNoRefinementResult != null) {
+ result.rebuildNoRefinementResult.printToStdout("rebuild_no_refinement", result);
}
- if (result.rebuildContainerDexOptSize != null) {
- System.out.println("rebuild_container_dex_opt_size=" + result.rebuildContainerDexOptSize);
- System.out.println(
- "rebuild_container_dex_opt_size_improvement="
- + getImprovementString(result.dexSize.total, result.rebuildContainerDexOptSize));
+ if (result.rebuildContainerResult != null) {
+ result.rebuildContainerResult.printToStdout("rebuild_container", result);
+ }
+ if (result.rebuildContainerDexOptResult != null) {
+ result.rebuildContainerDexOptResult.printToStdout("rebuild_container_dex_opt", result);
}
System.out.println("dex_file_types_min=" + result.types.min);
System.out.println("dex_file_types_max=" + result.types.max);
@@ -179,9 +173,6 @@
System.out.println("dex_file_methods_min=" + result.methods.min);
System.out.println("dex_file_methods_max=" + result.methods.max);
System.out.println("dex_file_methods_total=" + result.methods.total);
- System.out.println("dex_debug_info_none=" + result.debugInfoNone);
- System.out.println("dex_debug_info_embedded_pc=" + result.debugInfoEmbeddedPc);
- System.out.println("dex_debug_info_event_based=" + result.debugInfoEventBased);
for (int markerIndex = 0; markerIndex < result.dexMarkers.size(); markerIndex++) {
System.out.println("marker_" + markerIndex + "=" + result.dexMarkers.get(markerIndex));
}
@@ -217,45 +208,41 @@
sb.append(result.resSize.max).append(';');
sb.append(result.resSize.avg()).append(';');
sb.append(result.resSize.total).append(';');
- if (result.rebuildSize != null) {
- sb.append(result.rebuildSize).append(';');
- sb.append(getImprovementString(result.dexSize.total, result.rebuildSize)).append(';');
+ result.debugInfoStats.printCsv(sb, result.dexSegments);
+ if (result.rebuildResult != null) {
+ result.rebuildResult.printCsv(sb, result);
} else {
- sb.append(';').append(';');
+ RebuildDexStats.printEmptyCsv(sb);
}
- if (result.rebuildDexOptSize != null) {
- sb.append(result.rebuildDexOptSize).append(';');
- sb.append(getImprovementString(result.dexSize.total, result.rebuildDexOptSize)).append(';');
+ if (result.rebuildDexOptResult != null) {
+ result.rebuildDexOptResult.printCsv(sb, result);
} else {
- sb.append(';').append(';');
+ RebuildDexStats.printEmptyCsv(sb);
}
- if (result.rebuildReuseDistSize != null) {
- sb.append(result.rebuildReuseDistSize).append(';');
- sb.append(getImprovementString(result.dexSize.total, result.rebuildReuseDistSize))
- .append(';');
+ if (result.rebuildMapOutResult != null) {
+ result.rebuildMapOutResult.printCsv(sb, result);
} else {
- sb.append(';').append(';');
+ RebuildDexStats.printEmptyCsv(sb);
}
- if (result.rebuildNoRefinementSize != null) {
- sb.append(result.rebuildNoRefinementSize).append(';');
- sb.append(getImprovementString(result.dexSize.total, result.rebuildNoRefinementSize))
- .append(';');
+ if (result.rebuildReuseDistResult != null) {
+ result.rebuildReuseDistResult.printCsv(sb, result);
} else {
- sb.append(';').append(';');
+ RebuildDexStats.printEmptyCsv(sb);
}
- if (result.rebuildContainerSize != null) {
- sb.append(result.rebuildContainerSize).append(';');
- sb.append(getImprovementString(result.dexSize.total, result.rebuildContainerSize))
- .append(';');
+ if (result.rebuildNoRefinementResult != null) {
+ result.rebuildNoRefinementResult.printCsv(sb, result);
} else {
- sb.append(';').append(';');
+ RebuildDexStats.printEmptyCsv(sb);
}
- if (result.rebuildContainerDexOptSize != null) {
- sb.append(result.rebuildContainerDexOptSize).append(';');
- sb.append(getImprovementString(result.dexSize.total, result.rebuildContainerDexOptSize))
- .append(';');
+ if (result.rebuildContainerResult != null) {
+ result.rebuildContainerResult.printCsv(sb, result);
} else {
- sb.append(';').append(';');
+ RebuildDexStats.printEmptyCsv(sb);
+ }
+ if (result.rebuildContainerDexOptResult != null) {
+ result.rebuildContainerDexOptResult.printCsv(sb, result);
+ } else {
+ RebuildDexStats.printEmptyCsv(sb);
}
sb.append(result.types.min).append(';');
sb.append(result.types.max).append(';');
@@ -269,9 +256,6 @@
sb.append(result.methods.max).append(';');
sb.append(result.methods.avg()).append(';');
sb.append(result.methods.total).append(';');
- sb.append(result.debugInfoNone).append(';');
- sb.append(result.debugInfoEmbeddedPc).append(';');
- sb.append(result.debugInfoEventBased).append(';');
if (result.desugaredLibraryInfo != null) {
sb.append(result.desugaredLibraryInfo.index).append(';');
sb.append(result.desugaredLibraryInfo.size).append(';');
@@ -310,7 +294,8 @@
System.out.println(sb);
}
- private static ApkAnalyzerResult analyzeApk(Path apkPath, boolean rebuild) throws IOException {
+ private static ApkAnalyzerResult analyzeApk(Path apkPath, boolean rebuild)
+ throws IOException, ResourceException {
DexApplication application = readApplication(apkPath);
int dexCompressedCount = 0;
MinMaxTotalStats dexSize = new MinMaxTotalStats();
@@ -320,35 +305,49 @@
MinMaxTotalStats types = new MinMaxTotalStats();
try (ZipFile zipFile = new ZipFile(apkPath.toFile())) {
DesugaredLibraryInfo desugaredLibraryInfo = findDesugaredLibrary(application, zipFile);
- Integer rebuildSize = null;
- Integer rebuildDexOptSize = null;
- Integer rebuildReuseDistSize = null;
- Integer rebuildNoRefinementSize = null;
- Integer rebuildContainerSize = null;
- Integer rebuildContainerDexOptSize = null;
+ RebuildDexStats rebuildSize = null;
+ RebuildDexStats rebuildDexOptSize = null;
+ RebuildDexStats rebuildMapOutSize = null;
+ RebuildDexStats rebuildReuseDistSize = null;
+ RebuildDexStats rebuildNoRefinementSize = null;
+ RebuildDexStats rebuildContainerSize = null;
+ RebuildDexStats rebuildContainerDexOptSize = null;
if (rebuild) {
try {
rebuildSize =
- rebuildApk(
- apkPath, desugaredLibraryInfo, AndroidApiLevel.CINNAMON_BUN, options -> {});
+ rebuildDex(
+ apkPath, desugaredLibraryInfo, null, AndroidApiLevel.CINNAMON_BUN, options -> {});
} catch (Throwable t) {
// Intentionally empty.
}
try {
rebuildDexOptSize =
- rebuildApk(
+ rebuildDex(
apkPath,
desugaredLibraryInfo,
+ null,
AndroidApiLevel.CINNAMON_BUN,
options -> options.enableDexToDexCodeOptimizations = true);
} catch (Throwable t) {
// Intentionally empty.
}
try {
- rebuildReuseDistSize =
- rebuildApk(
+ rebuildMapOutSize =
+ rebuildDex(
apkPath,
desugaredLibraryInfo,
+ StringConsumer.emptyConsumer(),
+ AndroidApiLevel.CINNAMON_BUN,
+ options -> {});
+ } catch (Throwable t) {
+ // Intentionally empty.
+ }
+ try {
+ rebuildReuseDistSize =
+ rebuildDex(
+ apkPath,
+ desugaredLibraryInfo,
+ null,
AndroidApiLevel.CINNAMON_BUN,
options -> options.enablePreserveExistingClassToDexDistributor = true);
} catch (Throwable t) {
@@ -356,9 +355,10 @@
}
try {
rebuildNoRefinementSize =
- rebuildApk(
+ rebuildDex(
apkPath,
desugaredLibraryInfo,
+ null,
AndroidApiLevel.CINNAMON_BUN,
options ->
options.getTestingOptions().classToDexDistributionRefinementPasses = 0);
@@ -367,9 +367,10 @@
}
try {
rebuildContainerSize =
- rebuildApk(
+ rebuildDex(
apkPath,
desugaredLibraryInfo,
+ null,
AndroidApiLevel.CINNAMON_BUN,
options -> options.getTestingOptions().forceDexContainerFormat = true);
} catch (Throwable t) {
@@ -377,9 +378,10 @@
}
try {
rebuildContainerDexOptSize =
- rebuildApk(
+ rebuildDex(
apkPath,
desugaredLibraryInfo,
+ null,
AndroidApiLevel.CINNAMON_BUN,
options -> {
options.getTestingOptions().forceDexContainerFormat = true;
@@ -423,26 +425,6 @@
}
}
- int debugInfoNone = 0;
- int debugInfoEmbeddedPc = 0;
- int debugInfoEventBased = 0;
-
- for (DexProgramClass clazz : application.classes()) {
- for (DexEncodedMethod method : clazz.methods()) {
- if (!method.isAbstract() && method.hasCode() && method.getCode().isDexCode()) {
- DexCode code = method.getCode().asDexCode();
- DexDebugInfo debugInfo = code.getDebugInfo();
- if (debugInfo == null) {
- debugInfoNone++;
- } else if (debugInfo.isPcBasedInfo()) {
- debugInfoEmbeddedPc++;
- } else if (debugInfo.isEventBasedInfo()) {
- debugInfoEventBased++;
- }
- }
- }
- }
-
String mostOccurringSourceFile = null;
int mostOccurringSourceFileCount = 0;
Map<String, Integer> sourceFileCounts = new HashMap<>();
@@ -495,15 +477,15 @@
methods.finish(),
getDexMarkers(application),
desugaredLibraryInfo,
- debugInfoNone,
- debugInfoEmbeddedPc,
- debugInfoEventBased,
+ DebugInfoStats.create(application),
+ DexSegments.run(AndroidApp.builder().addProgramFile(apkPath).build()),
mostOccurringSourceFile,
mostOccurringSourceFileCount,
runtimeInvisibleAnnotations,
depthCounts,
rebuildSize,
rebuildDexOptSize,
+ rebuildMapOutSize,
rebuildReuseDistSize,
rebuildNoRefinementSize,
rebuildContainerSize,
@@ -532,10 +514,14 @@
FilteredClassPath filteredPath =
new FilteredClassPath(apkPath, filters, new PathOrigin(apkPath), Position.UNKNOWN);
builder.createAndAddProvider(filteredPath);
+ return readApplication(builder.build());
+ }
+
+ private static DexApplication readApplication(AndroidApp app) throws IOException {
InternalOptions options = new InternalOptions();
options.skipReadingDexCode = false;
options.setMinApiLevel(AndroidApiLevel.P);
- return new ApplicationReader(builder.build(), options, Timing.empty()).read();
+ return new ApplicationReader(app, options, Timing.empty()).read();
}
private static DesugaredLibraryInfo findDesugaredLibrary(
@@ -652,7 +638,7 @@
return false;
}
- private static String getImprovementString(long baseline, long current) {
+ static String getImprovementString(long baseline, long current) {
if (baseline == 0) {
return "0.00%";
}
diff --git a/src/tools/java/com/android/tools/r8/tools/apkanalyzer/ApkAnalyzerResult.java b/src/tools/java/com/android/tools/r8/tools/apkanalyzer/ApkAnalyzerResult.java
index bcfddcf..d5c5177 100644
--- a/src/tools/java/com/android/tools/r8/tools/apkanalyzer/ApkAnalyzerResult.java
+++ b/src/tools/java/com/android/tools/r8/tools/apkanalyzer/ApkAnalyzerResult.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.tools.apkanalyzer;
+import com.android.tools.r8.DexSegments;
import com.android.tools.r8.dex.Marker;
import java.util.List;
@@ -23,9 +24,8 @@
final MinMaxTotalStats types;
// Debug info stats.
- final int debugInfoNone;
- final int debugInfoEmbeddedPc;
- final int debugInfoEventBased;
+ final DebugInfoStats debugInfoStats;
+ final DexSegments.Result dexSegments;
// Desugared library info.
final DesugaredLibraryInfo desugaredLibraryInfo;
@@ -44,12 +44,13 @@
final int[] classDepthCounts;
// Rebuilt size using D8.
- final Integer rebuildSize;
- final Integer rebuildDexOptSize;
- final Integer rebuildReuseDistSize;
- final Integer rebuildNoRefinementSize;
- final Integer rebuildContainerSize;
- final Integer rebuildContainerDexOptSize;
+ final RebuildDexStats rebuildResult;
+ final RebuildDexStats rebuildDexOptResult;
+ final RebuildDexStats rebuildMapOutResult;
+ final RebuildDexStats rebuildReuseDistResult;
+ final RebuildDexStats rebuildNoRefinementResult;
+ final RebuildDexStats rebuildContainerResult;
+ final RebuildDexStats rebuildContainerDexOptResult;
ApkAnalyzerResult(
int dexCountCompressed,
@@ -60,19 +61,19 @@
MinMaxTotalStats methods,
List<Marker> dexMarkers,
DesugaredLibraryInfo desugaredLibInfo,
- int debugInfoNone,
- int debugInfoEmbeddedPc,
- int debugInfoEventBased,
+ DebugInfoStats debugInfoStats,
+ DexSegments.Result dexSegments,
String mostOccurringSourceFile,
int mostOccurringSourceFileCount,
int runtimeInvisibleAnnotations,
int[] classDepthCounts,
- Integer rebuildSize,
- Integer rebuildDexOptSize,
- Integer rebuildReuseDistSize,
- Integer rebuildNoRefinementSize,
- Integer rebuildContainerSize,
- Integer rebuildContainerDexOptSize) {
+ RebuildDexStats rebuildResult,
+ RebuildDexStats rebuildDexOptResult,
+ RebuildDexStats rebuildMapOutResult,
+ RebuildDexStats rebuildReuseDistResult,
+ RebuildDexStats rebuildNoRefinementResult,
+ RebuildDexStats rebuildContainerResult,
+ RebuildDexStats rebuildContainerDexOptResult) {
this.dexCompressedCount = dexCountCompressed;
this.dexSize = dexSize;
this.resSize = resSize;
@@ -81,18 +82,18 @@
this.methods = methods;
this.dexMarkers = dexMarkers;
this.desugaredLibraryInfo = desugaredLibInfo;
- this.debugInfoNone = debugInfoNone;
- this.debugInfoEmbeddedPc = debugInfoEmbeddedPc;
- this.debugInfoEventBased = debugInfoEventBased;
+ this.debugInfoStats = debugInfoStats;
+ this.dexSegments = dexSegments;
this.mostOccurringSourceFile = mostOccurringSourceFile;
this.mostOccurringSourceFileCount = mostOccurringSourceFileCount;
this.runtimeInvisibleAnnotations = runtimeInvisibleAnnotations;
this.classDepthCounts = classDepthCounts;
- this.rebuildSize = rebuildSize;
- this.rebuildDexOptSize = rebuildDexOptSize;
- this.rebuildReuseDistSize = rebuildReuseDistSize;
- this.rebuildNoRefinementSize = rebuildNoRefinementSize;
- this.rebuildContainerSize = rebuildContainerSize;
- this.rebuildContainerDexOptSize = rebuildContainerDexOptSize;
+ this.rebuildResult = rebuildResult;
+ this.rebuildDexOptResult = rebuildDexOptResult;
+ this.rebuildMapOutResult = rebuildMapOutResult;
+ this.rebuildReuseDistResult = rebuildReuseDistResult;
+ this.rebuildNoRefinementResult = rebuildNoRefinementResult;
+ this.rebuildContainerResult = rebuildContainerResult;
+ this.rebuildContainerDexOptResult = rebuildContainerDexOptResult;
}
}
diff --git a/src/tools/java/com/android/tools/r8/tools/apkanalyzer/DebugInfoStats.java b/src/tools/java/com/android/tools/r8/tools/apkanalyzer/DebugInfoStats.java
new file mode 100644
index 0000000..a59fa2d
--- /dev/null
+++ b/src/tools/java/com/android/tools/r8/tools/apkanalyzer/DebugInfoStats.java
@@ -0,0 +1,57 @@
+// Copyright (c) 2026, 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.tools.apkanalyzer;
+
+import com.android.tools.r8.DexSegments;
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexCode;
+import com.android.tools.r8.graph.DexDebugInfo;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+
+public class DebugInfoStats {
+
+ int debugInfoNone = 0;
+ int debugInfoEmbeddedPc = 0;
+ int debugInfoEventBased = 0;
+
+ public static DebugInfoStats create(DexApplication application) {
+ DebugInfoStats stats = new DebugInfoStats();
+ for (DexProgramClass clazz : application.classes()) {
+ for (DexEncodedMethod method : clazz.methods()) {
+ if (!method.isAbstract() && method.hasCode() && method.getCode().isDexCode()) {
+ DexCode code = method.getCode().asDexCode();
+ DexDebugInfo debugInfo = code.getDebugInfo();
+ if (debugInfo == null) {
+ stats.debugInfoNone++;
+ } else if (debugInfo.isPcBasedInfo()) {
+ stats.debugInfoEmbeddedPc++;
+ } else if (debugInfo.isEventBasedInfo()) {
+ stats.debugInfoEventBased++;
+ }
+ }
+ }
+ }
+ return stats;
+ }
+
+ void printCsv(StringBuilder sb, DexSegments.Result dexSegments) {
+ sb.append(debugInfoNone).append(';');
+ sb.append(debugInfoEmbeddedPc).append(';');
+ sb.append(debugInfoEventBased).append(';');
+ sb.append(dexSegments.getDebugInfo().getSegmentSize()).append(';');
+ }
+
+ static void printEmptyCsv(StringBuilder sb) {
+ sb.append(";;;;");
+ }
+
+ void printToStdout(String prefix, DexSegments.Result dexSegments) {
+ System.out.println(prefix + "_dex_debug_info_none=" + debugInfoNone);
+ System.out.println(prefix + "_dex_debug_info_embedded_pc=" + debugInfoEmbeddedPc);
+ System.out.println(prefix + "_dex_debug_info_event_based=" + debugInfoEventBased);
+ System.out.println(
+ prefix + "_dex_debug_info_size=" + dexSegments.getDebugInfo().getSegmentSize());
+ }
+}
diff --git a/src/tools/java/com/android/tools/r8/tools/apkanalyzer/RebuildDexStats.java b/src/tools/java/com/android/tools/r8/tools/apkanalyzer/RebuildDexStats.java
new file mode 100644
index 0000000..71ed787
--- /dev/null
+++ b/src/tools/java/com/android/tools/r8/tools/apkanalyzer/RebuildDexStats.java
@@ -0,0 +1,39 @@
+// Copyright (c) 2026, 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.tools.apkanalyzer;
+
+import static com.android.tools.r8.tools.apkanalyzer.ApkAnalyzer.getImprovementString;
+
+import com.android.tools.r8.DexSegments;
+
+class RebuildDexStats {
+
+ final int size;
+ final DebugInfoStats debugInfoStats;
+ final DexSegments.Result dexSegments;
+
+ RebuildDexStats(int size, DebugInfoStats debugInfoStats, DexSegments.Result dexSegments) {
+ this.size = size;
+ this.debugInfoStats = debugInfoStats;
+ this.dexSegments = dexSegments;
+ }
+
+ void printCsv(StringBuilder sb, ApkAnalyzerResult result) {
+ sb.append(size).append(';');
+ sb.append(getImprovementString(result.dexSize.total, size)).append(';');
+ debugInfoStats.printCsv(sb, dexSegments);
+ }
+
+ static void printEmptyCsv(StringBuilder sb) {
+ sb.append(";;;");
+ DebugInfoStats.printEmptyCsv(sb);
+ }
+
+ void printToStdout(String prefix, ApkAnalyzerResult result) {
+ System.out.println(prefix + "_size=" + size);
+ System.out.println(
+ prefix + "_size_improvement=" + getImprovementString(result.dexSize.total, size));
+ debugInfoStats.printToStdout(prefix, dexSegments);
+ }
+}