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){}){}