@@ -51,7 +51,7 @@ def get_machines(results: Iterable[mod_result.Result]) -> set[str]:
51
51
52
52
def compare_pair (
53
53
output_dir : PathLike ,
54
- machine : str ,
54
+ machine : str | None ,
55
55
ref_name : str ,
56
56
ref : mod_result .Result ,
57
57
head_name : str ,
@@ -60,11 +60,17 @@ def compare_pair(
60
60
) -> str :
61
61
output_dir = Path (output_dir )
62
62
63
- rich .print (f"Comparing { counter [0 ]+ 1 } /{ counter [1 ]} " , end = "\r " )
63
+ rich .print (
64
+ f"Comparing { counter [0 ]+ 1 : 2} /{ counter [1 ]: 2} : { head_name } vs. { ref_name } "
65
+ )
64
66
counter [0 ] += 1
65
67
66
- name = f"{ machine } -{ head_name } -vs-{ ref_name } "
67
- comparison = mod_result .BenchmarkComparison (ref , head , "base" )
68
+ name_parts = []
69
+ if machine is not None :
70
+ name_parts .append (machine )
71
+ name_parts .extend ([head_name , "vs" , ref_name ])
72
+ name = "-" .join (name_parts )
73
+ comparison = mod_result .BenchmarkComparison (ref , head , "base" , True )
68
74
entry = [comparison .summary ]
69
75
for func , suffix , file_type in comparison .get_files ():
70
76
output_filename = util .apply_suffix (output_dir / name , suffix )
@@ -78,46 +84,56 @@ def write_row(fd: TextIO, columns: Iterable[str]):
78
84
fd .write (f"| { ' | ' .join (columns )} |\n " )
79
85
80
86
87
+ def name_and_hash (name : str , hash : str ) -> str :
88
+ if name == hash :
89
+ return name
90
+ return f"{ name } ({ hash } )"
91
+
92
+
93
+ def get_first_result_for_machine (
94
+ results : Iterable [mod_result .Result ], machine : str | None
95
+ ) -> mod_result .Result :
96
+ return next (
97
+ result for result in results if machine is None or result .nickname == machine
98
+ )
99
+
100
+
81
101
def do_one_to_many (
82
102
fd : TextIO ,
83
103
parsed_commits : ParsedCommits ,
84
- machine : str ,
104
+ machine : str | None ,
85
105
output_dir : PathLike ,
86
106
counter : list [int ],
87
107
) -> None :
88
108
_ , _ , first_name , first_results = parsed_commits [0 ]
89
- first_result = next (
90
- result for result in first_results if result .nickname == machine
91
- )
109
+ first_result = get_first_result_for_machine (first_results , machine )
92
110
write_row (fd , ["commit" , "change" ])
93
111
write_row (fd , ["--" ] * 2 )
94
112
for hash , _ , name , results in parsed_commits [1 :]:
95
- result = next ( result for result in results if result . nickname == machine )
113
+ result = get_first_result_for_machine ( results , machine )
96
114
link = compare_pair (
97
115
output_dir , machine , first_name , first_result , name , result , counter
98
116
)
99
- write_row (fd , [f" { name } ( { hash } )" , link ])
117
+ write_row (fd , [name_and_hash ( name , hash ) , link ])
100
118
101
119
102
120
def do_many_to_many (
103
121
fd ,
104
122
parsed_commits : ParsedCommits ,
105
- machine : str ,
123
+ machine : str | None ,
106
124
output_dir : PathLike ,
107
125
counter : list [int ],
108
126
) -> None :
109
- write_row (fd , ["" , * [f" { x [2 ]} ( { x [0 ]} )" for x in parsed_commits ]])
127
+ write_row (fd , ["" , * [name_and_hash ( x [2 ], x [0 ]) for x in parsed_commits ]])
110
128
write_row (fd , ["--" ] * (len (parsed_commits ) + 1 ))
111
129
for hash1 , flags1 , name1 , results1 in parsed_commits :
112
130
columns = [name1 ]
113
- result1 = next ( result for result in results1 if result . nickname == machine )
131
+ result1 = get_first_result_for_machine ( results1 , machine )
114
132
for hash2 , flags2 , name2 , results2 in parsed_commits :
115
133
if hash1 == hash2 and flags1 == flags2 :
116
134
columns .append ("" )
117
135
else :
118
- result2 = next (
119
- result for result in results2 if result .nickname == machine
120
- )
136
+ result2 = get_first_result_for_machine (results2 , machine )
121
137
link = compare_pair (
122
138
output_dir , machine , name1 , result1 , name2 , result2 , counter
123
139
)
@@ -127,14 +143,11 @@ def do_many_to_many(
127
143
fd .write ("\n \n Rows are 'bases', columns are 'heads'\n " )
128
144
129
145
130
- def _main (commits : Sequence [str ], output_dir : PathLike , comparison_type : str ):
146
+ def _main_with_hashes (commits : Sequence [str ], output_dir : Path , comparison_type : str ):
131
147
results = mod_result .load_all_results (
132
148
None , Path ("results" ), sorted = False , match = False
133
149
)
134
150
135
- if len (commits ) < 2 :
136
- raise ValueError ("Must provide at least 2 commits" )
137
-
138
151
parsed_commits = []
139
152
machines = set ()
140
153
@@ -163,10 +176,6 @@ def _main(commits: Sequence[str], output_dir: PathLike, comparison_type: str):
163
176
if len (machines ) == 0 :
164
177
raise ValueError ("No single machine in common with all of the results" )
165
178
166
- output_dir_path = Path (output_dir )
167
- if not output_dir_path .exists ():
168
- output_dir_path .mkdir ()
169
-
170
179
match comparison_type :
171
180
case "1:n" :
172
181
total = (len (parsed_commits ) - 1 ) * len (machines )
@@ -180,14 +189,61 @@ def _main(commits: Sequence[str], output_dir: PathLike, comparison_type: str):
180
189
runners = mod_runners .get_runners_by_nickname ()
181
190
182
191
counter = [0 , total ]
183
- with (output_dir_path / "README.md" ).open ("w" , encoding = "utf-8" ) as fd :
192
+ with (output_dir / "README.md" ).open ("w" , encoding = "utf-8" ) as fd :
184
193
for machine in machines :
185
194
fd .write (f"# { runners [machine ].display_name } \n \n " )
186
- func (fd , parsed_commits , machine , output_dir_path , counter )
195
+ func (fd , parsed_commits , machine , output_dir , counter )
187
196
fd .write ("\n " )
188
197
rich .print ()
189
198
190
199
200
+ def _main_with_files (commits : Sequence [str ], output_dir : Path , comparison_type : str ):
201
+ parsed_results = []
202
+ for commit in commits :
203
+ if "," in commit :
204
+ commit_path , name = commit .split ("," , 1 )
205
+ commit_path = Path (commit_path )
206
+ else :
207
+ commit_path = Path (commit )
208
+ name = commit_path .stem
209
+ parsed_results .append (
210
+ (name , [], name , [mod_result .Result .from_arbitrary_filename (commit_path )])
211
+ )
212
+
213
+ match comparison_type :
214
+ case "1:n" :
215
+ total = len (commits ) - 1
216
+ func = do_one_to_many
217
+ case "n:n" :
218
+ total = (len (commits ) ** 2 ) - len (commits )
219
+ func = do_many_to_many
220
+ case _:
221
+ raise ValueError (f"Unknown comparison type { comparison_type } " )
222
+
223
+ counter = [0 , total ]
224
+ with (output_dir / "README.md" ).open ("w" , encoding = "utf-8" ) as fd :
225
+ fd .write ("# Comparisons\n \n " )
226
+ func (fd , parsed_results , None , output_dir , counter )
227
+ fd .write ("\n " )
228
+ rich .print ()
229
+
230
+
231
+ def _main (commits : Sequence [str ], output_dir : PathLike , comparison_type : str ):
232
+ if len (commits ) < 2 :
233
+ raise ValueError ("Must provide at least 2 commits" )
234
+
235
+ output_dir_path = Path (output_dir )
236
+ if not output_dir_path .exists ():
237
+ output_dir_path .mkdir ()
238
+
239
+ if all (commit .endswith (".json" ) for commit in commits ):
240
+ _main_with_files (commits , output_dir_path , comparison_type )
241
+ elif any (commit .endswith (".json" ) for commit in commits ):
242
+ raise ValueError ("All commits must be either hashes or JSON files" )
243
+ else :
244
+ _main_with_hashes (commits , output_dir_path , comparison_type )
245
+
246
+
191
247
def main ():
192
248
parser = argparse .ArgumentParser (
193
249
description = """
@@ -204,7 +260,8 @@ def main():
204
260
"commit" ,
205
261
nargs = "+" ,
206
262
help = """
207
- Commits to compare. Must be a git commit hash prefix. May optionally
263
+ Commits or files to compare. If ends with ".json", it is a path to a
264
+ JSON file, otherwise, it is a git commit hash prefix. May optionally
208
265
have a friendly name after a comma, e.g. c0ffee,main. If ends with
209
266
a "T", use the Tier 2 run for that commit. If ends with a "J", use
210
267
the JIT run for that commit. If ends with a "N", use the NOGIL run
0 commit comments