Skip to content

Commit b012ec4

Browse files
committed
Add asv
1 parent acc7531 commit b012ec4

File tree

4 files changed

+283
-0
lines changed

4 files changed

+283
-0
lines changed

asv.conf.json

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
{
2+
// The version of the config file format. Do not change, unless
3+
// you know what you are doing.
4+
"version": 1,
5+
6+
// The name of the project being benchmarked
7+
"project": "flox",
8+
9+
// The project's homepage
10+
"project_url": "http://flox.readthedocs.io/",
11+
12+
// The URL or local path of the source code repository for the
13+
// project being benchmarked
14+
"repo": ".",
15+
16+
// The Python project's subdirectory in your repo. If missing or
17+
// the empty string, the project is assumed to be located at the root
18+
// of the repository.
19+
// "repo_subdir": "",
20+
21+
// Customizable commands for building, installing, and
22+
// uninstalling the project. See asv.conf.json documentation.
23+
//
24+
// "install_command": ["in-dir={env_dir} python -mpip install {wheel_file}"],
25+
// "uninstall_command": ["return-code=any python -mpip uninstall -y {project}"],
26+
// "build_command": [
27+
// "python setup.py build",
28+
// "PIP_NO_BUILD_ISOLATION=false python -mpip wheel --no-deps --no-index -w {build_cache_dir} {build_dir}"
29+
// ],
30+
31+
// List of branches to benchmark. If not provided, defaults to "master"
32+
// (for git) or "default" (for mercurial).
33+
"branches": ["main"], // for git
34+
// "branches": ["default"], // for mercurial
35+
36+
// The DVCS being used. If not set, it will be automatically
37+
// determined from "repo" by looking at the protocol in the URL
38+
// (if remote), or by looking for special directories, such as
39+
// ".git" (if local).
40+
// "dvcs": "git",
41+
42+
// The tool to use to create environments. May be "conda",
43+
// "virtualenv" or other value depending on the plugins in use.
44+
// If missing or the empty string, the tool will be automatically
45+
// determined by looking for tools on the PATH environment
46+
// variable.
47+
"environment_type": "conda",
48+
49+
// timeout in seconds for installing any dependencies in environment
50+
// defaults to 10 min
51+
//"install_timeout": 600,
52+
53+
// the base URL to show a commit for the project.
54+
"show_commit_url": "http://github.com/dcherian/flox/commit/",
55+
56+
// The Pythons you'd like to test against. If not provided, defaults
57+
// to the current version of Python used to run `asv`.
58+
"pythons": ["3.9"],
59+
60+
// The list of conda channel names to be searched for benchmark
61+
// dependency packages in the specified order
62+
"conda_channels": ["conda-forge", "nodefaults"],
63+
64+
// The matrix of dependencies to test. Each key is the name of a
65+
// package (in PyPI) and the values are version numbers. An empty
66+
// list or empty string indicates to just test against the default
67+
// (latest) version. null indicates that the package is to not be
68+
// installed. If the package to be tested is only available from
69+
// PyPi, and the 'environment_type' is conda, then you can preface
70+
// the package name by 'pip+', and the package will be installed via
71+
// pip (with all the conda available packages installed first,
72+
// followed by the pip installed packages).
73+
//
74+
"matrix": {
75+
"numpy_groupies": [""],
76+
"numpy": [""],
77+
"pandas": [""],
78+
"dask-core": [""],
79+
"xarray": [""],
80+
},
81+
82+
// Combinations of libraries/python versions can be excluded/included
83+
// from the set to test. Each entry is a dictionary containing additional
84+
// key-value pairs to include/exclude.
85+
//
86+
// An exclude entry excludes entries where all values match. The
87+
// values are regexps that should match the whole string.
88+
//
89+
// An include entry adds an environment. Only the packages listed
90+
// are installed. The 'python' key is required. The exclude rules
91+
// do not apply to includes.
92+
//
93+
// In addition to package names, the following keys are available:
94+
//
95+
// - python
96+
// Python version, as in the *pythons* variable above.
97+
// - environment_type
98+
// Environment type, as above.
99+
// - sys_platform
100+
// Platform, as in sys.platform. Possible values for the common
101+
// cases: 'linux2', 'win32', 'cygwin', 'darwin'.
102+
//
103+
// "exclude": [
104+
// {"python": "3.2", "sys_platform": "win32"}, // skip py3.2 on windows
105+
// {"environment_type": "conda", "six": null}, // don't run without six on conda
106+
// ],
107+
//
108+
// "include": [
109+
// // additional env for python2.7
110+
// {"python": "2.7", "numpy": "1.8"},
111+
// // additional env if run on windows+conda
112+
// {"platform": "win32", "environment_type": "conda", "python": "2.7", "libpython": ""},
113+
// ],
114+
115+
// The directory (relative to the current directory) that benchmarks are
116+
// stored in. If not provided, defaults to "benchmarks"
117+
// "benchmark_dir": "benchmarks",
118+
119+
// The directory (relative to the current directory) to cache the Python
120+
// environments in. If not provided, defaults to "env"
121+
"env_dir": ".asv/env",
122+
123+
// The directory (relative to the current directory) that raw benchmark
124+
// results are stored in. If not provided, defaults to "results".
125+
"results_dir": ".asv/results",
126+
127+
// The directory (relative to the current directory) that the html tree
128+
// should be written to. If not provided, defaults to "html".
129+
"html_dir": ".asv/html",
130+
131+
// The number of characters to retain in the commit hashes.
132+
// "hash_length": 8,
133+
134+
// `asv` will cache results of the recent builds in each
135+
// environment, making them faster to install next time. This is
136+
// the number of builds to keep, per environment.
137+
// "build_cache_size": 2,
138+
139+
// The commits after which the regression search in `asv publish`
140+
// should start looking for regressions. Dictionary whose keys are
141+
// regexps matching to benchmark names, and values corresponding to
142+
// the commit (exclusive) after which to start looking for
143+
// regressions. The default is to start from the first commit
144+
// with results. If the commit is `null`, regression detection is
145+
// skipped for the matching benchmark.
146+
//
147+
// "regressions_first_commits": {
148+
// "some_benchmark": "352cdf", // Consider regressions only after this commit
149+
// "another_benchmark": null, // Skip regression detection altogether
150+
// },
151+
152+
// The thresholds for relative change in results, after which `asv
153+
// publish` starts reporting regressions. Dictionary of the same
154+
// form as in ``regressions_first_commits``, with values
155+
// indicating the thresholds. If multiple entries match, the
156+
// maximum is taken. If no entry matches, the default is 5%.
157+
//
158+
// "regressions_thresholds": {
159+
// "some_benchmark": 0.01, // Threshold of 1%
160+
// "another_benchmark": 0.5, // Threshold of 50%
161+
// },
162+
}

