Hacker News new | ask | show | jobs
by phire 9 days ago
> so alloc() doesn’t just need to hand back a pointer. it needs to hand back a pointer that’s correctly aligned for whatever type the caller is about to store there.

Malloc doesn't know the required alignment (because has no idea what the type is, everything is cast through void). So all malloc implementations have a minimum alignment guarantee. Typically 16 bytes these days on x86, as that means even 128bit SSE values will end up aligned by default.

You couldn't go below the sizeof(void ) anyway, the backpointer needs to aligned too.

The padding only happens when you use memalign or aligned_malloc to specify a much larger alignment.

4 comments

There is no reason an allocation needs to contain any inline metadata. And even if it does, the allocator could choose to make it unalined, and pay the cost of an unalined access on de-allocation.
This is explained in TFA, where it is mentioned that you can replace inline metadata with a pointer to metadata (or an index), which may be unaligned, if necessary.

However, the pointer to metadata is not really necessary.

The associated metadata could be stored in a table, and the index of the metadata could be computed from the offset of the pointer returned by malloc to the start of the heap (possibly using a hash function).

The ancient versions of the Microsoft C/C++ compilers were using a malloc with inline metadata. I have no idea if they replaced this more recently.

I consider an inline-pointer a form of inline-metadata. When I mentioned that inline metadata isn't necessary I was referring to the kind of external lookup you describe.
True.

But most C code out there assumes malloc will always return something that is at least aligned to sizeof(void *), it's very rare to see aligned_alloc. So how is your alloc allocation going to know when it can get away with a smaller alignment?

Even if you are on a cpu that doesn't fault on unaligned memory access, any malloc implementation that doesn't align by default will have serious disadvantages in any benchmarks. IMO, There is no good reason to use an unaligned backpointer.

Yes, large allocations need to be aligned to `alignof(max_align_t)`. But small allocations could have a smaller alignment. For example a single byte allocation can actually be a single byte with no alignment, since types can't have an alignment larger than their size.
> So all malloc implementations have a minimum alignment guarantee. Typically 16 bytes these days on x86

Fun story. Back in the early 2000s, my Delphi OpenGL program randomly crashed when I tried to use vertex buffers. I spent a lot of time checking this and that, before I realized it might be an alignment issue.

Sure enough, Delphi memory allocator at the time only provided 4-byte alignment, while NVIDIA's drivers used aligned SSE instructions which require 16-byte alignment.

So, had to manually align the buffers before passing them to OpenGL.

IMO that sounds either like a bug in Nvidia's drivers (IIRC OpenGL doesn't require that sort of alignment) or -more likely- your code having some other memory related-bug (e.g. accessing data out of bounds) that the extra bytes you got from alignment masked it.
Nah it was definitely NVIDIA's fault. As you say there's nothing in the specs about alignment of those buffers, so they shouldn't be using aligned load instructions.

However Microsoft's malloc at the time was indeed returning 16-byte aligned buffers so they probably didn't notice it in internal testing.

That's a good point, and I could have worded that better. What I implemented accepts an explicit alignment parameter because it made the allocator easier to explain. A real malloc() only guarantees alignment suitable for any object type (typically alignof(max_align_t)), since it has no idea what the caller will store there.
Isn't 64 bytes needed for AVX512, then?
There are two types of load/store instructions, one type requires alignment (vmovdqa), the other can load unaligned data (vmovdqu), in the case of AVX-512 the required alignment is 64 bytes. I assume aligned loads and stores are faster/have lower latency. For SSE/AVX you can look up the alignment requirements in Intel's intrinsics guide [0].

[0] https://www.intel.com/content/www/us/en/docs/intrinsics-guid...