| #!/usr/bin/env python3 | 
 | # 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. | 
 |  | 
 | import argparse | 
 | import os | 
 | import subprocess | 
 | import sys | 
 |  | 
 | import compiledump | 
 | import gradle | 
 | import jdk | 
 | import utils | 
 |  | 
 | GOLEM_BUILD_TARGETS_TESTS = [ | 
 |     utils.GRADLE_TASK_ALL_TESTS_WITH_APPLY_MAPPING_JAR, | 
 |     utils.GRADLE_TASK_TESTBASE_WITH_APPLY_MAPPING_JAR, | 
 |     utils.GRADLE_TASK_TEST_DEPS_JAR | 
 | ] | 
 | GOLEM_BUILD_TARGETS = [ | 
 |     utils.GRADLE_TASK_R8LIB, utils.GRADLE_TASK_KEEP_ANNO_JAR | 
 | ] + GOLEM_BUILD_TARGETS_TESTS | 
 |  | 
 |  | 
 | def get_golem_resource_path(benchmark): | 
 |     return os.path.join('benchmarks', benchmark) | 
 |  | 
 |  | 
 | def get_jdk_home(options, benchmark): | 
 |     if options.golem: | 
 |         return os.path.join(get_golem_resource_path(benchmark), 'linux') | 
 |     return None | 
 |  | 
 |  | 
 | def parse_options(argv): | 
 |     result = argparse.ArgumentParser(description='Run test-based benchmarks.') | 
 |     result.add_argument('--golem', | 
 |                         help='Indicate this as a run on golem', | 
 |                         default=False, | 
 |                         action='store_true') | 
 |     result.add_argument('--benchmark', | 
 |                         help='The test benchmark to run', | 
 |                         required=True) | 
 |     result.add_argument( | 
 |         '--target', | 
 |         help='The test target to run', | 
 |         required=True, | 
 |         # These should 1:1 with benchmarks/BenchmarkTarget.java | 
 |         choices=['d8', 'r8-full', 'r8-force', 'r8-compat', 'retrace']) | 
 |     result.add_argument( | 
 |         '--debug-agent', | 
 |         '--debug_agent', | 
 |         help= | 
 |         'Enable Java debug agent and suspend compilation (default disabled)', | 
 |         default=False, | 
 |         action='store_true') | 
 |     result.add_argument('--nolib', | 
 |                         '--no-lib', | 
 |                         '--no-r8lib', | 
 |                         help='Run the non-lib R8 build (default false)', | 
 |                         default=False, | 
 |                         action='store_true') | 
 |     result.add_argument('--no-build', | 
 |                         '--no_build', | 
 |                         help='Run without building first (default false)', | 
 |                         default=False, | 
 |                         action='store_true') | 
 |     result.add_argument('--enable-assertions', | 
 |                         '--enable_assertions', | 
 |                         '-ea', | 
 |                         help='Enable assertions when running', | 
 |                         default=False, | 
 |                         action='store_true') | 
 |     result.add_argument('--iterations', | 
 |                         '-i', | 
 |                         help='Number of iterations to run', | 
 |                         type=int) | 
 |     result.add_argument('--output', | 
 |                         help='Output path where to write the result') | 
 |     result.add_argument('--print-times', | 
 |                         help='Print timing information from r8', | 
 |                         default=False, | 
 |                         action='store_true') | 
 |     result.add_argument( | 
 |         '--version', | 
 |         '-v', | 
 |         help='Use R8 version/hash for the run (default local build)', | 
 |         default=None) | 
 |     result.add_argument( | 
 |         '--version-jar', | 
 |         help='The r8.jar corresponding to the version given at --version.', | 
 |         default=None) | 
 |     result.add_argument('--temp', | 
 |                         help='A directory to use for temporaries and outputs.', | 
 |                         default=None) | 
 |     result.add_argument('--verbose', | 
 |                         help='To enable verbose logging.', | 
 |                         action='store_true', | 
 |                         default=False) | 
 |     options, args = result.parse_known_args(argv) | 
 |     options.quiet = not options.verbose | 
 |     # We must download the non-lib distribution when running with a specific | 
 |     # version, since BenchmarkMainEntryRunner is using R8 internals. | 
 |     # TODO(b/346477461): Look into removing this limitation. | 
 |     assert options.version is None or options.nolib | 
 |     return options, args | 
 |  | 
 |  | 
 | def main(argv, temp): | 
 |     options, args = parse_options(argv) | 
 |  | 
 |     if options.output: | 
 |         options.output = os.path.abspath(options.output) | 
 |  | 
 |     if options.temp: | 
 |         temp = options.temp | 
 |         os.makedirs(temp, exist_ok=True) | 
 |  | 
 |     if options.golem: | 
 |         options.no_build = True | 
 |         if options.nolib: | 
 |             print("Error: golem should always run r8lib") | 
 |             return 1 | 
 |  | 
 |     if options.nolib: | 
 |         testBuildTargets = [ | 
 |             utils.GRADLE_TASK_TEST_JAR, utils.GRADLE_TASK_TEST_DEPS_JAR, | 
 |             utils.GRADLE_TASK_TEST_UNZIP_TESTBASE | 
 |         ] | 
 |         buildTargets = [utils.GRADLE_TASK_R8, utils.GRADLE_TASK_KEEP_ANNO_JAR | 
 |                        ] + testBuildTargets | 
 |         r8jar = utils.R8_JAR | 
 |         testjars = [ | 
 |             utils.R8_TESTS_JAR, utils.R8_TESTS_DEPS_JAR, utils.R8_TESTBASE_JAR | 
 |         ] | 
 |     else: | 
 |         testBuildTargets = GOLEM_BUILD_TARGETS_TESTS | 
 |         buildTargets = GOLEM_BUILD_TARGETS | 
 |         r8jar = utils.R8LIB_JAR | 
 |         testjars = [ | 
 |             os.path.join(utils.R8LIB_TESTS_JAR), | 
 |             os.path.join(utils.R8LIB_TESTS_DEPS_JAR), | 
 |             os.path.join(utils.R8LIB_TESTBASE_JAR) | 
 |         ] | 
 |  | 
 |     if options.version or options.version_jar: | 
 |         # r8 is downloaded so only test jar needs to be built. | 
 |         buildTargets = testBuildTargets | 
 |         r8jar = options.version_jar or compiledump.download_distribution( | 
 |             options.version, options, temp) | 
 |  | 
 |     if not options.no_build: | 
 |         gradle.RunGradle(buildTargets + ['-Pno_internal']) | 
 |  | 
 |     if not options.golem: | 
 |         # When running locally, change the working directory to be in 'temp'. | 
 |         # This is hard to do properly within the JVM so we do it here. | 
 |         with utils.ChangedWorkingDirectory(temp): | 
 |             return run(options, r8jar, testjars) | 
 |     else: | 
 |         return run(options, r8jar, testjars) | 
 |  | 
 |  | 
 | def run(options, r8jar, testjars): | 
 |     jdkhome = get_jdk_home(options, options.benchmark) | 
 |     cmd = [ | 
 |         jdk.GetJavaExecutable(jdkhome), | 
 |         '-Xms8g', | 
 |         '-Xmx8g', | 
 |         '-XX:+TieredCompilation', | 
 |         '-XX:TieredStopAtLevel=4', | 
 |         '-DBENCHMARK_IGNORE_CODE_SIZE_DIFFERENCES', | 
 |         f'-DBUILD_PROP_KEEPANNO_RUNTIME_PATH={utils.REPO_ROOT}/d8_r8/keepanno/build/classes/java/main', | 
 |         # Since we change the working directory to a temp folder. | 
 |         f'-DREPO_ROOT={utils.REPO_ROOT}' | 
 |     ] | 
 |     if options.enable_assertions: | 
 |         cmd.append('-ea') | 
 |     if options.print_times: | 
 |         cmd.append('-Dcom.android.tools.r8.printtimes=1') | 
 |     if not options.golem: | 
 |         cmd.extend([ | 
 |             f'-DTEST_DATA_LOCATION={utils.REPO_ROOT}/d8_r8/test_modules/tests_java_8/build/classes/java/test', | 
 |             f'-DTESTBASE_DATA_LOCATION={utils.REPO_ROOT}/d8_r8/test_modules/testbase/build/classes/java/main', | 
 |         ]) | 
 |     if options.iterations is not None: | 
 |         if options.iterations == 0: | 
 |             return | 
 |         cmd.append(f'-DBENCHMARK_ITERATIONS={options.iterations}') | 
 |     if options.output: | 
 |         cmd.append(f'-DBENCHMARK_OUTPUT={options.output}') | 
 |     cmd.extend(['-cp', ':'.join([r8jar] + testjars)]) | 
 |     if options.debug_agent: | 
 |         cmd.append( | 
 |             '-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005' | 
 |         ) | 
 |     cmd.extend([ | 
 |         'com.android.tools.r8.benchmarks.BenchmarkMainEntryRunner', | 
 |         options.benchmark, | 
 |         options.target, | 
 |         # When running locally the working directory is moved and we pass the | 
 |         # repository root as an argument. The runner can then setup dependencies. | 
 |         'golem' if options.golem else utils.REPO_ROOT, | 
 |     ]) | 
 |     utils.PrintCmd(cmd, quiet=options.quiet) | 
 |     return subprocess.check_call(cmd) | 
 |  | 
 |  | 
 | if __name__ == '__main__': | 
 |     with utils.TempDir() as temp: | 
 |         sys.exit(main(sys.argv[1:], temp)) |