/ thirdparty / hyperfine / scripts / advanced_statistics.py
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()