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+
3941import abc
4042import argparse
4143import json
44+ import mx
4245import os
4346import re
4447import shlex
45- import sys
4648import types
47-
48- import mx
49+ from pathlib import Path
4950
5051
5152def 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
141137class 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,49 @@ 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-
274- def checkout_enterprise ():
275- ee_suite = get_suite ('/vm-enterprise' )
276- mx .run_mx (['checkout-downstream' , 'vm' , 'vm-enterprise' , '--no-fetch' ], suite = ee_suite )
277-
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' ))
268+ def checkout (repo_path : Path , commit ):
269+ GIT .update_to_branch (repo_path , commit )
270+ suite_dir = SUITE_MAPPING .get (repo_path , repo_path )
271+ mx .run_mx (['sforceimports' ], suite = str (suite_dir ))
272+ mx .run_mx (['--env' , 'ce' , 'sforceimports' ], suite = str (VM_DIR ))
282273 if args .enterprise :
283- if suite .name != 'vm-enterprise' :
284- 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' )))
274+ if repo_path .name != 'graal-enterprise' :
275+ mx .run_mx (['--quiet' , 'checkout-downstream' , 'vm' , 'vm-enterprise' , '--no-fetch' ],
276+ suite = str (VM_ENTERPRISE_DIR ))
277+ mx .run_mx (['--env' , 'ee' , 'sforceimports' ], suite = str (VM_ENTERPRISE_DIR ))
278+ GIT .update_to_branch (repo_path , commit )
279+ mx .run_mx (['sforceimports' ], suite = str (suite_dir ))
280+ debug_str = f"debug: { SUITE .name } ={ get_commit (SUITE .vc_dir )} graal={ get_commit (GRAAL_DIR )} "
292281 if args .enterprise :
293- debug_str += " graal-enterprise={}" . format ( get_commit (get_suite ( '/vm-enterprise' )))
282+ debug_str += f " graal-enterprise={ get_commit (GRAAL_ENTERPRISE_DIR ) } "
294283 print (debug_str )
295284
296- def checkout_and_build_suite (suite , commit ):
297- checkout_suite (suite , commit )
285+ def fetch_jdk ():
286+ import mx_fetchjdk
287+ if args .enterprise :
288+ fetch_args = [
289+ '--configuration' , str (GRAAL_ENTERPRISE_DIR / 'common.json' ),
290+ '--jdk-binaries' , str (GRAAL_ENTERPRISE_DIR / 'ci' / 'jdk-binaries.json' ),
291+ 'labsjdk-ee-latest' ,
292+ ]
293+ else :
294+ fetch_args = [
295+ '--configuration' , str (GRAAL_DIR / 'common.json' ),
296+ 'labsjdk-ce-latest' ,
297+ ]
298+ # Awkward way to suppress the confirmation prompt
299+ ci = 'CI' in os .environ
300+ if not ci :
301+ os .environ ['CI' ] = '1'
302+ try :
303+ return mx_fetchjdk .fetch_jdk (fetch_args )
304+ finally :
305+ if not ci :
306+ del os .environ ['CI' ]
307+
308+ def checkout_and_build (repo_path , commit ):
309+ checkout (repo_path , commit )
310+ os .environ ['JAVA_HOME' ] = fetch_jdk ()
298311 build_command = shlex .split (args .build_command )
299312 if not args .no_clean :
300313 try :
@@ -308,8 +321,8 @@ def checkout_and_build_suite(suite, commit):
308321 if retcode :
309322 raise RuntimeError ("Failed to execute the build command for {}" .format (commit ))
310323
311- def benchmark_callback (suite , commit , bench_command = args .benchmark_command ):
312- checkout_and_build_suite ( suite , commit )
324+ def benchmark_callback (repo_path : Path , commit , bench_command = args .benchmark_command ):
325+ checkout_and_build ( repo_path , commit )
313326 retcode = mx .run (shlex .split (bench_command ), nonZeroIsFatal = False )
314327 if args .benchmark_metric == 'WORKS' :
315328 return WorksResult (retcode )
@@ -333,9 +346,9 @@ def benchmark_callback(suite, commit, bench_command=args.benchmark_command):
333346 result_class = HigherIsBetterResult if doc .get ('metric.better' , 'lower' ) == 'higher' else LowerIsBetterResult
334347 return result_class (doc ['metric.value' ], doc ['metric.unit' ])
335348
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 )
349+ bad = get_commit (DIR , args .bad )
350+ good = get_commit (DIR , args .good )
351+ result = run_bisect_benchmark (DIR , bad , good , benchmark_callback )
339352 visualization = result .visualize ()
340353 summary = result .summarize ()
341354
@@ -346,23 +359,22 @@ def benchmark_callback(suite, commit, bench_command=args.benchmark_command):
346359
347360 if args .rerun_with_commands :
348361 print ('\n \n Rerunning the good and bad commits with extra benchmark commands:' )
362+ repo_path = DIR
349363 current_result = result
350- current_suite = primary_suite
351364 while current_result .subresults and current_result .bad_index in current_result .subresults :
352- downstream_suite = get_downstream_suite ( current_suite )
365+ downstream_repo_path = DOWNSTREAM_REPO_MAPPING . get ( repo_path )
353366 next_result = current_result .subresults [current_result .bad_index ]
354367 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 ) )
368+ print (f "Next downstream repo { downstream_repo_path . name } does not have both good and bad commits" )
356369 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 )
370+ print (f"Recursing to downstream repo: { downstream_repo_path .name } , commit: { current_result .bad_commit } " )
371+ checkout (downstream_repo_path , current_result .bad_commit )
360372 current_result = next_result
361- current_suite = downstream_suite
373+ repo_path = downstream_repo_path
362374 for commit in [current_result .good_commit , current_result .bad_commit ]:
363375 print_line (80 )
364376 print ("Commit: {}" .format (commit ))
365- checkout_and_build_suite ( current_suite , commit )
377+ checkout_and_build ( repo_path , commit )
366378 for cmd in args .rerun_with_commands .split (";" ):
367379 print_line (40 )
368380 mx .run (shlex .split (cmd .strip ()), nonZeroIsFatal = False )
@@ -378,12 +390,14 @@ def benchmark_callback(suite, commit, bench_command=args.benchmark_command):
378390
379391
380392def 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 ()
393+ initial_branch = GIT .git_command (DIR , ['rev-parse' , '--abbrev-ref' , 'HEAD' ]).strip ()
394+ initial_commit = GIT .git_command (DIR , ['log' , '--format=%s' , '-n' , '1' ]).strip ()
395+ email_to = GIT .git_command (DIR , ['log' , '--format=%cE' , '-n' , '1' ]).strip ()
385396 bisect_id = f'{ initial_branch } : { initial_commit } '
386- _bisect_benchmark (argv , bisect_id , email_to )
397+ try :
398+ _bisect_benchmark (argv , bisect_id , email_to )
399+ finally :
400+ GIT .update_to_branch (DIR , initial_branch )
387401
388402
389403def send_email (bisect_id , email_to , content ):
0 commit comments