Re: [cython-users] Recommendations for efficient typed arrays in Cython?

2,025 views
Skip to first unread message

Robert Bradshaw

unread,
Jan 28, 2013, 2:29:48 PM1/28/13
to cython...@googlegroups.com
On Mon, Jan 28, 2013 at 9:56 AM, Sal <svf...@gmail.com> wrote:
> What is the recommended 'most efficient' way to do homogeneous lists in
> Cython? Top concern being efficiency? Can anyone point me to some examples
> or snippets. Or, is it as easy as a 'cdef list' ?
>
> I have two use cases - one where lists need to be resized at runtime, and
> another where one static size will do. I'm looking for a fast equivalent to
> something like C's int array[10]; array[3]=1;, but with the ability to
> resize and not manage memory manually? I have been reading the docs but
> can't seem to find much. Maybe I'm missing something obvious.

"cdef list" is the most efficient way to store a list of objects. For
C types, (ints, doubles, etc.) you should go with memory views (e.g.
backed by numpy or array.array). Raw pointers are another option, but
require memory management which you said you'd like to avoid, but
depending on the application there's often a natural container class
associated with the raw data which can be used to encapsulate the
memory management.

- Robert

Sal

unread,
Jan 28, 2013, 3:12:02 PM1/28/13
to cython...@googlegroups.com
Robert,

Thanks much for the help!


. For
C types, (ints, doubles, etc.) you should go with memory views (e.g.
backed by numpy or array.array).

My use case is pure-Cython code, all cdef-ed classes and variables, that need to operate on/as high performance lists. (Used in time sensitive graphical/rendering code).  If I took the numpy/array.array route for my lists/arrays, can they be used to properly store 'cdef class' type references just as well?   I will do some reading on this now as well.

Say for example storing Matrices as arrays of floats, but also lists of cdef class Quaternion objects that also need to be rapidly iterated in intensive real time fashion.  Most of the code is C++ or Java style currently, I would like to move over to Cython efficiently.

Thanks again!!

Robert Bradshaw

unread,
Jan 28, 2013, 3:19:09 PM1/28/13
to cython...@googlegroups.com
On Mon, Jan 28, 2013 at 12:12 PM, Sal <svf...@gmail.com> wrote:
> Robert,
>
> Thanks much for the help!
>
>
>> . For
>> C types, (ints, doubles, etc.) you should go with memory views (e.g.
>> backed by numpy or array.array).
>
>
> My use case is pure-Cython code, all cdef-ed classes and variables, that
> need to operate on/as high performance lists. (Used in time sensitive
> graphical/rendering code). If I took the numpy/array.array route for my
> lists/arrays, can they be used to properly store 'cdef class' type
> references just as well? I will do some reading on this now as well.

Unfortunately, there's no way to restrict a list of objects to a list
of subtypes, so you would have to cast on access (which shouldn't have
a runtime penalty, isn't the prettiest in your code). This is because
we don't have a way of enforcing that only objects of a specified type
are put in a list/numpy object array.

> Say for example storing Matrices as arrays of floats, but also lists of cdef
> class Quaternion objects that also need to be rapidly iterated in intensive
> real time fashion. Most of the code is C++ or Java style currently, I would
> like to move over to Cython efficiently.

You may also be interested in using 2-dimensional arrays for both of
these cases.

- Robert

Sal

unread,
Jan 28, 2013, 3:34:06 PM1/28/13
to cython...@googlegroups.com

Unfortunately, there's no way to restrict a list of objects to a list
of subtypes, so you would have to cast on access (which shouldn't have
a runtime penalty, isn't the prettiest in your code). This is because
we don't have a way of enforcing that only objects of a specified type
are put in a list/numpy object array.

Hmm, OK.  I think I'm understanding a bit more.

Say for example if I tried:

cdef list quatList
cdef Quaternion q
for q in quatList: q.expensiveOperation()

You're saying there will be expensive or sub-optimal things happening behind the scenes? Or this simply won't work without casting?  Generally how would you advise approaching this in a high performance fashion within Cython ?


Thanks again for your help.


 

Robert Bradshaw

unread,
Jan 28, 2013, 3:44:31 PM1/28/13
to cython...@googlegroups.com
On Mon, Jan 28, 2013 at 12:34 PM, Sal <svf...@gmail.com> wrote:
>
>> Unfortunately, there's no way to restrict a list of objects to a list
>> of subtypes, so you would have to cast on access (which shouldn't have
>> a runtime penalty, isn't the prettiest in your code). This is because
>> we don't have a way of enforcing that only objects of a specified type
>> are put in a list/numpy object array.
>
>
> Hmm, OK. I think I'm understanding a bit more.
>
> Say for example if I tried:
>
> cdef list quatList
> cdef Quaternion q
> for q in quatList: q.expensiveOperation()
>
> You're saying there will be expensive or sub-optimal things happening behind
> the scenes? Or this simply won't work without casting?

That'll work fine. It'll involve a type check, but as long as
expensiveOperation takes more than a couple of nanoseconds it should
be just fine.

> Generally how would
> you advise approaching this in a high performance fashion within Cython ?

(1) Write some working code.
(2) Profile.
(3) Fix the hot spots by adding types, cdef'ing methods, etc.

(This supposes of course you're already using the appropriate algorithms.)

- Robert

Chris Barker - NOAA Federal

unread,
Jan 28, 2013, 3:45:56 PM1/28/13
to cython...@googlegroups.com
On Mon, Jan 28, 2013 at 12:34 PM, Sal <svf...@gmail.com> wrote:

> Say for example if I tried:
>
> cdef list quatList
> cdef Quaternion q
> for q in quatList: q.expensiveOperation()
>
> You're saying there will be expensive or sub-optimal things happening behind
> the scenes?

sub-optimal, sort of -- you'll get a pyhon list of python objects,
which is a re-sizable array of pointers to python objects, so a bit of
extra memory overhead, but if a Quaternion object is more than a
handful of bytes, not much.

then when you loop through the list, you'll be getting python objects,
and the method is called on them -- a bit of extra overhead.

but if expensiveOperation() lives up to its name, then all that will
get lost in the wash anyway.

Where you'd want to do something different is if you had a
not-very-expensive operation, that you needed to do a lot on a lot of
objects. In which case, I think Robert was suggesting that rather than
have a python object (even a cdef class) for your core object, you
structure your code around arrays of primative objects -- so have an
_array_of_quaterenions as a first class object. In that case, each one
would be 16? floating point numbers, and could all be packed together
in an array. Your some_operation() method would then do the loop
through the _array_of_quaterenions, and this could easily be
cythonized to be raw-C speed, with memory localized at all that.

By the way, I have a vague memory that someone had written a
quaternion numpy dtype a couple years ago -- maybe you could use that?

-Chris







Or this simply won't work without casting? Generally how would
> you advise approaching this in a high performance fashion within Cython ?
>
>
> Thanks again for your help.
>
>
>
>
> --
>
> ---
> You received this message because you are subscribed to the Google Groups
> "cython-users" group.
> To unsubscribe from this group, send email to
> cython-users...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>



--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris....@noaa.gov

Sal

unread,
Jan 28, 2013, 3:57:57 PM1/28/13
to cython...@googlegroups.com

I know, I know, I should 'shut up and try a few things' =)  But thanks for the help nonetheless.

By the way, (slightly offthread, but) I'm also attempting a little experiment.  Taking the following:


(a Java to python source convertor) and retro-fitting to output Cython instead.  So far its working great.  I'm using it to convert several (very large) real-time graphics libraries over from Java.  Unfortunately 'efficient arrays' are still on my TODO list, hence partly my motivation for posting - just pre-thinking the array strategy I'll use.  Overall though, strongly typed Java code seems to convert fairly well, and my benchmarks so far are pretty impressive!  The current implementation is putting out one pxd/pxi per class, basically inserting cdef's everywhere. So far so good.

Thanks again for the help.

Sal

unread,
Jan 28, 2013, 4:12:05 PM1/28/13
to cython...@googlegroups.com

Where you'd want to do something different is if you had a
not-very-expensive operation, that you needed to do a lot on a lot of
objects. In which case, I think Robert was suggesting that rather than
have a python object (even a cdef class) for your core object, you
structure your code around arrays of primative objects -- so have an
_array_of_quaterenions as a first class object. In that case, each one
would be 16? floating point numbers, and could all be packed together
in an array. Your some_operation() method would then do the loop
through the _array_of_quaterenions, and this could easily be
cythonized to be raw-C speed, with memory localized at all that.

This describes perfectly my use case.  Attempting to get close-to-C performance out of 'pure Cython' code that does a lot of array manipulation.  The arrays are containing both primitive types and cdef types. (Your typical floats, doubles, int vectors for triangle indexes, Matrice, Vector, Quat classes, etc.). In fact I dont have 'any' Python classes yet, everything is cdef-ed for performance so far.

I was hoping to devise a sortof 'one size fits all' array strategy that'll give me C performance but hopefully not have to manage memory manually.  I see some nice snippets in the docs that wrap 'malloc' but I was hoping there was a less-manual approach someone might have devised, that worked more similar to typical 'lists'.
 

By the way, I have a vague memory that someone had written a
quaternion numpy dtype a couple years ago -- maybe you could use that?

It was more a general example, there are probably dozens of more use cases similar in my project.  Matrices, Vector3s, Vector2s, Triangle lists, index lists, z-buffers, just a lot of array oriented data.

Thanks for the tips!! Very much appreciated as I'm new to Cython yet.

Gabriel Jacobo

unread,
Jan 28, 2013, 5:43:17 PM1/28/13
to cython...@googlegroups.com



2013/1/28 Sal <svf...@gmail.com>


Where you'd want to do something different is if you had a
not-very-expensive operation, that you needed to do a lot on a lot of
objects. In which case, I think Robert was suggesting that rather than
have a python object (even a cdef class) for your core object, you
structure your code around arrays of primative objects -- so have an
_array_of_quaterenions as a first class object. In that case, each one
would be 16? floating point numbers, and could all be packed together
in an array. Your some_operation() method would then do the loop
through the _array_of_quaterenions, and this could easily be
cythonized to be raw-C speed, with memory localized at all that.

This describes perfectly my use case.  Attempting to get close-to-C performance out of 'pure Cython' code that does a lot of array manipulation.  The arrays are containing both primitive types and cdef types. (Your typical floats, doubles, int vectors for triangle indexes, Matrice, Vector, Quat classes, etc.). In fact I dont have 'any' Python classes yet, everything is cdef-ed for performance so far.

I was hoping to devise a sortof 'one size fits all' array strategy that'll give me C performance but hopefully not have to manage memory manually.  I see some nice snippets in the docs that wrap 'malloc' but I was hoping there was a less-manual approach someone might have devised, that worked more similar to typical 'lists'.
 


As an alternative, if you can/want to incorporate C++ code, Cython has working "bindings" to the STL containers (deque, vector, map, pair, etc). While frowned upon by some, they are pretty handy and fast and using them in Cython is quite similar to using them on C++. 



--
Gabriel.

Sturla Molden

unread,
Jan 29, 2013, 10:15:18 AM1/29/13
to cython...@googlegroups.com
The most obvious: A list is not an array. A list can efficiently grow
and shrink in size, an array is a fixed-size buffer.

Although a Python list is implemented as a dynamic array under the hood
(i.e. not linked lists as in Lisp), lists and arrays are different beasts.

If you need a typed array, I would suggest a typed memory view. They can
e.g. be used with a C pointer or a NumPy array.

If you need a typed list, I would suggest a C++ STL container. You
should look at std::list, std::deque, and std::vector, and select the
one that better fits your need (they behave slightly differently).
std::vector is closest to Python's list with respect to behavior.


Sturla



On 28.01.2013 18:56, Sal wrote:
> What is the recommended 'most efficient' way to do homogeneous lists in
> Cython? Top concern being efficiency? Can anyone point me to some
> examples or snippets. Or, is it as easy as a 'cdef list' ?
>
> I have two use cases - one where lists need to be resized at runtime,
> and another where one static size will do. I'm looking for a fast
> equivalent to something like C's int array[10]; array[3]=1;, but with
> the ability to resize and not manage memory manually? I have been
> reading the docs but can't seem to find much. Maybe I'm missing
> something obvious.
>
> Thanks,

Robert Bradshaw

unread,
Jan 29, 2013, 12:43:07 PM1/29/13
to cython...@googlegroups.com
On Tue, Jan 29, 2013 at 7:15 AM, Sturla Molden <stu...@molden.no> wrote:
> The most obvious: A list is not an array. A list can efficiently grow and
> shrink in size, an array is a fixed-size buffer.
>
> Although a Python list is implemented as a dynamic array under the hood
> (i.e. not linked lists as in Lisp), lists and arrays are different beasts.
>
> If you need a typed array, I would suggest a typed memory view. They can
> e.g. be used with a C pointer or a NumPy array.
>
> If you need a typed list, I would suggest a C++ STL container. You should
> look at std::list, std::deque, and std::vector, and select the one that
> better fits your need (they behave slightly differently). std::vector is
> closest to Python's list with respect to behavior.

Note that C++ STL containers can't, without some manual memory
management, contain Python objects. For Python objects, the best fit
is typically a Python list.

> On 28.01.2013 18:56, Sal wrote:
>>
>> What is the recommended 'most efficient' way to do homogeneous lists in
>> Cython? Top concern being efficiency? Can anyone point me to some
>> examples or snippets. Or, is it as easy as a 'cdef list' ?
>>
>> I have two use cases - one where lists need to be resized at runtime,
>> and another where one static size will do. I'm looking for a fast
>> equivalent to something like C's int array[10]; array[3]=1;, but with
>> the ability to resize and not manage memory manually? I have been
>> reading the docs but can't seem to find much. Maybe I'm missing
>> something obvious.
>>
>> Thanks,
>>
>> --
>>
>> ---
>> You received this message because you are subscribed to the Google
>> Groups "cython-users" group.
>> To unsubscribe from this group, send email to
>> cython-users...@googlegroups.com.
>> For more options, visit https://groups.google.com/groups/opt_out.
>>
>>
>
> --
>
> --- You received this message because you are subscribed to the Google
> Groups "cython-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an

Sal

unread,
Jan 29, 2013, 4:15:43 PM1/29/13
to cython...@googlegroups.com

Note that C++ STL containers can't, without some manual memory
management, contain Python objects. For Python objects, the best fit
is typically a Python list.

Let me take a guess to see if I'm understanding this part right -

I don't have any 'typical' Python code yet, everything is 'cdef' type stuff, but reference counting is still performed by Cython on 'cdef' types, so sticking them into a C++ array probably ignores that fact. Makes sense... probably good from a performance perspective not to have the ref counting, but harder to manage, since Cython can deference elsewhere and delete the things you'd be iterating there?  Is there any GC level tweaking I can do to prevent any of this?

It's not a problem if I have to 'bite the bullet' and do more work for really-fast arrays of object references, I just wanted to make sure there isn't some common approach before rolling my own here.

Thanks!


Sal

unread,
Jan 29, 2013, 4:50:45 PM1/29/13
to cython...@googlegroups.com


On Tuesday, January 29, 2013 10:15:18 AM UTC-5, Sturla Molden wrote:
The most obvious: A list is not an array. A list can efficiently grow
and shrink in size, an array is a fixed-size buffer.

Agreed.  I'm hoping not to lose much performance in code like:

//in c++:
while(index++<a_zillion) triangles[index]->calculateNormal();

//the same syntax for primitive types as for object pretty much
while(index++<screenSize) zbuffer[index] = 0.0f;

(this kind of thing needs to run every frame when convoluting 3d, every cycle counts.  Hardware acceleration helps yes but, its an example :)

One's first impulse is to use a traditional Python 'list' since they're so easy to work with, but I'm under the impression there is likely a more performant way to do it easily in Cython-land.  I don't mind if it means moving to a 'list' kind of model versus an 'array' type preallocated scenario, performance being King (but ease of use & finger-friendly interface is nice too).

Thanks much for all the tips.

Sturla Molden

unread,
Jan 29, 2013, 11:04:39 PM1/29/13
to cython...@googlegroups.com
Den 29. jan. 2013 kl. 18:43 skrev Robert Bradshaw <robe...@gmail.com>:

>
> Note that C++ STL containers can't, without some manual memory
> management, contain Python objects. For Python objects, the best fit
> is typically a Python list.

Yes, we obviously have to cast them to PyObject* or use some cppclass wrapper for storing Python objects in STL containers. But in Cython code a "typed array" will usually mean a container for C types. In fact learned to use the STL by programming Python. Before I learned Python, I saw no use for the STL as a C++ programmer. Now the STL is the reason I will not use C, as it allows me to program C++ almost like Python :-)

Sturla

Sturla Molden

unread,
Jan 29, 2013, 10:54:24 PM1/29/13
to cython...@googlegroups.com
Den 29. jan. 2013 kl. 22:15 skrev Sal <svf...@gmail.com>:


Note that C++ STL containers can't, without some manual memory
management, contain Python objects. For Python objects, the best fit
is typically a Python list.

Let me take a guess to see if I'm understanding this part right -

I don't have any 'typical' Python code yet, everything is 'cdef' type stuff, but reference counting is still performed by Cython on 'cdef' types, so sticking them into a C++ array probably ignores that fact.

No.

Reference counting is only performed on Python types. Most of the uses for "cdef" types are C or C++ types which are not reference counted.

An example:


cdef class foobar:
   pass

cdef int a # STL ok, no refcounting
cdef double b # STL ok, no refcounting

cdef object c # avoid STL, automatic refcounting
cdef foobar d # avoid STL, automatic refcounting


If you need to store a Python object in an STL container, cast to PyObject* which is not reference counted.

cdef PyObject *e # STL ok, manual refcounting

However, there is very little reason to do this compared to using Python containers for Python types.



Sturla

Robert Bradshaw

unread,
Jan 30, 2013, 3:23:02 AM1/30/13
to cython...@googlegroups.com
One thing about Cython is that it's really easy to read the generated
code (compared to, for example, assembly or bytecode), which is what
you should do if you're worried about performance (as well as
benchmarking). cython -a is really helpful here.

In your case, you're worried about the time it takes to iterate over
an list an do something for every item. If you have an array of
primitives (e.g. your zbuffer) I'd use NumPy arrays (which support
multiple dimensions as well). If you have an array of objects, just
use a Python list, which as well as being the easiest to write and
use, is going to be just as fast as anything else, i.e. it's already
you're "really-fast array of object references."

