Skip to content

Use an aligned allocator for NumPy? #5312

Closed

Description

@sturlamolden

Regarding the f2py regression in NumPy 1.9 with failures on 32-bit Windows, the question is whether NumPy should start to use an allocator which gives guaranteed alignment.

scipy/scipy#4168

Activity

  1. sturlamolden commented on Nov 26, 2014

    @sturlamolden
    ContributorAuthor

    Here is one example of an allocator that should work on all platforms. It is shamelessly based on this:

    https://sites.google.com/site/ruslancray/lab/bookshelf/interview/ci/low-level/write-an-aligned-malloc-free-function

    There are not many ways to do this and similar code is floating around on the net, so extending it in this way is probable ok. (And besides it does not implement realloc.)

    Dropping this code into numpy/core/include/numpy/ndarraytypes.hshould ensure that freshly allocated ndarrays are properly aligned on all platforms.

    This platform-independent code could possibly be replaced with posix_memalign() on POSIX and _aligned_malloc() on Windows. However, combining posix_memalign() with realloc() is not possible, so implementing it ourselves is probably better.

    #define NPY_MEMALIGN 32   /* 16 for SSE2, 32 for AVX, 64 for Xeon Phi */ 
    
    static NPY_INLINE
    void *PyArray_realloc(void *p, size_t n)
    {
        void *p1, **p2, *base;
        size_t old_offs, offs = NPY_MEMALIGN - 1 + sizeof(void*);    
        if (NPY_UNLIKELY(p != NULL)) {
            base = *(((void**)p)-1);
            if (NPY_UNLIKELY((p1 = PyMem_Realloc(base,n+offs)) == NULL)) return NULL;
            if (NPY_LIKELY(p1 == base)) return p;
            p2 = (void**)(((Py_uintptr_t)(p1)+offs) & ~(NPY_MEMALIGN-1));
            old_offs = (size_t)((Py_uintptr_t)p - (Py_uintptr_t)base);
            memmove(p2,(char*)p1+old_offs,n);    
        } else {
            if (NPY_UNLIKELY((p1 = PyMem_Malloc(n + offs)) == NULL)) return NULL;
            p2 = (void**)(((Py_uintptr_t)(p1)+offs) & ~(NPY_MEMALIGN-1));   
        }
        *(p2-1) = p1;
        return (void*)p2;
    }    
    
    static NPY_INLINE
    void *PyArray_malloc(size_t n)
    {
        return PyArray_realloc(NULL, n);
    }
    
    static NPY_INLINE
    void *PyArray_calloc(size_t n, size_t s)
    {
        void *p;
        if (NPY_UNLIKELY((p = PyArray_realloc(NULL,n*s)) == NULL)) return NULL;
        memset(p, 0, n*s);
        return p;
    }
    
    static NPY_INLINE        
    void PyArray_free(void *p)
    {
        void *base = *(((void**)p)-1);
        PyMem_Free(base);
    } 
  2. changed the title [-]Use an aligned allocator for NumPy[/-] [+]Use an aligned allocator for NumPy?[/+] on Nov 26, 2014
  3. juliantaylor commented on Nov 26, 2014

    @juliantaylor
    Contributor

    I have already a branch which adds an aligned allocator, i'll dig it out.

    By using something like this we throw away the option to uses pythons tracemalloc framework and sparse memory (there is no aligned_calloc).
    @njsmith would you be willing to engage with python devs again to add yet another allocator to their slot before 3.5 is released? They already added calloc only for us, would be a schame if we now couldn't use it.

  4. sturlamolden commented on Nov 26, 2014

    @sturlamolden
    ContributorAuthor

    Presumably one could pass in alignment in the context data of PyMemAllocatorEx? But NumPy has to support Python versions from 2.6 and up, so doing this in Python 3.5 might not solve the problem.

  5. njsmith commented on Nov 26, 2014

    @njsmith
    Member

    I do think engaging with the python devs on this before 3.5 is a good idea,
    but I still am not convinced we have a good reason to use an aligned
    allocator in the near term. It cannot possibly be the case that struct {
    double, double } actually requires better-than-malloc alignment on win32 or
    SPARC, because if that were true then nothing would work.
    On 26 Nov 2014 09:10, "Julian Taylor" [email protected] wrote:

    I have already a branch which adds an aligned allocator, i'll dig it out.

    By using something like this we throw away the option to uses pythons
    tracemalloc framework and sparse memory (there is no aligned_calloc).
    @njsmith https://github.com/njsmith would you be willing to engage with
    python devs again to add yet another allocator to their slot before 3.5 is
    released? They already added calloc only for us, would be a schame if we
    now couldn't use it.

    —
    Reply to this email directly or view it on GitHub
    #5312 (comment).

  6. sturlamolden commented on Nov 26, 2014

    @sturlamolden
    ContributorAuthor

    The question with regard to f2py was what alignment Fortran would need, not the minimum requirement of C. Speed is also an issue. Both indexing and SIMD works better if the data is properly aligned.

  7. pv commented on Nov 26, 2014

    @pv
    Member

    A reason for using aligned allocator could indeed be speed, and ensuring SSE/AVX
    compatibility would remove the numerical jitter that comes from taking different
    code paths for differently aligned data.
    .
    f2py is older than the ISO C binding standard in Fortran, and the way it
    works is essentially the de facto standard way on interfacing Fortran
    with C, used extensively by everyone. In light of this experience, it's
    clear that alignment provided by system malloc is sufficient for the
    Fortran compilers that matter in practice for us.

  8. pitrou commented on Dec 5, 2014

    @pitrou
    Member
  9. sturlamolden commented on Dec 5, 2014

    @sturlamolden
    ContributorAuthor

    @pitrou And 64 byte alignment is recommended for Xeon Phi. Take a look at the comment behind the definition of NPY_MEMALIGN in my code example.

  10. njsmith commented on Dec 5, 2014

    @njsmith
    Member

    The main complication on providing aligned allocation is that ATM we can
    either hook into the tracemalloc infrastructure xor do aligned allocation,
    and fixing this will require some coordination with CPython upstream (see
    #4663).
    On 5 Dec 2014 16:44, "Sturla Molden" [email protected] wrote:

    @pitrou https://github.com/pitrou And 64 bit is recommended for Xeon
    Phi. Take a look at the comment behind the definition of NPY_MEMALIGN in
    my code example.

    —
    Reply to this email directly or view it on GitHub
    #5312 (comment).

  11. pitrou commented on Dec 5, 2014

    @pitrou
    Member

    So the CPython issue is at http://bugs.python.org/issue18835.

  12. pitrou commented on Jan 15, 2015

    @pitrou
    Member

    Given the complications with realloc(), it might not be realistic to expect CPython to solve this in the 3.5 timeframe. Numpy should perhaps use its own aligned allocated wrapper instead (which should be able to defer to the PyMem API, and take advantage of tracemalloc, anyway).

  13. sturlamolden commented on Jan 15, 2015

    @sturlamolden
    ContributorAuthor

    Code for such an allocator is included above. I don't understand @juliantaylor 's argument, but he probably understands this better than me.

    I can understand what he meant about calloc though. A calloc is not simply a malloc and a memset to zero. A memset will require the OS to fetch the pages before they are needed. AFAIK there is no PyMem_Calloc.

  14. pitrou commented on Jan 15, 2015

    @pitrou
    Member

    Actually CPython 3.5 has PyMem_Calloc and friends.
    I think @juliantaylor was considering the implementation case of using OS functions (posix_memalign, etc.). But that doesn't sound necessary.

    By the way @sturlamolden, your snippet redefines PyArray_Malloc and friends, but array allocation seems to use PyDataMem_NEW. Am I misunderstanding something?

  15. 44 remaining items

  16. mattip commented on Sep 27, 2019

    @mattip
    Member

    In merging randomgen, we gained PyArray_realloc_aligned and friends. Should we move these routines into numpy/core/include ?

  17. jakirkham commented on Nov 5, 2019

    @jakirkham
    Contributor

    That would certainly be useful, @mattip. Would it be possible to access this functionality from Python as well?

  18. sturlamolden commented on Nov 17, 2019

    @sturlamolden
    ContributorAuthor

    In merging randomgen, we gained PyArray_realloc_aligned and friends. Should we move these routines into numpy/core/include ?

    Ripped off my code, did ya? 😂

  19. sturlamolden commented on Nov 17, 2019

    @sturlamolden
    ContributorAuthor
  20. bashtage commented on Nov 17, 2019

    @bashtage
    Contributor
  21. mattip commented on Nov 17, 2019

    @mattip
    Member

    what was the original source of the code?

  22. sturlamolden commented on Nov 17, 2019

    @sturlamolden
    ContributorAuthor

    The link is dead, but it was adapted from an aligned malloc that looked like this:

    https://tianrunhe.wordpress.com/2012/04/23/aligned-malloc-in-c/

  23. bashtage commented on Nov 17, 2019

    @bashtage
    Contributor
  24. sturlamolden commented on Nov 17, 2019

    @sturlamolden
    ContributorAuthor
  25. bashtage commented on Nov 17, 2019

    @bashtage
    Contributor
  26. pitrou commented on Nov 17, 2019

    @pitrou
    Member

    Does everyone who contributes 50 lines of code to Numpy get a dedicated copyright header? I might go through my contributions and see if any applies :-)

  27. rgommers commented on Nov 17, 2019

    @rgommers
    Member

    It looks like I am no longer contributor for the code I have written for NumPy 🧐:

    You are and will always be:)

    Does everyone who contributes 50 lines of code to Numpy get a dedicated copyright header? I might go through my contributions and see if any applies :-)

    Nope. We try to avoid encoding such things inside the source code, since that will always be wildly incomplete and hard to maintain. We do ask people to list themselves in THANKS.txt; I'm looking at a better alternative to that, because that file often gives merge conflicts.

  28. seberg commented on Nov 5, 2021

    @seberg
    Member

    I am going to close the issue. Happy about a new one though! (It seems most of the discussion is simply outdated and should be re-evaluated based on Matti's work in gh-17582)

    Note that it is now – with the next release – possible to write a context manager outside NumPy to swap in an aligned allocator. Which alleviates the need to push it directly into NumPy and gives a chance for much clearer testing of the benefits.

  29. jakirkham commented on Nov 5, 2021

    @jakirkham
    Contributor

    Also there is a tracking issue with follow up items ( #20193 ). One of them is allocators with specific alignment ( #20193 (comment) )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions