blob: 7e2a67794b2fd76a65b4a466a6400ab31483fb0e [file] [log] [blame]
// Copyright (c) 2022, 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.LibraryDesugaringTestConfiguration;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.benchmarks.BenchmarkBase;
import com.android.tools.r8.benchmarks.BenchmarkConfig;
import com.android.tools.r8.benchmarks.BenchmarkConfigError;
import com.android.tools.r8.benchmarks.BenchmarkDependency;
import com.android.tools.r8.benchmarks.BenchmarkEnvironment;
import com.android.tools.r8.benchmarks.BenchmarkMethod;
import com.android.tools.r8.benchmarks.BenchmarkMetric;
import com.android.tools.r8.benchmarks.BenchmarkSuite;
import com.android.tools.r8.benchmarks.BenchmarkTarget;
import com.android.tools.r8.dump.CompilerDump;
import com.android.tools.r8.dump.DumpOptions;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class AppDumpBenchmarkBuilder {
public static AppDumpBenchmarkBuilder builder() {
return new AppDumpBenchmarkBuilder();
}
private String name;
private BenchmarkDependency dumpDependency;
private int fromRevision = -1;
private final List<String> programPackages = new ArrayList<>();
public void verify() {
if (name == null) {
throw new BenchmarkConfigError("Missing name");
}
if (dumpDependency == null) {
throw new BenchmarkConfigError("Missing dump");
}
if (fromRevision < 0) {
throw new BenchmarkConfigError("Missing from-revision");
}
}
public AppDumpBenchmarkBuilder setName(String name) {
this.name = name;
return this;
}
public AppDumpBenchmarkBuilder setDumpDependencyPath(Path dumpDependencyPath) {
return setDumpDependency(
new BenchmarkDependency(
"appdump",
dumpDependencyPath.getFileName().toString(),
dumpDependencyPath.getParent()));
}
public AppDumpBenchmarkBuilder setDumpDependency(BenchmarkDependency dependency) {
this.dumpDependency = dependency;
return this;
}
public AppDumpBenchmarkBuilder setFromRevision(int fromRevision) {
this.fromRevision = fromRevision;
return this;
}
public AppDumpBenchmarkBuilder addProgramPackages(String... pkgs) {
return addProgramPackages(Arrays.asList(pkgs));
}
public AppDumpBenchmarkBuilder addProgramPackages(Collection<String> pkgs) {
programPackages.addAll(pkgs);
return this;
}
public BenchmarkConfig buildR8() {
verify();
return BenchmarkConfig.builder()
.setName(name)
.setTarget(BenchmarkTarget.R8_NON_COMPAT)
.setSuite(BenchmarkSuite.OPENSOURCE_BENCHMARKS)
.setMethod(runR8(this))
.setFromRevision(fromRevision)
.addDependency(dumpDependency)
.measureRunTime()
.measureCodeSize()
.setTimeout(10, TimeUnit.MINUTES)
.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()) {
throw new BenchmarkConfigError(
"Incremental benchmark should specifiy at least one program package");
}
return BenchmarkConfig.builder()
.setName(name)
.setTarget(BenchmarkTarget.D8)
.setSuite(BenchmarkSuite.OPENSOURCE_BENCHMARKS)
.setMethod(runIncrementalD8(this))
.setFromRevision(fromRevision)
.addDependency(dumpDependency)
.addSubBenchmark(nameForLibraryPart(), BenchmarkMetric.RunTimeRaw)
.addSubBenchmark(nameForProgramPart(), BenchmarkMetric.RunTimeRaw)
.addSubBenchmark(nameForMergePart(), BenchmarkMetric.RunTimeRaw)
.setTimeout(10, TimeUnit.MINUTES)
.build();
}
public BenchmarkConfig buildBatchD8() {
verify();
return BenchmarkConfig.builder()
.setName(name)
.setTarget(BenchmarkTarget.D8)
.setSuite(BenchmarkSuite.OPENSOURCE_BENCHMARKS)
.setMethod(runBatchD8(this))
.setFromRevision(fromRevision)
.addDependency(dumpDependency)
.measureRunTime()
.measureCodeSize()
.setTimeout(10, TimeUnit.MINUTES)
.build();
}
private String nameForCodePart() {
return name + "Code";
}
private String nameForLibraryPart() {
return name + "Library";
}
private String nameForProgramPart() {
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 {
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());
}
private static void addDesugaredLibrary(
TestCompilerBuilder<?, ?, ?, ?, ?> builder, CompilerDump dump) {
Path config = dump.getDesugaredLibraryFile();
if (Files.exists(config)) {
builder.enableCoreLibraryDesugaring(
LibraryDesugaringTestConfiguration.forSpecification(config));
}
}
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, enableResourceShrinking);
DumpOptions dumpProperties = dump.getBuildProperties();
TestBase.testForR8(environment.getTemp(), Backend.DEX)
.addProgramFiles(dump.getProgramArchive())
.addLibraryFiles(dump.getLibraryArchive())
.addKeepRuleFiles(dump.getProguardConfigFile())
.setMinApi(dumpProperties.getMinApi())
.apply(b -> addDesugaredLibrary(b, dump))
.allowUnnecessaryDontWarnWildcards()
.allowUnusedDontWarnPatterns()
.allowUnusedProguardConfigurationRules()
// TODO(b/222228826): Disallow unrecognized diagnostics and open interfaces.
.allowDiagnosticMessages()
.addOptionsModification(
options ->
options.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
.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));
});
}
private static BenchmarkMethod runBatchD8(AppDumpBenchmarkBuilder builder) {
return environment ->
BenchmarkBase.runner(environment.getConfig())
.setWarmupIterations(1)
.run(
results -> {
CompilerDump dump = builder.getExtractedDump(environment);
DumpOptions dumpProperties = dump.getBuildProperties();
TestBase.testForD8(environment.getTemp(), Backend.DEX)
.addProgramFiles(dump.getProgramArchive())
.addLibraryFiles(dump.getLibraryArchive())
.setMinApi(dumpProperties.getMinApi())
.apply(b -> addDesugaredLibrary(b, dump))
.benchmarkCompile(results)
.benchmarkCodeSize(results);
});
}
private static BenchmarkMethod runIncrementalD8(AppDumpBenchmarkBuilder builder) {
return environment ->
BenchmarkBase.runner(environment.getConfig())
.setWarmupIterations(1)
.reportResultSum()
.run(
results -> {
CompilerDump dump = builder.getExtractedDump(environment);
DumpOptions dumpProperties = dump.getBuildProperties();
PackageSplitResources resources =
PackageSplitResources.create(
environment.getTemp(), dump.getProgramArchive(), builder.programPackages);
if (resources.getPackageFiles().isEmpty()) {
throw new RuntimeException("Unexpected empty set of program package files");
}
TestBase.testForD8(environment.getTemp(), Backend.DEX)
.addProgramFiles(resources.getOtherFiles())
.addLibraryFiles(dump.getLibraryArchive())
.setMinApi(dumpProperties.getMinApi())
.benchmarkCompile(results.getSubResults(builder.nameForLibraryPart()));
List<Path> programOutputs = new ArrayList<>();
for (Path programFile : resources.getPackageFiles()) {
programOutputs.add(
TestBase.testForD8(environment.getTemp(), Backend.DEX)
.addProgramFiles(programFile)
.addClasspathFiles(dump.getProgramArchive())
.addLibraryFiles(dump.getLibraryArchive())
.setMinApi(dumpProperties.getMinApi())
.apply(b -> addDesugaredLibrary(b, dump))
.setIntermediate(true)
.benchmarkCompile(results.getSubResults(builder.nameForProgramPart()))
.writeToZip());
}
TestBase.testForD8(environment.getTemp(), Backend.DEX)
.addProgramFiles(programOutputs)
.addLibraryFiles(dump.getLibraryArchive())
.setMinApi(dumpProperties.getMinApi())
.benchmarkCompile(results.getSubResults(builder.nameForMergePart()));
});
}
}