# see http://docs.cython.org/src/reference/compilation.html#compiler-directives
# cython: boundscheck=False, wraparound=False

cdef list triangles = ...
cdef long index
for index in range(a_zillion):
(<Triangle>L[index]).calculateNormal()

This will use PyList_GET_ITEM which is a macro that basically expands
to L->items[index] (where L->items is a PyObject**). It doesn't get
any faster than that. Note that

cdef Triangle triangle
for triangle in L:
triangle.calculateNormal()

will be nearly as fast and much more pythonic (it does an extra
incref/decref and typecheck, and checks the size of this list at ever
loop in case L shrank or grew).

- Robert

Sturla Molden

unread,
Jan 31, 2013, 3:31:49 PM1/31/13
to cython...@googlegroups.com, Core developer mailing list of the Cython compiler
On 29.01.2013 22:15, Sal wrote:

> I don't have any 'typical' Python code yet, everything is 'cdef' type
> stuff, but reference counting is still performed by Cython on 'cdef'
> types, so sticking them into a C++ array probably ignores that fact.

I think the main difficulty with Cython (for beginners at least) is
knowing 'when we are in C land' and 'when we are in Python land'. I
think this is the fundamental problem you are facing here.

I therefore think it is is unfortunate that we write

cdef object a
cdef list b
cdef foobar c

