Add nowinandroid benchmark

Contents of README.google:

Name: Now in Android App
URL: https://github.com/android/nowinandroid
Version: NA
Revision: 1d2029aa2c4273ff75a9239112f32800800bd26b
Date: Feb 20, 2024
License: Apache License 2.0

Fixes: b/308368445
Change-Id: Ib0def6ed3cc2304327123981339394580e82c5c4
diff --git a/.gitignore b/.gitignore
index a3f84c9..ba2303e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -270,6 +270,8 @@
 third_party/opensource-apps/wikipedia
 third_party/opensource-apps/wikipedia.tar.gz
 third_party/opensource-apps/android/compose-samples/*
+third_party/opensource-apps/android/nowinandroid
+third_party/opensource-apps/android/nowinandroid.tar.gz
 third_party/proguard/*
 third_party/proguardsettings.tar.gz
 third_party/proguardsettings/
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 51cab44..5184c82 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -953,6 +953,11 @@
     return addProgramClassFileData(testResource.getRClass().getClassFileData());
   }
 
+  public T setAndroidResourcesFromPath(Path input) throws IOException {
+    return setAndroidResourcesFromPath(
+        input, getState().getNewTempFile("resourceshrinkeroutput.zip"));
+  }
+
   public T setAndroidResourcesFromPath(Path input, Path output) {
     resourceShrinkerOutput = output;
     getBuilder()
diff --git a/src/test/java/com/android/tools/r8/R8TestCompileResult.java b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
index 7454ce3..ef7013b 100644
--- a/src/test/java/com/android/tools/r8/R8TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
@@ -11,6 +11,7 @@
 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.dexsplitter.SplitterTestBase.SplitRunner;
 import com.android.tools.r8.profile.art.model.ExternalArtProfile;
 import com.android.tools.r8.profile.art.utils.ArtProfileInspector;
@@ -27,6 +28,7 @@
 import com.android.tools.r8.utils.graphinspector.GraphInspector;
 import java.io.IOException;
 import java.io.UncheckedIOException;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.HashMap;
 import java.util.List;
@@ -70,6 +72,11 @@
     this.resourceShrinkerOutputForFeatures = resourceShrinkerOutputForFeatures;
   }
 
+  public R8TestCompileResult benchmarkResourceSize(BenchmarkResults results) throws IOException {
+    results.addCodeSizeResult(Files.size(resourceShrinkerOutput));
+    return self();
+  }
+
   @Override
   public R8TestCompileResult self() {
     return this;
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index 4c2d6a8..24cd012 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -24,13 +24,11 @@
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.FileUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.ThrowingConsumer;
 import com.android.tools.r8.utils.TriFunction;
-import com.android.tools.r8.utils.ZipUtils;
 import com.android.tools.r8.utils.codeinspector.ClassSubject;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
 import com.google.common.collect.ImmutableList;
@@ -708,18 +706,8 @@
         app, runtime, ToolHelper.runDex2OatRaw(jarFile, oatFile, vm), state);
   }
 
-  public CR benchmarkCodeSize(BenchmarkResults results) throws IOException {
-    Path out = writeToZip();
-    Box<Long> size = new Box<>(0L);
-    ZipUtils.iter(
-        out,
-        (entry, stream) -> {
-          if ((getBackend().isDex() && entry.getName().endsWith(".dex"))
-              || getBackend().isCf() && entry.getName().endsWith(".class")) {
-            size.set(size.get() + entry.getSize());
-          }
-        });
-    results.addCodeSizeResult(size.get());
+  public CR benchmarkCodeSize(BenchmarkResults results) throws IOException, ResourceException {
+    results.addCodeSizeResult(app.applicationSize());
     return self();
   }
 }
diff --git a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollection.java b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollection.java
index 5c30550..a8cdc56 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollection.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollection.java
@@ -5,6 +5,7 @@
 
 import static java.util.Collections.emptyList;
 
+import com.android.tools.r8.benchmarks.appdumps.NowInAndroidBenchmarks;
 import com.android.tools.r8.benchmarks.appdumps.TiviBenchmarks;
 import com.android.tools.r8.benchmarks.desugaredlib.L8Benchmark;
 import com.android.tools.r8.benchmarks.desugaredlib.LegacyDesugaredLibraryBenchmark;
@@ -49,6 +50,7 @@
     HelloWorldBenchmark.configs().forEach(collection::addBenchmark);
     LegacyDesugaredLibraryBenchmark.configs().forEach(collection::addBenchmark);
     L8Benchmark.configs().forEach(collection::addBenchmark);
+    NowInAndroidBenchmarks.configs().forEach(collection::addBenchmark);
     TiviBenchmarks.configs().forEach(collection::addBenchmark);
     RetraceStackTraceBenchmark.configs().forEach(collection::addBenchmark);
     return collection;
diff --git a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollectionPrinter.java b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollectionPrinter.java
index 1a26aa7..a0a073a 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollectionPrinter.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkCollectionPrinter.java
@@ -6,10 +6,12 @@
 import com.android.tools.r8.ToolHelper;
 import com.android.tools.r8.ToolHelper.ProcessResult;
 import com.android.tools.r8.utils.CollectionUtils;
+import com.android.tools.r8.utils.IterableUtils;
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.StringUtils;
 import com.android.tools.r8.utils.StringUtils.BraceType;
 import com.google.common.base.Strings;
+import com.google.common.collect.Sets;
 import com.google.common.hash.Hasher;
 import com.google.common.hash.Hashing;
 import java.io.IOException;
@@ -25,6 +27,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Function;
 
 public class BenchmarkCollectionPrinter {
 
@@ -143,16 +146,18 @@
   private void printGroupBenchmarkBlock(
       String benchmarkName, List<BenchmarkConfig> benchmarkVariants) throws IOException {
     String suite = BenchmarkConfig.getCommonSuite(benchmarkVariants).getDartName();
+    Map<String, Set<BenchmarkMetric>> subBenchmarks =
+        BenchmarkConfig.getCommonSubBenchmarks(benchmarkVariants);
+    Set<BenchmarkMetric> metrics =
+        Sets.newLinkedHashSet(IterableUtils.flatMap(subBenchmarks.values(), Function.identity()));
     printSemi("final name = " + quote(benchmarkName));
-    printSemi("final benchmark = GroupBenchmark(name, [])");
+    printSemi("final benchmark = GroupBenchmark(name, " + prettyMetrics(metrics) + ")");
     BenchmarkTimeout timeout = BenchmarkConfig.getCommonTimeout(benchmarkVariants);
     if (timeout != null) {
       printSemi("final timeout = const Duration(seconds: " + timeout.asSeconds() + ")");
       printSemi("ExecutionManagement.addTimeoutConstraint(timeout, benchmark: benchmark)");
     }
     printBenchmarkVariantOptionBlock(benchmarkVariants);
-    Map<String, Set<BenchmarkMetric>> subBenchmarks =
-        BenchmarkConfig.getCommonSubBenchmarks(benchmarkVariants);
     Collection<String> subNames = CollectionUtils.sort(subBenchmarks.keySet(), String::compareTo);
     for (String subName : subNames) {
       scopeBraces(
@@ -229,7 +234,8 @@
   }
 
   private static Path getJdkHome() throws IOException {
-    ProcessBuilder builder = new ProcessBuilder("python3", "tools/jdk.py");
+    ProcessBuilder builder =
+        new ProcessBuilder("python3", ToolHelper.getProjectRoot() + "tools/jdk.py");
     ProcessResult result = ToolHelper.runProcess(builder, QUIET);
     if (result.exitCode != 0) {
       throw new BenchmarkConfigError("Unexpected failure to determine jdk home: " + result);
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 e9b205d..29f0c78 100644
--- a/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsCollection.java
+++ b/src/test/java/com/android/tools/r8/benchmarks/BenchmarkResultsCollection.java
@@ -20,12 +20,14 @@
         (name, metrics) -> results.put(name, new BenchmarkResultsSingle(name, metrics)));
   }
 
+  @Override
   public void addRuntimeResult(long result) {
     throw new BenchmarkConfigError(
         "Unexpected attempt to add a runtime result to a the root of a benchmark with"
             + " sub-benchmarks");
   }
 
+  @Override
   public void addCodeSizeResult(long result) {
     throw new BenchmarkConfigError(
         "Unexpected attempt to add a runtime result to a the root of a benchmark with"
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 f69b30f..7e2a677 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
@@ -36,7 +36,7 @@
   private String name;
   private BenchmarkDependency dumpDependency;
   private int fromRevision = -1;
-  private List<String> programPackages = new ArrayList<>();
+  private final List<String> programPackages = new ArrayList<>();
 
   public void verify() {
     if (name == null) {
@@ -97,6 +97,22 @@
         .build();
   }
 
+  public BenchmarkConfig buildR8WithResourceShrinking() {
+    verify();
+    return BenchmarkConfig.builder()
+        .setName(name)
+        .setTarget(BenchmarkTarget.R8_NON_COMPAT)
+        .setSuite(BenchmarkSuite.OPENSOURCE_BENCHMARKS)
+        .setMethod(runR8WithResourceShrinking(this))
+        .setFromRevision(fromRevision)
+        .addDependency(dumpDependency)
+        .addSubBenchmark(nameForCodePart(), BenchmarkMetric.CodeSize)
+        .addSubBenchmark(nameForRuntimePart(), BenchmarkMetric.RunTimeRaw)
+        .addSubBenchmark(nameForResourcePart(), BenchmarkMetric.CodeSize)
+        .setTimeout(10, TimeUnit.MINUTES)
+        .build();
+  }
+
   public BenchmarkConfig buildIncrementalD8() {
     verify();
     if (programPackages.isEmpty()) {
@@ -132,6 +148,10 @@
         .build();
   }
 
+  private String nameForCodePart() {
+    return name + "Code";
+  }
+
   private String nameForLibraryPart() {
     return name + "Library";
   }
@@ -140,12 +160,26 @@
     return name + "Program";
   }
 
+  private String nameForResourcePart() {
+    return name + "Resource";
+  }
+
+  private String nameForRuntimePart() {
+    return name + "Runtime";
+  }
+
   private String nameForMergePart() {
     return name + "Merge";
   }
 
   private CompilerDump getExtractedDump(BenchmarkEnvironment environment) throws IOException {
-    Path dump = dumpDependency.getRoot(environment).resolve("dump_app.zip");
+    return getExtractedDump(environment, false);
+  }
+
+  private CompilerDump getExtractedDump(
+      BenchmarkEnvironment environment, boolean enableResourceShrinking) throws IOException {
+    String dumpName = enableResourceShrinking ? "dump_app_res.zip" : "dump_app.zip";
+    Path dump = dumpDependency.getRoot(environment).resolve(dumpName);
     return CompilerDump.fromArchive(dump, environment.getTemp().newFolder().toPath());
   }
 
@@ -159,12 +193,22 @@
   }
 
   private static BenchmarkMethod runR8(AppDumpBenchmarkBuilder builder) {
+    return internalRunR8(builder, false);
+  }
+
+  private static BenchmarkMethod runR8WithResourceShrinking(AppDumpBenchmarkBuilder builder) {
+    return internalRunR8(builder, true);
+  }
+
+  private static BenchmarkMethod internalRunR8(
+      AppDumpBenchmarkBuilder builder, boolean enableResourceShrinking) {
     return environment ->
         BenchmarkBase.runner(environment.getConfig())
             .setWarmupIterations(1)
             .run(
                 results -> {
-                  CompilerDump dump = builder.getExtractedDump(environment);
+                  CompilerDump dump =
+                      builder.getExtractedDump(environment, enableResourceShrinking);
                   DumpOptions dumpProperties = dump.getBuildProperties();
                   TestBase.testForR8(environment.getTemp(), Backend.DEX)
                       .addProgramFiles(dump.getProgramArchive())
@@ -180,8 +224,21 @@
                       .addOptionsModification(
                           options ->
                               options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
-                      .benchmarkCompile(results)
-                      .benchmarkCodeSize(results);
+                      .applyIf(
+                          enableResourceShrinking,
+                          b ->
+                              b.enableOptimizedShrinking()
+                                  .setAndroidResourcesFromPath(dump.getAndroidResources()))
+                      .applyIf(
+                          enableResourceShrinking,
+                          r ->
+                              r.benchmarkCompile(
+                                      results.getSubResults(builder.nameForRuntimePart()))
+                                  .benchmarkCodeSize(
+                                      results.getSubResults(builder.nameForCodePart()))
+                                  .benchmarkResourceSize(
+                                      results.getSubResults(builder.nameForResourcePart())),
+                          r -> r.benchmarkCompile(results).benchmarkCodeSize(results));
                 });
   }
 
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
new file mode 100644
index 0000000..c401bad
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/benchmarks/appdumps/NowInAndroidBenchmarks.java
@@ -0,0 +1,51 @@
+// 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.appdumps;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.benchmarks.BenchmarkBase;
+import com.android.tools.r8.benchmarks.BenchmarkConfig;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class NowInAndroidBenchmarks extends BenchmarkBase {
+
+  private static final Path dump =
+      Paths.get(ToolHelper.THIRD_PARTY_DIR, "opensource-apps", "android", "nowinandroid");
+
+  public NowInAndroidBenchmarks(BenchmarkConfig config, TestParameters parameters) {
+    super(config, parameters);
+  }
+
+  @Parameters(name = "{0}")
+  public static List<Object[]> data() {
+    return parametersFromConfigs(configs());
+  }
+
+  public static List<BenchmarkConfig> configs() {
+    return ImmutableList.of(
+        AppDumpBenchmarkBuilder.builder()
+            .setName("NowInAndroidApp")
+            .setDumpDependencyPath(dump)
+            .setFromRevision(16017)
+            .buildBatchD8(),
+        AppDumpBenchmarkBuilder.builder()
+            .setName("NowInAndroidApp")
+            .setDumpDependencyPath(dump)
+            .setFromRevision(16017)
+            .buildR8(),
+        AppDumpBenchmarkBuilder.builder()
+            .setName("NowInAndroidAppWithResourceShrinking")
+            .setDumpDependencyPath(dump)
+            .setFromRevision(16017)
+            .buildR8WithResourceShrinking());
+  }
+}
diff --git a/third_party/opensource-apps/android/nowinandroid.tar.gz.sha1 b/third_party/opensource-apps/android/nowinandroid.tar.gz.sha1
new file mode 100644
index 0000000..818d960
--- /dev/null
+++ b/third_party/opensource-apps/android/nowinandroid.tar.gz.sha1
@@ -0,0 +1 @@
+a7939d3a61e72f091071f19ad8532a0ea388a607
\ No newline at end of file