| // 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.helloworld; |
| |
| import com.android.tools.r8.TestParameters; |
| import com.android.tools.r8.benchmarks.BenchmarkBase; |
| import com.android.tools.r8.benchmarks.BenchmarkConfig; |
| 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.BenchmarkTarget; |
| import com.android.tools.r8.utils.AndroidApiLevel; |
| import com.android.tools.r8.utils.BooleanUtils; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableList.Builder; |
| import java.nio.file.Path; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.List; |
| import java.util.function.Function; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| import org.junit.runners.Parameterized.Parameters; |
| |
| /** Example of setting up a benchmark based on the testing infrastructure. */ |
| @RunWith(Parameterized.class) |
| public class HelloWorldBenchmark extends BenchmarkBase { |
| |
| @Parameters(name = "{0}") |
| public static List<Object[]> data() { |
| return parametersFromConfigs(configs()); |
| } |
| |
| public HelloWorldBenchmark(BenchmarkConfig config, TestParameters parameters) { |
| super(config, parameters); |
| } |
| |
| /** Static method to add benchmarks to the benchmark collection. */ |
| public static List<BenchmarkConfig> configs() { |
| Builder<BenchmarkConfig> benchmarks = ImmutableList.builder(); |
| makeBenchmark(BenchmarkTarget.D8, HelloWorldBenchmark::benchmarkD8, benchmarks); |
| makeBenchmark(BenchmarkTarget.R8_NON_COMPAT, HelloWorldBenchmark::benchmarkR8, benchmarks); |
| return benchmarks.build(); |
| } |
| |
| // Options/parameter setup to define variants of the benchmark above. |
| // Other benchmarks may not need this kind of options. It is just to help create the variants. |
| private static class Options { |
| final BenchmarkTarget target; |
| final Backend backend; |
| final BenchmarkDependency library; |
| final AndroidApiLevel minApi = AndroidApiLevel.B; |
| |
| public Options(BenchmarkTarget target, Backend backend, boolean includeLibrary) { |
| this.target = target; |
| this.backend = backend; |
| library = includeLibrary ? BenchmarkDependency.getRuntimeJarJava8() : null; |
| } |
| |
| public String getName() { |
| // The name include each non-target option for the variants to ensure unique benchmarks. |
| String backendString = backend.isCf() ? "Cf" : "Dex"; |
| String libraryString = library != null ? "" : "NoLib"; |
| return "HelloWorld" + backendString + libraryString; |
| } |
| } |
| |
| private static void makeBenchmark( |
| BenchmarkTarget target, |
| Function<Options, BenchmarkMethod> method, |
| ImmutableList.Builder<BenchmarkConfig> benchmarks) { |
| for (boolean includeLibrary : BooleanUtils.values()) { |
| for (Backend backend : Backend.values()) { |
| Options options = new Options(target, backend, includeLibrary); |
| BenchmarkConfig.Builder builder = |
| BenchmarkConfig.builder() |
| // The benchmark is required to have a unique combination of name and target. |
| .setName(options.getName()) |
| .setTarget(target) |
| // The benchmark is required to have at least one metric. |
| .measureRunTime() |
| .measureCodeSize() |
| // The benchmark is required to have a runner method which defines the actual |
| // execution. |
| .setMethod(method.apply(options)) |
| // The benchmark is required to set a "golem from revision". |
| // Find this value by looking at the current revision on golem. |
| .setFromRevision(12215) |
| // The benchmark can optionally time the warmup. This is not needed to use a warmup |
| // in the actual run, only to include it as its own benchmark entry on golem. |
| .measureWarmup(); |
| // If compiling with a library it needs to be added as a dependency. |
| if (options.library != null) { |
| builder.addDependency(options.library); |
| } |
| benchmarks.add(builder.build()); |
| } |
| } |
| } |
| |
| public static BenchmarkMethod benchmarkD8(Options options) { |
| return environment -> |
| runner(environment.getConfig()) |
| .setWarmupIterations(1) |
| .setBenchmarkIterations(100) |
| .reportResultSum() |
| .run( |
| results -> |
| testForD8(environment.getTemp(), options.backend) |
| .setMinApi(options.minApi) |
| .addLibraryFiles(getLibraryFiles(options, environment)) |
| .addProgramClasses(TestClass.class) |
| // Compile and measure the run time. |
| .benchmarkCompile(results) |
| // Measure the output size. |
| .benchmarkCodeSize(results)); |
| } |
| |
| public static BenchmarkMethod benchmarkR8(Options options) { |
| return environment -> |
| runner(environment.getConfig()) |
| .setWarmupIterations(1) |
| .setBenchmarkIterations(4) |
| .reportResultSum() |
| .run( |
| results -> |
| testForR8(environment.getTemp(), options.backend) |
| .addLibraryFiles(getLibraryFiles(options, environment)) |
| .applyIf(options.library == null, b -> b.addDontWarn("*")) |
| .setMinApi(options.minApi) |
| .addProgramClasses(TestClass.class) |
| .addKeepMainRule(TestClass.class) |
| // Compile and measure the run time. |
| .benchmarkCompile(results) |
| // Measure the output size. |
| .benchmarkCodeSize(results)); |
| } |
| |
| private static Collection<Path> getLibraryFiles( |
| Options options, BenchmarkEnvironment environment) { |
| return options.library != null |
| ? Collections.singletonList(options.library.getRoot(environment).resolve("rt.jar")) |
| : Collections.emptyList(); |
| } |
| |
| static class TestClass { |
| |
| public static void main(String[] args) { |
| System.out.println("Hello world!"); |
| } |
| } |
| } |