Dear Cython developers,
We are investigating what would be the consequences in Sagemath for moving to default "Binding=True". For instance, in
we're finding the following with
-------------
%%cython
cimport cython
@cython.binding(False)
cdef class Unbinding:
def test(self):
return 1
@cython.binding(True)
cdef class Binding:
def test(self):
return 1
def fetch_test(a, N=100):
for i in range(N):
_ = a.test
def call_test(a, N=100):
for i in range(N):
_ = a.test()
-------------
sage: U=Unbinding()
....: B=Binding()
sage: %timeit fetch_test(U,100000)
2.95 ms ± 37.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
sage: %timeit fetch_test(B,100000)
2.67 ms ± 31.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
sage: %timeit call_test(U,100000)
3.52 ms ± 44.7 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
sage: %timeit call_test(B,100000)
4.71 ms ± 99 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
-------------
so it seems fetching a method has become slightly cheaper (that was a surprise!) but calling it seems to be quite a bit more expensive. In fact, an unfortunate coding style in Sagemath of providing access to attributes mainly through accessor functions gets hit by this rather badly: a method like "basering" increases in time by something like 25%.
Is there any chance that on the cython side this overhead could be reduced? Presently we're faced with several options:
1) keep the default `Binding=False` in sage when we transition to Cython 3
2) somehow profile and determine particularly cheap functions and decorate those with `Binding=False`
3) just go with `Binding=True` everywhere
Each has significant drawbacks:
1) would place us in a rather non-standard use of cython (plus getting Binding=True has some call stack advantages -- probably why it's more expensive)
2) would be a lot of work and would make debugging sage more difficult, because different cython routines would have different call stack structures.
3) runs the risk of deteriorating performance measurably for certain programs, just by upgrading to Cython 3
It would be nice to be able to go with 3), hence the inquiry into whether its costs could be reduced. Any insights? Did we profile in a way that gives us skewed results (as far as we can see the effect is real and measurable on some doctests that weren't particularly written to challenge call cost, so it seems to be measurable in the real world).
Kind regards,
Nils Bruin