Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid underscored arithmetic methods in Python #21448

Closed
jdemeyer opened this issue Sep 8, 2016 · 19 comments
Closed

Avoid underscored arithmetic methods in Python #21448

jdemeyer opened this issue Sep 8, 2016 · 19 comments

Comments

@jdemeyer
Copy link
Contributor

jdemeyer commented Sep 8, 2016

In categories, it is better to write x + y instead of x._add_(y) since the latter can be a lot slower if _add_ is implemented in Cython.

We also remove several redundant implementations of _sub_ where they coincide with the default implementation from ModuleElement.

Depends on #20767

CC: @nthiery

Component: performance

Author: Jeroen Demeyer

Branch/Commit: ca0f7ba

Reviewer: Nicolas M. Thiéry

Issue created by migration from https://trac.sagemath.org/ticket/21448

@jdemeyer jdemeyer added this to the sage-7.4 milestone Sep 8, 2016
@jdemeyer

This comment has been minimized.

@jdemeyer

This comment has been minimized.

@jdemeyer

This comment has been minimized.

@jdemeyer

This comment has been minimized.

@jdemeyer
Copy link
Contributor Author

jdemeyer commented Sep 8, 2016

Branch: u/jdemeyer/ticket/21448

@jdemeyer
Copy link
Contributor Author

jdemeyer commented Sep 8, 2016

Last 10 new commits:

343131aFix doctest for Trac #20767
1f964c720767: minor documentation reformating / improvements
6b1f65f20767: additional test, use Element rather than RingElement in some tests, minor doc improvement
35b64a8Fix division action
2e8f9e4Return exception instead of error message
59a04e4Improve documentation and tests
2d4094820767: Proofreading doc + doc of cdef `_add_` trick + TODO about _add_long / _mul_long
fec4abeFurther doc additions
25c9d7dAdd tests for _add_long and _mul_long
ca0f7baAvoid underscored arithmetic methods in Python

@jdemeyer
Copy link
Contributor Author

jdemeyer commented Sep 8, 2016

Commit: ca0f7ba

@tscrim
Copy link
Collaborator

tscrim commented Sep 8, 2016

comment:7

This is counterintuitive to me:

In categories, it is better to write x + y instead of x.add(y) since the latter can be a lot slower if _add_ is implemented in Cython.

I would think that avoiding the additional call to __add__ (which does some additional checks) would result in a speed gain. Does this have to do with how cpdef functions are implemented in Cython?

@jdemeyer
Copy link
Contributor Author

jdemeyer commented Sep 8, 2016

comment:8

Rule number 1 of optimizing Python: a method is slow. Almost anything is faster than a method lookup.

@jdemeyer
Copy link
Contributor Author

jdemeyer commented Sep 8, 2016

comment:9

And the call of x + y to x.__add__(y) is optimized by Python, so it is reasonably fast. Compare:

sage: timeit('a + a', number=10^6, repeat=20)
1000000 loops, best of 20: 62.3 ns per loop
sage: timeit('a._add_(a)', number=10^6, repeat=20)
1000000 loops, best of 20: 115 ns per loop
sage: timeit('a.__add__(a)', number=10^6, repeat=20)
1000000 loops, best of 20: 162 ns per loop

I don't really have an explanation of why __add__ is slower than _add_, I would have expected them to be equally slow.

@jdemeyer
Copy link
Contributor Author

jdemeyer commented Sep 8, 2016

comment:10

On the topic of methods being slow, note the difference between:

sage: a = 1
sage: timeit('parent(a)', number=10^6, repeat=20)
1000000 loops, best of 20: 74.6 ns per loop
sage: timeit('a.parent()', number=10^6, repeat=20)
1000000 loops, best of 20: 93.5 ns per loop

@nthiery
Copy link
Contributor

nthiery commented Sep 8, 2016

comment:11

I checked the diff and it does what the ticket claims.

Just for a complete confirmation, could you post it a new benchmark where the code to be benchmarked is called 100 times in a loop inside a function? Just to make sure that there is no interference from the fact that we are timing at very low granularity.

Once confirmed, you can set a positive review on my behalf.

Thanks!

@nthiery
Copy link
Contributor

nthiery commented Sep 8, 2016

Reviewer: Nicolas M. Thiéry

@tscrim
Copy link
Collaborator

tscrim commented Sep 8, 2016

comment:13

Thank you for the explanations Jeroen!

@jdemeyer
Copy link
Contributor Author

jdemeyer commented Sep 9, 2016

comment:14

I made a benchmark which should be close to possible real-life usage. The conclusion:

With _add_: 5 loops, best of 3: 85.2 ms per loop

With +: 5 loops, best of 3: 78.1 ms per loop

@jdemeyer
Copy link
Contributor Author

jdemeyer commented Sep 9, 2016

comment:16

Note that the benchmark also shows that implementing arithmetic in the category is really slow:

With _add_ implemented in Cython: 125 loops, best of 3: 5.57 ms per loop

With _sub_ implemented in the category: 5 loops, best of 3: 78.1 ms per loop

@jdemeyer
Copy link
Contributor Author

jdemeyer commented Sep 9, 2016

Benchmark

@vbraun
Copy link
Member

vbraun commented Oct 3, 2016

Changed branch from u/jdemeyer/ticket/21448 to ca0f7ba

@vbraun
Copy link
Member

vbraun commented Oct 3, 2016

comment:17

Attachment: Single-underscore benchmark.ipynb.gz

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants