Skip to content

Commit 5a42a53

Browse files
committed
Fix bisect-benchmark
1 parent 228cb6c commit 5a42a53

File tree

1 file changed

+75
-83
lines changed

1 file changed

+75
-83
lines changed

mx.graalpython/mx_graalpython_bisect.py

Lines changed: 75 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -36,71 +36,67 @@
3636
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
3737
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3838
# SOFTWARE.
39+
import sys
40+
3941
import abc
4042
import argparse
4143
import json
44+
import mx
4245
import os
4346
import re
4447
import shlex
45-
import sys
4648
import types
47-
48-
import mx
49+
from pathlib import Path
4950

5051

5152
def print_line(l):
5253
print('=' * l)
5354

5455

55-
def get_suite(name):
56-
suite_name = name.lstrip('/')
57-
suite = mx.suite(suite_name, fatalIfMissing=False)
58-
if not suite:
59-
suite = mx.primary_suite().import_suite(suite_name, version=None, urlinfos=None, in_subdir=name.startswith('/'))
60-
assert suite
61-
return suite
56+
SUITE = mx.suite('graalpython')
57+
GIT = SUITE.vc
58+
DIR = Path(SUITE.vc_dir).absolute()
59+
GRAAL_DIR = DIR.parent / 'graal'
60+
VM_DIR = GRAAL_DIR / 'vm'
61+
GRAAL_ENTERPRISE_DIR = DIR.parent / 'graal-enterprise'
62+
VM_ENTERPRISE_DIR = GRAAL_ENTERPRISE_DIR / 'vm-enterprise'
6263

64+
SUITE_MAPPING = {
65+
GRAAL_DIR: VM_DIR,
66+
GRAAL_ENTERPRISE_DIR: VM_ENTERPRISE_DIR,
67+
}
6368

64-
def get_downstream_suite(suite):
65-
downstreams = {
66-
'graalpython-apptests': 'graalpython',
67-
'graalpython-extensions': 'graalpython',
68-
'graalpython': '/vm',
69-
'vm': '/vm-enterprise',
70-
}
71-
downstream = downstreams.get(suite.name)
72-
if downstream:
73-
return get_suite(downstream)
69+
DOWNSTREAM_REPO_MAPPING = {
70+
DIR: GRAAL_DIR,
71+
GRAAL_DIR: GRAAL_ENTERPRISE_DIR,
72+
}
7473

7574

76-
def get_commit(suite, ref='HEAD'):
77-
if not suite:
78-
return None
79-
return suite.vc.git_command(suite.vc_dir, ['rev-parse', ref], abortOnError=True).strip()
75+
def get_commit(repo_path: Path, ref='HEAD'):
76+
return GIT.git_command(repo_path, ['rev-parse', ref], abortOnError=True).strip()
8077

8178

82-
def get_message(suite, commit):
83-
return suite.vc.git_command(suite.vc_dir, ['log', '--format=%s', '-n', '1', commit]).strip()
79+
def get_message(repo_path: Path, commit):
80+
return GIT.git_command(repo_path, ['log', '--format=%s', '-n', '1', commit]).strip()
8481

8582

86-
def run_bisect_benchmark(suite, bad, good, callback, good_result=None, bad_result=None):
87-
git_dir = suite.vc_dir
88-
commits = suite.vc.git_command(
89-
git_dir,
83+
def run_bisect_benchmark(repo_path: Path, bad, good, callback, good_result=None, bad_result=None):
84+
commits = GIT.git_command(
85+
repo_path,
9086
['log', '--first-parent', '--format=format:%H', '{}^..{}'.format(good, bad)],
9187
abortOnError=True,
9288
).splitlines()
9389
if not commits:
9490
raise RuntimeError("No merge commits found in the range. Did you swap good and bad?")
95-
downstream_suite = get_downstream_suite(suite)
91+
downstream_repo_path = DOWNSTREAM_REPO_MAPPING.get(repo_path)
9692
results = [None] * len(commits)
9793
if good_result is None and bad_result is None:
9894
bad_index = 0
9995
good_index = len(commits) - 1
100-
bad_result = results[bad_index] = callback(suite, bad)
101-
downstream_bad = get_commit(downstream_suite)
102-
good_result = results[good_index] = callback(suite, good)
103-
downstream_good = get_commit(downstream_suite)
96+
bad_result = results[bad_index] = callback(repo_path, bad)
97+
downstream_bad = get_commit(downstream_repo_path)
98+
good_result = results[good_index] = callback(repo_path, good)
99+
downstream_good = get_commit(downstream_repo_path)
104100
if not good_result.bound_is_valid(bad_result):
105101
raise RuntimeError(
106102
"Didn't detect a regression: "
@@ -122,25 +118,25 @@ def run_bisect_benchmark(suite, bad, good, callback, good_result=None, bad_resul
122118
assert good_index - bad_index == 1
123119
break
124120
commit = commits[index]
125-
result = results[index] = callback(suite, commit)
121+
result = results[index] = callback(repo_path, commit)
126122
if result.is_good(good_result, bad_result):
127123
good_index = index
128-
downstream_good = get_commit(downstream_suite)
124+
downstream_good = get_commit(downstream_repo_path)
129125
else:
130126
bad_index = index
131-
downstream_bad = get_commit(downstream_suite)
127+
downstream_bad = get_commit(downstream_repo_path)
132128
subresults = {}
133129
if downstream_bad and downstream_good and downstream_bad != downstream_good:
134-
suite.vc.update_to_branch(suite.vc_dir, commits[good_index])
135-
subresult = run_bisect_benchmark(downstream_suite, downstream_bad, downstream_good, callback, good_result,
130+
GIT.update_to_branch(DIR, commits[good_index])
131+
subresult = run_bisect_benchmark(downstream_repo_path, downstream_bad, downstream_good, callback, good_result,
136132
bad_result)
137133
subresults[bad_index] = subresult
138-
return BisectResult(suite, commits, results, good_index, bad_index, subresults)
134+
return BisectResult(downstream_repo_path, commits, results, good_index, bad_index, subresults)
139135

140136

141137
class BisectResult:
142-
def __init__(self, suite, commits, results, good_index, bad_index, dependency_results):
143-
self.suite = suite
138+
def __init__(self, repo_path: Path, commits, results, good_index, bad_index, dependency_results):
139+
self.repo_path = repo_path
144140
self.commits = commits
145141
self.results = results
146142
self.good_index = good_index
@@ -149,7 +145,7 @@ def __init__(self, suite, commits, results, good_index, bad_index, dependency_re
149145

150146
@property
151147
def repo_name(self):
152-
return os.path.basename(self.suite.vc_dir)
148+
return self.repo_path.name
153149

154150
@property
155151
def good_commit(self):
@@ -166,7 +162,7 @@ def visualize(self, level=1):
166162
out = ["{} {}".format(level_marker, self.repo_name)]
167163
for index, (commit, value) in enumerate(zip(self.commits, self.results)):
168164
if value is not None:
169-
out.append(f"{level_marker} {commit} {value} {get_message(self.suite, commit)}")
165+
out.append(f"{level_marker} {commit} {value} {get_message(self.repo_path, commit)}")
170166
if self.dependency_results and index in self.dependency_results:
171167
out.append(self.dependency_results[index].visualize(level + 1))
172168
return '\n'.join(out)
@@ -178,7 +174,7 @@ def summarize(self):
178174
if summary:
179175
return summary
180176
return ("Detected bad commit in {} repository:\n{} {}"
181-
.format(self.repo_name, self.bad_commit, get_message(self.suite, self.bad_commit)))
177+
.format(self.repo_name, self.bad_commit, get_message(self.repo_path, self.bad_commit)))
182178
return ''
183179

184180

@@ -269,32 +265,27 @@ def _bisect_benchmark(argv, bisect_id, email_to):
269265
parser.add_argument('--no-clean', action='store_true', help="Do not run 'mx clean' between runs")
270266
args = parser.parse_args(argv)
271267

272-
primary_suite = mx.primary_suite()
273-
274268
def checkout_enterprise():
275-
ee_suite = get_suite('/vm-enterprise')
276-
mx.run_mx(['checkout-downstream', 'vm', 'vm-enterprise', '--no-fetch'], suite=ee_suite)
269+
mx.run_mx(['checkout-downstream', 'vm', 'vm-enterprise', '--no-fetch'], suite=str(VM_ENTERPRISE_DIR))
277270

278-
def checkout_suite(suite, commit):
279-
suite.vc.update_to_branch(suite.vc_dir, commit)
280-
mx.run_mx(['sforceimports'], suite=suite)
281-
mx.run_mx(['--env', 'ce', 'sforceimports'], suite=get_suite('/vm'))
271+
def checkout(repo_path: Path, commit):
272+
GIT.update_to_branch(repo_path, commit)
273+
suite_dir = SUITE_MAPPING.get(repo_path, repo_path)
274+
mx.run_mx(['sforceimports'], suite=str(suite_dir))
275+
mx.run_mx(['--env', 'ce', 'sforceimports'], suite=str(VM_DIR))
282276
if args.enterprise:
283-
if suite.name != 'vm-enterprise':
277+
if repo_path.name != 'graal-enterprise':
284278
checkout_enterprise()
285-
# Make sure vm is imported before vm-enterprise
286-
get_suite('/vm')
287-
mx.run_mx(['--env', 'ee', 'sforceimports'], suite=get_suite('/vm-enterprise'))
288-
suite.vc.update_to_branch(suite.vc_dir, commit)
289-
mx.run_mx(['sforceimports'], suite=suite)
290-
debug_str = "debug: graalpython={} graal={}".format(
291-
get_commit(get_suite('graalpython')), get_commit(get_suite('/vm')))
279+
mx.run_mx(['--env', 'ee', 'sforceimports'], suite=str(VM_ENTERPRISE_DIR))
280+
GIT.update_to_branch(repo_path, commit)
281+
mx.run_mx(['sforceimports'], suite=str(suite_dir))
282+
debug_str = f"debug: {SUITE.name}={get_commit(SUITE.vc_dir)} graal={get_commit(GRAAL_DIR)}"
292283
if args.enterprise:
293-
debug_str += " graal-enterprise={}".format(get_commit(get_suite('/vm-enterprise')))
284+
debug_str += f" graal-enterprise={get_commit(GRAAL_ENTERPRISE_DIR)}"
294285
print(debug_str)
295286

296-
def checkout_and_build_suite(suite, commit):
297-
checkout_suite(suite, commit)
287+
def checkout_and_build(repo_path, commit):
288+
checkout(repo_path, commit)
298289
build_command = shlex.split(args.build_command)
299290
if not args.no_clean:
300291
try:
@@ -308,8 +299,8 @@ def checkout_and_build_suite(suite, commit):
308299
if retcode:
309300
raise RuntimeError("Failed to execute the build command for {}".format(commit))
310301

311-
def benchmark_callback(suite, commit, bench_command=args.benchmark_command):
312-
checkout_and_build_suite(suite, commit)
302+
def benchmark_callback(repo_path: Path, commit, bench_command=args.benchmark_command):
303+
checkout_and_build(repo_path, commit)
313304
retcode = mx.run(shlex.split(bench_command), nonZeroIsFatal=False)
314305
if args.benchmark_metric == 'WORKS':
315306
return WorksResult(retcode)
@@ -333,9 +324,9 @@ def benchmark_callback(suite, commit, bench_command=args.benchmark_command):
333324
result_class = HigherIsBetterResult if doc.get('metric.better', 'lower') == 'higher' else LowerIsBetterResult
334325
return result_class(doc['metric.value'], doc['metric.unit'])
335326

336-
bad = get_commit(primary_suite, args.bad)
337-
good = get_commit(primary_suite, args.good)
338-
result = run_bisect_benchmark(primary_suite, bad, good, benchmark_callback)
327+
bad = get_commit(DIR, args.bad)
328+
good = get_commit(DIR, args.good)
329+
result = run_bisect_benchmark(DIR, bad, good, benchmark_callback)
339330
visualization = result.visualize()
340331
summary = result.summarize()
341332

@@ -346,23 +337,22 @@ def benchmark_callback(suite, commit, bench_command=args.benchmark_command):
346337

347338
if args.rerun_with_commands:
348339
print('\n\nRerunning the good and bad commits with extra benchmark commands:')
340+
repo_path = DIR
349341
current_result = result
350-
current_suite = primary_suite
351342
while current_result.subresults and current_result.bad_index in current_result.subresults:
352-
downstream_suite = get_downstream_suite(current_suite)
343+
downstream_repo_path = DOWNSTREAM_REPO_MAPPING.get(repo_path)
353344
next_result = current_result.subresults[current_result.bad_index]
354345
if not next_result.good_commit or not next_result.bad_commit:
355-
print("Next downstream suite {} does not have both good and bad commits".format(downstream_suite.name))
346+
print(f"Next downstream repo {downstream_repo_path.name} does not have both good and bad commits")
356347
break
357-
print("Recursing to downstream suite: {}, commit: {}".format(downstream_suite.name,
358-
current_result.bad_commit))
359-
checkout_suite(current_suite, current_result.bad_commit)
348+
print(f"Recursing to downstream repo: {downstream_repo_path.name}, commit: {current_result.bad_commit}")
349+
checkout(downstream_repo_path, current_result.bad_commit)
360350
current_result = next_result
361-
current_suite = downstream_suite
351+
repo_path = downstream_repo_path
362352
for commit in [current_result.good_commit, current_result.bad_commit]:
363353
print_line(80)
364354
print("Commit: {}".format(commit))
365-
checkout_and_build_suite(current_suite, commit)
355+
checkout_and_build(repo_path, commit)
366356
for cmd in args.rerun_with_commands.split(";"):
367357
print_line(40)
368358
mx.run(shlex.split(cmd.strip()), nonZeroIsFatal=False)
@@ -378,12 +368,14 @@ def benchmark_callback(suite, commit, bench_command=args.benchmark_command):
378368

379369

380370
def bisect_benchmark(argv):
381-
suite = mx.primary_suite()
382-
initial_branch = suite.vc.git_command(suite.vc_dir, ['rev-parse', '--abbrev-ref', 'HEAD']).strip()
383-
initial_commit = suite.vc.git_command(suite.vc_dir, ['log', '--format=%s', '-n', '1']).strip()
384-
email_to = suite.vc.git_command(suite.vc_dir, ['log', '--format=%cE', '-n', '1']).strip()
371+
initial_branch = GIT.git_command(DIR, ['rev-parse', '--abbrev-ref', 'HEAD']).strip()
372+
initial_commit = GIT.git_command(DIR, ['log', '--format=%s', '-n', '1']).strip()
373+
email_to = GIT.git_command(DIR, ['log', '--format=%cE', '-n', '1']).strip()
385374
bisect_id = f'{initial_branch}: {initial_commit}'
386-
_bisect_benchmark(argv, bisect_id, email_to)
375+
try:
376+
_bisect_benchmark(argv, bisect_id, email_to)
377+
finally:
378+
GIT.update_to_branch(DIR, initial_branch)
387379

388380

389381
def send_email(bisect_id, email_to, content):

0 commit comments

Comments
 (0)