[Cython] Bindings performance issue

Robert Bradshaw robertwb at math.washington.edu
Thu Jun 2 18:31:20 CEST 2011


On Thu, Jun 2, 2011 at 1:30 AM, Vitja Makarov <vitja.makarov at gmail.com> wrote:
> 2011/6/2 Robert Bradshaw <robertwb at math.washington.edu>:
>> On Wed, Jun 1, 2011 at 7:26 AM, Vitja Makarov <vitja.makarov at gmail.com> wrote:
>>> 2011/6/1 mark florisson <markflorisson88 at gmail.com>:
>>>> On 31 May 2011 20:25, Vitja Makarov <vitja.makarov at gmail.com> wrote:
>>>>> Hi!
>>>>>
>>>>> Is bindings performance issue valuable?
>>>>>
>>>>> $ cat bindbench.pyx
>>>>> def wo_bindings():
>>>>>    pass
>>>>>
>>>>> def outer():
>>>>>    def inner():
>>>>>        pass
>>>>>    return inner
>>>>> with_bindings = outer()
>>>>>
>>>>> $ python
>>>>>>>> import timeit
>>>>>>>> timeit.repeat('with_bindings()', setup='from bindbench import wo_bindings, with_bindings', repeat=1, number=100000000)
>>>>> [6.169871807098389]
>>>>>>>> timeit.repeat('wo_bindings()', setup='from bindbench import wo_bindings, with_bindings', repeat=1, number=100000000)
>>>>> [4.609416961669922]
>>>>>
>>>>> PyCBindings makes it 1.3 (difference is about 15ns on my laptop) times
>>>>> slower for CPython interpreter execution.
>>>>> As CPython has some optimizations for CFunctions and PyCFunctions.
>>>>>
>>>>> Does it make sense for us? Or we can easily switch to bindings?
>>>>>
>>>>> --
>>>>> vitja.
>>>>> _______________________________________________
>>>>> cython-devel mailing list
>>>>> cython-devel at python.org
>>>>> http://mail.python.org/mailman/listinfo/cython-devel
>>>>>
>>>>
>>>> I think switching should be fine, if you'd desperately need the speed
>>>> you'd be calling c(p)def functions from Cython. In fact, when the
>>>> fused cfunction will be ready it will be even slightly slower, as it
>>>> overrides the tp_call. But perhaps that should really be made into a
>>>> subclass...
>>
>> Yes, this should be a subclass, slowing all calls down is a bad idea.
>>
>>>> Anyway, would you use these for Python classes and module-level def
>>>> functions (and closures) only, or would you also use them in extension
>>>> classes? Because I found at least a bit of problem there, as extension
>>>> class methods get 'self' passed as the first argument to the C
>>>> function (as PyCFunctionObject.m_self), whereas methods in Python
>>>> classes get 'self' passed in the args tuple (and the m_self is
>>>> unused).
>>>>
>>>
>>> Recently I've found a problem with static methods (__new__ for
>>> example) of inner classes (classes created inside a function, for
>>> instance)
>>> I think binding version should be used for all regular def functions
>>> (defs, staticmethods, classmethods and so on).
>>
>> +1 to moving that way. (Well, static and class methods bind
>> differently, right?)
>>
>>> I also think that it's better to rename binding_PyCFunction_Type to
>>> something like CyFunctionType and make it more like PyFunction.
>>
>> +1
>>
>> Is there any advantage to the method descriptors (other than that
>> they're easier for a human to write?)
>
> Initially bindings was written to support bound class methods (am I right?)
> So when we use it for regular functions 'binding' in the name doesn't
> reflect its purpose.

There's three kinds of functions we create: PyCFunctions, binding
PyCFunctions, and extension class methods (via descriptors). I was
asking about the latter.

As for the first two, it reflects the difference in behavior. If I
take the function and assign it to a class, it will bind as a method
when I go to look it up. This is arguably the biggest difference
between built-in functions and Python functions.

> One the other hand it's much more easy to write manually.
>
> About staticmethods: I think that CyFunction type should handle it as well
> because staticmethods can have custom attributes and act just like
> normal def one.
>
> The difference is insde descr_get it should return bound method for
> normal and self for staticmethods.

Yep. Does that merit a new class, or a flag that's checked on every
function invocation (false 99.9% of the time)?

> Here I've tried to support staticmethods inside bindings type:
> https://github.com/vitek/cython/commit/c0725ab340a8173d8e6724c62be3a135df58980e
>
>>
>> I think that small speed regression for better compatibility is OK if
>> we add a directive to not create binding functions. (It'd be nice if
>> we could work around it, but that's hard as CPython has special
>> hooks...) The bigger issue is that the binding behavior is backwards
>> incompatible, and perhaps in a subtle way. Perhaps we need to have a
>> phase where all currently non-binding functions that will become
>> binding functions will raise an error (or at least a warning) to wean
>> people off of the old behavior before making a switch.
>>
>
> Is the difference so significant?

If anyone is assigning a Cython function to an object and then using
it they're counting on the current non-binding behavior, and it will
break. The speed is probably a lesser issue, which is what benchmarks
are for.

- Robert


More information about the cython-devel mailing list