Recent

Author Topic: GetMem default aligment  (Read 368 times)

LemonParty

  • Hero Member
  • *****
  • Posts: 534
GetMem default aligment
« on: June 01, 2026, 02:48:35 pm »
I detected that default aligment of GetMem pointers is 8.
Is this a constant behavior or this can vary depending on compiler version?
Is there a way to get a pointer with specific aligment, for example 16 or 32?
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

Thaddy

  • Hero Member
  • *****
  • Posts: 19268
  • Glad to be alive.
Re: GetMem default aligment
« Reply #1 on: June 01, 2026, 03:09:10 pm »
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2. {$codealign varmin=16}
  3. {$codealign varmax=16}
  4. {$assertions on}
  5. var
  6.   test1,test2,test3:PInteger;
  7. begin
  8.   test1 := AllocMem(100);
  9.   Assert(NativeUint(test1) mod 16 = 0,'Alignment not 16');
  10.   test2 := AllocMem(100);
  11.   Assert(NativeUint(test2) mod 16 = 0,'Alignment not 16');
  12.   test3 := AllocMem(100);
  13.   Assert(NativeUint(test3) mod 16 = 0,'Alignment not 16');
  14.   Freemem(test1);
  15.   Freemem(test2);
  16.   Freemem(test3);
  17. end.
See the documentation: https://www.freepascal.org/docs-html/prog/progsu9.html

Also tested with 32.

« Last Edit: June 01, 2026, 03:19:40 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

Zvoni

  • Hero Member
  • *****
  • Posts: 3398
Re: GetMem default aligment
« Reply #2 on: June 01, 2026, 03:18:41 pm »
is
{$codealign varmax=16}
really necessary?
acc. to the docs it's only meaningful if smaller than "natural" alignment
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

LemonParty

  • Hero Member
  • *****
  • Posts: 534
Re: GetMem default aligment
« Reply #3 on: June 01, 2026, 03:24:58 pm »
Thank you for answer.
I think documentation is not quite clear. It doesn't say that this directive affects the pointers.
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

Thaddy

  • Hero Member
  • *****
  • Posts: 19268
  • Glad to be alive.
Re: GetMem default aligment
« Reply #4 on: June 01, 2026, 03:35:53 pm »
For 16 alignment my assumptions are correct, but 32 seems to fail on some platforms.
Which means that 32 align may not be supported, even in trunk:
Code: Pascal  [Select][+][-]
  1. {$mode objfpc}
  2. {$assertions on}
  3. {$codealign varmin=32}
  4. {$codealign varmax=32}
  5. const
  6.   N = 100000;
  7. var
  8.   ptrs: array of Pointer;
  9.   i: Integer;
  10.   r16, r32: NativeUInt;
  11.   bad16, bad32: Integer;
  12.   minAddr, maxAddr: NativeUInt;
  13. begin
  14.   SetLength(ptrs, N);
  15.   bad16 := 0;
  16.   bad32 := 0;
  17.   minAddr := High(NativeUInt);
  18.   maxAddr := 0;
  19.  
  20.   for i := 0 to N - 1 do
  21.   begin
  22.     ptrs[i] := AllocMem(100);
  23.     r16 := NativeUInt(ptrs[i]) mod 16;
  24.     r32 := NativeUInt(ptrs[i]) mod 32;
  25.     if r16 <> 0 then Inc(bad16);
  26.     if r32 <> 0 then Inc(bad32);
  27.     if NativeUInt(ptrs[i]) < minAddr then minAddr := NativeUInt(ptrs[i]);
  28.     if NativeUInt(ptrs[i]) > maxAddr then maxAddr := NativeUInt(ptrs[i]);
  29.   end;
  30.  
  31.   Writeln('allocations=', N);
  32.   Writeln('bad16=', bad16);
  33.   Writeln('bad32=', bad32);
  34.   Writeln('min=', minAddr);
  35.   Writeln('max=', maxAddr);
  36.  
  37.   Assert(bad16 = 0, 'Some allocations were not 16-byte aligned');
  38.   Assert(bad32 = 0, 'Some allocations were not 32-byte aligned');
  39.  
  40.   for i := 0 to N - 1 do
  41.     FreeMem(ptrs[i]);
  42. end.

