To make it specific, I only want to know why on my 64 bit mac, the Swift compiler says the alignment of some types like Float80
is 16.
To check the memory alignment requirement of a type, I use the alignof
function.
sizeof(Float80) // ~> 16 bytes, it only needs 10 bytes, but because of hardware design decisions it has to be a power of 2
strideof(Float80) // ~> 16 bytes, clear because it is exact on a power of 2, struct types with Float80 in it, can be bigger
alignof(Float80) // ~> 16 bytes, why not 8 bytes, like String ?
I understand the memory alignment of types less or equal the size of the word is beneficial.
sizeof(String) // ~> 24 bytes, clear because 24 is multiple of 8
strideof(String) // ~> 24 bytes, clear because 24 is multiple of 8
alignof(String) // ~> 8 bytes, clear because something greater or equal to 8 bytes should align to 8 bytes
Many types with a bigger memory size footprint like String
(with a size of 24) does have a memory alignment requirement of 8 bytes. I expect that is the size of my CPU/RAM bus in use, because I have a 64 bit mac and os.
I check the size of the type without the last padding with the sizeof
function and with the adding padding to the end with the strideof
function (strideof is more helpful in arrays of structs, Swift then adds bytes to the end to reach the next multiple of the alignment requirement.)
I understand that padding is necessary for types lesser or equal than the size of 8 byte.
But I don't understand why it is advantageous to have a memory alignment requirement bigger than 8 bytes on my 64 bit mac.
Float80 needs 80 bits for its value, that are 10 bytes, with 6 filler bytes.
Here is an image to make it more clear, what I mean. The green positions are allowed for a Float80, the red positions not. The memory is in 8 byte chunks in this picture.
What is alignment? Alignment refers to the arrangement of data in memory, and specifically deals with the issue of accessing data as proper units of information from main memory. First we must conceptualize main memory as a contiguous block of consecutive memory locations. Each location contains a fixed number of bits.
Word size for sequence alignment algorithms is the minimum number of characters required to seed a match between two sequences. For example, a word size of 8 means that at least 8 characters much match between two sequences before the an alignment is considered by the algorithm.
Alignment helps the CPU fetch data from memory in an efficient manner: less cache miss/flush, less bus transactions etc. Some memory types (e.g. RDRAM, DRAM etc.) need to be accessed in a structured manner (aligned "words" and in "burst transactions" i.e. many words at one time) in order to yield efficient results.
Yes both alignment and arrangement of your data can make a big difference in performance, not just a few percent but few to many hundreds of a percent. Take this loop, two instructions matter if you run enough loops. A performance test you can very easily do yourself.
Align arraysSIMD register-size aligned data accesses are performed much faster by the processor than unaligned ones. In some cases, the compiler and/or hardware can minimize the performance impact, but often significant performance increases—especially for vector codes—can be achieved by ensuring alignment.
All "primitive data types" (the term may be wrong, what I mean is the data types that are used by the processor) have a "natural boundary", and the compiler will align them in memory accordingly. The alignment depends on the processor (e.g. x86 or ARM) and the programming environment (e.g. 32-bit vs 64-bit). Some processors allow misaligned data (perhaps at a lower speed), and some do not allow it.
For the 64-Bit Intel architecture, the requirements are listed in Data Alignment when Migrating to 64-Bit Intel® Architecture:
The 64-bit environment, however, imposes more-stringent requirements on data items. Misaligned objects cause program exceptions.
[...]
- Align 8-bit data at any address
- Align 16-bit data to be contained within an aligned four-byte word
- Align 32-bit data so that its base address is a multiple of four
- Align 64-bit data so that its base address is a multiple of eight
- Align 80-bit data so that its base address is a multiple of sixteen
- Align 128-bit data so that its base address is a multiple of sixteen
So the alignment is not necessarily equal to the "word size", it can be
less or more. Float80
corresponds to the "Extended Precision"
floating point type of the x86 processor, and its alignment is
required to be 16 bytes.
Composite types like C struct
are layed out in memory such that
each member is on its natural boundary (and padding is inserted
in between if necessary). The alignment of the struct
itself is the largest alignment of each member.
The memory layout of a Swift Struct
is not documented officially (as far as I know) but it is probably be similar to the C struct
.
Here is a simple example:
struct AStruct {
var a = Int32(0)
var b = Int8(0)
var c = Int16(0)
var d = Int8(0)
}
println(sizeof(AStruct)) // 9
println(alignof(AStruct)) // 4
println(strideof(AStruct)) // 12
The memory layout (probably) is (* = padding):
aaaab*ccd
Here the alignment is 4 because that is the required alignment for Int32
. The struct occupies 9 bytes, but the "stride" is 12:
This guarantees that in an array of structs all elements satisfy
the same alignments.
(Note that the Swift strideOf()
corresponds to the C the sizeof()
function, this is explained in https://devforums.apple.com/message/1086107#1086107.)
The declaration of a Swift string shown as
struct String {
init()
}
but the actual members are not visible to us mere mortals. In the debugger it looks like this:
which indicates that its members are a pointer,
an unsigned word and another pointer. All these types have a size and
alignment of 8 bytes on 64-bit. This would explain the size (24 bytes)
and alignment (8 bytes) of struct Swift
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With