Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +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 historic_run |
Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +0200 | [diff] [blame] | 7 | import perf |
| 8 | import utils |
| 9 | |
Christoffer Adamsen | 71711a3 | 2024-09-16 14:24:45 +0200 | [diff] [blame] | 10 | import argparse |
| 11 | import json |
| 12 | import os |
Christoffer Adamsen | 96e6e7e | 2024-12-18 12:30:10 +0100 | [diff] [blame] | 13 | import re |
| 14 | import subprocess |
Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +0200 | [diff] [blame] | 15 | import sys |
| 16 | |
Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +0200 | [diff] [blame] | 17 | TARGETS = ['r8-full'] |
Christoffer Adamsen | 987b637 | 2024-06-17 09:34:11 +0200 | [diff] [blame] | 18 | NUM_COMMITS = 1000 |
Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +0200 | [diff] [blame] | 19 | |
Christoffer Adamsen | f05505b | 2024-09-03 13:48:14 +0200 | [diff] [blame] | 20 | FILES = [ |
Christoffer Adamsen | 58f03d3 | 2024-09-04 09:08:14 +0200 | [diff] [blame] | 21 | 'chart.js', 'd8.html', 'dom.js', 'extensions.js', 'r8.html', 'retrace.html', |
Christoffer Adamsen | f19a990 | 2024-12-18 14:21:59 +0100 | [diff] [blame] | 22 | 'scales.js', 'state.js', 'stylesheet.css', 'tooltip.js', 'url.js', |
| 23 | 'utils.js' |
Christoffer Adamsen | f05505b | 2024-09-03 13:48:14 +0200 | [diff] [blame] | 24 | ] |
Christoffer Adamsen | b43ff59 | 2024-06-12 18:49:01 +0200 | [diff] [blame] | 25 | |
Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +0200 | [diff] [blame] | 26 | |
Christoffer Adamsen | c09ba6f | 2024-06-12 18:48:36 +0200 | [diff] [blame] | 27 | def DownloadCloudBucket(dest): |
| 28 | os.makedirs(dest) |
| 29 | utils.download_file_from_cloud_storage(perf.GetGSLocation('*'), |
| 30 | dest, |
| 31 | concurrent=True, |
| 32 | flags=['-R']) |
| 33 | |
| 34 | |
Christoffer Adamsen | 96e6e7e | 2024-12-18 12:30:10 +0100 | [diff] [blame] | 35 | def GetMainCommits(): |
| 36 | top = utils.get_sha1_from_revision('origin/main') |
| 37 | bottom = utils.get_nth_sha1_from_revision(NUM_COMMITS - 1, 'origin/main') |
| 38 | commits = historic_run.enumerate_git_commits(top, bottom) |
| 39 | assert len(commits) == NUM_COMMITS |
| 40 | return commits |
| 41 | |
| 42 | |
| 43 | def GetReleaseBranches(): |
| 44 | remote_branches = subprocess.check_output( |
| 45 | ['git', 'branch', '-r']).decode('utf-8').strip().splitlines() |
| 46 | result = [] |
| 47 | for remote_branch in remote_branches: |
| 48 | remote_branch = remote_branch.strip() |
| 49 | |
| 50 | # Strip 'origin/'. |
| 51 | try: |
| 52 | remote_name_end_index = remote_branch.index('/') |
| 53 | remote_branch = remote_branch[remote_name_end_index + 1:] |
| 54 | except ValueError: |
| 55 | pass |
| 56 | |
| 57 | # Filter out branches that are not on the form X.Y |
| 58 | if not re.search('^(0|[1-9]\d*)\.(0|[1-9]\d*)$', remote_branch): |
| 59 | continue |
| 60 | |
| 61 | # Filter out branches prior to 8.9. |
| 62 | dot_index = remote_branch.index('.') |
| 63 | [major, minor] = remote_branch.split('.') |
| 64 | if int(major) < 8 or (major == '8' and int(minor) < 9): |
| 65 | continue |
| 66 | |
| 67 | result.append(remote_branch) |
| 68 | return result |
| 69 | |
| 70 | |
| 71 | def GetReleaseCommits(): |
| 72 | release_commits = [] |
| 73 | for branch in GetReleaseBranches(): |
| 74 | (major, minor) = branch.split('.') |
| 75 | candidate_commits = subprocess.check_output([ |
| 76 | 'git', 'log', '--grep=-dev', '--max-count=100', |
| 77 | '--pretty=format:%H %s', 'origin/' + branch, '--', |
| 78 | 'src/main/java/com/android/tools/r8/Version.java' |
| 79 | ]).decode('utf-8').strip().splitlines() |
| 80 | for candidate_commit in candidate_commits: |
| 81 | separator_index = candidate_commit.index(' ') |
| 82 | git_hash = candidate_commit[:separator_index] |
| 83 | git_title = candidate_commit[separator_index + 1:] |
| 84 | if not re.search( |
| 85 | '^Version %s\.%s\.(0|[1-9]\d*)-dev$' % |
| 86 | (major, minor), git_title): |
| 87 | continue |
| 88 | release_commits.append(historic_run.git_commit_from_hash(git_hash)) |
| 89 | return release_commits |
| 90 | |
| 91 | |
Christoffer Adamsen | eeb8d32 | 2024-12-18 18:45:06 +0100 | [diff] [blame] | 92 | def ParseJsonFromCloudStorage(filename, local_bucket_dict): |
| 93 | if not filename in local_bucket_dict: |
Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +0200 | [diff] [blame] | 94 | return None |
Christoffer Adamsen | eeb8d32 | 2024-12-18 18:45:06 +0100 | [diff] [blame] | 95 | return json.loads(local_bucket_dict[filename]) |
Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +0200 | [diff] [blame] | 96 | |
| 97 | |
Christoffer Adamsen | eeb8d32 | 2024-12-18 18:45:06 +0100 | [diff] [blame] | 98 | def RecordBenchmarkResult(commit, benchmark, benchmark_info, local_bucket_dict, |
Christoffer Adamsen | f0d74a1 | 2024-09-03 18:41:36 +0200 | [diff] [blame] | 99 | target, benchmarks): |
| 100 | if not target in benchmark_info['targets']: |
Christoffer Adamsen | 3146d50 | 2024-09-03 15:01:49 +0200 | [diff] [blame] | 101 | return |
Christoffer Adamsen | c12e43b | 2024-09-06 10:15:51 +0200 | [diff] [blame] | 102 | sub_benchmarks = benchmark_info.get('subBenchmarks', {}) |
| 103 | sub_benchmarks_for_target = sub_benchmarks.get(target, []) |
| 104 | if sub_benchmarks_for_target: |
| 105 | for sub_benchmark in sub_benchmarks_for_target: |
| 106 | RecordSingleBenchmarkResult(commit, benchmark + sub_benchmark, |
Christoffer Adamsen | eeb8d32 | 2024-12-18 18:45:06 +0100 | [diff] [blame] | 107 | local_bucket_dict, target, benchmarks) |
Christoffer Adamsen | c12e43b | 2024-09-06 10:15:51 +0200 | [diff] [blame] | 108 | else: |
Christoffer Adamsen | eeb8d32 | 2024-12-18 18:45:06 +0100 | [diff] [blame] | 109 | RecordSingleBenchmarkResult(commit, benchmark, local_bucket_dict, |
| 110 | target, benchmarks) |
Christoffer Adamsen | c12e43b | 2024-09-06 10:15:51 +0200 | [diff] [blame] | 111 | |
| 112 | |
Christoffer Adamsen | eeb8d32 | 2024-12-18 18:45:06 +0100 | [diff] [blame] | 113 | def RecordSingleBenchmarkResult(commit, benchmark, local_bucket_dict, target, |
Christoffer Adamsen | c12e43b | 2024-09-06 10:15:51 +0200 | [diff] [blame] | 114 | benchmarks): |
Christoffer Adamsen | 96e6e7e | 2024-12-18 12:30:10 +0100 | [diff] [blame] | 115 | filename = perf.GetArtifactLocation(benchmark, |
| 116 | target, |
| 117 | commit.hash(), |
| 118 | 'result.json', |
| 119 | branch=commit.branch()) |
Christoffer Adamsen | eeb8d32 | 2024-12-18 18:45:06 +0100 | [diff] [blame] | 120 | benchmark_data = ParseJsonFromCloudStorage(filename, local_bucket_dict) |
Christoffer Adamsen | 3146d50 | 2024-09-03 15:01:49 +0200 | [diff] [blame] | 121 | if benchmark_data: |
| 122 | benchmarks[benchmark] = benchmark_data |
| 123 | |
| 124 | |
| 125 | def RecordBenchmarkResults(commit, benchmarks, benchmark_data): |
| 126 | if benchmarks or benchmark_data: |
Christoffer Adamsen | 3396d81 | 2024-12-18 14:50:15 +0100 | [diff] [blame] | 127 | data = { |
Christoffer Adamsen | 3146d50 | 2024-09-03 15:01:49 +0200 | [diff] [blame] | 128 | 'author': commit.author_name(), |
| 129 | 'hash': commit.hash(), |
| 130 | 'submitted': commit.committer_timestamp(), |
| 131 | 'title': commit.title(), |
| 132 | 'benchmarks': benchmarks |
Christoffer Adamsen | 3396d81 | 2024-12-18 14:50:15 +0100 | [diff] [blame] | 133 | } |
| 134 | version = commit.version() |
| 135 | if version: |
| 136 | data['version'] = version |
| 137 | benchmark_data.append(data) |
Christoffer Adamsen | 3146d50 | 2024-09-03 15:01:49 +0200 | [diff] [blame] | 138 | |
| 139 | |
| 140 | def TrimBenchmarkResults(benchmark_data): |
| 141 | new_benchmark_data_len = len(benchmark_data) |
| 142 | while new_benchmark_data_len > 0: |
| 143 | candidate_len = new_benchmark_data_len - 1 |
| 144 | if not benchmark_data[candidate_len]['benchmarks']: |
| 145 | new_benchmark_data_len = candidate_len |
| 146 | else: |
| 147 | break |
| 148 | return benchmark_data[0:new_benchmark_data_len] |
| 149 | |
| 150 | |
Christoffer Adamsen | 71711a3 | 2024-09-16 14:24:45 +0200 | [diff] [blame] | 151 | def ArchiveBenchmarkResults(benchmark_data, dest, outdir, temp): |
Christoffer Adamsen | 3146d50 | 2024-09-03 15:01:49 +0200 | [diff] [blame] | 152 | # Serialize JSON to temp file. |
| 153 | benchmark_data_file = os.path.join(temp, dest) |
| 154 | with open(benchmark_data_file, 'w') as f: |
| 155 | json.dump(benchmark_data, f) |
| 156 | |
| 157 | # Write output files to public bucket. |
| 158 | perf.ArchiveOutputFile(benchmark_data_file, |
| 159 | dest, |
Christoffer Adamsen | 71711a3 | 2024-09-16 14:24:45 +0200 | [diff] [blame] | 160 | header='Cache-Control:no-store', |
| 161 | outdir=outdir) |
Christoffer Adamsen | 3146d50 | 2024-09-03 15:01:49 +0200 | [diff] [blame] | 162 | |
| 163 | |
Christoffer Adamsen | 71711a3 | 2024-09-16 14:24:45 +0200 | [diff] [blame] | 164 | def run_bucket(): |
Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +0200 | [diff] [blame] | 165 | # Get the N most recent commits sorted by newest first. |
Christoffer Adamsen | 96e6e7e | 2024-12-18 12:30:10 +0100 | [diff] [blame] | 166 | main_commits = GetMainCommits() |
| 167 | |
| 168 | # Get all release commits from 8.9 and onwards. |
| 169 | release_commits = GetReleaseCommits() |
Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +0200 | [diff] [blame] | 170 | |
Christoffer Adamsen | c09ba6f | 2024-06-12 18:48:36 +0200 | [diff] [blame] | 171 | # Download all benchmark data from the cloud bucket to a temp folder. |
Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +0200 | [diff] [blame] | 172 | with utils.TempDir() as temp: |
Christoffer Adamsen | c09ba6f | 2024-06-12 18:48:36 +0200 | [diff] [blame] | 173 | local_bucket = os.path.join(temp, perf.BUCKET) |
| 174 | DownloadCloudBucket(local_bucket) |
Christoffer Adamsen | 96e6e7e | 2024-12-18 12:30:10 +0100 | [diff] [blame] | 175 | run(main_commits + release_commits, local_bucket, temp) |
Christoffer Adamsen | c09ba6f | 2024-06-12 18:48:36 +0200 | [diff] [blame] | 176 | |
Christoffer Adamsen | c09ba6f | 2024-06-12 18:48:36 +0200 | [diff] [blame] | 177 | |
Christoffer Adamsen | 71711a3 | 2024-09-16 14:24:45 +0200 | [diff] [blame] | 178 | def run_local(local_bucket): |
| 179 | commit_hashes = set() |
| 180 | for benchmark in os.listdir(local_bucket): |
| 181 | benchmark_dir = os.path.join(local_bucket, benchmark) |
| 182 | if not os.path.isdir(benchmark_dir): |
| 183 | continue |
| 184 | for target in os.listdir(benchmark_dir): |
| 185 | target_dir = os.path.join(local_bucket, benchmark, target) |
| 186 | if not os.path.isdir(target_dir): |
| 187 | continue |
| 188 | for commit_hash in os.listdir(target_dir): |
| 189 | commit_hash_dir = os.path.join(local_bucket, benchmark, target, |
| 190 | commit_hash) |
| 191 | if not os.path.isdir(commit_hash_dir): |
| 192 | continue |
| 193 | commit_hashes.add(commit_hash) |
| 194 | commits = [] |
| 195 | for commit_hash in commit_hashes: |
| 196 | commits.append(historic_run.git_commit_from_hash(commit_hash)) |
| 197 | commits.sort(key=lambda c: c.committer_timestamp(), reverse=True) |
| 198 | with utils.TempDir() as temp: |
| 199 | outdir = os.path.join(utils.TOOLS_DIR, 'perf') |
| 200 | run(commits, local_bucket, temp, outdir=outdir) |
Christoffer Adamsen | b43ff59 | 2024-06-12 18:49:01 +0200 | [diff] [blame] | 201 | |
Christoffer Adamsen | 3146d50 | 2024-09-03 15:01:49 +0200 | [diff] [blame] | 202 | |
Christoffer Adamsen | 71711a3 | 2024-09-16 14:24:45 +0200 | [diff] [blame] | 203 | def run(commits, local_bucket, temp, outdir=None): |
Christoffer Adamsen | eeb8d32 | 2024-12-18 18:45:06 +0100 | [diff] [blame] | 204 | print('Loading bucket into memory') |
| 205 | local_bucket_dict = {} |
| 206 | for (root, dirs, files) in os.walk(local_bucket): |
| 207 | for file in files: |
| 208 | if file != 'result.json': |
| 209 | continue |
| 210 | abs_path = os.path.join(root, file) |
| 211 | rel_path = os.path.relpath(abs_path, local_bucket) |
| 212 | with open(abs_path, 'r') as f: |
| 213 | local_bucket_dict[rel_path] = f.read() |
| 214 | |
Christoffer Adamsen | 71711a3 | 2024-09-16 14:24:45 +0200 | [diff] [blame] | 215 | # Aggregate all the result.json files into a single file that has the |
| 216 | # same format as tools/perf/benchmark_data.json. |
Christoffer Adamsen | eeb8d32 | 2024-12-18 18:45:06 +0100 | [diff] [blame] | 217 | print('Processing commits') |
Christoffer Adamsen | 71711a3 | 2024-09-16 14:24:45 +0200 | [diff] [blame] | 218 | d8_benchmark_data = [] |
| 219 | r8_benchmark_data = [] |
| 220 | retrace_benchmark_data = [] |
| 221 | for commit in commits: |
| 222 | d8_benchmarks = {} |
| 223 | r8_benchmarks = {} |
| 224 | retrace_benchmarks = {} |
| 225 | for benchmark, benchmark_info in perf.ALL_BENCHMARKS.items(): |
| 226 | RecordBenchmarkResult(commit, benchmark, benchmark_info, |
Christoffer Adamsen | eeb8d32 | 2024-12-18 18:45:06 +0100 | [diff] [blame] | 227 | local_bucket_dict, 'd8', d8_benchmarks) |
Christoffer Adamsen | 71711a3 | 2024-09-16 14:24:45 +0200 | [diff] [blame] | 228 | RecordBenchmarkResult(commit, benchmark, benchmark_info, |
Christoffer Adamsen | eeb8d32 | 2024-12-18 18:45:06 +0100 | [diff] [blame] | 229 | local_bucket_dict, 'r8-full', r8_benchmarks) |
Christoffer Adamsen | 71711a3 | 2024-09-16 14:24:45 +0200 | [diff] [blame] | 230 | RecordBenchmarkResult(commit, benchmark, benchmark_info, |
Christoffer Adamsen | eeb8d32 | 2024-12-18 18:45:06 +0100 | [diff] [blame] | 231 | local_bucket_dict, 'retrace', |
| 232 | retrace_benchmarks) |
Christoffer Adamsen | 71711a3 | 2024-09-16 14:24:45 +0200 | [diff] [blame] | 233 | RecordBenchmarkResults(commit, d8_benchmarks, d8_benchmark_data) |
| 234 | RecordBenchmarkResults(commit, r8_benchmarks, r8_benchmark_data) |
| 235 | RecordBenchmarkResults(commit, retrace_benchmarks, |
| 236 | retrace_benchmark_data) |
| 237 | |
| 238 | # Trim data. |
Christoffer Adamsen | eeb8d32 | 2024-12-18 18:45:06 +0100 | [diff] [blame] | 239 | print('Trimming data') |
Christoffer Adamsen | 71711a3 | 2024-09-16 14:24:45 +0200 | [diff] [blame] | 240 | d8_benchmark_data = TrimBenchmarkResults(d8_benchmark_data) |
| 241 | r8_benchmark_data = TrimBenchmarkResults(r8_benchmark_data) |
| 242 | retrace_benchmark_data = TrimBenchmarkResults(retrace_benchmark_data) |
| 243 | |
| 244 | # Write output JSON files to public bucket, or to tools/perf/ if running |
| 245 | # with --local-bucket. |
Christoffer Adamsen | eeb8d32 | 2024-12-18 18:45:06 +0100 | [diff] [blame] | 246 | print('Writing JSON') |
Christoffer Adamsen | 71711a3 | 2024-09-16 14:24:45 +0200 | [diff] [blame] | 247 | ArchiveBenchmarkResults(d8_benchmark_data, 'd8_benchmark_data.json', outdir, |
| 248 | temp) |
| 249 | ArchiveBenchmarkResults(r8_benchmark_data, 'r8_benchmark_data.json', outdir, |
| 250 | temp) |
| 251 | ArchiveBenchmarkResults(retrace_benchmark_data, |
| 252 | 'retrace_benchmark_data.json', outdir, temp) |
| 253 | |
| 254 | # Write remaining files to public bucket. |
Christoffer Adamsen | eeb8d32 | 2024-12-18 18:45:06 +0100 | [diff] [blame] | 255 | print('Writing static files') |
Christoffer Adamsen | 71711a3 | 2024-09-16 14:24:45 +0200 | [diff] [blame] | 256 | if outdir is None: |
Christoffer Adamsen | f05505b | 2024-09-03 13:48:14 +0200 | [diff] [blame] | 257 | for file in FILES: |
| 258 | dest = os.path.join(utils.TOOLS_DIR, 'perf', file) |
| 259 | perf.ArchiveOutputFile(dest, file) |
| 260 | |
Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +0200 | [diff] [blame] | 261 | |
Christoffer Adamsen | 71711a3 | 2024-09-16 14:24:45 +0200 | [diff] [blame] | 262 | def ParseOptions(): |
| 263 | result = argparse.ArgumentParser() |
| 264 | result.add_argument('--local-bucket', help='Local results dir.') |
| 265 | return result.parse_known_args() |
| 266 | |
| 267 | |
Christoffer Adamsen | 19d093d | 2024-06-13 14:20:52 +0200 | [diff] [blame] | 268 | def main(): |
Christoffer Adamsen | 71711a3 | 2024-09-16 14:24:45 +0200 | [diff] [blame] | 269 | options, args = ParseOptions() |
| 270 | if options.local_bucket: |
| 271 | run_local(options.local_bucket) |
| 272 | else: |
| 273 | run_bucket() |
Christoffer Adamsen | 19d093d | 2024-06-13 14:20:52 +0200 | [diff] [blame] | 274 | |
| 275 | |
Christoffer Adamsen | 3028371 | 2024-06-12 13:08:14 +0200 | [diff] [blame] | 276 | if __name__ == '__main__': |
| 277 | sys.exit(main()) |