alignment vs stride in Swift
Asked Answered
P

1

15

In Swift 4, the MemoryLayout struct tells you the size, stride, and alignment of a type.

I understand size and stride but not alignment really.

Is there an example that shows what alignment is, how it is different from stride, when it has a different value from stride, and where it would be incorrect to use stride but correct to use alignment?

Can I always compute one from the other?

Peking answered 2/12, 2017 at 18:13 Comment(9)
Have you seen github.com/apple/swift/blob/master/docs/ABI/TypeLayout.rst ?Enwind
If you understand stride and the difference between size and stride, you should already know what the alignment is, because stride is usually the result of the need for alignment. And alignment (on an x-byte border, depending on the size of the type) is necessary on several processors, to make accessing certain types faster.Trunk
@JoshCaswell thank you! I was not aware of this. This is a very helpful link.Peking
@RudyVelthuis Then perhaps I do not understand stride either! If you understand both, I’d be grateful if you could offer an example like the one I said would help me understand this as well.Peking
I think the link that @JoshCaswell posted explains it pretty well. If you are really unfamiliar with alignment in general, then read the Wikipedia link on alignment. Alignment determines the offset a data type has in memory or inside a structure. The required alignment is determined by the size and by the processor (some processors have problems accessing unaligned data). Stride is extra padding outside a structure to make the entire structure align properly in, say, an array.Trunk
You're welcome. Note that it's still subject to revision (AFAIK).Enwind
@RudyVelthuis I am not looking for an explanation only. Explanations are plentiful. I am looking for an example that shows where I would use alignment but not stride. I could explain all of this myself convincingly by parroting what I’ve read and that would be fine for a school exercise, but I find I don’t truly understand something until I can generate a rich example. I’ve used stride many times, so that’s easy. I’ve never had to use alignment, so it’s not for me. If you have an example to share, please do.Peking
I must admit that stride is something rather unusual. Size and stride of a struct are the same in many languages. Alignment is what I said: the offsets of struct members are determined by their sizes, so an 8 byte element is aligned on an 8 byte boundary (hex ...8 or hex ...0), a 4 byte element on a 4 byte boundary (hex ...0, ...4, ...8, ...C), etc. because this way, processors can handle them much better (no need to fetch an unaligned type in two parts, etc.). In other words: alignment determines how types are laid out in memory.Trunk
@algal: The alignment determines where you can put the struct into memory (so that all struct members are properly aligned). The stride is the offset from one aligned struct item to the next aligned struct item in memory. You can compute the stride from size and alignment, but not the other way around.Pastry
P
17

Here is a simple example:

struct Foo {
    let a: Int16
    let b: Int8
}

print(MemoryLayout<Foo>.size)       // 3
print(MemoryLayout<Foo>.alignment)  // 2
print(MemoryLayout<Foo>.stride)     // 4
  • The alignment of the struct is the maximal alignment of all its fields, in this case the maximum of 2 and 1.
  • The stride of the struct is the size rounded up to alignment, here 3 rounded up to a multiple of 4.

The stride is the distance between (the start of) contiguous instance of the same type in memory:

let array = [Foo(a: 1, b:2), Foo(a: 3, b: 4), Foo(a: 5, b: 6)]
array.withUnsafeBytes {
    print(Data($0) as NSData) // <01000234 03000474 0500066f>
    print($0.count) // 12
}

The struct stride is a multiple of the struct alignment, so that all instances (and therefore all instance fields) are properly aligned.

The details can be found in Type Layout:

Fragile Struct and Tuple Layout

Structs and tuples currently share the same layout algorithm, noted as the "Universal" layout algorithm in the compiler implementation. The algorithm is as follows:

  • Start with a size of 0 and an alignment of 1.
  • Iterate through the fields, in element order for tuples, or in var declaration order for structs. For each field:
    • Update size by rounding up to the alignment of the field, that is, increasing it to the least value greater or equal to size and evenly divisible by the alignment of the field.
    • Assign the offset of the field to the current value of size.
    • Update size by adding the size of the field.
    • Update alignment to the max of alignment and the alignment of the field.
  • The final size and alignment are the size and alignment of the aggregate. The stride of the type is the final size rounded up to alignment.
Pastry answered 2/12, 2017 at 18:28 Comment(5)
I take it the last byte shown in each 4 byte group of the output from your print(Data) statement is a garbage filler byte? (The bolded digits in <01000234 03000474 0500066f >.)Martelle
Further, I gather you're assuming little-endian byte ordering?Martelle
@DuncanC: Yes, the contents of the padding bytes is unspecified. – Size/alignment/stride do not depend on the endianness, so I am not assuming anything. The example however is little-endian – which is no wonder because all current macOS and iOS platforms are little-endian.Pastry
@MartinR Thanks so much for this, which is the only concrete explanation I've found anywhere! What confuses me is everyone rushes to explain the concept of data alignment but I cannot find a statement describing the meaning of the value of the alignment property. The size is the bytes used to represent an element. The stride is the byte offset needed to maintain data alignment in a buffer of elements. The alignment is ... what? Is it at least correct to say "a value used internally to compute stride for aggregates, but which I would never need to access directly"?Peking
@algal: The processor data types (short, int, long, float, double) have certain alignment requirements (given by the processor architecture and the ABI). The struct alignment is determined in such a way that all its members are properly aligned (even in nested structs), this is the important value. The stride is just a result of size and alignment.Pastry

© 2022 - 2024 — McMap. All rights reserved.