Recent

Author Topic: Padding rules in memory allocation  (Read 2635 times)

jollytall

  • Sr. Member
  • ****
  • Posts: 306
Padding rules in memory allocation
« on: September 25, 2021, 12:02:08 pm »
What is the padding logic when memory is used?
I have some objects, all 24 bytes long on an X64 machine. I would have expected that the objects are placed next to each other both in stack and heap, as 24 is dividable by 8 (bytes = 64 bits), but what I see in memory is that they are placed 32 bytes from each other adding an extra 8 byte to pad.
Similarly, when I have pointers (8 bytes) right after each other, I would have thought that they are right after each other again, but what I see is that they are 16 bytes apart.
Why is that that on a 64 bit computer padding is done to 128 bits?

Thaddy

  • Hero Member
  • *****
  • Posts: 14199
  • Probably until I exterminate Putin.
Re: Padding rules in memory allocation
« Reply #1 on: September 25, 2021, 01:39:29 pm »
If you want them sequentally and without the spacing, put your objects in a packed array.
Specialize a type, not a var.

jollytall

  • Sr. Member
  • ****
  • Posts: 306
Re: Padding rules in memory allocation
« Reply #2 on: September 25, 2021, 07:15:11 pm »
Thanks, I know that. Packed is always a good option if I do not want padding (or is it called spacing?). My question was why the padding is done to 128 bits, when the processor is 64? I have another issue, where the actual data is 56 bytes (see a separate question), so the padding is not aligned to 128 bits. So I am confused, what is the rule without "packed".

BobDog

  • Sr. Member
  • ****
  • Posts: 394
Re: Padding rules in memory allocation
« Reply #3 on: September 25, 2021, 09:24:08 pm »

The spacing looks OK here, or am I missing something?
Win 10 64 bits
fpc 3.2.2 (64 bit compiler)
Code: Pascal  [Select][+][-]
  1. type
  2. udt=object
  3. b:array[1 .. 24] of byte;
  4. end;
  5.  
  6. var
  7.  a:array[0 .. 10] of udt;
  8.  i:int32;
  9. begin
  10. writeln(sizeof(udt));
  11. for i:=0 to high(a) do writeln(int64(@a[i]));
  12. readln;
  13. end.
24
4295016448
4295016472
4295016496
4295016520
4295016544
4295016568
4295016592
4295016616
4295016640
4295016664
4295016688


jollytall

  • Sr. Member
  • ****
  • Posts: 306
Re: Padding rules in memory allocation
« Reply #4 on: September 25, 2021, 09:44:20 pm »
Thanks. I checked your code. If it is in an array as you wrote, I get the same result as you, i.e. 24 bytes aligned.
But I checked the following code:
Code: Pascal  [Select][+][-]
  1. type
  2.   udt=object
  3.     b:array[1 .. 24] of byte;
  4.     end;
  5. var
  6.   a, a2: udt;
  7. begin
  8. writeln(sizeof(udt));
  9. writeln(int64(@a),' ',int64(@a2));
  10. readln;
  11. end.
   
Result:
Code: Pascal  [Select][+][-]
  1. 24
  2. 4398224 4398256
The alignment is 32 bytes. It is clearly not something hidden field (size is 24) and also if I reduce the array size to 16, then there is no padding. If it is 17 bytes then the alignment jumps up to 32 bytes not to 24 bytes as I would expect.

I use Linux on x64 FPC 3.2.0

BobDog

  • Sr. Member
  • ****
  • Posts: 394
Re: Padding rules in memory allocation
« Reply #5 on: September 25, 2021, 10:11:05 pm »
Looks like the jump is always a multiple of eight  sixteen, so each 24 bytes must be allocated at the smallest next multiple, i.e. 32.
This is why the 16 byte udt can sit next  to the next 16 byte udt, but  a 17 byte udt needs the 32 byte jump (next multiple of 16)
But the array elements are contiguous in memory, seems to be in other compilers also.
 
« Last Edit: September 25, 2021, 11:24:52 pm by BobDog »

jollytall

  • Sr. Member
  • ****
  • Posts: 306
Re: Padding rules in memory allocation
« Reply #6 on: September 26, 2021, 08:38:32 am »
Yes, it is clear, what happens. The question, I would like to understand, why?

BobDog

  • Sr. Member
  • ****
  • Posts: 394
Re: Padding rules in memory allocation
« Reply #7 on: September 26, 2021, 09:32:36 am »
I had a google around, seems it is in theory 8 byte aligned with padding to suit the c language which of course writes both windows and Linux.
I cannot get pascal to re-align the memory slots to 24 bytes for two 24 byte objects.
It can be done easily in C type languages, freebasic for example;
type udt
   a(1 to 24) as byte
end type
dim as udt z(1 to 2)

dim byref x as udt=z(1)
dim byref y as udt=z(2)

print @x,@y

sleep

result
6421936       6421960

But is pascal low level enough to do this?
I am sure there must be some way, after all they say that Delphi can do anything C++ can.







marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Padding rules in memory allocation
« Reply #8 on: September 26, 2021, 12:25:08 pm »
Stack on 64-bit windows is aligned to 16 byte, and it is getting more popular on 32-bit too.

One reason is SSE2 being part of the X86_64 standard, and keeping the stack aligned is cheaper than aligning before every (SSE2) operation.

Note that trying to abuse stack positioning is not guaranteed to work. It is not defined that stack variables declared after each other are also on the stack after each other, and exploiting that can be dangerous. Same for global variables. Compilers are allowed to move them around if it suits their purpose.

Thaddy

  • Hero Member
  • *****
  • Posts: 14199
  • Probably until I exterminate Putin.
Re: Padding rules in memory allocation
« Reply #9 on: September 26, 2021, 04:01:30 pm »
Well, please note that the AVX family relaxes the alignment requirements and with the newer ones one can even completely ignore alignment provisions. (For the past 10-11 years, Marco). FPC has good AVX (+) support. Use SSE2 and its alignment requirement only if you need to support legacy hardware, I guess.
« Last Edit: September 26, 2021, 04:03:51 pm by Thaddy »
Specialize a type, not a var.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: Padding rules in memory allocation
« Reply #10 on: September 26, 2021, 04:22:41 pm »
Well, please note that the AVX family relaxes the alignment requirements and with the newer ones one can even completely ignore alignment provisions.

Some provisions. As said vmodqa requires alignment, and even when one ignores it.

Even when ignored, if the target is unaligned, it amounts to two cache line read operations instead of one, and iirc there might be problems cross-page too.

Quote
(For the past 10-11 years, Marco). FPC has good AVX (+) support. Use SSE2 and its alignment requirement only if you need to support legacy hardware, I guess.

Regardless of the details, the default for most x86_64 is still SSE2. 

jollytall

  • Sr. Member
  • ****
  • Posts: 306
Re: Padding rules in memory allocation
« Reply #11 on: September 26, 2021, 05:45:03 pm »
One reason is SSE2 being part of the X86_64 standard, and keeping the stack aligned is cheaper than aligning before every (SSE2) operation.

Thanks, it was very useful.
Now, knowing about SSE2, I could google some more and found a bit more explanation: https://community.intel.com/t5/Software-Tuning-Performance/Why-should-data-be-aligned-to-16-bytes-for-SSE-instructions/td-p/1164004, https://research.csiro.au/tsblog/debugging-stories-stack-alignment-matters/ and here https://en.wikipedia.org/wiki/X86_calling_conventions.

Interesting topic...

 

TinyPortal © 2005-2018