Skip to content

add ASV (continued)#264

Merged
rgommers merged 11 commits intoPyWavelets:masterfrom
grlee77:asv_v2
Jan 1, 2017
Merged

add ASV (continued)#264
rgommers merged 11 commits intoPyWavelets:masterfrom
grlee77:asv_v2

Conversation

@grlee77
Copy link
Contributor

@grlee77 grlee77 commented Dec 31, 2016

This is a revival of @kwohlfahrt's work in #158 (which has not been updated in several months).

I have rebased that PR on current master and made some updates. The first new commit here addresses minor comments @rgommers made in the old PR.

I added several other benchmarks for the majority of the remaining transforms. I have tried to keep the run time down to around 5 minutes for current master when calling via:

asv run --python=same --quick

I have also attempted to make tests skip functions that were not present on older commits by raising a NotImplementedError whenever a function under test cannot be imported. As is, for v0.3.0, several benchmarks get skipped and there are only a handful of test cases that result in failures (i.e. some tests use complex dtypes which was not supported then).

Kai Wohlfahrt and others added 8 commits December 30, 2016 15:41
No benchmarks setup, but ASV builds correctly
Interestingly, 1D dwt is significantly slower on python 3.
Benchmarking these functions should hopefully give a closer view of how
performance in the C core changes without requiring a lot of effort to
instrument them separately.

The different modes should have somewhat different performance, especially
for small sizes/large filters. If this doesn't happen, there is too much
overhead to benchmark the convolution directly and this needs to be done
separately.

modes are only set for 1D, since n-dimensional path is not affected by the
mode (it is just passed through to the 1D).
raises NotImplementedErrors on various functions that may not be present on
older commits so that those tests are skipped.

special case to support the now outdated pywt.MODES syntax from the 0.3.0 API
@grlee77 grlee77 added this to the v1.0 milestone Dec 31, 2016
@codecov-io
Copy link

codecov-io commented Dec 31, 2016

Current coverage is 86.17% (diff: 100%)

Merging #264 into master will decrease coverage by 0.89%

@@             master       #264   diff @@
==========================================
  Files            20         20          
  Lines          2962       3045    +83   
  Methods           0         45    +45   
  Messages          0          0          
  Branches        297        521   +224   
==========================================
+ Hits           2579       2624    +45   
- Misses          333        371    +38   
  Partials         50         50          

Powered by Codecov. Last update 45314ce...01733e2

try:
from pywt import cwt
except ImportError:
raise NotImplementedError("cwt not available")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there an advantage to doing this within setup and raising an exception? SciPy does it like I described at #158 (comment). Here's an example for lgmres, https://github.com/scipy/scipy/blob/master/benchmarks/benchmarks/sparse_linalg_solve.py#L15, works fine and seems simpler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The difference seems to be that with my approach the test shows up as "n/a" instead of as "failed". I used NotImplementedError in setup based on the following text in the ASV docs

If setup raises a NotImplementedError, the benchmark is marked as skipped for the parameter values in question.

see for example the following output when running the CWT tests on 0.4.0 where it is not present:
(scroll right to see the n/a)

12:58 $ asv run --python=3.5 --quick --bench="Cwt*" v0.4.0^!
· No `environment_type` specified in asv.conf.json. This will be required in the future.
· Creating environments
· Discovering benchmarks
·· Uninstalling from conda-py3.5-Cython-numpy
·· Building for conda-py3.5-Cython-numpy.......
·· Installing into conda-py3.5-Cython-numpy..
· Running 1 total benchmarks (1 commits * 1 environments * 1 benchmarks)
[  0.00%] · For pywt commit hash 3f4f46a9:
[  0.00%] ·· Building for conda-py3.5-Cython-numpy.^[[1;2C....
[  0.00%] ·· Benchmarking conda-py3.5-Cython-numpy
[100.00%] ··· Running cwt_benchmarks.CwtTimeSuite.time_cwt                                                                                          n/a;...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting, didn't know that. +1 for NotImplemented


class CwtTimeSuite(CwtTimeSuiteBase):
def time_cwt(self, n, wavelet, max_scale):
pywt.cwt(self.data, self.scales, self.wavelet)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should use the max_scale and wavelet parameters that are passed to time_cwt it looks like.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this benchmark, self.scales is a range while max_scale is an integer

for self.wavelet vs. wavelet I think it depends which code path you want to benchmark. For small sizes, the benchmark runs a bit faster if the input is already a Wavelet object, but for larger transforms the overhead of converting a string to a Wavelet object is negligable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That said, I am fine with just passing the wavelet string instead of the self.wavelet object. The same goes for the mode parameter in some of the other tests.


class DwtTimeSuite(DwtTimeSuiteBase):
def time_dwt(self, n, wavelet, mode):
pywt.dwt(self.data, self.wavelet, self.mode)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, remove self. to use the parameters passed to time_dwt.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and same again for time_idwt below

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and more cases further on



class Wavedec2TimeSuite(Wavedec2TimeSuiteBase):
def time_wavedec2(self, n, wavelet, dtype):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dtype isn't used

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and n isn't either

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The benchmarks fail if I remove any of these unused parameters that were defined in the parent class. (They are used, but only in the setup method of the parent).

I do not see this clearly stated in the docs: https://asv.readthedocs.io/en/latest/writing_benchmarks.html#parameterized-benchmarks

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah that makes sense. not much to be done about it then



class WavedecnTimeSuite(WavedecnTimeSuiteBase):
def time_wavedecn(self, D, n, wavelet, dtype):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more unused parameters

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true for multiple benchmarks below

@rgommers
Copy link
Member

Thanks for picking this up, would be nice to get these in!

@rgommers
Copy link
Member

A couple more review comments from gh-158:

  • rename asv/ to benchmarks/
  • add a benchmarks/README with basic instructions (a simple pip install asv and then asv run --python=same will do)

@rgommers rgommers mentioned this pull request Dec 31, 2016
credit to @pv who wrote the corresponding README for the scipy project, upon
which this one is based.
@grlee77
Copy link
Contributor Author

grlee77 commented Dec 31, 2016

I have addressed most comments, but see my responses above on the inability to remove unused parameters and on the logic behind raising a NotImplementedError in setup.py

on my macbook, the quick version of the benchmarks took 4:32 on current master. I am running it now without --quick to see how long this takes. It is also possible that benchmarks on old revisions may take much longer (e.g. dwtn/idwtn are more than an order of magnitude faster on current master vs. 0.3.0).

@grlee77
Copy link
Contributor Author

grlee77 commented Dec 31, 2016

full duration was 36:15 for current master without `--quick`` (for a single commit).

@rgommers
Copy link
Member

rgommers commented Jan 1, 2017

LGTM. In it goes. Thanks @grlee77!

@rgommers rgommers merged commit 45cf2a5 into PyWavelets:master Jan 1, 2017
@grlee77 grlee77 deleted the asv_v2 branch March 9, 2017 04:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants