[Numpy-discussion] [SciPy-user] numpy aligned memory

Sturla Molden sturla at molden.no
Thu Mar 12 14:15:32 EDT 2009


On 3/12/2009 4:05 PM, Andrew Straw wrote:

> So, what's your take on having each row aligned? Is this also useful for
> FFTW, for example? If so, we should perhaps come up with a better
> routine for the cookbook.


Ok, so here is how it could be done. It fails for a reason  I'll 
attribute to a bug in NumPy.


import numpy as np

def _nextpow(b,isize):
     i = 1
     while b**i < isize:
         i += 1
     return b**i

def aligned_zeros(shape, boundary=16, dtype=float, order='C',
                   imagealign=True):

     if (not imagealign) or (not hasattr(shape,'__len__')):
         N = np.prod(shape)
         d = np.dtype(dtype)
         tmp = np.zeros(N * d.itemsize + boundary, dtype=np.uint8)
         address = tmp.__array_interface__['data'][0]
         offset = (boundary - address % boundary) % boundary
         return tmp[offset:offset+N*d.itemsize]\
             .view(dtype=d)\
             .reshape(shape, order=order)
     else:
         if order == 'C':
             ndim0 = shape[-1]
             dim0 = -1
         else:
             ndim0 = shape[0]
             dim0 = 0
         d = np.dtype(dtype)
         bshape = [i for i in shape]
         padding = boundary + _nextpow(boundary, d.itemsize) - d.itemsize
         bshape[dim0] = ndim0*d.itemsize + padding
         print bshape
         tmp = np.zeros(bshape, dtype=np.uint8, order=order)
         address = tmp.__array_interface__['data'][0]
         offset = (boundary - address % boundary) % boundary
         aligned_slice = slice(offset, offset + ndim0*d.itemsize)
     if tmp.flags['C_CONTIGUOUS']:
         tmp = tmp[..., aligned_slice]
         print tmp.shape
     else:
         tmp = tmp[aligned_slice, ...]
         print tmp.shape

     return tmp.view(dtype=dtype) # this will often fail,
                                  # probably a bug in numpy



So lets reproduce the NumPy issue:


 >>> a = zeros((10,52), dtype=uint8)
 >>> b = a[:, 3:8*2+3]
 >>> b.shape
(10, 16)
 >>> b.view(dtype=float)

Traceback (most recent call last):
   File "<pyshell#86>", line 1, in <module>
     b.view(dtype=float)
ValueError: new type not compatible with array.



However:

 >>> a = zeros((10,16), dtype=uint8)
 >>> a.view(dtype=float)
array([[ 0.,  0.],
        [ 0.,  0.],
        [ 0.,  0.],
        [ 0.,  0.],
        [ 0.,  0.],
        [ 0.,  0.],
        [ 0.,  0.],
        [ 0.,  0.],
        [ 0.,  0.],
        [ 0.,  0.]])


Until we find a way to overcome this, it will be difficult to align rows 
to particular byte boundaries. It fails even if we make sure the padding 
is a multiple of the item size:

padding = (boundary + _nextpow(boundary, d.itemsize) \
                   - d.itemsize) * d.itemsize

Very annoying..

Using allocators in libraries (e.g. FFTW) would not help either, as 
NumPy would fail in the same way.

Maybe we can force NumPy to do the right thing by hard-coding an array 
descriptor?

We can do this in Cython though, as it supports pointers and double 
indirection. But it would be like using C.


Sturla Molden





More information about the NumPy-Discussion mailing list