I think I have to re-run my example code with other alignment settings. It may very well be that the alignment for getmem and allocmem depends on platform and e.g. 32/64. I used two 64 bit platforms and no 32 bit. So I may be wrong.
If you compile for 32 bit, I expect in that case that 16 fails and only 8 succeeds.

Anyway you can do the alignment also by hand.

[edit: yes on 64 bit Windows and Linux the alignment is always 16, also when 4 or 8 is specified.
So my code is a wrong assumption. I will later show some code to do the alignment manually.
« Last Edit: June 01, 2026, 03:47:24 pm by Thaddy »
objects are fine constructs. You can even initialize them with constructors.

runewalsh

  • Full Member
  • ***
  • Posts: 126
Re: GetMem default aligment
« Reply #5 on: June 01, 2026, 04:40:31 pm »
Are you compiling 32-bit applications or what? Natural alignment is usually 2 * sizeof(pointer).

To align a pointer manually, say to 64 bytes:

Code: Pascal  [Select][+][-]
  1. const
  2.         Size = 100;
  3.         Alignment = 64;
  4. var
  5.         ptrPhysical, ptr: pointer;
  6. begin
  7.         ptrPhysical := GetMem(Size + Alignment - 1);
  8.         ptr := pointer((PtrUint(ptrPhysical) + Alignment - 1) div Alignment * Alignment);
  9.         ... ptr is 100-byte block aligned to 64 bytes, work with ptr ...
  10.         FreeMem(ptrPhysical);
  11. end;

This is almost never useful.

Thaddy

  • Hero Member
  • *****
  • Posts: 19268
  • Glad to be alive.
Re: GetMem default aligment
« Reply #6 on: June 01, 2026, 05:45:58 pm »
64 byte yes, but 32 byte alignment can be necessary.
objects are fine constructs. You can even initialize them with constructors.

MathMan

  • Hero Member
  • *****
  • Posts: 516
Re: GetMem default aligment
« Reply #7 on: June 01, 2026, 08:19:07 pm »
Are you compiling 32-bit applications or what? Natural alignment is usually 2 * sizeof(pointer).

To align a pointer manually, say to 64 bytes:

Code: Pascal  [Select][+][-]
  1. const
  2.         Size = 100;
  3.         Alignment = 64;
  4. var
  5.         ptrPhysical, ptr: pointer;
  6. begin
  7.         ptrPhysical := GetMem(Size + Alignment - 1);
  8.         ptr := pointer((PtrUint(ptrPhysical) + Alignment - 1) div Alignment * Alignment);
  9.         ... ptr is 100-byte block aligned to 64 bytes, work with ptr ...
  10.         FreeMem(ptrPhysical);
  11. end;

This is almost never useful.

The code above is unfortunately the only way to get aligned heap under FPC - afaik.

Regarding the "This is almost never useful." statement I'm of the opinion "It depends"  ;)

If there is AVX/AVX2 code in you program then misaligned reads will not degrade performance by much - I measured ~5% on modern cores (Intel Skylake/AMD Zen 1, or later). However misaligned stores can degrade performance by 40% (or more). So at least alignment on 32 bytes can be helpful, depending on what you are programming.

Beside that the modern cores have an internal cache-line buffer which can help in two ways. If you can follow a strict read/modify/write scheme on this buffer core loops can achieve max performance with an unroll factor of 2 (for AVX/AVX2) or even 1 (AVX512). This can reduces code size and provide more cache hits in the instruction cache. So @Thaddy - even alignment on 64 bytes can be useful. And if an application is e.g. streaming data where non-temporal hinting is beneficial one is anyway restricted to aligned read/write.

 

TinyPortal © 2005-2018