Home > Mobile >  Module function in cython gets extra check that a static method doesn't
Module function in cython gets extra check that a static method doesn't

Time:12-02

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.

  • Related