I have the following class static method and method user:
@cython.cclass
class TestClass:
@staticmethod
@cython.cfunc
def func(v: float) -> float:
return v 1.0
def test_call(self):
res = TestClass.func(2)
return res
The line res = TestClass.func(2)
shows as white in the annnotated version (as expected) and gets translated to C as
__pyx_t_1 = __pyx_f_8crujisim_11cythontests_9TestClass_func(2.0); if (unlikely(PyErr_Occurred())) __PYX_ERR(0, 521, __pyx_L1_error)__pyx_v_res = __pyx_t_1;
But if I now take that static method out of the class and turn it into a function, as in
@cython.cfunc
def func(v: float) -> float:
return v 1.0
@cython.cclass
class TestClass:
def test_call(self):
res = func(2)
return res
Then the res = func(2)
line is now yellow, and the C translation shows an additional test
__pyx_t_1 = __pyx_f_8crujisim_11cythontests_func(2.0); if (unlikely(__pyx_t_1 == ((double)-1) && PyErr_Occurred())) __PYX_ERR(0, 521, __pyx_L1_error)__pyx_v_res = __pyx_t_1;
I am forced to get the method out of the class because of this behaviour I reported, which I believe is a bug https://github.com/cython/cython/issues/5159 . But the method call is inside a tight loop in the critical path and there is a noticeable performance loss.
Is it perhaps an argument overflow check? Can it be disabled? Any hints? Thanks.
CodePudding user response:
You can make a cdef
/cfunc
function unable to raise an exception using @cython.exceptval(check=False)
(or cdef float func() noexcept
in the non-pure-Python syntax). See the documentation for full details about exceptions. If you do this it won't be checked.
Cython 3 has changed the default behaviour from "cdef
functions swallow exceptions" to "cdef
functions can raise exceptions", but it's possible to pick either.
The difference you see between staticmethod
and a module-level function is probably a minor bug - there's no reason for them to behave differently.
However, I'd actually expect the extra check to be an optimization in the non-error case: PyErr_Occurred()
is expected to be expensive, so using -1
as a sentinal value to indicate that an error might have happened avoids it most of the time. I haven't measured it in your exact case though - it's probably a balance between skipping expensive checks vs greater code size.
The annotated HTML highlighting is pretty crude so is almost working on the basis that "more text == slower" which isn't quite right here. So don't take it too seriously.