Alignment

  • Alignment and Size are different things.

  • Alignment == "Divisible by".

  • Required byte boundary a value must start on, typically a power of two.

  • Hardware or ABI rule ensuring each type begins at addresses divisible by its alignment requirement.

  • .

  • An address is said to be aligned to N  bytes , if the addresses's numeric value is divisible by N . The number N  in this case can be referred to as the alignment boundary . Typically an alignment is a power of two integer value.

  • A natural alignment  of an object is typically equal to its size. For example a 16 bit integer has a natural alignment of 2 bytes.

Why to align

  • The scenario below causes unnecessary wastage of CPU cycles.

  • .

  • If we use padding (empty space) we can improve the CPU cycles, at the cost of the struct storing more memory.

  • .

  • .

  • The order of the elements matters, as it can introduce more padding than necessary:

  • .

  • .

  • When an object is not located on its natural alignment boundary, accesses to that object are considered unaligned .

  • Some machines issue a hardware exception , or experience slowdowns  when a memory access operation occurs from an unaligned address. Examples of such operations are:

    • SIMD instructions on x86. These instructions require all memory accesses to be on an address that is aligned to 16 bytes.

    • On ARM unaligned loads have an extra cycle penalty.

  • If you have an unaligned memory access (on a processor that allows it), the processor will have to read multiple “words”. This means that an unaligned memory access may  be much slower than an aligned memory access.

  • This can also lead to undefined behavior if the unaligned memory is within cache bounds.

Memory Access

  • Processors don't read 1 byte at a time from memory.

  • They read 1 word  at a time.

  • 32-bit Processor :

    • Word size is 4 bytes.

  • 64-bit Processor :

    • Word size is 8 bytes.

Size

  • The total number of bytes that a single element actually occupies in memory, including  any internal padding required by alignment.

Offset

  • Defines where a field resides relative to a structure’s base address.

  • Example :

    • In struct { int a; char b; } , if a  starts at offset 0 , b  might be at offset 4  due to alignment padding.

Stride

  • Byte distance between consecutive elements in an array or buffer.

  • It’s not “after the element finishes”, it’s the total distance between consecutive starts .

  • That’s why stride includes all bytes (data + padding) in a single element.

  • Example :

    • In a vertex buffer with position (12 bytes) + color (4 bytes), stride = 16 bytes. The next vertex starts 16 bytes after the previous one.

      • Vertex 0 starts at byte 0 .

      • Vertex 0 occupies bytes 0–15 .

      • Vertex 1 starts at byte 16 .

Implicit Alignment

  • When placing a field, the compiler ensures the field's offset is a multiple of the field's alignment. If the current offset is not  a multiple of the field's alignment, the compiler inserts padding before the field so the resulting offset becomes a multiple of the alignment.

    • When placing field F the compiler ensures offset(F) % align(F) == 0 .

    • If not, it inserts padding = (align(F) - (offset % align(F))) % align(F)  bytes before F.

    • The struct’s overall alignment is max(align(member)) . The compiler may add trailing padding so sizeof(struct)  is a multiple of that max alignment.

  • A struct adds implicit padding between members, based on the alignment of the member with the highest alignment.

  • The gray dots indicate the implicit padding added by the compiler.

  • .

  • It may also add padding at the end of the struct, so the struct is divisible by its alignment. This ensures that when the struct is used as an array, each struct will be properly aligned along with its members.

Odin
  • Alignment, Size and the Pointer are related, such as:

    • size_of(T) % align_of(T) == 0 .

    • uintptr(&t) % align_of(t) == 0 .

    • Check Odin#Alignment .

  • Many operations that allocate memory in this package allow to explicitly specify the alignment of allocated pointers/slices.

  • The default alignment for all operations is specified in a constant mem.DEFAULT_ALIGNMENT .

std140 and std430