Page 1 of 1

How to align memory?

Posted: Fri Oct 08, 2010 7:41 am
by Mistrel
I've been having some unexpected memory access violations with InterlockedCompareExchange. I believe this is due to memory alignment, according to MSDN:
The parameters for this function must be aligned on a 32-bit boundary; otherwise, the function will behave unpredictably on multiprocessor x86 systems and any non-x86 systems. See _aligned_malloc.
I've been looking at pcfreak's code as a solution:

http://www.purebasic.fr/english/viewtop ... 12&t=41127

However, if I want to align a long on a 32-bit system, what do I specify for the alignment in bytes? Also, what would I specify for an integer on a 64-bit system? I don't follow exactly how alignment works.

Re: How to align memory?

Posted: Fri Oct 08, 2010 8:59 am
by Thorium
4 byte

Alignment means the memory address is devidable by a fixed number.
Alignment is for performance. A memory access is fastest if the address is alignt to a number equal to the datatyp size that will be accessed. So if you access a long memory should be alignt to 4 byte = 32bit.
You also can align code, which can speed up
loops. For code you should use the native register size for alignment.

Re: How to align memory?

Posted: Fri Oct 08, 2010 9:18 am
by Mistrel
Is it still 4 bytes for 64-bit?

Re: How to align memory?

Posted: Fri Oct 08, 2010 11:07 am
by inc.
64bit -> 8 Byte alignment.
Some instructions even do expect 16 byte alignment (128bit)

Code: Select all

Procedure AllocateMemoryAligned(size.l)
  Protected diff.l, *ptr.Long = #Null
  If size > ($7FFFFFFF-16) 
    ProcedureReturn #Null
  EndIf 
  *ptr = AllocateMemory(size+16)
  If Not *ptr
    ProcedureReturn *ptr
  EndIf 
  diff = ((-*ptr - 1)&15) + 1
  *ptr = *ptr + diff;
  PokeB(*ptr-1, diff)
  ProcedureReturn *ptr
EndProcedure

Procedure FreememoryAligned(*ptr)
  If *ptr
    FreeMemory(*ptr - PeekB(*ptr-1))
  EndIf 
EndProcedure

Procedure ReAllocateMemoryAligned(*ptr, size.l)
  Protected diff.l
  If size > ($7FFFFFFF-16) 
    ProcedureReturn #Null
  EndIf
  If Not *ptr
    ProcedureReturn AllocateMemoryAligned(size.l)
  EndIf
  diff = PeekB(*ptr-1)
  ProcedureReturn ReAllocateMemory(*ptr-diff, size+diff)+diff
EndProcedure

Procedure zeroAllocateMemoryAligned(size.l)
  Protected *ptr = AllocateMemoryAligned(size)
  Protected *ptr_b.Byte = *ptr
  Protected *ptr_l.Long = *ptr
  Protected *ptr_end = *ptr+size
  If *ptr
    If Not size%4 ; size gots a 32Bit boundary?
      While *ptr_l < *ptr_end
        *ptr_l\l = 0
        *ptr_l+4
      Wend
    Else
      While *ptr_b < *ptr_end
        *ptr_b\b = 0
        *ptr_b+1
      Wend
    EndIf 
    ProcedureReturn *ptr
  EndIf
EndProcedure

test = zeroAllocateMemoryAligned(1024)

Debug test

FreememoryAligned(test)

Re: How to align memory?

Posted: Fri Oct 08, 2010 11:10 am
by Mistrel
So alignment according to the register size is literally the number of bytes in the total bits supported by the processor?

16-bit is 2 bytes, 32-bit 4 bytes, 64-bit is 8 bytes?

Re: How to align memory?

Posted: Fri Oct 08, 2010 1:16 pm
by cas
Isn't already all memory that AllocateMemory returns aligned? We need to worry about alignment only when we deal with pointers math (for example: *mem+k in loop will not be aligned always). Here on 64bit OS everything is aligned to 64bit boundary so there should be no problem with that function that needs memory to be aligned to 32bit boundary.

Code: Select all

EnableExplicit
DisableDebugger
Define k,count,*mem
For k=0 To 1000000
  *mem=AllocateMemory(20+Random(20))
  If *mem%8<>0 ;check if it is not aligned to 64bit boundary
    count+1
  EndIf
  ;FreeMemory(*mem) ;don't free memory!
Next
EnableDebugger
Debug count

Re: How to align memory?

Posted: Fri Oct 08, 2010 6:32 pm
by Thorium
Mistrel wrote:So alignment according to the register size is literally the number of bytes in the total bits supported by the processor?

