Add R8 partial NowInAndroid benchmark

Bug: b/388742651
Change-Id: Ia5229edf768441c71c607b815eae06f538354ac2
diff --git a/src/main/java/com/android/tools/r8/BaseCommand.java b/src/main/java/com/android/tools/r8/BaseCommand.java
index cc4cffe..e07018d 100644
--- a/src/main/java/com/android/tools/r8/BaseCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCommand.java
@@ -119,7 +119,15 @@
     }
 
     Builder(DiagnosticsHandler handler) {
-      this(AndroidApp.builder(new Reporter(handler)));
+      this(AndroidApp.builder(createReporter(handler)));
+    }
+
+    static Reporter createReporter(DiagnosticsHandler handler) {
+      if (handler instanceof Reporter) {
+        return (Reporter) handler;
+      } else {
+        return new Reporter(handler);
+      }
     }
 
     Builder(AndroidApp.Builder builder) {
diff --git a/src/main/java/com/android/tools/r8/R8Partial.java b/src/main/java/com/android/tools/r8/R8Partial.java
index dda3e6e..ebca5fa 100644
--- a/src/main/java/com/android/tools/r8/R8Partial.java
+++ b/src/main/java/com/android/tools/r8/R8Partial.java
@@ -172,7 +172,7 @@
     // Compile D8 input with D8.
     Path d8Output = tmp.resolve("d8-output.zip");
     D8Command.Builder d8Builder =
-        D8Command.builder()
+        D8Command.builder(options.reporter)
             .setMinApiLevel(dump.getBuildProperties().getMinApi())
             .addLibraryFiles(dump.getLibraryArchive())
             .addClasspathFiles(dump.getClasspathArchive())
@@ -195,6 +195,7 @@
       d8InputAppConsumer.accept(d8App);
     }
     InternalOptions d8Options = d8command.getInternalOptions();
+    options.partialCompilationConfiguration.d8DexOptionsConsumer.accept(d8Options);
     assert d8Options.getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N)
         : "Default interface methods not yet supported";
     D8.runInternal(d8App, d8Options, executor);
@@ -251,7 +252,7 @@
     Path r8Output = tmp.resolve("r8-output.zip");
     R8DataResources r8DataResources = new R8DataResources();
     R8Command.Builder r8Builder =
-        R8Command.builder()
+        R8Command.builder(options.reporter)
             .setMinApiLevel(dump.getBuildProperties().getMinApi())
             .addLibraryFiles(dump.getLibraryArchive())
             .addClasspathFiles(dump.getClasspathArchive())
@@ -282,6 +283,7 @@
       r8InputAppConsumer.accept(r8App);
     }
     InternalOptions r8Options = r8Command.getInternalOptions();
+    options.partialCompilationConfiguration.r8OptionsConsumer.accept(r8Options);
     r8Options.mapConsumer = originalMapConsumer;
     r8Options.quiet = true; // Don't write the R8 version.
     R8.runInternal(r8App, r8Options, executor);
@@ -291,7 +293,7 @@
 
     // TODO(b/309743298): Handle jumbo string rewriting with PCs in mapping file.
     D8Command.Builder mergerBuilder =
-        D8Command.builder()
+        D8Command.builder(options.reporter)
             .setMinApiLevel(dump.getBuildProperties().getMinApi())
             .addLibraryFiles(dump.getLibraryArchive())
             .addClasspathFiles(dump.getClasspathArchive())
@@ -302,6 +304,7 @@
     D8Command mergeCommand = mergerBuilder.makeCommand();
     AndroidApp mergeApp = mergeCommand.getInputApp();
     InternalOptions mergeOptions = mergeCommand.getInternalOptions();
+    options.partialCompilationConfiguration.d8MergeOptionsConsumer.accept(mergeOptions);
     D8.runInternal(mergeApp, mergeOptions, executor);
     // Feed the data resource output by R8 to the output consumer. Keeping this at the end after the
     // merge keeps the order of calls to the output consumer closer to full R8.
diff --git a/src/main/java/com/android/tools/r8/utils/R8PartialCompilationConfiguration.java b/src/main/java/com/android/tools/r8/utils/R8PartialCompilationConfiguration.java
index a1c3b2d..2586b2d 100644
--- a/src/main/java/com/android/tools/r8/utils/R8PartialCompilationConfiguration.java
+++ b/src/main/java/com/android/tools/r8/utils/R8PartialCompilationConfiguration.java
@@ -28,6 +28,10 @@
   public Consumer<AndroidApp> r8OutputAppConsumer;
   public Consumer<AndroidApp> d8OutputAppConsumer;
 
