1

I am trying to figure out if there could be situations where using "packed array of [type]" could be advantageous if trying to save memory.

You can read that on Win32 bit, it is not the case: http://docwiki.embarcadero.com/RADStudio/XE4/en/Internal_Data_Formats#Dynamic_Array_Types

Generally speaking, it would seem to me runtime code for dynamic arrays would be fasterif never using padding between items. But since I believe default alignment in Delphi/64bit is 8byte, it would seem to be there would be a a chance that you some day could not count on dynamic arrays containg e.g. booleans being "packed" by default

Tom
  • 3,587
  • 9
  • 69
  • 124
  • 1
    No, The only use I can think of for using `packed` on any array or record type is backward-compatibility for reading data stored in a disk file, or occasionally interacting with the WinAPI. There is IMO absolutely no memory advantage by doing so that is meaningful for modern CPU architectures and RAM availability, and it can actually slow performance of code because it uses other than the native alignment. – Ken White Nov 28 '13 at 00:46
  • I can't find the place where it is stated in the document you linked. – Sertac Akyuz Nov 28 '13 at 01:30
  • Using packed types forcibly aligns data on BYTE boundaries (ie, no padding), which causes *more* work for CPUs, especially on memory fetches, because data is not being aligned on natural WORD/DWORD/QWORD boundaries that CPUs are optimized to handle. A 32-bit CPU is optimized for DWORD alignment. A 64-bit CPU is optimized for QWORD alignment. – Remy Lebeau Nov 28 '13 at 01:50
  • @RemyLebeau In fact, in modern versions of the compiler, `packed` arrays are aligned and the use of `packed` has no impact on arrays. – David Heffernan Nov 28 '13 at 09:50

1 Answers1

2

First of all I think you need to be careful how you read the documentation. It has not been updated consistently and the fact that some parts appear specific to Win32 can in no way be used to infer that Win64 differs. In fact, for the issues raised in your question, there are no substantive differences between 32 and 64 bit.

For Delphi, using packed on an array does not change the padding between successive elements. The distance between two adjacent elements of an array is equal to SizeOf(T) where T is the element type. This holds true irrespective of the use of the packed modifier. And using packed on an array does not even affect the alignment of the array.

So, to be completely clear and explicit, packed has no impact at all when used on arrays. The compiler treats a packed array in exactly the same way as it treats a non-packed array.

This statement seems to be at odds with the documentation. The documentation states:

Alignment of Structured Types

By default, the values in a structured type are aligned on word- or double-word boundaries for faster access.

You can, however, specify byte alignment by including the reserved word packed when you declare a structured type. The packed word specifies compressed data storage. Here is an example declaration:

type TNumbers = packed array [1..100] of Real;

But consider this program:

{$APPTYPE CONSOLE}

type
  TNumbers = packed array [1..100] of Real;

type
  TRec = record
    a: Byte;
    b: TNumbers;
  end;

begin
  Writeln(Integer(@TRec(nil^).a));
  Writeln(Integer(@TRec(nil^).b));
  Readln;
end.

The output of which, using Delphi XE2, is:

0
8

So, using packed with arrays, in contradiction of the documentation, does not modify alignment of the type.

Note that the above program, when compiled by Delphi 6, has output

0
1

So it would appear that the compiler has changed, but the documentation has not caught up.

A related question can be found here: Are there any difference between array and packed array in Delphi? But note that the answer of Barry Kelly (an Embarcadero compiler engineer at the time he wrote the answer) does not mention the change in compiler behaviour.


Generally speaking, it would seem to me runtime code would be faster if never using padding between items.

As discussed above, for arrays there never is padding between array elements.

I believe default alignment in Delphi/64bit is 8 byte.

The alignment is determined by the data type and is not related to the target architecture. So a Boolean has alignment of 1. A Word has alignment of 2. An Integer has alignment of 4. A Double has alignment of 8. These alignment values are the same on 32 and 64 bit.

Alignment has an enormous impact on performance. If you care about performance you should, as a general rule, never pack data structures. If you wish to minimise the size of a structure (class or record), put the larger elements first to minimise padding. This could improve performance, but it could also worsen it.

But there is no single hard and fast rule. I can imagine that packing could improve performance if the thing that was packed was hardly ever accessed. And I can, more readily in fact, imagine that changing the order of elements in a structure to group related elements could improve performance.

Community
  • 1
  • 1
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • "...changing the order of elements in a structure to group related elements could improve performance." ... or sometimes decrease performance, e.g. in a multi threaded access to those elements. – iamjoosy Nov 28 '13 at 07:47
  • @iam False sharing. Indeed. I'm thinking of data private to a thread. By related data I mean data that is operated on together. Usually that happens on the same thread. Generally false sharing tends to be an issue with arrays and access of adjacent elements from different threads. That quote you picked out was considering records and classes rather than arrays. The bottom line is that there is no one single rule to follow. – David Heffernan Nov 28 '13 at 07:57
  • Indeed, there is no single rule to follow, it all depends on the usage context, that was the whole point of my comment. But I think we are digressing here from the question the OP asked. Btw. it was a link from you here on SO to Herb Sutter's Dr.Dobb's concurrent programming articles where I learned a lot about false sharing and other issues - thanks for that. – iamjoosy Nov 28 '13 at 08:08
  • Just a side note: The alignment of dynamic arrays by the way is broken by design. The fastest access on x86 and x64 machines is that the first element in the array would have an alignement of 16bytes but by designe it does not have that (though the address of the dyn array structure has that..). See QC 70204 – mrabat Nov 28 '13 at 09:50
  • @mrabat I don't know what you mean by that. Can you elaborate? – David Heffernan Nov 28 '13 at 09:51
  • Sure: Take an dynamic double array for example. the address of the first element is not aligned to a 16 byte address (@data[0] and $F <> 0). It's by the way just a side node but does have a performance hit + these can't be used for SIMD instructions. – mrabat Nov 28 '13 at 10:05
  • @mrabat I see. That's because `TDynArrayRec` has size 8 on x86. On x64 it has size 16 and so long as the memory manager aligns on 16 byte boundaries you are fine for SSE. – David Heffernan Nov 28 '13 at 10:09