1- from _operator import sub
21import argparse
2+ import os
33import subprocess
44
55# The default regression threshold is 10%
6- DEFAULT_REGRESSION_THRESHOLD = 0.1
6+ REGRESSION_THRESHOLD = float (os .environ .get ("REGRESSION_THRESHOLD" , 0.1 ))
7+ REPRO_CMDLINE = os .environ .get ("REPRO_CMDLINE" , None )
8+ FUNCTIONAL = os .environ .get ("FUNCTIONAL" , False )
9+ BASELINE_LOG = os .environ .get ("BASELINE_LOG" , None )
710
811def get_baseline (baseline_log ) -> float :
912 with open (baseline_log , "r" ) as f :
@@ -15,49 +18,46 @@ def get_current_value(stdout_lines) -> float:
1518 return float (last_line .strip ())
1619
1720if __name__ == "__main__" :
18- parser = argparse .ArgumentParser ()
19- parser .add_argument ("--repro" , type = str , required = True , help = "Command to reproduce the regression" )
20- parser .add_argument ("--baseline" , action = "store_true" , help = "Whether this is running the baseline" )
21- parser .add_argument ("--baseline-log" , type = str , help = "Baseline standard output file" )
22- parser .add_argument ("--functional" , type = str , help = "This is to bisect a functional regression (e.g., exception, OOM, etc)" )
23- parser .add_argument ("--regression-threshold" , type = float , default = DEFAULT_REGRESSION_THRESHOLD , help = "Threshold for regression detection" )
24- args = parser .parse_args ()
25- if "--simple-output" not in args .repro :
21+ if "--simple-output" not in REPRO_CMDLINE :
2622 print ("Regression detector requires --simple-output as it only reads the last line in the benchmark output." )
2723 exit (1 )
28- if args . baseline_log :
29- assert os . path . exists ( args . baseline_log ), f"Baseline log file { args . baseline_log } does not exist."
30- # run the command
31- cmdline = args . repro . split ()
32- if args . functional :
24+ assert REPRO_CMDLINE is not None , "REPRO_CMDLINE is not set."
25+ cmdline = REPRO_CMDLINE . split ()
26+
27+ # functional regression
28+ if FUNCTIONAL :
3329 try :
3430 subprocess .check_call (cmdline )
3531 except subprocess .CalledProcessError as e :
3632 print (f"cmd line { cmdline } failed: { e } " )
3733 exit (e .returncode )
34+
35+ if os .path .exists (BASELINE_LOG ):
36+ has_baseline = True
37+ else :
38+ has_baseline = False
39+ p = subprocess .Popen (cmdline , stdout = subprocess .PIPE , stderr = subprocess .STDERR )
40+ assert p .stdout is not None
41+ stdout_lines = []
42+ for line in p .stdout :
43+ print (line )
44+ stdout_lines .append (line )
45+ rc = p .wait ()
46+ if not has_baseline :
47+ with open (BASELINE_LOG , "w" ) as f :
48+ f .write ("\n " .join (stdout_lines ))
49+ exit (rc )
50+ # if subprocess failed, exit with the return code
51+ if not rc == 0 :
52+ exit (rc )
53+ # otherwise, check for the perf regression
54+ baseline = get_baseline (BASELINE_LOG )
55+ current_value = get_current_value (stdout_lines )
56+ smaller_value = min (baseline , current_value )
57+ larger_value = max (baseline , current_value )
58+ if larger_value > smaller_value * (1 + REGRESSION_THRESHOLD ):
59+ print (f"Regression detected: current value { current_value } regresses over the baseline { baseline } by { REGRESSION_THRESHOLD * 100 } %)" )
60+ exit (1 )
3861 else :
39- baseline = get_baseline (args .baseline_log )
40- p = subprocess .Popen (cmdline , stdout = subprocess .PIPE , stderr = subprocess .STDERR )
41- assert p .stdout is not None
42- stdout_lines = []
43- for line in p .stdout :
44- print (line )
45- stdout_lines .append (line )
46- rc = p .wait ()
47- if args .baseline :
48- with open (args .baseline_log , "w" ) as f :
49- f .write ("\n " .join (stdout_lines ))
50- exit (rc )
51- # if subprocess failed, exit with the return code
52- if rc :
53- return rc
54- # otherwise, check for the perf regression
55- current_value = get_current_value (stdout_lines )
56- smaller_value = min (baseline , current_value )
57- larger_value = max (baseline , current_value )
58- if larger_value > smaller_value * (1 + args .regression_threshold ):
59- print (f"Regression detected: current value { current_value } regresses over the baseline { baseline } by { args .regression_threshold * 100 } %)" )
60- exit (1 )
61- else :
62- print (f"No regression detected: current value { current_value } regresses over the baseline { baseline } by { args .regression_threshold * 100 } %)" )
63- exit (0 )
62+ print (f"No regression detected: current value { current_value } regresses over the baseline { baseline } by { REGRESSION_THRESHOLD * 100 } %)" )
63+ exit (0 )
0 commit comments