+  public Consumer<InternalOptions> d8DexOptionsConsumer = ConsumerUtils.emptyConsumer();
+  public Consumer<InternalOptions> d8MergeOptionsConsumer = ConsumerUtils.emptyConsumer();
+  public Consumer<InternalOptions> r8OptionsConsumer = ConsumerUtils.emptyConsumer();
+
   private static final R8PartialCompilationConfiguration disabledConfiguration =
       new R8PartialCompilationConfiguration(false, null, null);
 
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 7380554..1ea5acf 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
@@ -3,9 +3,14 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.benchmarks.appdumps;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+
 import com.android.tools.r8.CompilationMode;
 import com.android.tools.r8.LibraryDesugaringTestConfiguration;
 import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.R8PartialTestBuilder;
+import com.android.tools.r8.R8TestBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestBase.Backend;
 import com.android.tools.r8.TestCompilerBuilder;
@@ -22,10 +27,12 @@
 import com.android.tools.r8.benchmarks.BenchmarkTarget;
 import com.android.tools.r8.dump.CompilerDump;
 import com.android.tools.r8.dump.DumpOptions;
+import com.android.tools.r8.errors.Unimplemented;
 import com.android.tools.r8.keepanno.annotations.AnnotationPattern;
 import com.android.tools.r8.keepanno.annotations.KeepEdge;
 import com.android.tools.r8.keepanno.annotations.KeepItemKind;
 import com.android.tools.r8.keepanno.annotations.KeepTarget;
+import com.android.tools.r8.utils.AndroidApiLevel;
 import com.google.common.collect.ImmutableSet;
 import java.io.IOException;
 import java.lang.annotation.RetentionPolicy;
@@ -139,6 +146,25 @@
         .build();
   }
 
+  public BenchmarkConfig buildR8WithPartialShrinking() {
+    verify();
+    return BenchmarkConfig.builder()
+        .setName(name)
+        .setTarget(BenchmarkTarget.R8)
+        .setSuite(BenchmarkSuite.OPENSOURCE_BENCHMARKS)
+        .setMethod(runR8WithPartialShrinking(this))
+        .setFromRevision(fromRevision)
+        .addDependency(dumpDependency)
+        .measureRunTime()
+        .measureCodeSize()
+        .measureInstructionCodeSize()
+        .measureComposableInstructionCodeSize()
+        .measureDexSegmentsCodeSize()
+        .measureDex2OatCodeSize()
+        .setTimeout(10, TimeUnit.MINUTES)
+        .build();
+  }
+
   public BenchmarkConfig buildR8WithResourceShrinking() {
     return buildR8WithResourceShrinking(getDefaultR8Configuration());
   }
@@ -253,7 +279,20 @@
                 options -> options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces());
   }
 
-  private static ThrowableConsumer<? super R8FullTestBuilder>
+  private static ThrowableConsumer<? super R8PartialTestBuilder>
+      getDefaultR8PartialConfiguration() {
+    return testBuilder ->
+        testBuilder
+            .allowUnnecessaryDontWarnWildcards()
+            .allowUnusedDontWarnPatterns()
+            .allowUnusedProguardConfigurationRules()
+            // TODO(b/222228826): Disallow unrecognized diagnostics and open interfaces.
+            .allowDiagnosticMessages()
+            .addR8PartialOptionsModification(
+                options -> options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces());
+  }
+
+  private static ThrowableConsumer<? super R8TestBuilder<?, ?, ?>>
       getKeepComposableAnnotationsConfiguration() {
     return testBuilder ->
         testBuilder
@@ -268,6 +307,10 @@
     return internalRunR8(builder, false, configuration);
   }
 
+  private static BenchmarkMethod runR8WithPartialShrinking(AppDumpBenchmarkBuilder builder) {
+    return internalRunR8Partial(builder, getDefaultR8PartialConfiguration());
+  }
+
   private static BenchmarkMethod runR8WithResourceShrinking(
       AppDumpBenchmarkBuilder builder, ThrowableConsumer<? super R8FullTestBuilder> configuration) {
     return internalRunR8(builder, true, configuration);
@@ -331,6 +374,52 @@
                 });
   }
 
