99THRESHOLD = 1.20
1010
1111
12+ class BenchmarkDataError (ValueError ):
13+ """Raised when benchmark JSON input is malformed or missing required fields."""
14+
15+
1216def load_results (results_path : str | Path ) -> dict [str , float ]:
13- data = json .loads (Path (results_path ).read_text (encoding = "utf-8" ))
14- return {entry ["name" ]: float (entry ["stats" ]["mean" ]) for entry in data ["benchmarks" ]}
17+ path = Path (results_path )
18+ try :
19+ data = json .loads (path .read_text (encoding = "utf-8" ))
20+ except json .JSONDecodeError as exc :
21+ raise BenchmarkDataError (f"invalid JSON in { path } : { exc } " ) from exc
22+ try :
23+ benchmarks = data ["benchmarks" ]
24+ except (KeyError , TypeError ) as exc :
25+ raise BenchmarkDataError (f"{ path } missing top-level 'benchmarks' array" ) from exc
26+ if not isinstance (benchmarks , list ):
27+ raise BenchmarkDataError (f"{ path } 'benchmarks' must be an array" )
28+
29+ results : dict [str , float ] = {}
30+ for index , entry in enumerate (benchmarks ):
31+ if not isinstance (entry , dict ):
32+ raise BenchmarkDataError (f"{ path } benchmarks[{ index } ] must be an object" )
33+ try :
34+ name = entry ["name" ]
35+ mean = entry ["stats" ]["mean" ]
36+ except (KeyError , TypeError ) as exc :
37+ raise BenchmarkDataError (
38+ f"{ path } benchmarks[{ index } ] missing 'name' or 'stats.mean'"
39+ ) from exc
40+ results [str (name )] = float (mean )
41+ return results
1542
1643
1744def load_baseline_means (baselines_path : str | Path ) -> dict [str , float ]:
18- data = json .loads (Path (baselines_path ).read_text (encoding = "utf-8" ))
45+ path = Path (baselines_path )
46+ try :
47+ data = json .loads (path .read_text (encoding = "utf-8" ))
48+ except json .JSONDecodeError as exc :
49+ raise BenchmarkDataError (f"invalid JSON in { path } : { exc } " ) from exc
50+ if not isinstance (data , dict ):
51+ raise BenchmarkDataError (f"{ path } root value must be an object" )
52+
1953 groups = data .get ("groups" , data )
54+ if not isinstance (groups , dict ):
55+ raise BenchmarkDataError (f"{ path } missing 'groups' object" )
56+
2057 means : dict [str , float ] = {}
21- for key , value in groups .items ():
58+ for group_name , value in groups .items ():
2259 if not isinstance (value , dict ):
2360 continue
2461 for name , mean in value .items ():
25- means [name ] = float (mean )
62+ try :
63+ means [str (name )] = float (mean )
64+ except (TypeError , ValueError ) as exc :
65+ raise BenchmarkDataError (
66+ f"{ path } groups[{ group_name !r} ][{ name !r} ] is not a numeric mean"
67+ ) from exc
2668 return means
2769
2870
@@ -42,6 +84,9 @@ def check_regression(
4284 if cur is None :
4385 print (f"WARN: no current result for baseline { name !r} ; skipping" )
4486 continue
87+ if base == 0 :
88+ print (f"WARN: baseline for { name !r} is zero; skipping ratio check" )
89+ continue
4590 ratio = cur / base
4691 tag = "FAIL" if ratio > threshold else "ok"
4792 print (f"[{ tag } ] { name } : { cur :.6f} s vs { base :.6f} s ({ ratio :.2f} x)" )
0 commit comments