how does the processor read memory? - c

I'm trying to re-implement malloc and I need to understand the purpose of the alignment. As I understand it, if the memory is aligned, the code will be executed faster because the processor won't have to take an extra step to recover the bits of memory that are cut. I think I understand that a 64-bit processor reads 64-bit by 64-bit memory. Now, let's imagine that I have a structure with in order (without padding): a char, a short, a char, and an int. Why will the short be misaligned? We have all the data in the block! Why does it have to be on an address which is a multiple of 2. Same question for the integers and other types?
I also have a second question: With the structure I mentioned before, how does the processor know when it reads its 64 bits that the first 8 bits correspond to a char, then the next 16 correspond to a short etc...?

The effects can even include correctness, not just performance: C Undefined Behaviour (UB) leading to possible segfaults or other misbehaviour for example if you have a short object that doesn't satisfy alignof(short). (Faulting is expected on ISAs where load/store instructions require alignment by default, like SPARC, and MIPS before MIPS64r6. And possible even on x86 after compiler optimization of loops, even though x86 asm allows unaligned loads/stores except for some SIMD with 16-byte or wider.)
Or tearing of atomic operations if an _Atomic int doesn't have alignof(_Atomic int).
(Typically alignof(T) = sizeof(T) up to some size, often register width or wider, in any given ABI).
malloc should return memory with alignof(max_align_t) because you don't have any type info about how the allocation will be used.
For allocations smaller than sizeof(max_align_t), you can return memory that's merely naturally aligned (e.g. a 4-byte allocation aligned by 4 bytes) if you want, because you know that storage can't be used for anything with a higher alignment requirement.
Over-aligned stuff like the dynamically-allocated equivalent of alignas (16) int32_t foo needs to use a special allocator like C11 aligned_alloc. If you're implementing your own allocator library, you probably want to support aligned_realloc and aligned_calloc, filling those gaps that ISO C leave for no apparent reason.
And make sure you don't implement the braindead ISO C++17 requirement for aligned_alloc to fail if the allocation size isn't a multiple of the alignment. Nobody wants an allocator that rejects an allocation of 101 floats starting on a 16-byte boundary, or much larger for better transparent hugepages. aligned_alloc function requirements and How to solve the 32-byte-alignment issue for AVX load/store operations?
I think I understand that a 64-bit processor reads 64-bit by 64-bit memory
Nope. Data bus width and burst size, and load/store execution unit max width or actually-used width, don't have to be the same as width of integer registers, or however the CPU defines its bitness. (And in modern high performance CPUs typically aren't. e.g. 32-bit P5 Pentium had a 64-bit bus; modern 32-bit ARM has load/store-pair instructions that do atomic 64-bit accesses.)
Processors read whole cache lines from DRAM / L3 / L2 cache into L1d cache; 64 bytes on modern x86; 32 bytes on some other systems.
And when reading individual objects or array elements, they read from L1d cache with the element width. e.g. a uint16_t array may only benefit from alignment to a 2-byte boundary for 2-byte loads/stores.
Or if a compiler vectorizes a loop with SIMD, a uint16_t array can be read 16 or 32 bytes at a time, i.e. SIMD vectors of 8 or 16 elements. (Or even 64 with AVX512). Aligning arrays to the expected vector width can be helpful; unaligned SIMD load/store run fast on modern x86 when they don't cross a cache-line boundary.
Cache-line splits and especially page-splits are where modern x86 slows down from misalignment; unaligned within a cache line generally not because they spend the transistors for fast unaligned load/store. Some other ISAs slow down, and some even fault, on any misalignment, even within a cache line. The solution is the same: give types natural alignment: alignof(T) = sizeof(T).
In your struct example, modern x86 CPUs will have no penalty even though the short is misaligned. alignof(int) = 4 in any normal ABI, so the whole struct has alignof(struct) = 4, so the char;short;char block starts at a 4-byte boundary. Thus the short is contained within a single 4-byte dword, not crossing any wider boundary. AMD and Intel both handle this with full efficiency. (And the x86 ISA guarantees that accesses to it are atomic, even uncached, on CPUs compatible with P5 Pentium or later: Why is integer assignment on a naturally aligned variable atomic on x86?)
Some non-x86 CPUs would have penalties for the misaligned short, or have to use other instructions. (Since you know the alignment relative to an aligned 32-bit chunk, for loads you'd probably do a 32-bit load and shift.)
So yes there's no problem accessing one single word containing the short, but the problem is for load-port hardware to extract and zero-extend (or sign-extend) that short into a full register. This is where x86 spends the transistors to make this fast. (#Eric's answer on a previous version of this question goes into more detail about the shifting required.)
Committing an unaligned store back into cache is also non-trivial. For example, L1d cache might have ECC (error-correction against bit flips) in 32-bit or 64-bit chunks (which I'll call "cache words"). Writing only part of a cache word is thus a problem for that reason, as well as for shifting it to an arbitrary byte boundary within the cache word you want to access. (Coalescing of adjacent narrow stores in the store buffer can produce a full-width commit that avoids an RMW cycle to update part of a word, in caches that handle narrow stores that way). Note that I'm saying "word" now because I'm talking about hardware that's more word-oriented instead of being designed around unaligned loads/stores the way modern x86 is. See Are there any modern CPUs where a cached byte store is actually slower than a word store? (storing a single byte is only slightly simpler than an unaligned short)
(If the short spans two cache words, it would of course needs to separate RMW cycles, one for each byte.)
And of course the short is misaligned for the simple reason that alignof(short) = 2 and it violates this ABI rule (assuming an ABI that does have that). So if you pass a pointer to it to some other function, you could get into trouble. Especially on CPUs that have fault-on-misaligned loads, instead of hardware handling that case when it turns out to be misaligned at runtime. Then you can get cases like Why does unaligned access to mmap'ed memory sometimes segfault on AMD64? where GCC auto-vectorization expected to reach a 16-byte boundary by doing some multiple of 2-byte elements scalar, so violating the ABI leads to a segfault on x86 (which is normally tolerant of misalignment.)
For the full details on memory access, from DRAM RAS / CAS latency up to cache bandwidth and alignment, see What Every Programmer Should Know About Memory? It's pretty much still relevant / applicable
Also Purpose of memory alignment has a nice answer. There are plenty of other good answers in SO's memory-alignment tag.
For a more detailed look at (somewhat) modern Intel load/store execution units, see: https://electronics.stackexchange.com/questions/329789/how-can-cache-be-that-fast/329955#329955
how does the processor know when it reads its 64 bits that the first 8 bits correspond to a char, then the next 16 correspond to a short etc...?
It doesn't, other than the fact it's running instructions which treat the data that way.
In asm / machine-code, everything is just bytes. Every instruction specifies exactly what to do with which data. It's up to the compiler (or human programmer) to implement variables with types, and the logic of a C program, on top of a raw array of bytes (main memory).
What I mean by that is that in asm, you can run any load or store instruction you want to, and it's up to you to use the right ones on the right addresses. You could load 4 bytes that overlap two adjacent int variable into a floating-point register, then and run addss (single-precision FP add) on it, and the CPU won't complain. But you probably don't want to because making the CPU interpret those 4 bytes as an IEEE754 binary32 float is unlikely to be meaningful.

modern processors and memory are built to optimize memory access as much as possible. One the current way of accessing memory is to address it not byte by byte but by an address of a bigger block, e.g. by an 8 byte blocks. You do not need 3 lower bits of the address this way. To access a certain byte within the block the processs needs to get the block at the aligned address, then shift and mask the byte. So, it gets slower.
When fields in the struct are not aligned, there is a risk of slowing down the access to them. Therefore, it is better to align them.
But the alignment requirements are based on the underlying platform. For systems which support word access (32 bit), 4-byte alignment is ok, otherwise 8-byte can be used or some other. The compiler (and libc) knows the requirements.
So, in your example char, short, char, the short will start with an odd byte position if not padded. To access it, the system might need to read the 64 bit word for the struct, then shift it 1 byte right and then mask 2 bytes in order to provide you with this byte.

As I understand it, if the memory is aligned, the code will be executed faster because the processor won't have to take an extra step to recover the bits of memory that are cut.
It's not necessarily an execution thing, an x86 has variable length instructions starting with single 8 bit instructions on up to a handful to several bytes, its all about being unaligned. but they have taken measures to smooth that out for the most part.
If I have a 64 bit bus on the edge of my processor that doesn't mean edge of chip that means edge of the core. The other side of this is a memory controller that knows the bus protocol and is the first place the addresses start to be decoded and the transactions start to split up down other buses toward their destination.
It is very much architecture and bus design specific and you can have architectures with different buses over time or different versions you can get an arm with a 64 bus or a 32 bit bus for example. But let's say we have a not atypical situation where the bus is 64 bits wide and all transactions on that bus are aligned on a 64 bit boundary.
If I were to do a 64 bit write to 0x1000 that would be a single bus transaction, which these days is some sort of write address bus with some id x and a length of 0 (n-1) then the other side acks that I see you want to do a write with id x, I am ready to take your data. Then the processor uses the data bus with id x to send the data, one clock per 64 bits this is a single 64 bit so one clock on that bus. and maybe an ack comes back or maybe not.
But if I wanted to do a 64 bit write to 0x1004, what would happen is that turns into two transactions one complete 64 bit address/data transaction at address 0x1000 with only four byte lanes enabled lanes 4-7 (representing bytes at address 0x1004-0x1007). Then a complete transaction at 0x1008 with 4 byte lanes enabled, lanes 0-3. So the actual data movement across the bus goes from one clock to two, but there is also twice the overhead of the handshakes to get to those data cycles. On that bus it is very noticeable, how the overall system design is though you may feel it or not, or may have to do many of them to feel it or not. But the inefficiency is there, buried in the noise or not.
I think I understand that a 64-bit processor reads 64-bit by 64-bit memory.
Not a good assumption at all. 32 bit ARMs have 64 bit buses these days the ARMv6 and ARMv7s for example come with them or can.
Now, let's imagine that I have a structure with in order (without padding): a char, a short, a char, and an int. Why will the short be misaligned? We have all the data in the block! Why does it have to be on an address which is a multiple of 2. Same question for the integers and other types?
unsigned char a 0x1000
unsigned short b 0x1001
unsigned char c 0x1003
unsigned int d 0x1004
You would normally use the structure items in the code something.a something.b something.c something.d. When you access something.b that is a 16 bit transaction against the bus. In a 64 bit system you are correct that if aligned as I have addressed it, then the whole structure is being read when you do x = something.b but the processor is going to discard all but byte lanes 1 and 2 (discarding 0 and 3-7), then if you access something.c it will do another bus transaction at 0x1000 and discard all but lane 3.
When you do a write to something.b with a 64 bit bus only byte lanes 1 and 2 are enabled. Now where more pain comes in is if there is a cache it is likely also constructed of a 64 bit ram to mate up with this bus, doesn't have to, but let's assume it does. You want to write through the cache to something.b, a write transaction at 0x1000 with byte lanes 1 and 2 enabled 0, 3-7 disabled. The cache ultimately gets this transaction, it internally has to do a read-modify write because it is not a full 64 bit wide transaction (all lanes enabled) so you are taking hit with that read-modify write from a performance perspective as well (same was true for the unaligned 64 bit write above).
The short is unaligned because when packed its address lsbit is set, to be aligned a 16 bit item in an 8 bit is a byte world needs to be zero, for a 32 bit item to be aligned the lower two bits of its address are zero, 64 bit, three zeros and so on.
Depending on the system you may end up on a 32 or 16 bit bus (not for memory so much these days) so you can end up with the multiple transfers thing.
Your highly efficient processors like MIPS and ARM took the approach of aligned instructions, and forced aligned transactions even in the something.b case that specifically doesn't have a penalty on a 32 nor 64 bit bus. The approach is performance over memory consumption, so the instructions are to some extent wasteful in their consumption to be more efficient in their fetching and execution. The data bus is likewise much simpler. When high level concepts like a struct in C are constructed there is memory waste in padding to align each item in the struct to gain performance.
unsigned char a 0x1000
unsigned short b 0x1002
unsigned char c 0x1004
unsigned int d 0x1008
as an example
I also have a second question: With the structure I mentioned before, how does the processor know when it reads its 64 bits that the first 8 bits correspond to a char, then the next 16 correspond to a short etc...?
unsigned char c 0x1003
the compiler generates a single byte sized read at address 0x1003, this turns in to that specific instruction with that address and the processor generates the bus transaction to do that, the other side of the processor bus then does its job and so on down the line.
The compiler in general does not turn a packed version of that struct into a single 64 bit transaction that gives you all of the items, you burn a 64 bit bus transaction for each item.
it is possible that depending on the instruction set, prefetcher, caches and so on that instead of using a struct at a high level you create a single 64 bit integer and you do the work in the code, then you might or might not gain performance. This is not expected to perform better on most architectures running with caches and such, but when you get into embedded systems where you may have some number of wait states on the ram or some number of wait states on the flash or whatever code storage there is you can find times where instead of fewer instructions and more data transactions you want more instructions and fewer data transactions. code is linear a code section like this read, mask and shift, mask and shift, etc. the instruction storage may have a burst mode for linear transactions but data transactions take as many clocks as they take.
A middle ground is to just make everything a 32 bit variable or a 64 bit, then it is all aligned and performs relatively well at the cost of more memory used.
Because folks don't understand alignment, have been spoiled by x86 programming, choose to use structs across compile domains (such a bad idea), the ARMs and others are tolerating unaligned accesses, you can very much feel the performance hit on those platforms as they are so efficient if everything is aligned, but when you do something unaligned it just generates more bus transactions making everything take longer. So the older arms would fault by default, the arm7 could have the fault disabled but would rotate the data around the word (nice trick for swapping 16 bit values in a word) rather than spill over into the next word, later architectures default to not fault on aligned or most folks set them to not fault on aligned and they read/write the unaligned transfers as one would hope/expect.
For every x86 chip you have in your computer you have several if not handfuls of non-x86 processors in that same computer or peripherals hanging off that computer (mouse, keyboard, monitor, etc). A lot of those are 8-bit 8051s and z80s, but also a lot of them are arm based. So there is lots of non-x86 development going on not just all the phones and tablets main processors. Those others desire to be low cost and low power so more efficiency in the coding both in its bus performance so the clock can be slower but also a balance of code/data usage overall to reduce the cost of the flash/ram.
It is quite difficult to force these alignment issues on an x86 platform there is a lot of overhead to overcome its architectural issues. But you can see this on more efficient platforms. Its like a train vs a sports car, something falls off a train a person jumps off or on there is so much momentum its not noticed one bit, but step change the mass on the sports car and you will feel it. So trying to do this on an x86 you are going to have to work a lot harder if you can even figure out how to do it. But on other platforms its easier to see the effects. Unless you find an 8086 chip and I suspect you can feel the differences there, would have to pull out my manual to confirm.
If you are lucky enough to have access to chip sources/simulations then you can see this kind of thing happening all over the place and can really start to hand tune your program (for that platform). Likewise you can see what caching, write buffering, instruction prefetching in its various forms and so on do for overall performance and at times create parallel periods of time where other not-so-efficient transactions can hide, and or intentional spare cycles are created so that transactions that take extra time can have a time slice.

Related

Why must an int have a memory address that is divisible by four on most current architectures? [duplicate]

Admittedly I don't get it. Say you have a memory with a memory word of length of 1 byte. Why can't you access a 4 byte long variable in a single memory access on an unaligned address(i.e. not divisible by 4), as it's the case with aligned addresses?
The memory subsystem on a modern processor is restricted to accessing memory at the granularity and alignment of its word size; this is the case for a number of reasons.
Speed
Modern processors have multiple levels of cache memory that data must be pulled through; supporting single-byte reads would make the memory subsystem throughput tightly bound to the execution unit throughput (aka cpu-bound); this is all reminiscent of how PIO mode was surpassed by DMA for many of the same reasons in hard drives.
The CPU always reads at its word size (4 bytes on a 32-bit processor), so when you do an unaligned address access — on a processor that supports it — the processor is going to read multiple words. The CPU will read each word of memory that your requested address straddles. This causes an amplification of up to 2X the number of memory transactions required to access the requested data.
Because of this, it can very easily be slower to read two bytes than four. For example, say you have a struct in memory that looks like this:
struct mystruct {
char c; // one byte
int i; // four bytes
short s; // two bytes
}
On a 32-bit processor it would most likely be aligned like shown here:
The processor can read each of these members in one transaction.
Say you had a packed version of the struct, maybe from the network where it was packed for transmission efficiency; it might look something like this:
Reading the first byte is going to be the same.
When you ask the processor to give you 16 bits from 0x0005 it will have to read a word from 0x0004 and shift left 1 byte to place it in a 16-bit register; some extra work, but most can handle that in one cycle.
When you ask for 32 bits from 0x0001 you'll get a 2X amplification. The processor will read from 0x0000 into the result register and shift left 1 byte, then read again from 0x0004 into a temporary register, shift right 3 bytes, then OR it with the result register.
Range
For any given address space, if the architecture can assume that the 2 LSBs are always 0 (e.g., 32-bit machines) then it can access 4 times more memory (the 2 saved bits can represent 4 distinct states), or the same amount of memory with 2 bits for something like flags. Taking the 2 LSBs off of an address would give you a 4-byte alignment; also referred to as a stride of 4 bytes. Each time an address is incremented it is effectively incrementing bit 2, not bit 0, i.e., the last 2 bits will always continue to be 00.
This can even affect the physical design of the system. If the address bus needs 2 fewer bits, there can be 2 fewer pins on the CPU, and 2 fewer traces on the circuit board.
Atomicity
The CPU can operate on an aligned word of memory atomically, meaning that no other instruction can interrupt that operation. This is critical to the correct operation of many lock-free data structures and other concurrency paradigms.
Conclusion
The memory system of a processor is quite a bit more complex and involved than described here; a discussion on how an x86 processor actually addresses memory can help (many processors work similarly).
There are many more benefits to adhering to memory alignment that you can read at this IBM article.
A computer's primary use is to transform data. Modern memory architectures and technologies have been optimized over decades to facilitate getting more data, in, out, and between more and faster execution units–in a highly reliable way.
Bonus: Caches
Another alignment-for-performance that I alluded to previously is alignment on cache lines which are (for example, on some CPUs) 64B.
For more info on how much performance can be gained by leveraging caches, take a look at Gallery of Processor Cache Effects; from this question on cache-line sizes
Understanding of cache lines can be important for certain types of program optimizations. For example, the alignment of data may determine whether an operation touches one or two cache lines. As we saw in the example above, this can easily mean that in the misaligned case, the operation will be twice slower.
It's a limitation of many underlying processors. It can usually be worked around by doing 4 inefficient single byte fetches rather than one efficient word fetch, but many language specifiers decided it would be easier just to outlaw them and force everything to be aligned.
There is much more information in this link that the OP discovered.
you can with some processors (the nehalem can do this), but previously all memory access was aligned on a 64-bit (or 32-bit) line, because the bus is 64 bits wide, you had to fetch 64 bit at a time, and it was significantly easier to fetch these in aligned 'chunks' of 64 bits.
So, if you wanted to get a single byte, you fetched the 64-bit chunk and then masked off the bits you didn't want. Easy and fast if your byte was at the right end, but if it was in the middle of that 64-bit chunk, you'd have to mask off the unwanted bits and then shift the data over to the right place. Worse, if you wanted a 2 byte variable, but that was split across 2 chunks, then that required double the required memory accesses.
So, as everyone thinks memory is cheap, they just made the compiler align the data on the processor's chunk sizes so your code runs faster and more efficiently at the cost of wasted memory.
Fundamentally, the reason is because the memory bus has some specific length that is much, much smaller than the memory size.
So, the CPU reads out of the on-chip L1 cache, which is often 32KB these days. But the memory bus that connects the L1 cache to the CPU will have the vastly smaller width of the cache line size. This will be on the order of 128 bits.
So:
262,144 bits - size of memory
128 bits - size of bus
Misaligned accesses will occasionally overlap two cache lines, and this will require an entirely new cache read in order to obtain the data. It might even miss all the way out to the DRAM.
Furthermore, some part of the CPU will have to stand on its head to put together a single object out of these two different cache lines which each have a piece of the data. On one line, it will be in the very high order bits, in the other, the very low order bits.
There will be dedicated hardware fully integrated into the pipeline that handles moving aligned objects onto the necessary bits of the CPU data bus, but such hardware may be lacking for misaligned objects, because it probably makes more sense to use those transistors for speeding up correctly optimized programs.
In any case, the second memory read that is sometimes necessary would slow down the pipeline no matter how much special-purpose hardware was (hypothetically and foolishly) dedicated to patching up misaligned memory operations.
#joshperry has given an excellent answer to this question. In addition to his answer, I have some numbers that show graphically the effects which were described, especially the 2X amplification. Here's a link to a Google spreadsheet showing what the effect of different word alignments look like.
In addition here's a link to a Github gist with the code for the test.
The test code is adapted from the article written by Jonathan Rentzsch which #joshperry referenced. The tests were run on a Macbook Pro with a quad-core 2.8 GHz Intel Core i7 64-bit processor and 16GB of RAM.
If you have a 32bit data bus, the address bus address lines connected to the memory will start from A2, so only 32bit aligned addresses can be accessed in a single bus cycle.
So if a word spans an address alignment boundary - i.e. A0 for 16/32 bit data or A1 for 32 bit data are not zero, two bus cycles are required to obtain the data.
Some architectures/instruction sets do not support unaligned access and will generate an exception on such attempts, so compiler generated unaligned access code requires not just additional bus cycles, but additional instructions, making it even less efficient.
If a system with byte-addressable memory has a 32-bit-wide memory bus, that means there are effectively four byte-wide memory systems which are all wired to read or write the same address. An aligned 32-bit read will require information stored in the same address in all four memory systems, so all systems can supply data simultaneously. An unaligned 32-bit read would require some memory systems to return data from one address, and some to return data from the next higher address. Although there are some memory systems that are optimized to be able to fulfill such requests (in addition to their address, they effectively have a "plus one" signal which causes them to use an address one higher than specified) such a feature adds considerable cost and complexity to a memory system; most commodity memory systems simply cannot return portions of different 32-bit words at the same time.
On PowerPC you can load an integer from an odd address with no problems.
Sparc and I86 and (I think) Itatnium raise hardware exceptions when you try this.
One 32 bit load vs four 8 bit loads isnt going to make a lot of difference on most modern processors. Whether the data is already in cache or not will have a far greater effect.

Is 8-byte alignment for "double" type necessary?

I understand word-alignment, which makes the cpu only need to read once when reading an integer into a register.
But is 8-byte alignment (let's assume 32bit system) for "double" necessary? What is the benefit? What will happen if the space for storing a "double" is just 4-byte alignment?
There are multiple hardware components that may be adversely affected by unaligned loads or stores.
The interface to memory might be eight bytes wide and only able to access memory at multiples of eight bytes. Loading an unaligned eight-byte double then requires two reads on the bus. Stores are worse, because an aligned eight-byte store can simply write eight bytes to memory, but an unaligned eight-byte store must read two eight-byte pieces, merge the new data with the old data, and write two eight-byte pieces.
Cache lines are typically 32 or 64 bytes. If eight-byte objects are aligned to multiples of eight bytes, then each object is in just one cache line. If they are unaligned, then some of the objects are partly in one cache line and partly in another. Loading or storing these objects then requires using two cache lines instead of one. This effect occurs at all levels of cache (three levels is not uncommon in modern processors).
Memory system pages are typically 512 bytes or more. Again, each aligned object is in just one page, but some unaligned objects are in multiple pages. Each page that is accessed requires hardware resources: The virtual address must be translated to a physical address, this may require accessing translation tables, and address collisions must be detected. (Processors may have multiple load and store operations in operation simultaneously. Even though your program may appear to be single-threaded, the processor reads instructions in advance and tries to execute those that it can. So a processor may start a load instruction before preceding instructions have completed. However, to be sure this does not cause an error, the processor checks each load instruction to be sure it is not loading from an address that a prior store instruction is changing. If an access crosses a page boundary, the two parts of the loaded data have to be checked separately.)
The response of the system to unaligned operations varies from system to system. Some systems are designed to support only aligned accesses. In these cases, unaligned accesses either cause exceptions that lead to program termination or exceptions that cause execution of special handlers that emulate unaligned operations in software (by performing aligned operations and merging the data as necessary). Software handlers such as these are much slower than hardware operations.
Some systems support unaligned accesses, but this usually consumes more hardware resources than aligned accesses. In the best case, the hardware performs two operations instead of one. But some hardware is designed to start operations as if they were aligned and then, upon discovering the operation is not aligned, to abort it and start over using different paths in the hardware to handle the unaligned operation. In such systems, unaligned accesses have a significant performance penalty, although it is not as great as in systems where software handles unaligned accesses.
In some systems, the hardware may have multiple load-store execution units that can perform the two operations required of unaligned accesses just as quickly as one unit can perform the operation of aligned accesses. So there is no direct performance degradation of unaligned accesses. However, because multiple execution units are kept busy by unaligned accesses, they are unavailable to perform other operations. Thus, programs that perform many load-store operations, normally in parallel, will execute more slowly with unaligned accesses than with aligned accesses.
On many architectures, unaligned access of any load/store unit (short, int, long) is simply an exception. Compilers are responsible for ensuring it doesn't happen on potentially mis-aligned data, by emitting smaller access instructions and re-assembling in registers if they can't prove a given pointer is OK.
Performance-wise, 8-byte alignment of doubles on 32-bit systems can be valuable for a few reasons. The most apparent is that 4-byte alignment of an 8-byte double means that one element could cross the boundary of two cache lines. Memory access occurs in units of whole cache lines, and so misalignment doubles the cost of access.
I seem to remember that the recommendation for 486 was to align double on 32 bits boundaries, so requiring 64 bits alignment is not mandatory.
You seem to think that there is a relationship between the data bus width and the processor bitness. While it is often the case, you can find variation in both direction. For instance the Pentium was a 32-bit processor, but its data bus size was 64 bits.
Caches offer something else which may explain the usefulness of having 64-bit alignment for 64-bit types. Here the external bus is not a factor, it is the cache line size which is important. Data crossing the line cache is costlier to access than data not crossing it (even if it is unaligned in both cases). Aligning types on their size makes it sure that they won't cross cache lines as long as cache line size is a multiple of the type size.
I just found the answer:
"6. When memory reading is efficient in reading 4 bytes at a time on 32 bit machine, why should a double type be aligned on 8 byte boundary?
It is important to note that most of the processors will have math co-processor, called Floating Point Unit (FPU). Any floating point operation in the code will be translated into FPU instructions. The main processor is nothing to do with floating point execution. All this will be done behind the scenes.
As per standard, double type will occupy 8 bytes. And, every floating point operation performed in FPU will be of 64 bit length. Even float types will be promoted to 64 bit prior to execution.
The 64 bit length of FPU registers forces double type to be allocated on 8 byte boundary. I am assuming (I don’t have concrete information) in case of FPU operations, data fetch might be different, I mean the data bus, since it goes to FPU. Hence, the address decoding will be different for double types (which is expected to be on 8 byte boundary). It means, the address decoding circuits of floating point unit will not have last 3 pins."
Edited:
The advantage of byte alignment is to reduce the number of memory cycles to retrieve the data. For example, an 8 byte which might take a single cycle if it is aligned might now take 2 cycles since a part of it is obtained the first time and the second part in the next memory cycle.
I came across this:
"Aligned access is faster because the external bus to memory is not a single byte wide - it is typically 4 or 8 bytes wide (or even wider). So the CPU doesn't fetch a single byte at a time - it fetches 4 or 8 bytes starting at the requested address. Therefore, the 2 or 3 least significant bits of the memory address are not actually sent by the CPU - the external memory can only be read or written at addresses that are a multiple of the bus width. If you requested a byte at address "9", the CPU would actually ask the memory for the block of bytes beginning at address 8, and load the second one into your register (discarding the others).
This implies that a misaligned access can require two reads from memory: If you ask for 8 bytes beginning at address 9, the CPU must fetch the 8 bytes beginning at address 8 as well as the 8 bytes beginning at address 16, then mask out the bytes you wanted. On the other hand, if you ask for the 8 bytes beginning at address 8, then only a single fetch is needed. Some CPUs will not even perform such a misaligned load - they will simply raise an exception (or even silently load the wrong data!)."
You might see this link for more details.
http://www.ibm.com/developerworks/library/pa-dalign/

How does one access individual characters of a string properly aligned in memory, on ARM platform?

Since (from what I have read) ARM9 platform may fail to correctly load data at an unaligned memory address, let's assume unaligned meaning that the address value is not multiple of 2 (i.e. not aligned on 16-bit), then how would one access say, fourth character on a string of characters pointed to by a properly aligned pointer?
char buf[] = "Hello world.";
buf[3]; // (buf + 3) is unaligned here, is it not?
Does compiler generate extra code, as opposed to the case when buf + 3 is properly aligned? Or will the last statement in the example above have undesired results at runtime - yielding something else than the fourth character, the second l in Hello?
Byte accesses don't have to be aligned. The compiler will generate a ldrb instruction, which does not need any sort of alignment.
If you're curious as to why, this is because ARM will load the entire aligned word that contains the target byte, and then simply select that byte out of the four it just loaded.
The concept to remember is that the compiler will try to optimize access based on the type in order to get the most efficiency of your processor. So when accessing ints, it'll want to use things like the ldr instruction which will fault if it's an unaligned access. For something link a char access, the compiler will work some of the details for you. Where you have to be concerned are things like:
Casting pointers. If you cast a char * to an int * and the pointer is not aligned correctly, you'll get an alignment trap. In general, it's okay to cast down (from an int to a char), but not the other way around. You would not want to do this:
char buf[] = "12345678";
int *p = &buf[1];
printf("0x%08X\n", *p); // *p is badness here!
Trying to pull data off the wire with structures. I've seen this done a lot, and it's just plain bad practice. Endianess issues aside, you can cause an alignment trap if the elements aren't aligned correctly for the platform.
FWIW, casting pointers is probably the number one issue I've seen in practice.
There's a great book called Write Portable Code which goes over quite a few details about writing code for multiple platforms. The sample chapter on the linked site actually contains a section talking about alignment.
There's a little more that's going on too. Memory functions, like malloc, also give you back aligned blocks (generally on a double-word boundary) so that you can write in data and not hit an alignment fault.
One last bit, while newer ARMs can cope with unaligned accesses better, that does not mean they're performant. It just means they're tolerant. The same can be said for the X86 processors too. They'll do the unaligned access, but you're forcing extra memory fetches by doing so.
Most systems use byte based addressing. The address 0x1234 is in terms of bytes for example. Assume that I mean 8 bit bytes for this answer.
The definition of unaligned as to do with the size of the transfer. A 32 bit transfer for example is 4 bytes. 4 is 2 to the power 2 so if the lower 2 bits of the address are anything other than zeros then that address is an unaligned 32 bit transfer.
So using a table like this or just understanding powers of 2
8 1 0 []
16 2 1 [0]
32 4 2 [1:0]
64 8 3 [2:0]
128 16 4 [3:0]
the first column is the number of bits in the transfer. the second is the number of bytes that represents, the third is the number of bits at the bottom of the address that have to be zero to make it an aligned transfer, and the last column describes those bits.
It is not possible to have an unaligned 8 bit transfer. Not on arm, not on any system. Please understand that.
16 bit transfers. Once we get into transfers larger than 16 bits then you can START to talk about being unaligned. Then problem with unaligned transfers has to do with the number of bus cycles. Say you are doing 16 bit transfers on a system with a 16 bit wide bus and 16 bit wide memories. That means that we have items at memory at these addresses for example, address on left, data on right:
0x0100 : 0x1234
0x0102 : 0x5678
If you want to do a 16 bit transfer that is aligned the lsbit of your address must be zero, 0x100, 0x102, 0x104, etc. Unaligned transfers would be at addresses with the lsbit set, 0x101, 0x103, 0x105, etc. Why are they a problem? In this hypothetical (there were and are still real systems like this) system in order to get two bytes at address 0x0100 we only need to access the memory one time and take all 16 bits from that one address resulting in 0x1234. But if we want 16 bits starting at address 0x0101. We have to do two memory transactions 0x0100 and 0x0102 and take one byte from each combine those to get the result which little endian is 0x7812. That takes more clock cycles, more logic, etc. Inefficient and costly. Intel x86 and other systems from that era which were 8 or 16 bit processors but used 8 bit memory, everything larger than an 8 bit transfer was multiple clock cycles, instructions themselves took multiple clock cycles to execute before the next one could start, burning clock cycles and complication in the logic was not of interest (they saved themselves from pain in other ways).
The older arms may or may not have been from that era, but post acorn, the armv4 to the present is a 32 bit system from a perspective of the size of the general purpose registers, the data bus is 32 or 64 bits (the newest arms have 64 bit registers and I would assume if not already 128 bit busses) depending on your system. The core that put ARM on the map the ARM7TDMI which is an ARMv4T, I assume is a 32 bit data bus. The ARM7 and ARM9 ARM ARM (ARM Architectural Reference Manual) changed its language on each revision (I have several revisions going back to the paper only ones) with respect to words like UNPREDICTABLE RESULTS. When and where they would list something as bad or broken. Some of this was legal, understand ARM does not make chips, they sell IP, back then it was masks for a particular foundry today you get the source code to their core and you deal with it. So to survive you need a good legal defense, your secrets are exposed to customers, some of these items that were claimed not to be supported actually have deterministic results, if ARM were to find a clone (which is yet another legal discussion) with these unpredictable results being predictable and matching what arms logic does you have to be pretty good at explaining why. The clones have been crushed when they have tried (that or legally become licensed arm cores) so some of this is just interesting history. Another arm manual described quite clearly what happens when you do an unaligned transfer on the older ARM7 systems. And it is a bit of a duh moment when you see it, quite obvious what was going on (just plain keep it simple stupid logic).
The byte lanes rotated. On a 32 bit bus somewhere in the system, likely not on the amba/axi bus but inside the memory controller you would effectively get this:
0x0100 : 0x12345678
0x0101 : 0x78123456
0x0102 : 0x56781234
0x0103 : 0x34567812
address on the left resulting data on the right. Now why is that obvious you ask and what is the size of that transfer? The size of the transfer is irrelevant, doesnt matter, look at that address/data this way:
0x0100 : 0x12345678
0x0101 : 0xxx123456
0x0102 : 0xxxxx1234
0x0103 : 0xxxxxxx12
Using aligned transfers, 0x0100 is legal for 32, 16, and 8 bit and look at the lower 8, 16, or 32 bits you get the right answer with the data as shown. For address 0x0101 only an 8 bit transfer is legal, and the lower 8 bits of that data is in the lower 8 bits, just copy those over to the registers lower 8 bits. for address 0x0102 8 and 16 are legal, unaligned, transfers and 0x1234 is the right answer for 16 bit and 0x34 for 8. lastly 0x0103 8 bit is the only transfer size without alignment issues and 0x12 is the right answer.
This above information is all from publicly available documents, no secrets here or special insider knowledge, just generic programming experience.
ARM put an exception in, data abort or prefetch abort (thumb is a separate topic) to discourage the use of unaligned transfers as do other architectures. Unfortunately x86 has lead people to be very lazy and also not care about the performance hit that they incur when doing such a thing on an x86, which allows the transfer at the price of extra cycles and extra logic. The prefetch abort if I remember was not on by default on the ARM7 platforms I used, but was on by default on the ARM9 platforms I used, my memory could be wrong and since I dont know how the defaults worked that could have been a strap option on the core so it could have varied from chip to chip, vendor to vendor. You could disable it and do unaligned transfers so long as you understood what happened with the data (rotate not spill over into the next word).
More modern ARM processors do support unaligned transfers and they are as one would expect, I wont use 64 bit examples here to save typing and space but go back to that 16 bit example to paint the picture
0x0100: 0x1234
0x0102: 0x5678
With a 16 bit wide system, memory and bus, little endian, if you did a 16 bit unaligned transfer at address 0x0101 you would expect to see 0x7812 and that is what you get now on the modern arm systems. But it is still a software controlled feature, you can enable exceptions on unaligned transfers and you will get a data abort instead of a completed transfer.
As far as your question goes look at the ldrb instruction, that instruction does an 8 bit read from memory, being 8 bit there is no such thing as unaligned all addresses are valid, if buf[] happened to live at address 0x1234 then buf[3] is at address 0x1237 and that is a perfectly valid address for an 8 bit read. No alignment issues of any kind, no exceptions will fire. Where you would get into trouble is if you do one of these very ugly programming hacks:
char buf[]="hello world";
short *sptr;
int *iptr;
sptr=(short *)&buf[3];
iptr=(int *)&buf[3];
...
something=*sptr;
something=*iptr;
...
short_something=*(short *)&buf[3];
int_something=*(int *)&buf[3];
And then yes you would need to worry about unaligned transfers as well as hoping that you dont have any compiler optimization issues making the code not work as you had thought it would. +1 to jszakmeister for already covering this sub topic.
short answer:
char buf[]="hello world";
char is generally assumed to mean an 8 bit byte so this is a quantity of 8 bit items. certainly compiled for ARM that is what you will get (or mips or x86 or power pc, etc). So accessing buf[X] for any X within that string, cannot be unaligned because
something = buf[X];
Is an 8 bit transfer and you cant have unaligned 8 bit transfers. If you were to do this
short buf[]={1,2,1,2,3,2,1};
short is assumed but not always the case, to be 16, bit, for the arm compilers I know it is 16 bit. but that doesnt matter buf[X] here also cannot be unaligned because the compiler computes the offset for you. As follows address of buf[X] is base_address_of_buf + (X<<1). And the compiler and/or linker will insure, on ARM, MIPS, and other systems that buf is placed on a 16 bit aligned address so that math will always result in an aligned address.

CPU and Data alignment

Pardon me if you feel this has been answered numerous times, but I need answers to the following queries!
Why data has to be aligned (on 2-byte / 4-byte / 8-byte boundaries)? Here my doubt is when the CPU has address lines Ax Ax-1 Ax-2 ... A2 A1 A0 then it is quite possible to address the memory locations sequentially. So why there is the need to align the data at specific boundaries?
How to find the alignment requirements when I am compiling my code and generating the executable?
If for e.g the data alignment is 4-byte boundary, does that mean each consecutive byte is located at modulo 4 offsets? My doubt is if data is 4-byte aligned does that mean that if a byte is at 1004 then the next byte is at 1008 (or at 1005)?
CPUs are word oriented, not byte oriented. In a simple CPU, memory is generally configured to return one word (32bits, 64bits, etc) per address strobe, where the bottom two (or more) address lines are generally don't-care bits.
Intel CPUs can perform accesses on non-word boundries for many instructions, however there is a performance penalty as internally the CPU performs two memory accesses and a math operation to load one word. If you are doing byte reads, no alignment applies.
Some CPUs (ARM, or Intel SSE instructions) require aligned memory and have undefined operation when doing unaligned accesses (or throw an exception). They save significant silicon space by not implementing the much more complicated load/store subsystem.
Alignment depends on the CPU word size (16, 32, 64bit) or in the case of SSE the SSE register size (128 bits).
For your last question, if you are loading a single data byte at a time there is no alignment restriction on most CPUs (some DSPs don't have byte level instructions, but its likely you won't run into one).
Very little data "has" to be aligned. It's more that certain types of data may perform better or certain cpu operations require a certain data alignment.
First of all, let's say you're reading 4 bytes of data at a time. Let's also say that your CPU has a 32 bit data buss. Let's also say your data is stored at byte 2 in the system memory.
Now since you can load 4 bytes of data at once, it doesn't make too much sense to have your Address register to point to a single byte. By making your address register point to every 4 bytes you can manipulate 4 times the data. So in other words your CPU may only be able to read data starting at bytes 0, 4, 8, 12, 16, etc.
So here's the issue. If you want the data starting at byte 2 and you're reading 4 bytes, then half your data will be in address position 0 and the other half in position 1.
So basically you'd end up hitting the memory twice to read your one 4 byte data element. Some CPUs don't support this sort of operation (or force you to load and combine the two results manually).
Go here for more details: http://en.wikipedia.org/wiki/Data_structure_alignment
1.) Some architectures do not have this requirement at all, some encourage alignment (there is a speed penalty when accessing non-alignet data items), and some may enforce it strictly (misaligment causes a processor exception).
Many of todays popular architectures fall in the speed penalty category. The CPU designers had to make a trade between flexibility/performance and cost (silicon area/number of control signals required for bus cycles).
2.) What language, which architecture? Consult your compilers manual and/or the CPU architecture documentation.
3.) Again this is totally architecture dependent (some architectures may not permit access on byte-sized items at all, or have bus widths which are not even a multiple of 8 bits). So unless you are asking about a specific architecture you wont get any useful answers.
In general, the one answer to all three of those questions is "it depends on your system". Some more details:
Your memory system might not be byte-addressable. Besides that, you might incur a performance penalty to have your processor access unaligned data. Some processors (like older ARM chips, for example) just can't do it at all.
Read the manual for your processor and whatever ABI specification your code is being generated for,
Usually when people refer to data being at a certain alignment, it refers only to the first byte. So if the ABI spec said "data structure X must be 4-byte aligned", it means that X should be placed in memory at an address that's divisible by 4. Nothing is implied by that statment about the size or internal layout of structure X.
As far as your particular example goes, if the data is 4-byte aligned starting at address 1004, the next byte will be at 1005.
Its completely depends on the CPU you are using!
Some architectures deal only in 32 (or 36!) bit words and you need special instructions to load singel characters or haalf words.
Some cpus (notably PowerPC and other IBM risc chips) dont care about alignments and will load integers from odd addresses.
For most modern architectures you need to align integers to word boundies and long integers to double word boundries. This simplifies the circutry for loading registers and speeds things up ever so slighly.
Data alignment is required by CPU for performance reason. Intel website give out the detail on how to align the data in the memory
Data Alignment when Migrating to 64-Bit Intel® Architecture
One of these is the alignment of data items – their location in memory in relation to addresses that are multiples of four, eight or 16 bytes. Under the 16-bit Intel architecture, data alignment had little effect on performance, and its use was entirely optional. Under IA-32, aligning data correctly can be an important optimization, although its use is still optional with a very few exceptions, where correct alignment is mandatory. The 64-bit environment, however, imposes more-stringent requirements on data items. Misaligned objects cause program exceptions. For an item to be aligned properly, it must fulfill the requirements imposed by 64-bit Intel architecture (discussed shortly), plus those of the linker used to build the application.
The fundamental rule of data alignment is that the safest (and most widely supported) approach relies on what Intel terms "the natural boundaries." Those are the ones that occur when you round up the size of a data item to the next largest size of two, four, eight or 16 bytes. For example, a 10-byte float should be aligned on a 16-byte address, whereas 64-bit integers should be aligned to an eight-byte address. Because this is a 64-bit architecture, pointer sizes are all eight bytes wide, and so they too should align on eight-byte boundaries.
It is recommended that all structures larger than 16 bytes align on 16-byte boundaries. In general, for the best performance, align data as follows:
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
A 64-byte or greater data structure or array should be aligned so that its base address is a multiple of 64. Sorting data in decreasing size order is one heuristic for assisting with natural alignment. As long as 16-byte boundaries (and cache lines) are never crossed, natural alignment is not strictly necessary, although it is an easy way to enforce adherence to general alignment recommendations.
Aligning data correctly within structures can cause data bloat (due to the padding necessary to place fields correctly), so where necessary and possible, it is useful to reorganize structures so that fields that require the widest alignment are first in the structure. More on solving this problem appears in the article "Preparing Code for the IA-64 Architecture (Code Clean)."
For Intel Architecture, Chapter 4 DATA TYPES of Intel 64 and IA-32 Architectures Software Developer’s Manual answers your question 1.