+  private static BenchmarkMethod internalRunR8Partial(
+      AppDumpBenchmarkBuilder builder,
+      ThrowableConsumer<? super R8PartialTestBuilder> configuration) {
+    return environment ->
+        BenchmarkBase.runner(environment)
+            .setWarmupIterations(0)
+            .run(
+                results -> {
+                  CompilerDump dump = builder.getExtractedDump(environment);
+                  DumpOptions dumpProperties = dump.getBuildProperties();
+
+                  // Verify that the dump does not use features that are not implemented below.
+                  dump.forEachFeatureArchive(
+                      feature -> {
+                        throw new Unimplemented();
+                      });
+                  assertFalse(dumpProperties.getEnableSameFilePolicy());
+                  assertFalse(dumpProperties.getIsolatedSplits());
+                  assertNull(dumpProperties.getAndroidApiExtensionPackages());
+
+                  // Run R8.
+                  TestBase.testForR8Partial(environment.getTemp(), Backend.DEX)
+                      .addProgramFiles(dump.getProgramArchive())
+                      .addLibraryFiles(dump.getLibraryArchive())
+                      .addKeepRuleFiles(dump.getProguardConfigFile())
+                      // TODO(b/388452773): Fix support for default interface methods.
+                      .setMinApi(Math.max(dumpProperties.getMinApi(), AndroidApiLevel.N.getLevel()))
+                      .setR8PartialConfiguration(
+                          b -> builder.programPackages.forEach(b::addJavaTypeIncludePattern))
+                      .apply(b -> addDesugaredLibrary(b, dump))
+                      .apply(configuration)
+                      .applyIf(
+                          environment.getConfig().containsComposableCodeSizeMetric(),
+                          getKeepComposableAnnotationsConfiguration())
+                      .apply(
+                          r ->
+                              r.benchmarkCompile(results)
+                                  .benchmarkCodeSize(results)
+                                  .benchmarkInstructionCodeSize(results)
+                                  .benchmarkDexSegmentsCodeSize(results)
+                                  .benchmarkDex2OatCodeSize(
+                                      results,
+                                      environment.getConfig().isDex2OatVerificationEnabled()));
+                });
+  }
+
   private static BenchmarkMethod runBatchD8(AppDumpBenchmarkBuilder builder) {
     assert builder.compilationMode != null;
     return environment ->
diff --git a/src/test/java/com/android/tools/r8/benchmarks/appdumps/NowInAndroidBenchmarks.java b/src/test/java/com/android/tools/r8/benchmarks/appdumps/NowInAndroidBenchmarks.java
index e2fca85..9ed646a 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/appdumps/NowInAndroidBenchmarks.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/appdumps/NowInAndroidBenchmarks.java
@@ -80,6 +80,12 @@
             .setFromRevision(16017)
             .buildR8(),
         AppDumpBenchmarkBuilder.builder()
+            .setName("NowInAndroidAppPartial")
+            .setDumpDependencyPath(dump)
+            .addProgramPackages("androidx.**", "kotlin.**", "kotlinx.**")
+            .setFromRevision(16017)
+            .buildR8WithPartialShrinking(),
+        AppDumpBenchmarkBuilder.builder()
             .setName("NowInAndroidAppWithResourceShrinking")
             .setDumpDependencyPath(dump)
             .setFromRevision(16017)
diff --git a/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java b/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java
index 3dacb92..d3320d3 100644
--- a/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java
+++ b/src/test/testbase/java/com/android/tools/r8/R8PartialTestBuilder.java
@@ -6,6 +6,7 @@
 import com.android.tools.r8.R8Command.Builder;
 import com.android.tools.r8.TestBase.Backend;
 import com.android.tools.r8.benchmarks.BenchmarkResults;
+import com.android.tools.r8.errors.Unreachable;
 import com.android.tools.r8.shaking.ProguardConfigurationRule;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.Box;
@@ -38,10 +39,25 @@
 
   @Override
   public boolean isR8TestBuilder() {
+    return false;
+  }
+
+  @Override
+  public R8TestBuilder<?, ?, ?> asR8TestBuilder() {
+    return null;
+  }
+
+  @Override
+  public boolean isR8PartialTestBuilder() {
     return true;
   }
 
   @Override
+  public R8PartialTestBuilder asR8PartialTestBuilder() {
+    return this;
+  }
+
+  @Override
   R8PartialTestBuilder self() {
     return this;
   }
@@ -117,4 +133,57 @@
         r8OutputAppBox.get(),
         d8OutputAppBox.get());
   }