etc to define Python variables. 'cdef' seems to indicate that it is a C
declaration, yet here it is not.

Neither does this cdef syntax allow us to declare Python int and float
statically.

Perhaps it would be easier if Python variables were declared with
'pydef'? Or perhaps just 'def'?

Then it might be easier to see what is Python and what is C.


Sturla




Robert Bradshaw

unread,
Jan 31, 2013, 6:15:47 PM1/31/13
to cython...@googlegroups.com
On Thu, Jan 31, 2013 at 12:31 PM, Sturla Molden <stu...@molden.no> wrote:
> On 29.01.2013 22:15, Sal wrote:
>
>> I don't have any 'typical' Python code yet, everything is 'cdef' type
>> stuff, but reference counting is still performed by Cython on 'cdef'
>> types, so sticking them into a C++ array probably ignores that fact.
>
>
> I think the main difficulty with Cython (for beginners at least) is knowing
> 'when we are in C land' and 'when we are in Python land'. I think this is
> the fundamental problem you are facing here.
>
> I therefore think it is is unfortunate that we write
>
> cdef object a
> cdef list b
> cdef foobar c
>
> etc to define Python variables. 'cdef' seems to indicate that it is a C
> declaration, yet here it is not.
>
> Neither does this cdef syntax allow us to declare Python int and float
> statically.

