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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
|
import copy
import fnmatch
import os
from timeit import Timer
import yaml
def time_stmt(stmt="pass", setup="pass", number=0, repeat=3):
"""Timer function with the same behaviour as running `python -m timeit `
in the command line.
Parameters
----------
stmt : str
(Default value = "pass")
setup : str
(Default value = "pass")
number : int
(Default value = 0)
repeat : int
(Default value = 3)
Returns
-------
float
elapsed time in seconds or NaN if the command failed.
"""
t = Timer(stmt, setup)
if not number:
# determine number so that 0.2 <= total time < 2.0
for i in range(1, 10):
number = 10 ** i
try:
x = t.timeit(number)
except Exception:
print(t.print_exc())
return float("NaN")
if x >= 0.2:
break
try:
r = t.repeat(repeat, number)
except Exception:
print(t.print_exc())
return float("NaN")
best = min(r)
return best / number
def build_task(task, name="", setup="", number=0, repeat=3):
nt = copy.copy(task)
nt["name"] = (name + " " + task.get("name", "")).strip()
nt["setup"] = (setup + "\n" + task.get("setup", "")).strip("\n")
nt["stmt"] = task.get("stmt", "")
nt["number"] = task.get("number", number)
nt["repeat"] = task.get("repeat", repeat)
return nt
def time_task(name, stmt="pass", setup="pass", number=0, repeat=3, stmts="", base=""):
if base:
nvalue = time_stmt(stmt=base, setup=setup, number=number, repeat=repeat)
yield name + " (base)", nvalue
suffix = " (normalized)"
else:
nvalue = 1.0
suffix = ""
if stmt:
value = time_stmt(stmt=stmt, setup=setup, number=number, repeat=repeat)
yield name, value / nvalue
for task in stmts:
new_task = build_task(task, name, setup, number, repeat)
for task_name, value in time_task(**new_task):
yield task_name + suffix, value / nvalue
def time_file(filename, name="", setup="", number=0, repeat=3):
"""Open a yaml benchmark file an time each statement,
yields a tuple with filename, task name, time in seconds.
Parameters
----------
filename :
name :
(Default value = "")
setup :
(Default value = "")
number :
(Default value = 0)
repeat :
(Default value = 3)
Returns
-------
"""
with open(filename, "r") as fp:
tasks = yaml.load(fp)
for task in tasks:
new_task = build_task(task, name, setup, number, repeat)
for task_name, value in time_task(**new_task):
yield task_name, value
def recursive_glob(rootdir=".", pattern="*"):
return [
os.path.join(looproot, filename)
for looproot, _, filenames in os.walk(rootdir)
for filename in filenames
if fnmatch.fnmatch(filename, pattern)
]
def main(filenames=None):
if not filenames:
filenames = recursive_glob(".", "bench_*.yaml")
elif isinstance(filenames, str):
filenames = [filenames]
for filename in filenames:
print(filename)
print("-" * len(filename))
print()
for task_name, value in time_file(filename):
print(f"{value:.2e} {task_name}")
print()
if __name__ == "__main__":
main()
|