+
+  @Override
+  public R8PartialTestBuilder addOptionsModification(Consumer<InternalOptions> optionsConsumer) {
+    throw new Unreachable(
+        "Unexpected use of R8PartialTestBuilder#addOptionsModification. "
+            + "Did you mean addD8PartialOptionsModification or addR8PartialOptionsModification?");
+  }
+
+  public R8PartialTestBuilder addD8PartialOptionsModification(Consumer<InternalOptions> consumer) {
+    return super.addOptionsModification(
+        options ->
+            options.partialCompilationConfiguration.d8DexOptionsConsumer =
+                options.partialCompilationConfiguration.d8DexOptionsConsumer.andThen(consumer));
+  }
+
+  public R8PartialTestBuilder addD8MergeOptionsModification(Consumer<InternalOptions> consumer) {
+    return super.addOptionsModification(
+        options ->
+            options.partialCompilationConfiguration.d8MergeOptionsConsumer =
+                options.partialCompilationConfiguration.d8MergeOptionsConsumer.andThen(consumer));
+  }
+
+  public R8PartialTestBuilder addR8PartialOptionsModification(Consumer<InternalOptions> consumer) {
+    return super.addOptionsModification(
+        options ->
+            options.partialCompilationConfiguration.r8OptionsConsumer =
+                options.partialCompilationConfiguration.r8OptionsConsumer.andThen(consumer));
+  }
+
+  public R8PartialTestBuilder addGlobalOptionsModification(Consumer<InternalOptions> consumer) {
+    return addD8PartialOptionsModification(consumer)
+        .addD8MergeOptionsModification(consumer)
+        .addR8PartialOptionsModification(consumer);
+  }
+
+  @Override
+  public R8PartialTestBuilder allowUnnecessaryDontWarnWildcards() {
+    return addR8PartialOptionsModification(
+        options -> options.getTestingOptions().allowUnnecessaryDontWarnWildcards = true);
+  }
+
+  @Override
+  public R8PartialTestBuilder allowUnusedDontWarnPatterns() {
+    return addR8PartialOptionsModification(
+        options -> options.getTestingOptions().allowUnusedDontWarnRules = true);
+  }
+
+  @Override
+  public R8PartialTestBuilder enableExperimentalKeepAnnotations() {
+    return addR8PartialOptionsModification(
+            o -> o.getTestingOptions().enableEmbeddedKeepAnnotations = true)
+        .addKeepAnnoLibToClasspath();
+  }
 }
diff --git a/src/test/testbase/java/com/android/tools/r8/R8TestBuilder.java b/src/test/testbase/java/com/android/tools/r8/R8TestBuilder.java
index b5da273..3e294f0 100644
--- a/src/test/testbase/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/testbase/java/com/android/tools/r8/R8TestBuilder.java
@@ -445,7 +445,7 @@
     return addOptionsModification(options -> options.testing.allowUnusedDontWarnRules = true);
   }
 
