Skip to main content
GameDev.net gamedev.net
🔒 Locked

Memory Alignment

Started by TonyFish Apr 29, 2004 at 4:24 PM 12 replies 1k views
Original Post
TonyFish
TonyFish
Hi, I''ve been reading up on memory alignment as a further optimisation and was wondering how I could test the performance increase in changing this struct: struct Test { char c ; __int64 d ; int b ; char a ; }; to this: struct Test { __int64 d ; int b ; char a ; char c; char unused[2]; }; I did something with a for loop and a high-res timer but nothing particularly conclusive came of it. Also I was wondering if aligning to 4bytes is still appropriate? Cheers
<Fish>{
nonpop
nonpop
quote:
nothing particularly conclusive came of it

What does that mean exactly?

Anyway, my guess is that your compiler already padded your structure in an appropriate way and thus you won''t see much difference.
bytecoder
bytecoder
Usually compilers will pad structures for you, so the only noticable benifit of doing largest-smallest order is that you might save some space.
quote:

Also I was wondering if aligning to 4bytes is still appropriate?


If you allocate the structure on the stack it WILL be padded to 4 bytes; the stack on a PC, which I assume you''re using, has to be alligned on a 4 byte boundary. I''m not sure whether things have to be alligned on a 4 byte boundary if you allocate it on the heap; it''s probably operating system dependant.
Thoooms
Thoooms
Many x86 based machines only have a 30 bit address bus, they therefore set the granularity of the addresses to 32 bit. For example, if you want two bytes straddling a 4 byte boundary you have to fetch eight bytes, of which you only use the last byte of the first four and the first one of the last four. This is ofcourse slower than fetching four bytes once.

[edited by - thoooms on April 29, 2004 6:14:02 PM]
Namethatnobodyelsetook
Namethatnobodyelsetook
SSE gets performance gains when data is aligned to 16 bytes... but the instructions must know before hand that you are aligning... it''s a seperate instruction to read aligned vs. unaligned data.
LizardCPP
LizardCPP
What exactly is "memory alignment", I have seen it mentioned sometimes, but I don''t know ecaxtly what it is?

LizardCPP
Namethatnobodyelsetook
Namethatnobodyelsetook
It means the address can be divided by the alignment without a fraction.

For 4 byte alignment, addresses that are fine would be: 0, 4, 8, 12, 16, ... 1020, 1024, 1028, ... 65536, 65540, etc.

For 16 byte alignment, addresses that are fine would be: 0, 16, 32, 48, 64, .... 1008, 1024, 1040, ..., 65536, 65552, etc.

The reason, as mentioned above, is because of how the memory bus works. In order for most 32bit CPUs to read a 32 bit number at address 1, 2, or 3 the CPU needs to read a DWORD at 0, and a DWORD at 4, and take the appropriate parts of each. This double fetch is naturally slower than just a single fetch.
nonpop
nonpop
quote:
Original post by OrangyTang
Usually there are compiler settings for optimising for speed or size, and using the speed setting will probably get you the padding done for you. See if you can tinker with those and redo the tests.

At least VC supports a #pragma directive which allows you to change struct alignment; something like #pragma (pack: 1) will remove all padding. I very much believe many other compilers can do this, too. In some way or another.
Tachikoma
Tachikoma
If you''re using Visual C++ use these (Note: You''ll need the latest processor pack if you use Visual C++ 6.0):

# define CACHE_ALIGN_8 __declspec(align( 8)) //Alignment on the 8-byte boundary

# define CACHE_ALIGN_16 __declspec(align(16)) //Alignment on the 16-byte boundary

# define CACHE_ALIGN_32 __declspec(align(32)) //Alignment on the 32-byte boundary

# define CACHE_ALIGN_64 __declspec(align(64)) //Alignment on the 64-byte boundary



To align the entire Test structure at 64-byte boundaries, do this:


struct Test
{
__int64 d ;
int b ;
char a ;
char c;
char unused[2];
};

//The MyTest structure will be aligned at the nearest 64-byte boundary

CACHE_ALIGN_64 Test MyTest;


To align only certain data members at byte boundaries in your Test structure, do this:


struct Test
{
CACHE_ALIGN_64 __int64 d ; //This data member will be aliganed the nearest 64-byte boundary

CACHE_ALIGN_32 int b ; //This data member will be aliganed the nearest 32-byte boundary

char a ;
char c;
CACHE_ALIGN_16 char unused[2]; //This data member will be aliganed the nearest 16-byte boundary

};

Test MyTest;
TonyFish
TonyFish
yeah I forgot to mention that I was using
#pragma pack(push,1)
blahlbahlblah
#pragma pack(pop)
<Fish>{
nonpop
nonpop
If that''s the case you could finally explain this:
quote:
I did something with a for loop and a high-res timer but nothing particularly conclusive came of it.

How did you test and what were the results?
TonyFish
TonyFish
I tested the various forms of the struct using a high-res timer. I basically created an array of structs and looped through at setting values. Basically there was veryvery little difference in the times. Obviously the test loop was crap. Can you think of something better?
<Fish>{
Tachikoma
Tachikoma
Alinging data is only useful if:

- You use SSE assembly wich requires data to be alinged at cache boundaries.

- When you process a large array of data, such as image manipulation, etc. Accessing such data at cache boundaries reduces stalls due chache thrashing, etc.

Other than that, there is no need to align data as it will not make a big difference in terms of performace. Most of aligning is taken care by the compiler anyway. For example, 1 byte char data members in a struct is expanded to align at 4-byte boundaries.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.