Skip to content

Commit b8ddd4d

Browse files
authored
DEV/MAINT: fix benchmarks for latest asv, and add a spin bench command (#835)
* BENCH: ensure benchmarks run with latest asv The environment type now must be selected, or asv will error out. * DEV: add `spin bench` command
2 parents ae22ed6 + 68068a4 commit b8ddd4d

File tree

3 files changed

+170
-2
lines changed

3 files changed

+170
-2
lines changed

.spin/cmds.py

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
import os
2+
import sys
3+
4+
import click
5+
import spin
6+
from spin.cmds import meson
7+
8+
9+
@click.command()
10+
@click.option(
11+
'--tests', '-t',
12+
default=None, metavar='TESTS', multiple=True,
13+
help="Which tests to run"
14+
)
15+
@click.option(
16+
'--compare', '-c',
17+
is_flag=True,
18+
default=False,
19+
help="Compare benchmarks between the current branch and main "
20+
"(unless other branches specified). "
21+
"The benchmarks are each executed in a new isolated "
22+
"environment."
23+
)
24+
@click.option(
25+
'--verbose', '-v', is_flag=True, default=False
26+
)
27+
@click.option(
28+
'--quick', '-q', is_flag=True, default=False,
29+
help="Run each benchmark only once (timings won't be accurate)"
30+
)
31+
@click.option(
32+
'--factor', '-f', default=1.05,
33+
help="The factor above or below which a benchmark result is "
34+
"considered reportable. This is passed on to the asv command."
35+
)
36+
@click.argument(
37+
'commits', metavar='',
38+
required=False,
39+
nargs=-1
40+
)
41+
@meson.build_dir_option
42+
@click.pass_context
43+
def bench(ctx, tests, compare, verbose, quick, factor, commits, build_dir):
44+
"""🏋 Run benchmarks.
45+
46+
\b
47+
Examples:
48+
49+
\b
50+
$ spin bench -t dwt_benchmarks
51+
$ spin bench -t swt_benchmarks.Swt2TimeSuite.time_swt2
52+
53+
Two benchmark runs can be compared.
54+
By default, `HEAD` is compared to `main`.
55+
You can also specify the branches/commits to compare:
56+
57+
\b
58+
$ spin bench --compare
59+
$ spin bench --compare main
60+
$ spin bench --compare main HEAD
61+
62+
You can also choose which benchmarks to run in comparison mode:
63+
64+
$ spin bench -t Swt2TimeSuite --compare
65+
66+
For a quicker but less accurate check to see if benchmarks work:
67+
68+
$ spin bench --quick
69+
70+
"""
71+
if not commits:
72+
commits = ('main', 'HEAD')
73+
elif len(commits) == 1:
74+
commits = commits + ('HEAD',)
75+
elif len(commits) > 2:
76+
raise click.ClickException(
77+
'Need a maximum of two revisions to compare'
78+
)
79+
80+
bench_args = []
81+
for t in tests:
82+
bench_args += ['--bench', t]
83+
84+
if verbose:
85+
bench_args = ['-v'] + bench_args
86+
87+
if quick:
88+
bench_args = ['--quick'] + bench_args
89+
90+
if not compare:
91+
# No comparison requested; we build and benchmark the current version
92+
93+
click.secho(
94+
"Invoking `build` prior to running benchmarks:",
95+
bold=True, fg="bright_green"
96+
)
97+
ctx.invoke(meson.build)
98+
99+
meson._set_pythonpath(build_dir)
100+
# Some weird bug, not sure what's going on here, but it seems necessary
101+
# on Python 3.14
102+
if not os.environ['PYTHONPATH'].endswith(os.sep):
103+
os.environ['PYTHONPATH'] += os.sep
104+
105+
p = spin.util.run(
106+
[sys.executable, '-c', 'import pywt; print(pywt.__version__)'],
107+
cwd='benchmarks',
108+
echo=False,
109+
output=False
110+
)
111+
pywt_ver = p.stdout.strip().decode('ascii')
112+
113+
click.secho(
114+
f'Running benchmarks on PyWavelets {pywt_ver}',
115+
bold=True, fg="bright_green"
116+
)
117+
cmd = [
118+
'asv', 'run', '--dry-run', '--show-stderr', '--python=same'
119+
] + bench_args
120+
121+
os.chdir('..')
122+
spin.util.run(cmd, cwd='benchmarks', env=os.environ)
123+
else:
124+
# Ensure that we don't have uncommitted changes
125+
commit_a, commit_b = (_commit_to_sha(c) for c in commits)
126+
127+
if commit_b == 'HEAD' and _dirty_git_working_dir():
128+
click.secho(
129+
"WARNING: you have uncommitted changes --- "
130+
"these will NOT be benchmarked!",
131+
fg="red"
132+
)
133+
134+
cmd_compare = [
135+
'asv', 'continuous', '--factor', str(factor),
136+
] + bench_args + [commit_a, commit_b]
137+
spin.util.run(cmd_compare, cwd='benchmarks')
138+
139+
140+
def _commit_to_sha(commit):
141+
p = spin.util.run(['git', 'rev-parse', commit], output=False, echo=False)
142+
if p.returncode != 0:
143+
raise (
144+
click.ClickException(
145+
f'Could not find SHA matching commit `{commit}`'
146+
)
147+
)
148+
149+
return p.stdout.decode('ascii').strip()
150+
151+
152+
def _dirty_git_working_dir():
153+
# Changes to the working directory
154+
p0 = spin.util.run(['git', 'diff-files', '--quiet'])
155+
156+
# Staged changes
157+
p1 = spin.util.run(['git', 'diff-index', '--quiet', '--cached', 'HEAD'])
158+
159+
return (p0.returncode != 0 or p1.returncode != 0)

benchmarks/asv.conf.json

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@
1919
"branches": ["main"], // for git
2020
// "branches": ["tip"], // for mercurial
2121

22+
// This is a frequent source of failures for `--compare`. Check the
23+
// asv docs for what `build_command` does.
24+
// Avoid build isolation, that will cause problems.
25+
"build_command": [
26+
"python -m build -wnx -o {build_cache_dir} {build_dir}"
27+
],
28+
2229
// The DVCS being used. If not set, it will be automatically
2330
// determined from "repo" by looking at the protocol in the URL
2431
// (if remote), or by looking for special directories, such as
@@ -30,7 +37,7 @@
3037
// If missing or the empty string, the tool will be automatically
3138
// determined by looking for tools on the PATH environment
3239
// variable.
33-
// "environment_type": "virtualenv",
40+
"environment_type": "virtualenv",
3441

3542
// the base URL to show a commit for the project.
3643
"show_commit_url": "http://github.com/PyWavelets/pywt/commit/",
@@ -46,6 +53,7 @@
4653
"matrix": {
4754
"numpy": [],
4855
"Cython": [],
56+
"meson-python": [],
4957
},
5058

5159
// The directory (relative to the current directory) that benchmarks are
@@ -71,5 +79,5 @@
7179
// `asv` will cache wheels of the recent builds in each
7280
// environment, making them faster to install next time. This is
7381
// number of builds to keep, per environment.
74-
// "wheel_cache_size": 0
82+
"wheel_cache_size": 20
7583
}

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,4 @@ Environments = [
9898
'spin.cmds.meson.python',
9999
]
100100
Documentation = ["spin.cmds.meson.docs"]
101+
Metrics = [".spin/cmds.py:bench"]

0 commit comments

Comments
 (0)