-
Notifications
You must be signed in to change notification settings - Fork 44
Expand file tree
/
Copy pathbenchmark_report.py
More file actions
executable file
·86 lines (69 loc) · 2.66 KB
/
benchmark_report.py
File metadata and controls
executable file
·86 lines (69 loc) · 2.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
from dataclasses import dataclass
from tabulate import tabulate
from typing import Union, Optional
@dataclass
class BenchmarkMetric:
name: str
value: Union[float, int]
unit: Optional[str] = None
class BenchmarkStep:
"""Captures measurements from a given operation"""
def __init__(self, description):
self.description: str = description
"""Description of the operation"""
self._metrics: dict[str, BenchmarkMetric] = {}
"""Description of the operation"""
def add(self, metric: BenchmarkMetric):
self._metrics[metric.name] = metric
def list_metrics(self):
"""List the metrics (sorted by name)"""
return sorted(self._metrics.values(), key=lambda x: x.name)
class BenchmarkRun:
"""Class for capturing measurements for a given test suite for comparison."""
def __init__(self, suite: str, description: str):
self.suite = suite
"""The test suite associated with this report."""
self.description = description
"""Description of the report"""
self.steps: list[BenchmarkStep] = []
"""List of steps and their metrics"""
def add(self, operation):
self.steps.append(operation)
class BenchmarkReport:
def __init__(self, name):
self.name = name
self.runs: list[BenchmarkRun] = []
def add(self, run):
self.runs.append(run)
def __str__(self):
"""Pretty-print a table that compares the metrics across each report.
We want to transpose these such that each report gets their own column and each metric gets its own row
(ideally grouped by operation).
"""
if not self.runs:
print("No runs to compare!")
return
suites = set(r.suite for r in self.runs)
if len(suites) > 1:
print("Found more than one type of suite")
return
suite = self.runs[0].suite
headers = [
f"{suite} Operation",
"Metric",
"Unit",
*[r.description for r in self.runs],
]
rows = []
for step_tranche in zip(*[r.steps for r in self.runs]):
# TODO zip by metric name instead of assuming all metrics are being measured
step_name = step_tranche[0].description
for metric_tuple in zip(*[x.list_metrics() for x in step_tranche]):
row = [
step_name,
metric_tuple[0].name,
metric_tuple[0].unit,
*[p.value for p in metric_tuple],
]
rows.append(row)
return tabulate(rows, headers=headers, tablefmt="fancy_outline")