Memory alignment on modern processors?

I often see code such as the following when, e.g., representing a large bitmap in memory:
size_t width = 1280;
size_t height = 800;
size_t bytesPerPixel = 3;
size_t bytewidth = ((width * bytesPerPixel) + 3) & ~3; /* Aligned to 4 bytes */
uint8_t *pixelData = malloc(bytewidth * height);
(that is, a bitmap allocated as a contiguous block of memory having a bytewidth aligned to a certain number of bytes, most commonly 4.)
A point on the image is then given via:
pixelData + (bytewidth * y) + (bytesPerPixel * x)
This leads me to two questions:
Does aligning a buffer like this have a performance impact on modern processors? Should I be worrying about alignment at all, or will the compiler handle this?
If it does have an impact, could someone point me to a resource to find the ideal byte alignment for various processors?
Thanks.
It depends on a lot of factors. If you're only accessing the pixel data one byte at a time, the alignment will not make any difference the vast majority of the time. For reading/writing one byte of data, most processors won't care at all whether that byte is on a 4-byte boundary or not.
However, if you're accessing data in units larger than a byte (say, in 2-byte or 4-byte units), then you will definitely see alignment effects. For some processors (e.g. many RISC processors), it is outright illegal to access unaligned data on certain levels: attempting to read a 4-byte word from an address that's not 4-byte aligned will generate a Data Access Exception (or Data Storage Exception) on a PowerPC, for example.
On other processors (e.g. x86), accessing unaligned addresses is permitted, but it often comes with a hidden performance penalty. Memory loads/stores are often implemented in microcode, and the microcode will detect the unaligned access. Normally, the microcode will fetch the proper 4-byte quantity from memory, but if it's not aligned, it will have to fetch two 4-byte locations from memory and reconstruct the desired 4-byte quantity from the appropriate bytes of the two locations. Fetching two memory locations is obviously slower than one.
That's just for simple loads and stores, though. Some instructions, such as those in the MMX or SSE instruction sets, require their memory operands to be properly aligned. If you attempt to access unaligned memory using those special instructions, you'll see something like an illegal instruction exception.
To summarize, I wouldn't really worry too much about alignment unless you're writing super performance-critical code (e.g. in assembly). The compiler helps you out a lot, e.g. by padding structures so that 4-byte quantities are aligned on 4-byte boundaries, and on x86, the CPU also helps you out when dealing with unaligned accesses. Since the pixel data you're dealing with is in quantities of 3 bytes, you'll almost always being doing single byte accesses anyways.
If you decide you instead want to access pixels in singular 4-byte accesses (as opposed to 3 1-byte accesses), it would be better to use 32-bit pixels and have each individual pixel aligned on a 4-byte boundary. Aligning each row to a 4-byte boundary but not each pixel will have little, if any, effect.
Based on your code, I'm guessing it's related to reading the Windows bitmap file format -- bitmap files require the length of each scanline to be a multiple of 4 bytes, so setting up your pixel data buffers with that property has the property that you can just read in the entire bitmap in one fell swoop into your buffer (of course, you still have to deal with the fact that the scanlines are stored bottom-to-top instead of top-to-bottom and that the pixel data is BGR instead of RGB). This isn't really much of an advantage, though -- it's not that much harder to read in the bitmap one scanline at a time.
Yes, alignment does have a performance impact on modern-- let's say x86--processors. Generally, loads and stores of data happen on natural alignment boundaries; if you're getting a 32-bit value into a register, it's going to be fastest if it's aligned on a 32-bit boundary already. If it's not, the x86 will "take care of it for you", in the sense that the CPU will still do the load, but it will take a significantly larger number of cycles to do it, because there will be internal wrangling to "re-align" the access.
Of course, in most cases, this overhead is trivial. Structures of binary data are frequently packed together in unaligned ways for transport over the network or for persistence on disk, and the size benefits of the packed storage outweigh any perf hit from operating occasionally on this data.
But particularly with large buffers of uniform data that get accessed randomly and where performance in the aggregate really is important, as in your pixel buffer above, keeping data structures aligned can still be beneficial.
Note that in the case of the example you give above, only each "line" of pixel data is aligned. The pixels themselves are still 3 bytes long and often unaligned within the "lines", so there's not much benefit here. There are texture formats, for example, that have 3 bytes of real data per pixel, and literally just waste an extra byte on each one to keep the data aligned.
There's some more general information here: http://en.wikipedia.org/wiki/Data_structure_alignment
(The specific characteristics vary between architectures, both in what the natural alignments are, whether the CPU handles unaligned loads/stores automatically, and in how expensive those end up being. In cases where the CPU doesn't handle access magically, often the compiler/C runtime will do what it can to do this work for you.)
Buffer alignment has an impact. The question is: is it a significant impact? The answer can be highly application specific. In architectures which do not natively support unaligned access—for example, the 68000 and 68010 (the 68020 adds unaligned access)—it's truly a performance and/or maintenance problem since the CPU will fault, or maybe trap to a handler to perform unaligned access.
The ideal alignment for various processors can be estimated: 4-byte alignment is appropriate for architectures with a 32-bit data path. 8-byte alignment for 64-bit. However, L1 caching has an effect. For many CPUs this is 64 bytes though it will no doubt change in the future.
Too high of an alignment (that is, eight byte where only two byte is needed) causes no performance inefficiency for any narrower system, even on an 8-bit microcontroller. It simply wastes (potentially) a few bytes of storage.
Your example is rather peculiar: the 3-byte elements have a 50% chance of individually being unaligned (to 32 bits), so aligning the buffer seems pointless—at least for performance reasons. However, in the case of a bulk transfer of the whole thing, it optimizes the first access. Note that an unaligned first byte might also have a performance impact in the transfer to a video controller.
Does aligning a buffer like this have a performance impact on modern processors?
Yes. For instance if memcpy is optimized using SIMD instructions (like MMX/SSE) some operations will be faster with aligned memory. In some architectures there are (processor) instructions that fail if the data is not aligned, thus something might work on your machine but not in another one.
With aligned data you also make a better use of the CPU caches.
Should I be worrying about alignment at all, or will the compiler handle this?
I should worry about alignment when I use dynamic memory and the compiler cannot handle this (see the reply to this comment).
For other stuff in your code you have the -malign flag and aligned attribute to play with.

Resources