blob: ed1d6e1d5db18023ade3dbbae799799c61b7c8de [file] [log] [blame]
Rico Wind7617be92024-05-22 10:19:46 +02001#!/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
6import argparse
Christoffer Adamsenc748e522024-06-12 18:48:45 +02007import compiledump
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +02008import json
Rico Wind7ff131f2024-05-27 13:31:36 +02009import os
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +020010import shutil
Rico Wind23a19722024-05-22 11:44:12 +020011import subprocess
Rico Wind7617be92024-05-22 10:19:46 +020012import sys
13
Rico Wind7ff131f2024-05-27 13:31:36 +020014import utils
15
Rico Wind73bac142024-06-04 09:51:22 +020016BUCKET = "r8-perf-results"
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +020017SAMPLE_BENCHMARK_RESULT_JSON = {
18 'benchmark_name': '<benchmark_name>',
19 'results': [{
20 'code_size': 0,
21 'runtime': 0
22 }]
23}
Rico Wind7ff131f2024-05-27 13:31:36 +020024
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 Wind7617be92024-05-22 10:19:46 +020030
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +020031
Rico Wind7617be92024-05-22 10:19:46 +020032def ParseOptions():
33 result = argparse.ArgumentParser()
34 result.add_argument('--app',
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +020035 help='Specific app(s) to measure.',
36 action='append')
37 result.add_argument('--iterations',
Christoffer Adamsen8c13d042024-06-12 13:08:06 +020038 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 Adamsene3b8b6d2024-06-12 13:07:49 +020043 type=int,
44 default=10)
45 result.add_argument('--outdir',
46 help='Output directory for running locally.')
Christoffer Adamsen9daa13b2024-06-12 13:07:58 +020047 result.add_argument('--skip-if-output-exists',
48 help='Skip if output exists.',
49 action='store_true',
50 default=False)
Rico Wind7ff131f2024-05-27 13:31:36 +020051 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 Adamsene3b8b6d2024-06-12 13:07:49 +020055 result.add_argument('--verbose',
56 help='To enable verbose logging.',
57 action='store_true',
58 default=False)
Christoffer Adamsen9daa13b2024-06-12 13:07:58 +020059 result.add_argument('--version',
60 '-v',
61 help='Use R8 hash for the run (default local build)',
62 default=None)
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +020063 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 Wind7617be92024-05-22 10:19:46 +020068
Rico Wind7ff131f2024-05-27 13:31:36 +020069
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +020070def 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 Wind7ff131f2024-05-27 13:31:36 +020081
82
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +020083def 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
92def 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 Adamsen30283712024-06-12 13:08:14 +020098def 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 Adamsene3b8b6d2024-06-12 13:07:49 +0200101
102
Christoffer Adamsenb43ff592024-06-12 18:49:01 +0200103def GetGSLocation(filename, bucket=BUCKET):
104 return f'gs://{bucket}/{filename}'
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +0200105
106
Christoffer Adamsenb43ff592024-06-12 18:49:01 +0200107def ArchiveOutputFile(file, dest, bucket=BUCKET, header=None, outdir=None):
Christoffer Adamsen30283712024-06-12 13:08:14 +0200108 if outdir:
109 dest_in_outdir = os.path.join(outdir, dest)
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +0200110 os.makedirs(os.path.dirname(dest_in_outdir), exist_ok=True)
111 shutil.copyfile(file, dest_in_outdir)
112 else:
Christoffer Adamsenb43ff592024-06-12 18:49:01 +0200113 utils.upload_file_to_cloud_storage(file,
114 GetGSLocation(dest, bucket=bucket),
115 header=header)
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +0200116
Rico Wind7ff131f2024-05-27 13:31:36 +0200117
Christoffer Adamsen9daa13b2024-06-12 13:07:58 +0200118# 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 Wind7617be92024-05-22 10:19:46 +0200124def main():
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +0200125 options, args = ParseOptions()
Rico Wind7ff131f2024-05-27 13:31:36 +0200126 with utils.TempDir() as temp:
Christoffer Adamsenc748e522024-06-12 18:48:45 +0200127 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 Adamsene3b8b6d2024-06-12 13:07:49 +0200133 for app in options.apps:
Christoffer Adamsen9daa13b2024-06-12 13:07:58 +0200134 if options.skip_if_output_exists:
135 if options.outdir:
136 raise NotImplementedError
137 output = GetGSLocation(
Christoffer Adamsen30283712024-06-12 13:08:14 +0200138 GetArtifactLocation(app, options.target, options.version,
139 'result.json'))
Christoffer Adamsen9daa13b2024-06-12 13:07:58 +0200140 if utils.cloud_storage_exists(output):
141 print(f'Skipping run, {output} already exists.')
142 continue
143
Christoffer Adamsen8c13d042024-06-12 13:08:06 +0200144 base_cmd = [
145 'tools/run_benchmark.py', '--benchmark', app, '--target',
146 options.target
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +0200147 ]
Christoffer Adamsen8c13d042024-06-12 13:08:06 +0200148 if options.verbose:
149 base_cmd.append('--verbose')
Christoffer Adamsen9daa13b2024-06-12 13:07:58 +0200150 if options.version:
Christoffer Adamsenc748e522024-06-12 18:48:45 +0200151 base_cmd.extend([
152 '--version', options.version, '--version-jar', r8jar,
153 '--nolib'
154 ])
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +0200155
Christoffer Adamsen8c13d042024-06-12 13:08:06 +0200156 # Build
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +0200157 utils.Print(f'Preparing {app}', quiet=options.quiet)
Christoffer Adamsen8c13d042024-06-12 13:08:06 +0200158 build_cmd = base_cmd + ['--iterations', '0']
159 subprocess.check_output(build_cmd)
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +0200160
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 Adamsen9daa13b2024-06-12 13:07:58 +0200166 benchhmark_result_file = os.path.join(temp, f'result_file_{i}')
Christoffer Adamsen8c13d042024-06-12 13:08:06 +0200167 iteration_cmd = base_cmd + [
168 '--iterations',
169 str(options.iterations_inner), '--output',
170 benchhmark_result_file, '--no-build'
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +0200171 ]
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 Adamsen30283712024-06-12 13:08:14 +0200181 ArchiveOutputFile(
182 result_file,
183 GetArtifactLocation(app, options.target, options.version,
184 'result.json'), options.outdir)
Christoffer Adamsene3b8b6d2024-06-12 13:07:49 +0200185
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 Adamsen30283712024-06-12 13:08:14 +0200191 ArchiveOutputFile(
192 meta_file,
193 GetArtifactLocation(app, options.target, options.version,
194 'meta'), options.outdir)
Rico Wind7ff131f2024-05-27 13:31:36 +0200195
Rico Wind7617be92024-05-22 10:19:46 +0200196
197if __name__ == '__main__':
198 sys.exit(main())