Rico Wind | 7617be9 | 2024-05-22 10:19:46 +0200 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | # Copyright (c) 2024, the R8 project authors. Please see the AUTHORS file |
| 3 | # for details. All rights reserved. Use of this source code is governed by a |
| 4 | # BSD-style license that can be found in the LICENSE file. |
| 5 | |
| 6 | import argparse |
Christoffer Adamsen | c748e52 | 2024-06-12 18:48:45 +0200 | [diff] [blame] | 7 | import compiledump |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 8 | import json |
Rico Wind | 7ff131f | 2024-05-27 13:31:36 +0200 | [diff] [blame] | 9 | import os |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 10 | import shutil |
Rico Wind | 23a1972 | 2024-05-22 11:44:12 +0200 | [diff] [blame] | 11 | import subprocess |
Rico Wind | 7617be9 | 2024-05-22 10:19:46 +0200 | [diff] [blame] | 12 | import sys |
| 13 | |
Rico Wind | 7ff131f | 2024-05-27 13:31:36 +0200 | [diff] [blame] | 14 | import utils |
| 15 | |
Rico Wind | 73bac14 | 2024-06-04 09:51:22 +0200 | [diff] [blame] | 16 | BUCKET = "r8-perf-results" |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 17 | SAMPLE_BENCHMARK_RESULT_JSON = { |
| 18 | 'benchmark_name': '<benchmark_name>', |
| 19 | 'results': [{ |
| 20 | 'code_size': 0, |
| 21 | 'runtime': 0 |
| 22 | }] |
| 23 | } |
Rico Wind | 7ff131f | 2024-05-27 13:31:36 +0200 | [diff] [blame] | 24 | |
| 25 | # Result structure on cloud storage |
| 26 | # gs://bucket/benchmark_results/APP/TARGET/GIT_HASH/results |
| 27 | # meta |
| 28 | # where results simply contains the result lines and |
| 29 | # meta contains information about the execution (machine) |
Rico Wind | 7617be9 | 2024-05-22 10:19:46 +0200 | [diff] [blame] | 30 | |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 31 | |
Rico Wind | 7617be9 | 2024-05-22 10:19:46 +0200 | [diff] [blame] | 32 | def ParseOptions(): |
| 33 | result = argparse.ArgumentParser() |
| 34 | result.add_argument('--app', |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 35 | help='Specific app(s) to measure.', |
| 36 | action='append') |
| 37 | result.add_argument('--iterations', |
Christoffer Adamsen | 8c13d04 | 2024-06-12 13:08:06 +0200 | [diff] [blame] | 38 | help='How many times run_benchmark is run.', |
| 39 | type=int, |
| 40 | default=1) |
| 41 | result.add_argument('--iterations-inner', |
| 42 | help='How many iterations to run inside run_benchmark.', |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 43 | type=int, |
| 44 | default=10) |
| 45 | result.add_argument('--outdir', |
| 46 | help='Output directory for running locally.') |
Christoffer Adamsen | 9daa13b | 2024-06-12 13:07:58 +0200 | [diff] [blame] | 47 | result.add_argument('--skip-if-output-exists', |
| 48 | help='Skip if output exists.', |
| 49 | action='store_true', |
| 50 | default=False) |
Rico Wind | 7ff131f | 2024-05-27 13:31:36 +0200 | [diff] [blame] | 51 | result.add_argument('--target', |
| 52 | help='Specific target to run on.', |
| 53 | default='r8-full', |
| 54 | choices=['d8', 'r8-full', 'r8-force', 'r8-compat']) |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 55 | result.add_argument('--verbose', |
| 56 | help='To enable verbose logging.', |
| 57 | action='store_true', |
| 58 | default=False) |
Christoffer Adamsen | 9daa13b | 2024-06-12 13:07:58 +0200 | [diff] [blame] | 59 | result.add_argument('--version', |
| 60 | '-v', |
| 61 | help='Use R8 hash for the run (default local build)', |
| 62 | default=None) |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 63 | options, args = result.parse_known_args() |
| 64 | options.apps = options.app or ['NowInAndroidApp', 'TiviApp'] |
| 65 | options.quiet = not options.verbose |
| 66 | del options.app |
| 67 | return options, args |
Rico Wind | 7617be9 | 2024-05-22 10:19:46 +0200 | [diff] [blame] | 68 | |
Rico Wind | 7ff131f | 2024-05-27 13:31:36 +0200 | [diff] [blame] | 69 | |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 70 | def MergeBenchmarkResultJsonFiles(benchmark_result_json_files): |
| 71 | merged_benchmark_result_json = None |
| 72 | for benchmark_result_json_file in benchmark_result_json_files: |
| 73 | benchmark_result_json = ParseBenchmarkResultJsonFile( |
| 74 | benchmark_result_json_file) |
| 75 | if merged_benchmark_result_json is None: |
| 76 | merged_benchmark_result_json = benchmark_result_json |
| 77 | else: |
| 78 | MergeBenchmarkResultJsonFile(merged_benchmark_result_json, |
| 79 | benchmark_result_json) |
| 80 | return merged_benchmark_result_json |
Rico Wind | 7ff131f | 2024-05-27 13:31:36 +0200 | [diff] [blame] | 81 | |
| 82 | |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 83 | def MergeBenchmarkResultJsonFile(merged_benchmark_result_json, |
| 84 | benchmark_result_json): |
| 85 | assert benchmark_result_json.keys() == SAMPLE_BENCHMARK_RESULT_JSON.keys() |
| 86 | assert merged_benchmark_result_json[ |
| 87 | 'benchmark_name'] == benchmark_result_json['benchmark_name'] |
| 88 | merged_benchmark_result_json['results'].extend( |
| 89 | benchmark_result_json['results']) |
| 90 | |
| 91 | |
| 92 | def ParseBenchmarkResultJsonFile(result_json_file): |
| 93 | with open(result_json_file, 'r') as f: |
| 94 | lines = f.readlines() |
| 95 | return json.loads(''.join(lines)) |
| 96 | |
| 97 | |
Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +0200 | [diff] [blame] | 98 | def GetArtifactLocation(app, target, version, filename): |
| 99 | version_or_head = version or utils.get_HEAD_sha1() |
| 100 | return f'{app}/{target}/{version_or_head}/{filename}' |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 101 | |
| 102 | |
Christoffer Adamsen | b43ff59 | 2024-06-12 18:49:01 +0200 | [diff] [blame^] | 103 | def GetGSLocation(filename, bucket=BUCKET): |
| 104 | return f'gs://{bucket}/{filename}' |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 105 | |
| 106 | |
Christoffer Adamsen | b43ff59 | 2024-06-12 18:49:01 +0200 | [diff] [blame^] | 107 | def ArchiveOutputFile(file, dest, bucket=BUCKET, header=None, outdir=None): |
Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +0200 | [diff] [blame] | 108 | if outdir: |
| 109 | dest_in_outdir = os.path.join(outdir, dest) |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 110 | os.makedirs(os.path.dirname(dest_in_outdir), exist_ok=True) |
| 111 | shutil.copyfile(file, dest_in_outdir) |
| 112 | else: |
Christoffer Adamsen | b43ff59 | 2024-06-12 18:49:01 +0200 | [diff] [blame^] | 113 | utils.upload_file_to_cloud_storage(file, |
| 114 | GetGSLocation(dest, bucket=bucket), |
| 115 | header=header) |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 116 | |
Rico Wind | 7ff131f | 2024-05-27 13:31:36 +0200 | [diff] [blame] | 117 | |
Christoffer Adamsen | 9daa13b | 2024-06-12 13:07:58 +0200 | [diff] [blame] | 118 | # Usage with historic_run.py: |
| 119 | # ./tools/historic_run.py |
| 120 | # --cmd "perf.py --skip-if-output-exists --version" |
| 121 | # --timeout -1 |
| 122 | # --top 3373fd18453835bf49bff9f02523a507a2ebf317 |
| 123 | # --bottom 7486f01e0622cb5935b77a92b59ddf1ca8dbd2e2 |
Rico Wind | 7617be9 | 2024-05-22 10:19:46 +0200 | [diff] [blame] | 124 | def main(): |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 125 | options, args = ParseOptions() |
Rico Wind | 7ff131f | 2024-05-27 13:31:36 +0200 | [diff] [blame] | 126 | with utils.TempDir() as temp: |
Christoffer Adamsen | c748e52 | 2024-06-12 18:48:45 +0200 | [diff] [blame] | 127 | if options.version: |
| 128 | # Download r8.jar once instead of once per run_benchmark.py invocation. |
| 129 | download_options = argparse.Namespace(no_build=True, nolib=True) |
| 130 | r8jar = compiledump.download_distribution(options.version, |
| 131 | download_options, temp) |
| 132 | |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 133 | for app in options.apps: |
Christoffer Adamsen | 9daa13b | 2024-06-12 13:07:58 +0200 | [diff] [blame] | 134 | if options.skip_if_output_exists: |
| 135 | if options.outdir: |
| 136 | raise NotImplementedError |
| 137 | output = GetGSLocation( |
Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +0200 | [diff] [blame] | 138 | GetArtifactLocation(app, options.target, options.version, |
| 139 | 'result.json')) |
Christoffer Adamsen | 9daa13b | 2024-06-12 13:07:58 +0200 | [diff] [blame] | 140 | if utils.cloud_storage_exists(output): |
| 141 | print(f'Skipping run, {output} already exists.') |
| 142 | continue |
| 143 | |
Christoffer Adamsen | 8c13d04 | 2024-06-12 13:08:06 +0200 | [diff] [blame] | 144 | base_cmd = [ |
| 145 | 'tools/run_benchmark.py', '--benchmark', app, '--target', |
| 146 | options.target |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 147 | ] |
Christoffer Adamsen | 8c13d04 | 2024-06-12 13:08:06 +0200 | [diff] [blame] | 148 | if options.verbose: |
| 149 | base_cmd.append('--verbose') |
Christoffer Adamsen | 9daa13b | 2024-06-12 13:07:58 +0200 | [diff] [blame] | 150 | if options.version: |
Christoffer Adamsen | c748e52 | 2024-06-12 18:48:45 +0200 | [diff] [blame] | 151 | base_cmd.extend([ |
| 152 | '--version', options.version, '--version-jar', r8jar, |
| 153 | '--nolib' |
| 154 | ]) |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 155 | |
Christoffer Adamsen | 8c13d04 | 2024-06-12 13:08:06 +0200 | [diff] [blame] | 156 | # Build |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 157 | utils.Print(f'Preparing {app}', quiet=options.quiet) |
Christoffer Adamsen | 8c13d04 | 2024-06-12 13:08:06 +0200 | [diff] [blame] | 158 | build_cmd = base_cmd + ['--iterations', '0'] |
| 159 | subprocess.check_output(build_cmd) |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 160 | |
| 161 | # Run benchmark. |
| 162 | benchmark_result_json_files = [] |
| 163 | for i in range(options.iterations): |
| 164 | utils.Print(f'Benchmarking {app} ({i+1}/{options.iterations})', |
| 165 | quiet=options.quiet) |
Christoffer Adamsen | 9daa13b | 2024-06-12 13:07:58 +0200 | [diff] [blame] | 166 | benchhmark_result_file = os.path.join(temp, f'result_file_{i}') |
Christoffer Adamsen | 8c13d04 | 2024-06-12 13:08:06 +0200 | [diff] [blame] | 167 | iteration_cmd = base_cmd + [ |
| 168 | '--iterations', |
| 169 | str(options.iterations_inner), '--output', |
| 170 | benchhmark_result_file, '--no-build' |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 171 | ] |
| 172 | subprocess.check_output(iteration_cmd) |
| 173 | benchmark_result_json_files.append(benchhmark_result_file) |
| 174 | |
| 175 | # Merge results and write output. |
| 176 | result_file = os.path.join(temp, 'result_file') |
| 177 | with open(result_file, 'w') as f: |
| 178 | json.dump( |
| 179 | MergeBenchmarkResultJsonFiles(benchmark_result_json_files), |
| 180 | f) |
Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +0200 | [diff] [blame] | 181 | ArchiveOutputFile( |
| 182 | result_file, |
| 183 | GetArtifactLocation(app, options.target, options.version, |
| 184 | 'result.json'), options.outdir) |
Christoffer Adamsen | e3b8b6d | 2024-06-12 13:07:49 +0200 | [diff] [blame] | 185 | |
| 186 | # Write metadata. |
| 187 | if os.environ.get('SWARMING_BOT_ID'): |
| 188 | meta_file = os.path.join(temp, "meta") |
| 189 | with open(meta_file, 'w') as f: |
| 190 | f.write("Produced by: " + os.environ.get('SWARMING_BOT_ID')) |
Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +0200 | [diff] [blame] | 191 | ArchiveOutputFile( |
| 192 | meta_file, |
| 193 | GetArtifactLocation(app, options.target, options.version, |
| 194 | 'meta'), options.outdir) |
Rico Wind | 7ff131f | 2024-05-27 13:31:36 +0200 | [diff] [blame] | 195 | |
Rico Wind | 7617be9 | 2024-05-22 10:19:46 +0200 | [diff] [blame] | 196 | |
| 197 | if __name__ == '__main__': |
| 198 | sys.exit(main()) |