array of pointers to memoryviews -- proper way to cleanup?

678 views
Skip to first unread message

shaunc

unread,
May 4, 2012, 6:17:26 PM5/4/12
to cython...@googlegroups.com
Hello group!

I am trying to use a slice of a memoryview inside a prange... when I copy to a "local" variable I get "Memoryview slices can only be shared in parallel sections" which I don't understand, but I guess might be logical somehow, as memoryviews aren't just simple values.

My new approach can be summarized:
 
    cdef double[ :, : ] large_view
    cdef double[ : ] *local
    try:
        n_threads = openmp.omp_get_max_threads() 
        local = <double[:]*>malloc( n_threads * sizeof( double[:] ) )
        for i in prange( n ):
            i_thread = threadid()
            local[ i_thread ] = large_view[ i ]
            ...
    finally:
        free( local )
 
My questions are -- is this the right approach? And do I need to do anything special to cleanup the slices? The "enchancements" proposal that introduces memoryviews says something about setting the dynamically allocated memoryviews to None -- but the official doc doesn't seem to mention that. What is the right approach here?

Thank you very much! 


shaunc

unread,
May 4, 2012, 6:48:31 PM5/4/12
to cython...@googlegroups.com
Update: local = <double[:]*>malloc( n_threads * sizeof( double[:] ) )

gives: "Cannot take sizeof incomplete type 'double[:, ::1]'"
and: "Stop must be provided to indicate shape"

hmm... so how come you can allocate empty memviews in stack-allocated objects but not dynamically?

I'm a bit at a loss... your suggestions will be gratefully appreciated!

mark florisson

unread,
May 5, 2012, 7:33:43 AM5/5/12
to cython...@googlegroups.com
Pointers to memoryviews aren't really supported, and I suppose taking
their size isn't either. Given their non-stable ABI, memoryview slices
only work in Cython and Python space. What it allowed however, is to
take a pointer to the data and the shape/strides, and use that, as
long as you have a reference to the memoryview slice. Deleting
memoryview slices or setting them to None is also only supported for
memoryview variables and attributes, not for pointers or arrays.

I suppose pointers should be disabled until and if they are officially
supported and can be used in a sane way.

As for your problem, can't you pass around your i index (if you're
using subroutines) and index large_view[i, j] everywhere? Otherwise,
as mentioned, you can take the extent and stride in the last dimension
and a pointer to large_view[i, 0].

Assigning to memoryviews in parallel sections was disabled as the code
should typically behave as sequential code, meaning that when you
assign to a variable in the loop, you want the last sequential
assignment after the loop. For memoryviews it's slightly tricky to
manage the reference counts and to manage the reference count for the
sequential last iteration (which can be in any thread).

mark florisson

unread,
May 5, 2012, 7:39:06 AM5/5/12
to cython...@googlegroups.com
Presumably, though, the user won't care at all about the last
sequential assignment, so it might be more useful to support
thread-private memoryviews. It's also not too hard to solve, by using
a guard that checks for the maximum value of the iteration variable,
and then assigns the private memoryview to a shared memoryview. Maybe
it can incref twice, and then a decref can happen in every thread
after the loop in the parallel section. You'd also have to handle
breaking, or the case where there is no last iteration.

Basically I'm not sure we should bother supporting this. You can
always assign to a local memoryview if you call a function.

shaunc

unread,
May 5, 2012, 11:00:22 AM5/5/12
to cython...@googlegroups.com
> Assigning to memoryviews in parallel sections was disabled as the code
> should typically behave as sequential code, meaning that when you
> assign to a variable in the loop, you want the last sequential
> assignment after the loop. For memoryviews it's slightly tricky to
> manage the reference counts and to manage the reference count for the
> sequential last iteration (which can be in any thread).

Presumably, though, the user won't care at all about the last
sequential assignment, so it might be more useful to support
thread-private memoryviews. It's also not too hard to solve, by using
a guard that checks for the maximum value of the iteration variable,
and then assigns the private memoryview to a shared memoryview. Maybe
it can incref twice, and then a decref can happen in every thread
after the loop in the parallel section. You'd also have to handle
breaking, or the case where there is no last iteration.

Basically I'm not sure we should bother supporting this. You can
always assign to a local memoryview if you call a function.

Indeed, in the current case I don't care about the last sequential assignment -- I just want a temp variable to assign to. In my actual code the slice I take is slightly more complex than just projecting out first dimension, and since I'm optimizing I thought I shouldn't do it repeatedly.

In fact my work-around was to create another function, but it definitely seems like a workaround for a bug. The local variables in the called function have exactly the semantics I would want for a variable in the loop, and the stuff on the inside is short but with lots of references -- the code clarity is not necessarily improved by calling a subroutine with 11 variables. :)

To support... if I really wanted to use a value after the loop -- hmm: why not have *this* (use after loop) cause the error for the moment if its tricky to support, then you can add support whenever  we all clamor for it enough?

... just a thought ... thanks very much!


shaunc

unread,
May 5, 2012, 11:05:11 AM5/5/12
to cython...@googlegroups.com
Another possibility I just thought of: if you allow cdefs inside the prange or parallel() block, then you could have thread-local variables which were scoped so they couldn't be used outside the loop anyway. This would be generally useful -- not just for memoryviews....

Robert Bradshaw

unread,
Mar 20, 2013, 11:49:42 PM3/20/13
to cython...@googlegroups.com
> Has there been any progress on this idea ?
> This is the way it is usually done in C++, how can I do something similar in
> a pythonic way ?

No. The C++ scoping rules are quite different than Python ones.

- Robert
Reply all
Reply to author
Forward
0 new messages