diff --git a/Makefile b/Makefile index c11734aa50..aeac4a2579 100644 --- a/Makefile +++ b/Makefile @@ -12,6 +12,7 @@ help: @echo "build --> Build the Cython extension modules" @echo "clean --> Remove all the build files for a fresh start" @echo "test --> Run unit tests" + @echo "readme --> Update benchmark results in README.rst" @echo "coverage--> Unit test coverage (doesn't check compiled functions)" @echo "all --> clean, pyx, build, test" @echo "bench --> Run performance benchmark" @@ -49,6 +50,9 @@ move: test: ${PYTHON} -c "import bottleneck;bottleneck.test()" +readme: + ${PYTHON} tools/update_readme.py + coverage: rm -rf .coverage python -c "import bottleneck; bottleneck.test(coverage=True)" diff --git a/README.rst b/README.rst index 959cc1f5f6..6cd60e540d 100644 --- a/README.rst +++ b/README.rst @@ -31,36 +31,36 @@ Bottleneck comes with a benchmark suite:: Speed is NumPy time divided by Bottleneck time NaN means approx one-third NaNs; float64 and axis=-1 are used - no NaN no NaN NaN NaN + no NaN no NaN NaN NaN (10,) (1000,1000) (10,) (1000,1000) - nansum 19.6 4.1 32.6 6.5 - nanmean 111.6 5.6 114.5 7.2 - nanstd 198.4 4.7 194.8 7.2 - nanvar 191.3 4.6 189.8 7.0 - nanmin 29.2 1.1 29.2 1.4 - nanmax 29.1 1.0 29.2 1.7 - median 48.5 0.8 55.7 1.0 - nanmedian 45.9 2.5 52.8 5.9 - ss 13.5 3.8 3.1 1.1 - nanargmin 52.8 4.0 52.5 5.3 - nanargmax 52.5 4.0 53.2 6.7 - anynan 13.8 1.5 14.3 180.1 - allnan 14.0 209.7 14.0 197.4 - rankdata 35.6 1.5 36.8 2.3 - nanrankdata 48.2 20.0 43.0 28.7 - partsort 4.6 0.8 4.8 1.1 - argpartsort 2.6 0.7 2.7 0.6 - replace 8.3 2.0 8.1 2.0 - push 208.3 11.0 205.2 14.6 - move_sum 301.8 204.5 301.5 330.9 - move_mean 740.3 237.7 751.4 481.6 - move_std 1156.1 126.0 1215.1 366.3 - move_var 1082.5 176.5 1107.3 362.9 - move_min 215.1 21.9 218.4 47.3 - move_max 228.5 22.3 232.4 70.2 - move_argmin 362.7 80.8 376.8 236.4 - move_argmax 351.4 77.2 363.3 246.9 - move_median 376.7 33.6 372.0 53.2 + nansum 31.2 4.0 31.1 6.4 + nanmean 113.1 5.6 113.6 7.5 + nanstd 192.4 4.3 192.1 7.1 + nanvar 185.5 4.5 188.2 6.8 + nanmin 27.3 1.1 27.1 1.4 + nanmax 27.4 1.0 27.4 1.7 + median 43.0 0.8 49.8 1.0 + nanmedian 44.3 2.4 51.6 5.9 + ss 12.5 3.9 2.9 1.1 + nanargmin 53.1 4.0 51.1 5.4 + nanargmax 50.2 4.0 50.4 6.6 + anynan 9.7 1.5 12.7 224.9 + allnan 12.6 261.2 12.0 245.9 + rankdata 36.8 1.6 36.1 2.2 + nanrankdata 46.3 19.2 48.6 33.3 + partsort 4.3 0.8 4.6 1.1 + argpartsort 2.1 0.8 2.2 0.5 + replace 9.0 1.9 8.2 1.9 + push 169.6 8.6 148.0 10.7 + move_sum 278.3 250.5 277.5 355.8 + move_mean 659.7 295.2 683.8 476.9 + move_std 997.3 161.2 1041.5 388.1 + move_var 1039.8 247.0 1149.5 443.9 + move_min 204.1 28.3 206.4 51.1 + move_max 212.6 25.2 212.1 77.7 + move_argmin 365.5 78.3 360.4 224.1 + move_argmax 399.8 102.1 318.6 253.7 + move_median 362.2 35.0 354.1 53.5 Only arrays with data type (dtype) int32, int64, float32, and float64 are accelerated. All other dtypes result in calls to slower, unaccelerated @@ -126,4 +126,4 @@ After you have installed Bottleneck, run the suite of unit tests:: Ran 92 tests in 70.712s OK - + \ No newline at end of file diff --git a/RELEASE.rst b/RELEASE.rst index 2a707db603..e6d1cf4425 100644 --- a/RELEASE.rst +++ b/RELEASE.rst @@ -17,9 +17,8 @@ This release makes Bottleneck more robust, releases GIL, adds new functions. - bn.move_std is slower but numerically more stable - bn.move_median is slower but can now handle NaNs and `min_count` parameter -- Bottleneck can now handle byte-swapped input arrays +- Bottleneck no longer crashes on byte-swapped input arrays - Bottleneck now checks that calls to PyArray_FillWithScalar are successful -- C files are now generated with Cython 0.24 instead of 0.21.1 **Multiple threads** @@ -32,6 +31,11 @@ This release makes Bottleneck more robust, releases GIL, adds new functions. - bn.move_argmax - bn.push +**Miscellaneous** + +- C files are now generated with Cython 0.24 instead of 0.21.1 +- Added script to automate updating of benchmark results in readme file + **Thanks** - Jennifer Olsen worked on bn.move_median diff --git a/tools/update_readme.py b/tools/update_readme.py new file mode 100644 index 0000000000..f21bb8a35b --- /dev/null +++ b/tools/update_readme.py @@ -0,0 +1,57 @@ +from cStringIO import StringIO +import sys +import os + +import bottleneck as bn + + +def update_readme(): + + # run benchmark suite while capturing output; indent + with Capturing() as bench_list: + bn.bench() + bench_list = [' ' + b for b in bench_list] + + # read readme + cwd = os.path.dirname(__file__) + readme_path = os.path.join(cwd, '../README.rst') + with open(readme_path) as f: + readme_list = f.readlines() + readme_list = [r.strip('\n') for r in readme_list] + + # remove old benchmark result from readme + idx1 = readme_list.index(' Bottleneck performance benchmark') + idx2 = [i for i, line in enumerate(readme_list) if line == ''] + idx2 = [i for i in idx2 if i > idx1] + idx2 = idx2[1] + del readme_list[idx1:idx2] + + # insert new benchmark result into readme; remove trailing whitespace + readme_list = readme_list[:idx1] + bench_list + readme_list[idx1:] + readme_list = [r.rstrip() for r in readme_list] + + # replace readme file + os.remove(readme_path) + with open(readme_path, 'w') as f: + f.write('\n'.join(readme_list)) + +# --------------------------------------------------------------------------- +# Capturing class taken from +# http://stackoverflow.com/questions/16571150/ +# how-to-capture-stdout-output-from-a-python-function-call + + +class Capturing(list): + + def __enter__(self): + self._stdout = sys.stdout + sys.stdout = self._stringio = StringIO() + return self + + def __exit__(self, *args): + self.extend(self._stringio.getvalue().splitlines()) + sys.stdout = self._stdout + + +if __name__ == '__main__': + update_readme()