True, but there's little if any value in being able to do that.

> Perhaps it would be easier if Python variables were declared with 'pydef'?
> Or perhaps just 'def'?
>
> Then it might be easier to see what is Python and what is C.

I think viewing things as "C land" and "Python land" is not the
clearest distinction to make. Really, the important distinction is
static vs. dynamically typed. When you write "cdef list b" you want
C-level access to the list b, same with "cdef MyCdefClass c." Also,
while static typing is often essential to achieving good performance,
blindly trying to "making everything cdef" is not always the most
effective way to get speed, and almost always overkill (and
inflexible).

- Robert

Sal

unread,
Feb 1, 2013, 3:59:22 PM2/1/13
to cython...@googlegroups.com

# see http://docs.cython.org/src/reference/compilation.html#compiler-directives
# cython: boundscheck=False, wraparound=False

cdef list triangles = ...
cdef long index
for index in range(a_zillion):
    (<Triangle>L[index]).calculateNormal()

 

Robert -

Thanks for the great tips! Thanks to your help (and this thread) I'm getting much closer to what I was hoping performance-wise.  I tried a simple list 'set' (with your recommended compiler flags) and here is what Cython gave me:

# array2[i] = y             # <<<<<<<<<<<<<<

    if (__Pyx_SetItemInt(((PyObject *)__pyx_v_array2), __pyx_v_i, ((PyObject *)__pyx_v_y), sizeof(int), PyInt_FromLong) < 0) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 161; __pyx_clineno = __LINE__; goto __pyx_L1_error;}


