@@ -63,12 +63,7 @@ def plain_text_comparison(data, metric, baseline_name=None, candidate_name=None)
6363 """
6464 Create a tabulated comparison of the baseline and the candidate for the given metric.
6565 """
66- # Compute additional info in new columns. In text mode, we can assume that we are
67- # comparing exactly two data sets (suffixed _0 and _1).
68- data ['difference' ] = data [f'{ metric } _1' ] - data [f'{ metric } _0' ]
69- data ['percent' ] = 100 * (data ['difference' ] / data [f'{ metric } _0' ])
70-
71- data = data .replace (numpy .nan , None ).sort_values (by = 'benchmark' ) # avoid NaNs in tabulate output
66+ data = data .replace (numpy .nan , None ) # avoid NaNs in tabulate output
7267 headers = ['Benchmark' , baseline_name , candidate_name , 'Difference' , '% Difference' ]
7368 fmt = (None , '.2f' , '.2f' , '.2f' , '.2f' )
7469 table = data [['benchmark' , f'{ metric } _0' , f'{ metric } _1' , 'difference' , 'percent' ]].set_index ('benchmark' )
@@ -78,7 +73,7 @@ def create_chart(data, metric, subtitle=None, series_names=None):
7873 """
7974 Create a bar chart comparing the given metric across the provided series.
8075 """
81- data = data .sort_values ( by = 'benchmark' ). rename (columns = {f'{ metric } _{ i } ' : series_names [i ] for i in range (len (series_names ))})
76+ data = data .rename (columns = {f'{ metric } _{ i } ' : series_names [i ] for i in range (len (series_names ))})
8277 title = ' vs ' .join (series_names )
8378 figure = plotly .express .bar (data , title = title , subtitle = subtitle , x = 'benchmark' , y = series_names , barmode = 'group' )
8479 figure .update_layout (xaxis_title = '' , yaxis_title = '' , legend_title = '' )
@@ -102,6 +97,15 @@ def main(argv):
10297 parser .add_argument ('--filter' , type = str , required = False ,
10398 help = 'An optional regular expression used to filter the benchmarks included in the comparison. '
10499 'Only benchmarks whose names match the regular expression will be included.' )
100+ parser .add_argument ('--sort' , type = str , required = False , default = 'benchmark' ,
101+ choices = ['benchmark' , 'baseline' , 'candidate' , 'percent_diff' ],
102+ help = 'Optional sorting criteria for displaying results. By default, results are displayed in '
103+ 'alphabetical order of the benchmark. Supported sorting criteria are: '
104+ '`benchmark` (sort using the alphabetical name of the benchmark), '
105+ '`baseline` (sort using the absolute number of the baseline run), '
106+ '`candidate` (sort using the absolute number of the candidate run), '
107+ 'and `percent_diff` (sort using the percent difference between the baseline and the candidate). '
108+ 'Note that when more than two input files are compared, the only valid sorting order is `benchmark`.' )
105109 parser .add_argument ('--format' , type = str , choices = ['text' , 'chart' ], default = 'text' ,
106110 help = 'Select the output format. `text` generates a plain-text comparison in tabular form, and `chart` '
107111 'generates a self-contained HTML graph that can be opened in a browser. The default is `text`.' )
@@ -116,6 +120,8 @@ def main(argv):
116120 'This option cannot be used with the plain text output.' )
117121 args = parser .parse_args (argv )
118122
123+ # Validate arguments (the values admissible for various arguments depend on other
124+ # arguments, the number of inputs, etc)
119125 if args .format == 'text' :
120126 if len (args .files ) != 2 :
121127 parser .error ('--format=text requires exactly two input files to compare' )
@@ -124,6 +130,9 @@ def main(argv):
124130 if args .open :
125131 parser .error ('Passing --open makes no sense with --format=text' )
126132
133+ if len (args .files ) != 2 and args .sort != 'benchmark' :
134+ parser .error ('Using any sort order other than `benchmark` requires exactly two input files.' )
135+
127136 if args .series_names is None :
128137 args .series_names = ['Baseline' ]
129138 if len (args .files ) == 2 :
@@ -142,10 +151,25 @@ def main(argv):
142151 # Join the inputs into a single dataframe
143152 data = functools .reduce (lambda a , b : a .merge (b , how = 'outer' , on = 'benchmark' ), inputs )
144153
154+ # If we have exactly two data sets, compute additional info in new columns
155+ if len (lnt_inputs ) == 2 :
156+ data ['difference' ] = data [f'{ args .metric } _1' ] - data [f'{ args .metric } _0' ]
157+ data ['percent' ] = 100 * (data ['difference' ] / data [f'{ args .metric } _0' ])
158+
145159 if args .filter is not None :
146160 keeplist = [b for b in data ['benchmark' ] if re .search (args .filter , b ) is not None ]
147161 data = data [data ['benchmark' ].isin (keeplist )]
148162
163+ # Sort the data by the appropriate criteria
164+ if args .sort == 'benchmark' :
165+ data = data .sort_values (by = 'benchmark' )
166+ elif args .sort == 'baseline' :
167+ data = data .sort_values (by = f'{ args .metric } _0' )
168+ elif args .sort == 'candidate' :
169+ data = data .sort_values (by = f'{ args .metric } _1' )
170+ elif args .sort == 'percent_diff' :
171+ data = data .sort_values (by = f'percent' )
172+
149173 if args .format == 'chart' :
150174 figure = create_chart (data , args .metric , subtitle = args .subtitle , series_names = args .series_names )
151175 do_open = args .output is None or args .open
0 commit comments