-  public T allowUnusedProguardConfigurationRules() {
+  public final T allowUnusedProguardConfigurationRules() {
     return allowUnusedProguardConfigurationRules(true);
   }
 
@@ -811,7 +811,11 @@
   }
 
   public T enableExperimentalKeepAnnotations() {
-    addOptionsModification(o -> o.testing.enableEmbeddedKeepAnnotations = true);
+    return addOptionsModification(o -> o.testing.enableEmbeddedKeepAnnotations = true)
+        .addKeepAnnoLibToClasspath();
+  }
+
+  public T addKeepAnnoLibToClasspath() {
     try {
       builder.addClasspathFiles(KeepAnnoTestUtils.getKeepAnnoLib(getState().getTempFolder()));
       return self();
diff --git a/src/test/testbase/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/testbase/java/com/android/tools/r8/TestCompilerBuilder.java
index f4f0034..ed19826 100644
--- a/src/test/testbase/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/testbase/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -62,19 +62,26 @@
   public static final Consumer<InternalOptions> DEFAULT_OPTIONS =
       options -> {
         options.testing.enableTestAssertions = true;
-        options.testing.allowUnusedDontWarnRules = false;
-        options.testing.allowUnnecessaryDontWarnWildcards = false;
-        options.testing.listIterationRewritingEnabled = true;
-        options.horizontalClassMergerOptions().enable();
-        options.horizontalClassMergerOptions().setEnableInterfaceMerging();
-        options.inlinerOptions().enableConstructorInliningWithFinalFields = true;
-        options
-            .getCfCodeAnalysisOptions()
-            .setAllowUnreachableCfBlocks(false)
-            .setEnableUnverifiableCodeReporting(true);
-        options.getOpenClosedInterfacesOptions().disallowOpenInterfaces();
       };
 
+  public static final Consumer<InternalOptions> DEFAULT_D8_OPTIONS = DEFAULT_OPTIONS;
+
+  public static final Consumer<InternalOptions> DEFAULT_R8_OPTIONS =
+      DEFAULT_OPTIONS.andThen(
+          options -> {
+            options.testing.allowUnusedDontWarnRules = false;
+            options.testing.allowUnnecessaryDontWarnWildcards = false;
+            options.testing.listIterationRewritingEnabled = true;
+            options.horizontalClassMergerOptions().enable();
+            options.horizontalClassMergerOptions().setEnableInterfaceMerging();
+            options.inlinerOptions().enableConstructorInliningWithFinalFields = true;
+            options
+                .getCfCodeAnalysisOptions()
+                .setAllowUnreachableCfBlocks(false)
+                .setEnableUnverifiableCodeReporting(true);
+            options.getOpenClosedInterfacesOptions().disallowOpenInterfaces();
+          });
+
   final Backend backend;
 
   // Default initialized setup. Can be overwritten if needed.
@@ -89,7 +96,7 @@
   private boolean noMinApiLevel = false;
   private int minApiLevel = -1;
   private boolean optimizeMultidexForLinearAlloc = false;
-  private Consumer<InternalOptions> optionsConsumer = DEFAULT_OPTIONS;
+  private Consumer<InternalOptions> optionsConsumer;
   private ByteArrayOutputStream stdout = null;
   private boolean stdOutForwarding = true;
   private PrintStream oldStdout = null;
@@ -124,6 +131,14 @@
     return null;
   }
 
+  public boolean isR8PartialTestBuilder() {
+    return false;
+  }
+
+  public R8PartialTestBuilder asR8PartialTestBuilder() {
+    return null;
+  }
+
   public boolean isTestShrinkerBuilder() {
     return false;
   }
@@ -152,6 +167,21 @@
       assert backend == Backend.CF;
       setOutputMode(OutputMode.ClassFile);
     }
+    if (isD8TestBuilder()) {
+      optionsConsumer = DEFAULT_D8_OPTIONS;
+    } else if (isR8TestBuilder()) {
+      optionsConsumer = DEFAULT_R8_OPTIONS;
+    } else if (isR8PartialTestBuilder()) {
+      optionsConsumer =
+          DEFAULT_OPTIONS.andThen(
+              options -> {
+                options.partialCompilationConfiguration.d8DexOptionsConsumer = DEFAULT_D8_OPTIONS;
+                options.partialCompilationConfiguration.d8MergeOptionsConsumer = DEFAULT_D8_OPTIONS;
+                options.partialCompilationConfiguration.r8OptionsConsumer = DEFAULT_R8_OPTIONS;
+              });
+    } else {
+      optionsConsumer = DEFAULT_OPTIONS;
+    }
   }
 
   protected int getMinApiLevel() {
@@ -298,7 +328,7 @@
     }
     if (!noMinApiLevel
         && backend.isDex()
-        && (isD8TestBuilder() || isR8TestBuilder())
+        && (isD8TestBuilder() || isR8TestBuilder() || isR8PartialTestBuilder())
         && !isBenchmarkRunner) {
       int minApiLevel = builder.getMinApiLevel();
       Consumer<InternalOptions> previousConsumer = optionsConsumer;
@@ -327,6 +357,12 @@
     if (isD8TestBuilder() || isR8TestBuilder()) {
       addOptionsModification(
           o -> o.getArtProfileOptions().setEnableCompletenessCheckForTesting(!isBenchmarkRunner));
+    } else if (isR8PartialTestBuilder()) {
+      asR8PartialTestBuilder()
+          .addGlobalOptionsModification(
+              o ->
+                  o.getArtProfileOptions()
+                      .setEnableCompletenessCheckForTesting(!isBenchmarkRunner));
     }
 
     builder.setOptimizeMultidexForLinearAlloc(optimizeMultidexForLinearAlloc);
diff --git a/tools/perf.py b/tools/perf.py
index 577647d..9bf5803 100755
--- a/tools/perf.py
+++ b/tools/perf.py
@@ -74,6 +74,9 @@
     'NowInAndroidAppNoJ$Release': {
         'targets': ['d8']
     },
+    'NowInAndroidAppPartial': {
+        'targets': ['r8-full']
+    },
     'OwlApp': {
         'targets': ['r8-full']
     },