__Pyx_SetItemInt seems to have a lot of logic in it, is there a way to reduce this to a more simple c-style 'set'? ie. without the error checking/etc.  I don't mind assuming some of the exception handling.

Also I'm understanding now that to store 'primitive' types (float, int) etc.  I should use something like the numpy lib.

My question here - can I wrap the above 'list' style for object references and also the numpy things for primitive arrays into a single unified interface?  Maybe create a new 'list' class with special methods to handle different cases, or will that kill Cython's ability to detect 'list' usage and optimize away a lot of the cruft?  I'll continue to experiment as well, again all the tips are much appreciated.


Thanks!

Chris Barker - NOAA Federal

unread,
Feb 1, 2013, 4:49:29 PM2/1/13
to cython...@googlegroups.com
On Fri, Feb 1, 2013 at 12:59 PM, Sal <svf...@gmail.com> wrote:

> My question here - can I wrap the above 'list' style for object references
> and also the numpy things for primitive arrays into a single unified
> interface?

numpy has an "object" data type that can store arbitrary python
objects, so that may work, though you may have to cast to specific
objects types when you pull stuff out of it in Cython -- not sure
about that.

-CHris

Robert Bradshaw

unread,
Feb 2, 2013, 2:10:50 AM2/2/13
to cython...@googlegroups.com
On Fri, Feb 1, 2013 at 12:59 PM, Sal <svf...@gmail.com> wrote:
>
>> # see
>> http://docs.cython.org/src/reference/compilation.html#compiler-directives
>> # cython: boundscheck=False, wraparound=False
>>
>> cdef list triangles = ...
>> cdef long index
>> for index in range(a_zillion):
>> (<Triangle>L[index]).calculateNormal()
>>
>
>
> Robert -
>
> Thanks for the great tips! Thanks to your help (and this thread) I'm getting
> much closer to what I was hoping performance-wise. I tried a simple list
> 'set' (with your recommended compiler flags) and here is what Cython gave
> me:
>
> # array2[i] = y # <<<<<<<<<<<<<<
>
> if (__Pyx_SetItemInt(((PyObject *)__pyx_v_array2), __pyx_v_i, ((PyObject
> *)__pyx_v_y), sizeof(int), PyInt_FromLong) < 0) {__pyx_filename =
> __pyx_f[0]; __pyx_lineno = 161; __pyx_clineno = __LINE__; goto
> __pyx_L1_error;}
>
>
> __Pyx_SetItemInt seems to have a lot of logic in it, is there a way to
> reduce this to a more simple c-style 'set'? ie. without the error
> checking/etc. I don't mind assuming some of the exception handling.

Ah, for setting we don't optimize for list or for the directives. We should.

Do you end up writing to these arrays a lot? If so you can use
PyList_SET_ITEM directly (take care to incref the item your setting
and decref the item already there). I wouldn't call it a lot of logic
though, the C code in Cython is carefully written so that any sane C
compiler will resolve conditions at compile time (e.g. sizeof(int) <
sizeof(Py_ssize_t)), remove dead code, and the fast (common) code path
comes first.

> Also I'm understanding now that to store 'primitive' types (float, int) etc.
> I should use something like the numpy lib.
>
> My question here - can I wrap the above 'list' style for object references
> and also the numpy things for primitive arrays into a single unified
> interface? Maybe create a new 'list' class with special methods to handle
> different cases, or will that kill Cython's ability to detect 'list' usage
> and optimize away a lot of the cruft? I'll continue to experiment as well,
> again all the tips are much appreciated.

You might want to just use NumPy arrays with an object data type.

- Robert

Stefan Behnel

unread,
Feb 2, 2013, 2:28:50 AM2/2/13
to cython...@googlegroups.com
Robert Bradshaw, 02.02.2013 08:10:
> On Fri, Feb 1, 2013 at 12:59 PM, Sal wrote:
>>> # see
>>> http://docs.cython.org/src/reference/compilation.html#compiler-directives
>>> # cython: boundscheck=False, wraparound=False
>>>
>>> cdef list triangles = ...
>>> cdef long index
>>> for index in range(a_zillion):
>>> (<Triangle>L[index]).calculateNormal()
>>
>> Thanks for the great tips! Thanks to your help (and this thread) I'm getting
>> much closer to what I was hoping performance-wise. I tried a simple list
>> 'set' (with your recommended compiler flags) and here is what Cython gave
>> me:
>>
>> # array2[i] = y # <<<<<<<<<<<<<<
>>
>> if (__Pyx_SetItemInt(((PyObject *)__pyx_v_array2), __pyx_v_i, ((PyObject
>> *)__pyx_v_y), sizeof(int), PyInt_FromLong) < 0) {__pyx_filename =
>> __pyx_f[0]; __pyx_lineno = 161; __pyx_clineno = __LINE__; goto
>> __pyx_L1_error;}
>>
>>
>> __Pyx_SetItemInt seems to have a lot of logic in it, is there a way to
>> reduce this to a more simple c-style 'set'? ie. without the error
>> checking/etc. I don't mind assuming some of the exception handling.
>
> Ah, for setting we don't optimize for list or for the directives. We should.

Should be easy to do, yes. And the resulting C code could be really concise
since we'll know in many cases that the object is exactly a list and not None.


> Do you end up writing to these arrays a lot? If so you can use
> PyList_SET_ITEM directly (take care to incref the item your setting
> and decref the item already there). I wouldn't call it a lot of logic
> though, the C code in Cython is carefully written so that any sane C
> compiler will resolve conditions at compile time (e.g. sizeof(int) <
> sizeof(Py_ssize_t)), remove dead code, and the fast (common) code path
> comes first.

Yep, it's not immediately clear that the current overhead is worth caring
about. After all, the value that gets assigned most likely didn't appear
out of nothing, so the time to generate it might easily dominate the time
it takes to assign it.

Still, we'd at least get rid of a list type test and the error handling
would also get dropped, so it might make a difference in some truly
critical cases.

Stefan

Robert Bradshaw

unread,
Feb 2, 2013, 2:57:17 AM2/2/13
to cython...@googlegroups.com
Yep. Done.

- Robert
Reply all
Reply to author
Forward
0 new messages