On Saturday, 21 January 2017 at 17:26:35 UTC, Andrei Alexandrescu wrote:
On 01/21/2017 12:14 PM, bitwise wrote:
On Saturday, 21 January 2017 at 16:28:16 UTC, Andrei Alexandrescu wrote:
alignedAllocate provides access to OS/clib-provided primitives for
aligned allocation. Those don't require a special deallocation
function, see e.g.
http://en.cppreference.com/w/c/memory/aligned_alloc. -- Andrei

This makes sense, but then shouldn't alignedAllocate() be a free
function that could be used to make an aligned allocator?

You mean an aligned allocation? But then the actual method, and whether it is supported at all or not, depends on the allocator.

Again, the point of an allocator is to provide a standard interface for memory allocation. The user of which shouldn't have to know how that memory was allocated, and I can't think of a case where this would be
desired either.

I don't understand this. It's possible there's a confusion at a different level, and we're discussing the consequences.

To reboot:

* Some applications need memory aligned at special powers of two, most are okay with more generic alignments such as word-level. See the "alignment" enum that each allocator must define.

* Some allocators do offer allocations at unusual powers of two by means of alignedAllocate. Don't call it naively! Only applications that need such things (e.g. page-aligned, cache-line-aligned, etc) should need those.

* Those allocators must be able to deallocate memory allocated with allocate() or alignedAllocate() with a single primitive deallocate().


Andrei

About alignedMalloc:

In C++ for example, I may want to use a vector full some SIMD type:

class alignas(16) Vec4 {
    union {
        struct { float x, y, z, w; };
        __m128 m;
    };
};

std::vector<Vec4> points = { ... };

In C++ however, 'new' does not respect over-alignment:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0035r2.html

Even if new respected alignment, there is no gauruntee all containers, STL or otherwise, would use 'new' as opposed to malloc by default(maybe one day?)

So I use a custom aligned allocator:

template <class T, int ALIGN>
class AlignedAllocator {
    T* allocate(size_type n) {
        return (T*)_aligned_malloc(ALIGN, n * sizeof(T));
    }
};

SIMD operations(aligned load and store) can now safely be used on the contents of the std::vector<Vec4>.

std::vector knows nothing about the alignment of the memory it uses. It only knows to call allocate() of whatever allocator it's given. If I had an allocator with a function 'alignedAllocate' it wouldn't do any good. I believe this is the _correct_ design, and that a container _shouldn't_ have to know about where from, or what kind of memory it's getting.

Considering the above use case, alignedAllocate() is redundant, and possibly confusing.

About missing alignedDeallocate:

while aligned_alloc(), which works in combination with regular 'free()', is supposed to be standard as of C++11, it's still not supported in visual studio 2015. Instead, one must use _aligned_malloc, and _aligned_free. Passing memory from _aligned_malloc to the regular version of free() causes a crash. Thus, different deallocation methods are needed for both. Also, there's homegrown aligned_allocate functions like the following, which require special deallocation functions because of the exta metadata prepended to the memory:
https://github.com/dlang/phobos/blob/366f6e4e66abe96bca9fd69d03042e08f787d040/std/experimental/allocator/mallocator.d#L134-L134

I suppose you could use aligned allocation for _all_ allocations, even allocations with default alignment, but that would add extra metadata(at least 8 bytes) to _all_ allocations even when its unnecessary.

So a solution could be to include the alignment as a template parameter of Mallocator, or provide an second AlignedMallocator(uint). The allocate() function of either option would return aligned memory if the 'alignment' template parameter was non-default. Then, the idea of memory alignment would be abstracted away from the containers themselves.

struct Mallocator(uint alignment = platformAlignment){}){}
or
struct AlignedMallocator(uint alignment = platformAlignment){}){}


Reply via email to