[Pyrex] Pyrex optimization chitchat
Phillip J. Eby
pje at telecommunity.com
Wed Jan 14 22:02:11 CET 2004
At 12:34 PM 1/14/04 -0800, Paul Prescod wrote:
>For instance, PySequence_SetItem, PyList_SetItem and PyList_SETITEM all
>handle references a little bit different. So you probably have to have
>syntax that says whether references are borrowed, stolen, lent or given by
>the function.
Good point.
>And I don't know if Greg cares much about performance issues. It obviously
>was not his highest priority (which is good!).
Well, the very first 'primes.pyx' example certainly emphasized speed. And,
speed is the "other" reason for using Pyrex besides accessing C
libraries. And, often, the reason for accessing a C library in the first
place is for speed... So it seems that all the roads tend to end back up
at performance. :)
> > For getting Pyrex into the Python core, it'd be a lot less
> > hassle to add a new e.g. 'sets.pxi' file than it would to hack the
> > Pyrex code generator again.
>
>Yes. But on the other hand, we need to keep two things in perspective.
>First, this is just a performance hack. Sets (for example) work with Pyrex
>out of the box just by virtue of its fallback to PyObject_GetItem. Second,
>how often are new types added to the Python core with their own high
>performance APIs? It isn't as if tomorrow someone is likey to add a
>PyQueue_GetItem or PyBag_GetItem.
That's true. I'm just also thinking that it would move Pyrex to a more
microkernel architecture, pulling its internal tables out into the language
itself. At that point, the language's operators, allocation, and so forth
would all just be generics.
> > E.g. something like
> >
> > cdef pytype sequence int PySequence_Check(object):
> > __getitem__ = object PySequence_GetItem(object,int)
> > __contains__ = int PySequence_In(object,object) except -1
> > #... etc.
>
>Interesting idea. Reminiscent of C++ type overlpading (in that it is done at
>compile time rather than runtime the way it is in Python). It might also be
>cool to define type conversions between arbitrary types in this way.
Hm. I don't think I'd want C++-style type conversions being applied,
though. I'd rather say, e.g.
cdef dict foo = dict(bar)
instead of expecting Pyrex to convert 'bar' to a 'dict' on its own.
>The other obvious slow bit in PyRex is stuff like this:
>
> /* "/Users/pprescod/code/bisect/rxbisect0.pyx":13 */
> __pyx_2 = __Pyx_GetName(__pyx_b, "len"); if (!__pyx_2) {__pyx_filename =
>__pyx_f[0]; __pyx_lineno = 13; goto __pyx_L1;}
> __pyx_3 = PyTuple_New(1); if (!__pyx_3) {__pyx_filename = __pyx_f[0];
>__pyx_lineno = 13; goto __pyx_L1;}
> Py_INCREF(__pyx_v_a);
> PyTuple_SET_ITEM(__pyx_3, 0, __pyx_v_a);
> __pyx_4 = PyObject_CallObject(__pyx_2, __pyx_3); if (!__pyx_4)
>{__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; goto __pyx_L1;}
> Py_DECREF(__pyx_2); __pyx_2 = 0;
> Py_DECREF(__pyx_3); __pyx_3 = 0;
> Py_DECREF(__pyx_v_hi);
> __pyx_v_hi = __pyx_4;
> __pyx_4 = 0;
> goto __pyx_L2;
> }
> __pyx_L2:;
Yes. And that also does the whole allocate-and-intern-the-string dance.
>There are a few different ways to handle this depending on how important you
>feel it is that len(foo) really always call __builtins__.len(foo) even if
>the type of "foo" is known. If the dynamicity of "len" is untouchable then
>you could define Pyrex modules like "listoptimizations" and
>"dictoptimizations" with functions like "listlen" and "dictlen" that could
>be statically bound rather than dynamically bound.
Oh, I see your point... I was mainly thinking that Pyrex should require e.g.
cdef public object len
in a module in order to allow a builtin to be overridden. To put it
another way, use of a global name that doesn't have an explicit definition
in the module source, should be considered fair game for
replacement/optimization.
AFAIK, this is the way Python's headed anyway. There was supposed to be a
warning about it added in 2.3, although there were some issues that caused
the warning to be dropped before the 2.3 final release.
More information about the Pyrex
mailing list