Archive and aggregate perf try runs
When running jobs on the 'perf' bot, the option --patch-set should be set for try jobs. When this option is set, we now archive the results to gs://r8-perf-results/try/.
When aggregating the data in the bucket as part of creating a single json file for go/r8perf, we now look for hashes in gs://r8-perf-results/try/ and treat include these as try runs.
The aggregated try runs are archived to their own json file at gs://r8-perf-results/r8_benchmark_try_data.json.
Change-Id: Id7acc6ed7a021b22dbeb3616d3a9b84672c88713
diff --git a/tools/historic_run.py b/tools/historic_run.py
index 74bb69b..b153276 100755
--- a/tools/historic_run.py
+++ b/tools/historic_run.py
@@ -66,7 +66,9 @@
branches = subprocess.check_output(
['git', 'branch', '--contains',
self.hash(), '-r']).decode('utf-8').strip().splitlines()
- if len(branches) != 1:
+ if len(branches) == 0:
+ self._branch = None
+ elif len(branches) != 1:
self._branch = 'main'
else:
branch = branches[0].strip()
@@ -102,6 +104,9 @@
def committer_timestamp(self):
return self.timestamp
+ def parent_hash(self):
+ return utils.get_nth_sha1_from_revision(1, self.hash())
+
def version(self):
if self._version_is_computed:
return self._version
diff --git a/tools/perf.py b/tools/perf.py
index 4f69209..ab933c4 100755
--- a/tools/perf.py
+++ b/tools/perf.py
@@ -198,7 +198,7 @@
help='Output directory for running locally.')
result.add_argument('--patch-ref',
help='The patch ref for a try run. '
- 'Should only be used from rex.py.')
+ 'Should only be used from rex.py.')
result.add_argument('--skip-if-output-exists',
help='Skip if output exists.',
action='store_true',
@@ -223,6 +223,7 @@
options.benchmarks = INTERNAL_BENCHMARKS.keys()
else:
options.benchmarks = EXTERNAL_BENCHMARKS.keys()
+ options.is_try = options.patch_ref is not None
options.quiet = not options.verbose
del options.benchmark
return options, args
@@ -275,14 +276,25 @@
return json.loads(''.join(lines))
-def GetArtifactLocation(benchmark, target, version, filename, branch=None):
+def GetArtifactLocation(benchmark,
+ target,
+ version,
+ filename,
+ branch=None,
+ is_try=False):
if version:
+ if is_try:
+ assert branch is None
+ return f'try/{benchmark}/{target}/{version}/{filename}'
if branch and branch != 'main':
return f'branches/{branch}/{benchmark}/{target}/{version}/{filename}'
return f'{benchmark}/{target}/{version}/{filename}'
else:
commit = utils.get_HEAD_commit()
branch = commit.branch()
+ if is_try:
+ assert branch is None
+ return f'try/{benchmark}/{target}/{commit.hash()}/{filename}'
if branch == 'main':
return f'{benchmark}/{target}/{commit.hash()}/{filename}'
return f'branches/{branch}/{benchmark}/{target}/{commit.hash()}/{filename}'
@@ -298,8 +310,11 @@
with open(result_file, 'w') as f:
json.dump(MergeBenchmarkResultJsonFiles(benchmark_result_json_files), f)
ArchiveOutputFile(result_file,
- GetArtifactLocation(benchmark, target, options.version,
- 'result.json'),
+ GetArtifactLocation(benchmark,
+ target,
+ options.version,
+ 'result.json',
+ is_try=options.is_try),
outdir=options.outdir)
@@ -322,9 +337,6 @@
# --bottom 7486f01e0622cb5935b77a92b59ddf1ca8dbd2e2
def main():
options, args = ParseOptions()
- if options.patch_ref:
- print('Received patch ref', options.patch_ref)
- return
Build(options)
any_failed = False
with utils.TempDir() as temp:
@@ -348,8 +360,11 @@
if options.outdir:
raise NotImplementedError
output = GetGSLocation(
- GetArtifactLocation(benchmark, target, options.version,
- 'result.json'))
+ GetArtifactLocation(benchmark,
+ target,
+ options.version,
+ 'result.json',
+ is_try=options.is_try))
if utils.cloud_storage_exists(output):
print(f'Skipping run, {output} already exists.')
continue
@@ -424,8 +439,11 @@
os.environ.get('SWARMING_BOT_ID'))
ArchiveOutputFile(meta_file,
GetArtifactLocation(
- benchmark, target, options.version,
- 'meta'),
+ benchmark,
+ target,
+ options.version,
+ 'meta',
+ is_try=options.is_try),
outdir=options.outdir)
# Only upload benchmark data when running on the perf bot.
diff --git a/tools/upload_benchmark_data_to_google_storage.py b/tools/upload_benchmark_data_to_google_storage.py
index 7020a5e..4d6c534 100755
--- a/tools/upload_benchmark_data_to_google_storage.py
+++ b/tools/upload_benchmark_data_to_google_storage.py
@@ -70,8 +70,10 @@
def CmpVersions(x, y):
- semver_x = utils.check_basic_semver_version(x.version(), allowPrerelease=True)
- semver_y = utils.check_basic_semver_version(y.version(), allowPrerelease=True)
+ semver_x = utils.check_basic_semver_version(x.version(),
+ allowPrerelease=True)
+ semver_y = utils.check_basic_semver_version(y.version(),
+ allowPrerelease=True)
if semver_x.larger_than(semver_y):
return 1
if semver_y.larger_than(semver_x):
@@ -101,6 +103,17 @@
return release_commits
+def GetTryCommits(local_bucket_try_dict):
+ try_commits = []
+ for key, value in local_bucket_try_dict.items():
+ # The hash is the 4th component in the path:
+ # try/{benchmark}/{target}/{commit.hash()}/{filename}.
+ try_hash = key.split('/')[3]
+ try_commit = historic_run.git_commit_from_hash(try_hash)
+ try_commits.append(try_commit)
+ return try_commits
+
+
def ParseJsonFromCloudStorage(filename, local_bucket_dict):
if not filename in local_bucket_dict:
return None
@@ -108,7 +121,7 @@
def RecordBenchmarkResult(commit, benchmark, benchmark_info, local_bucket_dict,
- target, benchmarks):
+ target, benchmarks, is_try):
if not target in benchmark_info['targets']:
return
sub_benchmarks = benchmark_info.get('subBenchmarks', {})
@@ -116,25 +129,27 @@
if sub_benchmarks_for_target:
for sub_benchmark in sub_benchmarks_for_target:
RecordSingleBenchmarkResult(commit, benchmark + sub_benchmark,
- local_bucket_dict, target, benchmarks)
+ local_bucket_dict, target, benchmarks,
+ is_try)
else:
RecordSingleBenchmarkResult(commit, benchmark, local_bucket_dict,
- target, benchmarks)
+ target, benchmarks, is_try)
def RecordSingleBenchmarkResult(commit, benchmark, local_bucket_dict, target,
- benchmarks):
+ benchmarks, is_try):
filename = perf.GetArtifactLocation(benchmark,
target,
commit.hash(),
'result.json',
- branch=commit.branch())
+ branch=commit.branch(),
+ is_try=is_try)
benchmark_data = ParseJsonFromCloudStorage(filename, local_bucket_dict)
if benchmark_data:
benchmarks[benchmark] = benchmark_data
-def RecordBenchmarkResults(commit, benchmarks, benchmark_data):
+def RecordBenchmarkResults(commit, benchmarks, benchmark_data, is_try):
if benchmarks or benchmark_data:
data = {
'author': commit.author_name(),
@@ -143,6 +158,10 @@
'title': commit.title(),
'benchmarks': benchmarks
}
+ if is_try:
+ # TODO(christofferqa): We should find the first parent on main
+ # to support running try jobs for CL chains.
+ data['parent_hash'] = commit.parent_hash()
version = commit.version()
if version:
data['version'] = version
@@ -191,7 +210,7 @@
commit_hashes = set()
for benchmark in os.listdir(local_bucket):
benchmark_dir = os.path.join(local_bucket, benchmark)
- if not os.path.isdir(benchmark_dir):
+ if benchmark == 'try' or not os.path.isdir(benchmark_dir):
continue
for target in os.listdir(benchmark_dir):
target_dir = os.path.join(local_bucket, benchmark, target)
@@ -215,6 +234,7 @@
def run(commits, local_bucket, temp, outdir=None):
print('Loading bucket into memory')
local_bucket_dict = {}
+ local_bucket_try_dict = {}
for (root, dirs, files) in os.walk(local_bucket):
for file in files:
if file != 'result.json':
@@ -222,10 +242,28 @@
abs_path = os.path.join(root, file)
rel_path = os.path.relpath(abs_path, local_bucket)
with open(abs_path, 'r') as f:
- local_bucket_dict[rel_path] = f.read()
+ dict_or_try_dict = local_bucket_try_dict if rel_path.startswith(
+ 'try/') else local_bucket_dict
+ dict_or_try_dict[rel_path] = f.read()
# Aggregate all the result.json files into a single file that has the
# same format as tools/perf/benchmark_data.json.
+ process_commits(commits, local_bucket_dict, temp, outdir)
+ process_commits(GetTryCommits(local_bucket_try_dict),
+ local_bucket_try_dict,
+ temp,
+ outdir,
+ is_try=True)
+
+ # Write remaining files to public bucket.
+ print('Writing static files')
+ if outdir is None:
+ for file in FILES:
+ dest = os.path.join(utils.TOOLS_DIR, 'perf', file)
+ perf.ArchiveOutputFile(dest, file)
+
+
+def process_commits(commits, local_bucket_dict, temp, outdir, is_try=False):
print('Processing commits')
d8_benchmark_data = []
r8_benchmark_data = []
@@ -236,16 +274,18 @@
retrace_benchmarks = {}
for benchmark, benchmark_info in perf.ALL_BENCHMARKS.items():
RecordBenchmarkResult(commit, benchmark, benchmark_info,
- local_bucket_dict, 'd8', d8_benchmarks)
+ local_bucket_dict, 'd8', d8_benchmarks,
+ is_try)
RecordBenchmarkResult(commit, benchmark, benchmark_info,
- local_bucket_dict, 'r8-full', r8_benchmarks)
+ local_bucket_dict, 'r8-full', r8_benchmarks,
+ is_try)
RecordBenchmarkResult(commit, benchmark, benchmark_info,
local_bucket_dict, 'retrace',
- retrace_benchmarks)
- RecordBenchmarkResults(commit, d8_benchmarks, d8_benchmark_data)
- RecordBenchmarkResults(commit, r8_benchmarks, r8_benchmark_data)
+ retrace_benchmarks, is_try)
+ RecordBenchmarkResults(commit, d8_benchmarks, d8_benchmark_data, is_try)
+ RecordBenchmarkResults(commit, r8_benchmarks, r8_benchmark_data, is_try)
RecordBenchmarkResults(commit, retrace_benchmarks,
- retrace_benchmark_data)
+ retrace_benchmark_data, is_try)
# Trim data.
print('Trimming data')
@@ -256,19 +296,14 @@
# Write output JSON files to public bucket, or to tools/perf/ if running
# with --local-bucket.
print('Writing JSON')
- ArchiveBenchmarkResults(d8_benchmark_data, 'd8_benchmark_data.json', outdir,
- temp)
- ArchiveBenchmarkResults(r8_benchmark_data, 'r8_benchmark_data.json', outdir,
- temp)
+ data_file_suffix = '_try_data.json' if is_try else '_data.json'
+ ArchiveBenchmarkResults(d8_benchmark_data,
+ 'd8_benchmark' + data_file_suffix, outdir, temp)
+ ArchiveBenchmarkResults(r8_benchmark_data,
+ 'r8_benchmark' + data_file_suffix, outdir, temp)
ArchiveBenchmarkResults(retrace_benchmark_data,
- 'retrace_benchmark_data.json', outdir, temp)
-
- # Write remaining files to public bucket.
- print('Writing static files')
- if outdir is None:
- for file in FILES:
- dest = os.path.join(utils.TOOLS_DIR, 'perf', file)
- perf.ArchiveOutputFile(dest, file)
+ 'retrace_benchmark' + data_file_suffix, outdir,
+ temp)
def ParseOptions():