[Cython] local variable handling in generators
Stefan Behnel
stefan_ml at behnel.de
Sun May 22 14:33:22 CEST 2011
Hi,
I've been looking at the nqueens benchmark for a while, and I think it's
actually not that a bad benchmark for generators.
http://hg.python.org/benchmarks/file/tip/performance/bm_nqueens.py
A better implementation only for Py2.7/Py3 is here:
https://github.com/cython/cython/blob/master/Demos/benchmarks/nqueens.py
Cython currently runs the first implementation about as fast as Py3.3:
https://sage.math.washington.edu:8091/hudson/job/cython-devel-pybenchmarks-py3k/lastSuccessfulBuild/artifact/chart.html
and the second one more than 3x as fast:
https://sage.math.washington.edu:8091/hudson/view/bench/job/cython-devel-cybenchmarks-py3k/lastSuccessfulBuild/artifact/chart.html
However, I think there's still some space for improvements, and local
variables are part of that. For generator functions that do non-trivial
things between yields, I think that local variables will quickly become a
bottleneck. Currently, they are always closure fields, so any access to
them will use a pointer indirection to a foreign struct, originally passed
in as an argument to the function. Given that generators often do Python
object manipulation through C-API calls, any such call will basically
require the C compiler to assume that all values in the closure may have
changed, thus disabling any optimisations for them. The same applies to
many other object related operations or pointer operations (even DECREF!),
as the C compiler cannot know that the generator function owns the closure
during its lifetime exclusively.
I think it would be worth changing the current implementation to use local
C variables for local Cython variables in the generator, and to copy the
values back into/from the closure around yields. I'd even let local Python
references start off as NULL when the generator is created, given that
Vitek's branch can eliminate None initialisations now.
I started looking into this a bit, but it's not a quick change. The main
problem I see is the current code duplication between the generator body
node and the DefNode. It would be better if both could share more code.
Basically, if local variables become truly local, the only differences will
be that they come from call arguments in one case and from the closure in
the other, and that generators have the additional jump-to-yield entry
step. Everything else could hopefully be identical.
Once again, this goes hand in hand with the still pending DefNode
refactoring...
Stefan
More information about the cython-devel
mailing list