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;
+  }
+}