benchmarks/__init__.py

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
def parameterized(names, params):
2+
def decorator(func):
3+
func.param_names = names
4+
func.params = params
5+
return func
6+
7+
return decorator

benchmarks/combine.py

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import numpy as np
2+
3+
import flox
4+
5+
from . import parameterized
6+
7+
N = 1000
8+
9+
10+
class Combine:
11+
def setup(self, *args, **kwargs):
12+
raise NotImplementedError
13+
14+
@parameterized("kind", ("cohorts", "mapreduce"))
15+
def time_combine(self, kind):
16+
flox.core._npg_combine(
17+
getattr(self, f"x_chunk_{kind}"),
18+
**self.kwargs,
19+
keepdims=True,
20+
engine="numpy",
21+
)
22+
23+
@parameterized("kind", ("cohorts", "mapreduce"))
24+
def peakmem_combine(self, kind):
25+
flox.core._npg_combine(
26+
getattr(self, f"x_chunk_{kind}"),
27+
**self.kwargs,
28+
keepdims=True,
29+
engine="numpy",
30+
)
31+
32+
33+
class Combine1d(Combine):
34+
"""
35+
Time the combine step for dask reductions,
36+
this is for reducting along a single dimension
37+
"""
38+
39+
def setup(self, *args, **kwargs):
40+
def construct_member(groups):
41+
return {
42+
"groups": groups,
43+
"intermediates": [
44+
np.ones((40, 120, 120, 4), dtype=float),
45+
np.ones((40, 120, 120, 4), dtype=int),
46+
],
47+
}
48+
49+
# motivated by
50+
self.x_chunk_mapreduce = [
51+
construct_member(groups)
52+
for groups in [
53+
np.array((1, 2, 3, 4)),
54+
np.array((5, 6, 7, 8)),
55+
np.array((9, 10, 11, 12)),
56+
]
57+
* 2
58+
]
59+
60+
self.x_chunk_cohorts = [construct_member(groups) for groups in [np.array((1, 2, 3, 4))] * 4]
61+
self.kwargs = {"agg": flox.aggregations.mean, "axis": (3,), "group_ndim": 1}

benchmarks/reduce.py

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import numpy as np
2+
3+
import flox
4+
5+
from . import parameterized
6+
7+
N = 1000
8+
9+
10+
class ChunkReduce:
11+
"""Time the core reduction function."""
12+
13+
def setup(self, *args, **kwargs):
14+
raise NotImplementedError
15+
16+
@parameterized("func", ["sum", "nansum", "mean", "nanmean", "argmax"])
17+
def time_reduce(self, func):
18+
flox.groupby_reduce(
19+
self.array,
20+
self.labels,
21+
func=func,
22+
axis=self.axis,
23+
)
24+
25+
@parameterized("func", ["sum", "nansum", "mean", "nanmean", "argmax"])
26+
def peakmem_reduce(self, func):
27+
flox.groupby_reduce(
28+
self.array,
29+
self.labels,
30+
func=func,
31+
axis=self.axis,
32+
)
33+
34+
35+
class ChunkReduce1D(ChunkReduce):
36+
def setup(self, *args, **kwargs):
37+
self.array = np.ones((N,))
38+
self.labels = np.repeat(np.arange(5), repeats=N // 5)
39+
self.axis = -1
40+
41+
42+
class ChunkReduce2D(ChunkReduce):
43+
def setup(self, *args, **kwargs):
44+
self.array = np.ones((N, N))
45+
self.labels = np.repeat(np.arange(N // 5), repeats=5)
46+
self.axis = -1
47+
48+
49+
class ChunkReduce2DAllAxes(ChunkReduce):
50+
def setup(self, *args, **kwargs):
51+
self.array = np.ones((N, N))
52+
self.labels = np.repeat(np.arange(N // 5), repeats=5)
53+
self.axis = None

0 commit comments

Comments
 (0)