16-bit is 2 bytes, 32-bit 4 bytes, 64-bit is 8 bytes?
No.
It's as i wrote. The size of the datatyp you want to access is what tells you the best alignment.

word = 2 byte
long = 4 byte
quad = 8 byte
integer = sizeof(integer)

The 16 byte alignment is to load xmm registers, they are 128bit big, so it's a long quad or what ever you call a 16 byte number.

This is according to Intels optimization guide.

Re: How to align memory?

Posted: Sat Oct 09, 2010 2:20 am
by Mistrel
Thorium wrote:The size of the datatype you want to access is what tells you the best alignment.
Would you give an example of how this would apply to a structure which uses several differently sized data types? I've never understood where padding should be applied and why.

Re: How to align memory?

Posted: Sat Oct 09, 2010 8:05 am
by Thorium
In a structure you can simply add alignment bytes.

Code: Select all

Structure TestAlign
  Blub.b

  ;Blub brackes the alignment as its only 1 byte big

  Align1[3].b

  ;we just insert a byte array with 3 elements to get the 4 byte alignment for the next structure element

  Bla.l
EndStructure

Re: How to align memory?

Posted: Sat Oct 09, 2010 8:48 am
by Mistrel
Is this correct?

Code: Select all

Structure Test
  A.w
  B.b
  C.b ; <- no alignment needed?
  ..[3].b
  D.l
  ..[4].b ; <- should be aligned for 8 bytes?
  E.q
  F.b
  ..[7].b ; <- should be aligned for 8 bytes?
  G.q
EndStructure
Also, why is alignment so important for 64-bit compiling but didn't seem to be an issue with 32-bit?

Wikipedia also mentions:
It is important to note that the last member is padded with the number of bytes required that the total size of the structure should be a least common multiple of the size of a largest structure member.
Does this apply to PureBasic as well?

Re: How to align memory?

Posted: Sat Oct 09, 2010 11:10 am
by Thorium
Mistrel wrote:Is this correct?

Code: Select all

Structure Test
  A.w
  B.b
  C.b ; <- no alignment needed? correct
  ..[3].b ;this is not needed, it's allready aligned to 4 bytes. A2 + B1 + C1 = 4  
  D.l
  ..[4].b ; <- should be aligned for 8 bytes? Yes but thats only needed on x64 or if you use mmx registers on x86
  E.q
  F.b
  ..[7].b ; <- should be aligned for 8 bytes? correct, but same as E
  G.q
EndStructure
Also, why is alignment so important for 64-bit compiling but didn't seem to be an issue with 32-bit?
It isnt important. It's just for performance and intel improved misaligned memory accesses a lot with the Core i7 and is still improving them, dont know how things are on AMD.
Mistrel wrote: Wikipedia also mentions:
It is important to note that the last member is padded with the number of bytes required that the total size of the structure should be a least common multiple of the size of a largest structure member.
For my understanding, that text does not make any sense.
A structure doesnt need to have a size padding. However it could improve performance of structure copieing. But it is not important at all. Except if a API function or lib specificaly askes for a size padding or alignment. Code can be written in a way it will only work with aligned data. Thats only do gain some performance.

Re: How to align memory?

Posted: Sat Oct 09, 2010 11:50 am
by Mistrel
I encounter a lot of posts regarding padding and Win32 structures, such as this:

http://www.purebasic.fr/english/viewtop ... 32#p288332

Is this more of a requirement of programming with Win32 on a 64-bit processor rather than a restriction imposed by the architecture itself?

Re: How to align memory?

Posted: Sat Oct 09, 2010 12:28 pm
by Thorium
Mistrel wrote: Is this more of a requirement of programming with Win32 on a 64-bit processor rather than a restriction imposed by the architecture itself?
There is no restriction on the CPU, there are even special instructions to load xmm registers with unaligned data. So even SSE2 dont needs a 16 byte alignment, but it's faster if it is alignt.

This is a specification of the WinAPI, not only for 64bit, it applies to 32bit as well: http://msdn.microsoft.com/en-us/library/aa296569.aspx

And it seems to be a C specification.

Re: How to align memory?

Posted: Sat Oct 30, 2010 12:14 am
by djes
Thorium wrote:There is no restriction on the CPU, there are even special instructions to load xmm registers with unaligned data. So even SSE2 dont needs a 16 byte alignment, but it's faster if it is alignt.
movups permits unaligned data, but try addps after that, and you realize that you still need aligned datas. :x