advanced_statistics.py
1 #!/usr/bin/env python 2 # /// script 3 # requires-python = ">=3.10" 4 # dependencies = [ 5 # "numpy", 6 # ] 7 # /// 8 9 import argparse 10 import json 11 from enum import Enum 12 13 import numpy as np 14 15 16 class Unit(Enum): 17 SECOND = 1 18 MILLISECOND = 2 19 20 def factor(self): 21 match self: 22 case Unit.SECOND: 23 return 1 24 case Unit.MILLISECOND: 25 return 1e3 26 27 def __str__(self): 28 match self: 29 case Unit.SECOND: 30 return "s" 31 case Unit.MILLISECOND: 32 return "ms" 33 34 35 parser = argparse.ArgumentParser() 36 parser.add_argument("file", help="JSON file with benchmark results") 37 parser.add_argument( 38 "--time-unit", 39 help="The unit of time.", 40 default="second", 41 action="store", 42 choices=["second", "millisecond"], 43 dest="unit", 44 ) 45 args = parser.parse_args() 46 47 unit = Unit.MILLISECOND if args.unit == "millisecond" else Unit.SECOND 48 unit_str = str(unit) 49 50 with open(args.file) as f: 51 results = json.load(f)["results"] 52 53 commands = [b["command"] for b in results] 54 times = [b["times"] for b in results] 55 56 for command, ts in zip(commands, times): 57 ts = [t * unit.factor() for t in ts] 58 59 p05 = np.percentile(ts, 5) 60 p25 = np.percentile(ts, 25) 61 p75 = np.percentile(ts, 75) 62 p95 = np.percentile(ts, 95) 63 64 iqr = p75 - p25 65 66 print(f"Command '{command}'") 67 print(f" runs: {len(ts):8d}") 68 print(f" mean: {np.mean(ts):8.3f} {unit_str}") 69 print(f" stddev: {np.std(ts, ddof=1):8.3f} {unit_str}") 70 print(f" median: {np.median(ts):8.3f} {unit_str}") 71 print(f" min: {np.min(ts):8.3f} {unit_str}") 72 print(f" max: {np.max(ts):8.3f} {unit_str}") 73 print() 74 print(" percentiles:") 75 print(f" P_05 .. P_95: {p05:.3f} {unit_str} .. {p95:.3f} {unit_str}") 76 print( 77 f" P_25 .. P_75: {p25:.3f} {unit_str} .. {p75:.3f} {unit_str} (IQR = {iqr:.3f} {unit_str})" 78 ) 79 print()