digitalmars.D - Optimal struct layout template?
- dsimcha <dsimcha yahoo.com> Dec 14 2008
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Dec 14 2008
- BCS <ao pathlink.com> Dec 14 2008
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Dec 14 2008
- Sergey Gromov <snake.scaly gmail.com> Dec 15 2008
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Dec 15 2008
- Don <nospam nospam.com> Dec 16 2008
- KennyTM~ <kennytm gmail.com> Dec 16 2008
- Sergey Gromov <snake.scaly gmail.com> Dec 17 2008
- Sergey Gromov <snake.scaly gmail.com> Dec 17 2008
- Don <nospam nospam.com> Dec 18 2008
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Dec 18 2008
- Don <nospam nospam.com> Jan 08 2009
- Robert Fraser <fraserofthenight gmail.com> Jan 08 2009
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Jan 08 2009
- Don <nospam nospam.com> Jan 09 2009
- grauzone <none example.net> Jan 09 2009
- Don <nospam nospam.com> Jan 09 2009
- dsimcha <dsimcha yahoo.com> Jan 09 2009
- Sergey Gromov <snake.scaly gmail.com> Dec 18 2008
- Rainer Deyke <rainerd eldwood.com> Dec 18 2008
- Don <nospam nospam.com> Dec 19 2008
- BCS <ao pathlink.com> Dec 15 2008
- dsimcha <dsimcha yahoo.com> Dec 15 2008
- Don <nospam nospam.com> Dec 15 2008
- Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> Dec 15 2008
- "Denis Koroskin" <2korden gmail.com> Dec 17 2008
- "Denis Koroskin" <2korden gmail.com> Dec 18 2008
According to the spec, data stored in structs is guaranteed to be laid out in the order specified in the source code. While this is necessary in some low-level code, I have a use case where I need to pack structs as efficiently as possible. These structs are to be stored in an array, and for efficiency reasons I want to store them directly rather than storing pointers, so using classes is out of the question. Does anyone know how to write a template that, given a tuple of types, will reorder the tuple so that it will produce the optimal struct layout? I don't care, at least for now, if it assumes x86-32/DMD instead of handling the more general case.
Dec 14 2008
dsimcha wrote:According to the spec, data stored in structs is guaranteed to be laid out in the order specified in the source code. While this is necessary in some low-level code, I have a use case where I need to pack structs as efficiently as possible. These structs are to be stored in an array, and for efficiency reasons I want to store them directly rather than storing pointers, so using classes is out of the question. Does anyone know how to write a template that, given a tuple of types, will reorder the tuple so that it will produce the optimal struct layout? I don't care, at least for now, if it assumes x86-32/DMD instead of handling the more general case.
I don't have such code, but if anyone wrote something, it sounds like a terrific addition to Phobos. Andrei
Dec 14 2008
Reply to dsimcha,According to the spec, data stored in structs is guaranteed to be laid out in the order specified in the source code. While this is necessary in some low-level code, I have a use case where I need to pack structs as efficiently as possible. These structs are to be stored in an array, and for efficiency reasons I want to store them directly rather than storing pointers, so using classes is out of the question. Does anyone know how to write a template that, given a tuple of types, will reorder the tuple so that it will produce the optimal struct layout? I don't care, at least for now, if it assumes x86-32/DMD instead of handling the more general case.
would "align 1" work?
Dec 14 2008
BCS wrote:Reply to dsimcha,According to the spec, data stored in structs is guaranteed to be laid out in the order specified in the source code. While this is necessary in some low-level code, I have a use case where I need to pack structs as efficiently as possible. These structs are to be stored in an array, and for efficiency reasons I want to store them directly rather than storing pointers, so using classes is out of the question. Does anyone know how to write a template that, given a tuple of types, will reorder the tuple so that it will produce the optimal struct layout? I don't care, at least for now, if it assumes x86-32/DMD instead of handling the more general case.
would "align 1" work?
That could make things excruciatingly slow. What's really needed is (in first approximation) to sort the members in decreasing order of size. Odd-sized arrays of char foil this plan to some extent, which is where the fun begins. Andrei
Dec 14 2008
Sun, 14 Dec 2008 13:17:45 -0800, Andrei Alexandrescu wrote:BCS wrote:Reply to dsimcha,According to the spec, data stored in structs is guaranteed to be laid out in the order specified in the source code. While this is necessary in some low-level code, I have a use case where I need to pack structs as efficiently as possible. These structs are to be stored in an array, and for efficiency reasons I want to store them directly rather than storing pointers, so using classes is out of the question. Does anyone know how to write a template that, given a tuple of types, will reorder the tuple so that it will produce the optimal struct layout? I don't care, at least for now, if it assumes x86-32/DMD instead of handling the more general case.
would "align 1" work?
That could make things excruciatingly slow. What's really needed is (in first approximation) to sort the members in decreasing order of size. Odd-sized arrays of char foil this plan to some extent, which is where the fun begins.
I would say in decreasing order of field/array element alignment requirement.
Dec 15 2008
Sergey Gromov wrote:Sun, 14 Dec 2008 13:17:45 -0800, Andrei Alexandrescu wrote:BCS wrote:Reply to dsimcha,According to the spec, data stored in structs is guaranteed to be laid out in the order specified in the source code. While this is necessary in some low-level code, I have a use case where I need to pack structs as efficiently as possible. These structs are to be stored in an array, and for efficiency reasons I want to store them directly rather than storing pointers, so using classes is out of the question. Does anyone know how to write a template that, given a tuple of types, will reorder the tuple so that it will produce the optimal struct layout? I don't care, at least for now, if it assumes x86-32/DMD instead of handling the more general case.
first approximation) to sort the members in decreasing order of size. Odd-sized arrays of char foil this plan to some extent, which is where the fun begins.
I would say in decreasing order of field/array element alignment requirement.
Sounds indeed right. Even simpler than I thought! Andrei
Dec 15 2008
Andrei Alexandrescu wrote:Sergey Gromov wrote:Sun, 14 Dec 2008 13:17:45 -0800, Andrei Alexandrescu wrote:BCS wrote:Reply to dsimcha,According to the spec, data stored in structs is guaranteed to be laid out in the order specified in the source code. While this is necessary in some low-level code, I have a use case where I need to pack structs as efficiently as possible. These structs are to be stored in an array, and for efficiency reasons I want to store them directly rather than storing pointers, so using classes is out of the question. Does anyone know how to write a template that, given a tuple of types, will reorder the tuple so that it will produce the optimal struct layout? I don't care, at least for now, if it assumes x86-32/DMD instead of handling the more general case.
(in first approximation) to sort the members in decreasing order of size. Odd-sized arrays of char foil this plan to some extent, which is where the fun begins.
I would say in decreasing order of field/array element alignment requirement.
Sounds indeed right. Even simpler than I thought!
Close, but doesn't work in all cases. You sometimes need to insert elements of smaller size. Example 1: Given real, double, double, short, int: real (10 bytes, wants 16 byte alignment) --(only on Windows, 12 byte size on Linux32, 16-byte size on Linux64) double (8 bytes, wants 8 byte alignment) short (2 bytes, wants 2 byte alignment) int (4 bytes, wants 4 byte alignment) There are only two solutions: { real, short, int, double, double } { double, double, real, short, int } Example 2: struct Foo { double, int } // 12 byte size, wants 8-byte alignment. given Foo, Foo, int, int: solution is { Foo, int, Foo, int }Andrei
Dec 16 2008
Don wrote:Andrei Alexandrescu wrote:Sergey Gromov wrote:Sun, 14 Dec 2008 13:17:45 -0800, Andrei Alexandrescu wrote:BCS wrote:Reply to dsimcha,According to the spec, data stored in structs is guaranteed to be laid out in the order specified in the source code. While this is necessary in some low-level code, I have a use case where I need to pack structs as efficiently as possible. These structs are to be stored in an array, and for efficiency reasons I want to store them directly rather than storing pointers, so using classes is out of the question. Does anyone know how to write a template that, given a tuple of types, will reorder the tuple so that it will produce the optimal struct layout? I don't care, at least for now, if it assumes x86-32/DMD instead of handling the more general case.
(in first approximation) to sort the members in decreasing order of size. Odd-sized arrays of char foil this plan to some extent, which is where the fun begins.
I would say in decreasing order of field/array element alignment requirement.
Sounds indeed right. Even simpler than I thought!
Close, but doesn't work in all cases. You sometimes need to insert elements of smaller size. Example 1: Given real, double, double, short, int: real (10 bytes, wants 16 byte alignment) --(only on Windows, 12 byte size on Linux32, 16-byte size on Linux64) double (8 bytes, wants 8 byte alignment) short (2 bytes, wants 2 byte alignment) int (4 bytes, wants 4 byte alignment) There are only two solutions: { real, short, int, double, double } { double, double, real, short, int } Example 2: struct Foo { double, int } // 12 byte size, wants 8-byte alignment. given Foo, Foo, int, int: solution is { Foo, int, Foo, int }
Greedy algorithm?
Dec 16 2008
Tue, 16 Dec 2008 10:09:41 +0100, Don wrote:Example 2: struct Foo { double, int } // 12 byte size, wants 8-byte alignment.
Foo.sizeof is 16. The thing is, array of Foo's must be properly aligned, and &foo[1] must be cast(byte*) &foo[0] + Foo.sizeof. This means that Foo.sizeof must be itself 8-aligned. The solution is { Foo, Foo, int, int }. The same with your other example. Sizeof cannot be less than alignment. Therefore you can never pack real and short in 16 bytes.
Dec 17 2008
Thu, 18 Dec 2008 00:21:58 +0300, Denis Koroskin wrote:On Thu, 18 Dec 2008 00:12:18 +0300, Sergey Gromov <snake.scaly gmail.com> wrote:Tue, 16 Dec 2008 10:09:41 +0100, Don wrote:Example 2: struct Foo { double, int } // 12 byte size, wants 8-byte alignment.
Foo.sizeof is 16.
It is 12 with align(1) (I see no problem with it).
With align(1) the Foo.alignof is 1 so there is no problem to talk about. The problem is when you have elements with non-trivial alignment requirements and want to pack them as tightly as possible.The thing is, array of Foo's must be properly aligned, and &foo[1] must be cast(byte*) &foo[0] + Foo.sizeof. This means that Foo.sizeof must be itself 8-aligned. The solution is { Foo, Foo, int, int }.
Stop right there. You can't access &foo[1] no matter what align or structure layout is used. Example: align(default): struct Data { int i1; short s2; char c1; int 12; } What is &i1[1]?
i1 is not an array. Sorry I wasn't clear enough. I was talking about an imaginary array of Foo's: Foo[] foo; You must admit that foo[1] and &foo[1] makes perfect sense for such construct. And that cast(byte*) &foo[1] - cast(byte*) &foo[0] == Foo.sizeof must hold.
Dec 17 2008
Denis Koroskin wrote:On Thu, 18 Dec 2008 01:38:32 +0300, Sergey GromovThu, 18 Dec 2008 00:21:58 +0300, Denis Koroskin wrote:On Thu, 18 Dec 2008 00:12:18 +0300, Sergey GromovTue, 16 Dec 2008 10:09:41 +0100, Don wrote:struct Foo { double, int } // 12 byte size, wants 8-byte alignment.
align(1): struct Foo { char c; double d; short s; bool b; }
[snip]so that Foo.d.alignof == 8. Align(1) is still necessary so that Foo.sizeof == 12.
Sergey is correct to the extent that in DMD, x.alignof <= x.sizeof for any x, and also x.sizeof is always an integer multiple of x.alignof. When you assume that DMD is correct, then the simple ordering by .alignof indeed gives an optimal solution. But these values *don't* reflect the machine behaviour. real.alignof is 2. But it's significantly faster (factor of 2) on most x86 machines to have real aligned to 16. These effects are not captured by the .alignof property for structs. To capture it in the Foo example, you'd need (for example) a Foo.memberalignof property, and a Foo.memberalignoffsetof property. But you could reasonably argue that if you're specifying align(1) then alignment is not important. The simple algorithm may well be good enough. (And note that you can use radix sort -- alignof can only be 1, 2, 4, 8, or 16 -- so it's in O(n) not O(n lg n)). Interestingly, this 'internal alignment' applies to function alignment, as well. D allows you to specify that a function be aligned to (for example) a 16-byte boundary. This is hardly ever useful; usually what you want is for the innermost loop to be aligned. And instead of a pile of nops before the loop, you'd like the function start address to be adjusted.
Dec 18 2008
Don wrote:Denis Koroskin wrote:On Thu, 18 Dec 2008 01:38:32 +0300, Sergey GromovThu, 18 Dec 2008 00:21:58 +0300, Denis Koroskin wrote:On Thu, 18 Dec 2008 00:12:18 +0300, Sergey GromovTue, 16 Dec 2008 10:09:41 +0100, Don wrote:struct Foo { double, int } // 12 byte size, wants 8-byte alignment.
align(1): struct Foo { char c; double d; short s; bool b; }
[snip]so that Foo.d.alignof == 8. Align(1) is still necessary so that Foo.sizeof == 12.
Sergey is correct to the extent that in DMD, x.alignof <= x.sizeof for any x, and also x.sizeof is always an integer multiple of x.alignof. When you assume that DMD is correct, then the simple ordering by .alignof indeed gives an optimal solution. But these values *don't* reflect the machine behaviour. real.alignof is 2. But it's significantly faster (factor of 2) on most x86 machines to have real aligned to 16. These effects are not captured by the .alignof property for structs. To capture it in the Foo example, you'd need (for example) a Foo.memberalignof property, and a Foo.memberalignoffsetof property. But you could reasonably argue that if you're specifying align(1) then alignment is not important. The simple algorithm may well be good enough. (And note that you can use radix sort -- alignof can only be 1, 2, 4, 8, or 16 -- so it's in O(n) not O(n lg n)). Interestingly, this 'internal alignment' applies to function alignment, as well. D allows you to specify that a function be aligned to (for example) a 16-byte boundary. This is hardly ever useful; usually what you want is for the innermost loop to be aligned. And instead of a pile of nops before the loop, you'd like the function start address to be adjusted.
That's cool! I think the way to the templates AlignForSpeed!(Foo) and AlignForSize!(Foo) is paved. Don, now all you have to do is a simple matter of coding :o). Andrei
Dec 18 2008
Andrei Alexandrescu wrote:Don wrote:Denis Koroskin wrote:On Thu, 18 Dec 2008 01:38:32 +0300, Sergey GromovThu, 18 Dec 2008 00:21:58 +0300, Denis Koroskin wrote:On Thu, 18 Dec 2008 00:12:18 +0300, Sergey GromovTue, 16 Dec 2008 10:09:41 +0100, Don wrote:struct Foo { double, int } // 12 byte size, wants 8-byte alignment.
about.
align(1): struct Foo { char c; double d; short s; bool b; }
[snip]so that Foo.d.alignof == 8. Align(1) is still necessary so that Foo.sizeof == 12.
Sergey is correct to the extent that in DMD, x.alignof <= x.sizeof for any x, and also x.sizeof is always an integer multiple of x.alignof. When you assume that DMD is correct, then the simple ordering by .alignof indeed gives an optimal solution. But these values *don't* reflect the machine behaviour. real.alignof is 2. But it's significantly faster (factor of 2) on most x86 machines to have real aligned to 16. These effects are not captured by the .alignof property for structs. To capture it in the Foo example, you'd need (for example) a Foo.memberalignof property, and a Foo.memberalignoffsetof property. But you could reasonably argue that if you're specifying align(1) then alignment is not important. The simple algorithm may well be good enough. (And note that you can use radix sort -- alignof can only be 1, 2, 4, 8, or 16 -- so it's in O(n) not O(n lg n)). Interestingly, this 'internal alignment' applies to function alignment, as well. D allows you to specify that a function be aligned to (for example) a 16-byte boundary. This is hardly ever useful; usually what you want is for the innermost loop to be aligned. And instead of a pile of nops before the loop, you'd like the function start address to be adjusted.
That's cool! I think the way to the templates AlignForSpeed!(Foo) and AlignForSize!(Foo) is paved. Don, now all you have to do is a simple matter of coding :o). Andrei
Here's a very simple implementation that should solve the problem described in the original post. It doesn't deal with the obscure and difficult cases of align(1) structs, or 80-bit reals. Implementation includes workarounds for FOUR compiler bugs. Works without modification on both D1 and D2. ---- /// Order the provided members to minimize size while preserving alignment /// BUG: bugzilla 2029 prevents the signature from being (string[] names...), /// so we need to use an ugly array literal instead. char [] alignForSize(E...)(string[E.length] names) { // Sort all of the members by .alignof. // BUG: Alignment is not always optimal for align(1) structs // or 80-bit reals. // TRICK: Use the fact that .alignof is always a power of 2, // and maximum 16 on extant systems. Thus, we can perform // a very limited radix sort. int [][] alignlist; // workaround for bugzilla 2569 // alignof = 1, 2, 4, 8, 16, 32, 64 alignlist = [ [],[],[],[],[],[],[]]; // workaround for bugzilla 2562 char[][] declaration; foreach(int i_bug,T; E) { int i = i_bug; // workaround for bugzilla 2564 (D2 only) declaration ~= T.stringof ~ " " ~ names[i].dup ~ ";\n"; int a = T.alignof; int k = a==2? 1 : a==4? 2 : a==8? 3 : a==16? 4 : a==32? 5 : a>=64? 6 : 0; alignlist[k]~=i; } char [] s; foreach_reverse(q; alignlist) { foreach(int i; q) { s ~= declaration[i]; } } return s; } // Example: struct Foo { mixin(alignForSize!(int[], char[13], short, double[5])(["x", "y","z", "w"])); } is equivalent to: struct Foo{ double[5u] w; // aligned to 8 bytes int[] x; // aligned to 4 short z; // aligned to 2 char[13u] y; // aligned to 1 } which will have a size of 63, followed by 1 byte of padding.
Jan 08 2009
Don wrote:Andrei Alexandrescu wrote:Don wrote:Denis Koroskin wrote:On Thu, 18 Dec 2008 01:38:32 +0300, Sergey GromovThu, 18 Dec 2008 00:21:58 +0300, Denis Koroskin wrote:On Thu, 18 Dec 2008 00:12:18 +0300, Sergey GromovTue, 16 Dec 2008 10:09:41 +0100, Don wrote:struct Foo { double, int } // 12 byte size, wants 8-byte alignment.
about.
align(1): struct Foo { char c; double d; short s; bool b; }
[snip]so that Foo.d.alignof == 8. Align(1) is still necessary so that Foo.sizeof == 12.
Sergey is correct to the extent that in DMD, x.alignof <= x.sizeof for any x, and also x.sizeof is always an integer multiple of x.alignof. When you assume that DMD is correct, then the simple ordering by .alignof indeed gives an optimal solution. But these values *don't* reflect the machine behaviour. real.alignof is 2. But it's significantly faster (factor of 2) on most x86 machines to have real aligned to 16. These effects are not captured by the .alignof property for structs. To capture it in the Foo example, you'd need (for example) a Foo.memberalignof property, and a Foo.memberalignoffsetof property. But you could reasonably argue that if you're specifying align(1) then alignment is not important. The simple algorithm may well be good enough. (And note that you can use radix sort -- alignof can only be 1, 2, 4, 8, or 16 -- so it's in O(n) not O(n lg n)). Interestingly, this 'internal alignment' applies to function alignment, as well. D allows you to specify that a function be aligned to (for example) a 16-byte boundary. This is hardly ever useful; usually what you want is for the innermost loop to be aligned. And instead of a pile of nops before the loop, you'd like the function start address to be adjusted.
That's cool! I think the way to the templates AlignForSpeed!(Foo) and AlignForSize!(Foo) is paved. Don, now all you have to do is a simple matter of coding :o). Andrei
Here's a very simple implementation that should solve the problem described in the original post. It doesn't deal with the obscure and difficult cases of align(1) structs, or 80-bit reals. Implementation includes workarounds for FOUR compiler bugs. Works without modification on both D1 and D2. ---- /// Order the provided members to minimize size while preserving alignment /// BUG: bugzilla 2029 prevents the signature from being (string[] names...), /// so we need to use an ugly array literal instead. char [] alignForSize(E...)(string[E.length] names) { // Sort all of the members by .alignof. // BUG: Alignment is not always optimal for align(1) structs // or 80-bit reals. // TRICK: Use the fact that .alignof is always a power of 2, // and maximum 16 on extant systems. Thus, we can perform // a very limited radix sort. int [][] alignlist; // workaround for bugzilla 2569 // alignof = 1, 2, 4, 8, 16, 32, 64 alignlist = [ [],[],[],[],[],[],[]]; // workaround for bugzilla 2562 char[][] declaration; foreach(int i_bug,T; E) { int i = i_bug; // workaround for bugzilla 2564 (D2 only) declaration ~= T.stringof ~ " " ~ names[i].dup ~ ";\n"; int a = T.alignof; int k = a==2? 1 : a==4? 2 : a==8? 3 : a==16? 4 : a==32? 5 : a>=64? 6 : 0; alignlist[k]~=i; } char [] s; foreach_reverse(q; alignlist) { foreach(int i; q) { s ~= declaration[i]; } } return s; } // Example: struct Foo { mixin(alignForSize!(int[], char[13], short, double[5])(["x", "y","z", "w"])); } is equivalent to: struct Foo{ double[5u] w; // aligned to 8 bytes int[] x; // aligned to 4 short z; // aligned to 2 char[13u] y; // aligned to 1 } which will have a size of 63, followed by 1 byte of padding
Wow; thanks; that's awesome.
Jan 08 2009
Don wrote:Andrei Alexandrescu wrote:Don wrote:Denis Koroskin wrote:On Thu, 18 Dec 2008 01:38:32 +0300, Sergey GromovThu, 18 Dec 2008 00:21:58 +0300, Denis Koroskin wrote:On Thu, 18 Dec 2008 00:12:18 +0300, Sergey GromovTue, 16 Dec 2008 10:09:41 +0100, Don wrote:struct Foo { double, int } // 12 byte size, wants 8-byte alignment.
about.
align(1): struct Foo { char c; double d; short s; bool b; }
[snip]so that Foo.d.alignof == 8. Align(1) is still necessary so that Foo.sizeof == 12.
Sergey is correct to the extent that in DMD, x.alignof <= x.sizeof for any x, and also x.sizeof is always an integer multiple of x.alignof. When you assume that DMD is correct, then the simple ordering by .alignof indeed gives an optimal solution. But these values *don't* reflect the machine behaviour. real.alignof is 2. But it's significantly faster (factor of 2) on most x86 machines to have real aligned to 16. These effects are not captured by the .alignof property for structs. To capture it in the Foo example, you'd need (for example) a Foo.memberalignof property, and a Foo.memberalignoffsetof property. But you could reasonably argue that if you're specifying align(1) then alignment is not important. The simple algorithm may well be good enough. (And note that you can use radix sort -- alignof can only be 1, 2, 4, 8, or 16 -- so it's in O(n) not O(n lg n)). Interestingly, this 'internal alignment' applies to function alignment, as well. D allows you to specify that a function be aligned to (for example) a 16-byte boundary. This is hardly ever useful; usually what you want is for the innermost loop to be aligned. And instead of a pile of nops before the loop, you'd like the function start address to be adjusted.
That's cool! I think the way to the templates AlignForSpeed!(Foo) and AlignForSize!(Foo) is paved. Don, now all you have to do is a simple matter of coding :o). Andrei
Here's a very simple implementation that should solve the problem described in the original post. It doesn't deal with the obscure and difficult cases of align(1) structs, or 80-bit reals. Implementation includes workarounds for FOUR compiler bugs. Works without modification on both D1 and D2. ---- /// Order the provided members to minimize size while preserving alignment /// BUG: bugzilla 2029 prevents the signature from being (string[] names...), /// so we need to use an ugly array literal instead. char [] alignForSize(E...)(string[E.length] names) { // Sort all of the members by .alignof. // BUG: Alignment is not always optimal for align(1) structs // or 80-bit reals. // TRICK: Use the fact that .alignof is always a power of 2, // and maximum 16 on extant systems. Thus, we can perform // a very limited radix sort. int [][] alignlist; // workaround for bugzilla 2569 // alignof = 1, 2, 4, 8, 16, 32, 64 alignlist = [ [],[],[],[],[],[],[]]; // workaround for bugzilla 2562 char[][] declaration; foreach(int i_bug,T; E) { int i = i_bug; // workaround for bugzilla 2564 (D2 only) declaration ~= T.stringof ~ " " ~ names[i].dup ~ ";\n"; int a = T.alignof; int k = a==2? 1 : a==4? 2 : a==8? 3 : a==16? 4 : a==32? 5 : a>=64? 6 : 0; alignlist[k]~=i; } char [] s; foreach_reverse(q; alignlist) { foreach(int i; q) { s ~= declaration[i]; } } return s; } // Example: struct Foo { mixin(alignForSize!(int[], char[13], short, double[5])(["x", "y","z", "w"])); } is equivalent to: struct Foo{ double[5u] w; // aligned to 8 bytes int[] x; // aligned to 4 short z; // aligned to 2 char[13u] y; // aligned to 1 } which will have a size of 63, followed by 1 byte of padding.
andrei:~$ grep unittest donscode.d andrei:~$ echo $? 1 andrei:~$ _ Other than that, I'd be glad if you included it in Phobos :o). Andrei
Jan 08 2009
Andrei Alexandrescu wrote:Don wrote:Andrei Alexandrescu wrote:Don wrote:Denis Koroskin wrote:On Thu, 18 Dec 2008 01:38:32 +0300, Sergey GromovThu, 18 Dec 2008 00:21:58 +0300, Denis Koroskin wrote:On Thu, 18 Dec 2008 00:12:18 +0300, Sergey GromovTue, 16 Dec 2008 10:09:41 +0100, Don wrote:struct Foo { double, int } // 12 byte size, wants 8-byte alignment.
about.
align(1): struct Foo { char c; double d; short s; bool b; }
[snip]so that Foo.d.alignof == 8. Align(1) is still necessary so that Foo.sizeof == 12.
Sergey is correct to the extent that in DMD, x.alignof <= x.sizeof for any x, and also x.sizeof is always an integer multiple of x.alignof. When you assume that DMD is correct, then the simple ordering by .alignof indeed gives an optimal solution. But these values *don't* reflect the machine behaviour. real.alignof is 2. But it's significantly faster (factor of 2) on most x86 machines to have real aligned to 16. These effects are not captured by the .alignof property for structs. To capture it in the Foo example, you'd need (for example) a Foo.memberalignof property, and a Foo.memberalignoffsetof property. But you could reasonably argue that if you're specifying align(1) then alignment is not important. The simple algorithm may well be good enough. (And note that you can use radix sort -- alignof can only be 1, 2, 4, 8, or 16 -- so it's in O(n) not O(n lg n)). Interestingly, this 'internal alignment' applies to function alignment, as well. D allows you to specify that a function be aligned to (for example) a 16-byte boundary. This is hardly ever useful; usually what you want is for the innermost loop to be aligned. And instead of a pile of nops before the loop, you'd like the function start address to be adjusted.
That's cool! I think the way to the templates AlignForSpeed!(Foo) and AlignForSize!(Foo) is paved. Don, now all you have to do is a simple matter of coding :o). Andrei
Here's a very simple implementation that should solve the problem described in the original post. It doesn't deal with the obscure and difficult cases of align(1) structs, or 80-bit reals. Implementation includes workarounds for FOUR compiler bugs. Works without modification on both D1 and D2. ---- /// Order the provided members to minimize size while preserving alignment /// BUG: bugzilla 2029 prevents the signature from being (string[] names...), /// so we need to use an ugly array literal instead. char [] alignForSize(E...)(string[E.length] names) { // Sort all of the members by .alignof. // BUG: Alignment is not always optimal for align(1) structs // or 80-bit reals. // TRICK: Use the fact that .alignof is always a power of 2, // and maximum 16 on extant systems. Thus, we can perform // a very limited radix sort. int [][] alignlist; // workaround for bugzilla 2569 // alignof = 1, 2, 4, 8, 16, 32, 64 alignlist = [ [],[],[],[],[],[],[]]; // workaround for bugzilla 2562 char[][] declaration; foreach(int i_bug,T; E) { int i = i_bug; // workaround for bugzilla 2564 (D2 only) declaration ~= T.stringof ~ " " ~ names[i].dup ~ ";\n"; int a = T.alignof; int k = a==2? 1 : a==4? 2 : a==8? 3 : a==16? 4 : a==32? 5 : a>=64? 6 : 0; alignlist[k]~=i; } char [] s; foreach_reverse(q; alignlist) { foreach(int i; q) { s ~= declaration[i]; } } return s; } // Example: struct Foo { mixin(alignForSize!(int[], char[13], short, double[5])(["x", "y","z", "w"])); } is equivalent to: struct Foo{ double[5u] w; // aligned to 8 bytes int[] x; // aligned to 4 short z; // aligned to 2 char[13u] y; // aligned to 1 } which will have a size of 63, followed by 1 byte of padding.
andrei:~$ grep unittest donscode.d andrei:~$ echo $? 1 andrei:~$ _ Other than that, I'd be glad if you included it in Phobos :o). Andrei
I'd really like to see bug 2029 fixed before standardizing it; I hate those ugly [] in the parameter list which will appear all over user code. It's a trivial change to the library code though. Where should it go? In typecons.d ?
Jan 09 2009
Don wrote:Andrei Alexandrescu wrote:Don wrote:Andrei Alexandrescu wrote:Don wrote:Denis Koroskin wrote:On Thu, 18 Dec 2008 01:38:32 +0300, Sergey GromovThu, 18 Dec 2008 00:21:58 +0300, Denis Koroskin wrote:On Thu, 18 Dec 2008 00:12:18 +0300, Sergey GromovTue, 16 Dec 2008 10:09:41 +0100, Don wrote:struct Foo { double, int } // 12 byte size, wants 8-byte alignment.
about.
align(1): struct Foo { char c; double d; short s; bool b; }
[snip]so that Foo.d.alignof == 8. Align(1) is still necessary so that Foo.sizeof == 12.
Sergey is correct to the extent that in DMD, x.alignof <= x.sizeof for any x, and also x.sizeof is always an integer multiple of x.alignof. When you assume that DMD is correct, then the simple ordering by .alignof indeed gives an optimal solution. But these values *don't* reflect the machine behaviour. real.alignof is 2. But it's significantly faster (factor of 2) on most x86 machines to have real aligned to 16. These effects are not captured by the .alignof property for structs. To capture it in the Foo example, you'd need (for example) a Foo.memberalignof property, and a Foo.memberalignoffsetof property. But you could reasonably argue that if you're specifying align(1) then alignment is not important. The simple algorithm may well be good enough. (And note that you can use radix sort -- alignof can only be 1, 2, 4, 8, or 16 -- so it's in O(n) not O(n lg n)). Interestingly, this 'internal alignment' applies to function alignment, as well. D allows you to specify that a function be aligned to (for example) a 16-byte boundary. This is hardly ever useful; usually what you want is for the innermost loop to be aligned. And instead of a pile of nops before the loop, you'd like the function start address to be adjusted.
That's cool! I think the way to the templates AlignForSpeed!(Foo) and AlignForSize!(Foo) is paved. Don, now all you have to do is a simple matter of coding :o). Andrei
Here's a very simple implementation that should solve the problem described in the original post. It doesn't deal with the obscure and difficult cases of align(1) structs, or 80-bit reals. Implementation includes workarounds for FOUR compiler bugs. Works without modification on both D1 and D2. ---- /// Order the provided members to minimize size while preserving alignment /// BUG: bugzilla 2029 prevents the signature from being (string[] names...), /// so we need to use an ugly array literal instead. char [] alignForSize(E...)(string[E.length] names) { // Sort all of the members by .alignof. // BUG: Alignment is not always optimal for align(1) structs // or 80-bit reals. // TRICK: Use the fact that .alignof is always a power of 2, // and maximum 16 on extant systems. Thus, we can perform // a very limited radix sort. int [][] alignlist; // workaround for bugzilla 2569 // alignof = 1, 2, 4, 8, 16, 32, 64 alignlist = [ [],[],[],[],[],[],[]]; // workaround for bugzilla 2562 char[][] declaration; foreach(int i_bug,T; E) { int i = i_bug; // workaround for bugzilla 2564 (D2 only) declaration ~= T.stringof ~ " " ~ names[i].dup ~ ";\n"; int a = T.alignof; int k = a==2? 1 : a==4? 2 : a==8? 3 : a==16? 4 : a==32? 5 : a>=64? 6 : 0; alignlist[k]~=i; } char [] s; foreach_reverse(q; alignlist) { foreach(int i; q) { s ~= declaration[i]; } } return s; } // Example: struct Foo { mixin(alignForSize!(int[], char[13], short, double[5])(["x", "y","z", "w"])); } is equivalent to: struct Foo{ double[5u] w; // aligned to 8 bytes int[] x; // aligned to 4 short z; // aligned to 2 char[13u] y; // aligned to 1 } which will have a size of 63, followed by 1 byte of padding.
andrei:~$ grep unittest donscode.d andrei:~$ echo $? 1 andrei:~$ _ Other than that, I'd be glad if you included it in Phobos :o). Andrei
I'd really like to see bug 2029 fixed before standardizing it; I hate those ugly [] in the parameter list which will appear all over user code. It's a trivial change to the library code though. Where should it go? In typecons.d ?
Yah, that's the place. That module quickly becomes one of my faves. Andrei
Jan 09 2009
Andrei Alexandrescu wrote:Don wrote:Andrei Alexandrescu wrote:Don wrote:Denis Koroskin wrote:On Thu, 18 Dec 2008 01:38:32 +0300, Sergey GromovThu, 18 Dec 2008 00:21:58 +0300, Denis Koroskin wrote:On Thu, 18 Dec 2008 00:12:18 +0300, Sergey GromovTue, 16 Dec 2008 10:09:41 +0100, Don wrote:struct Foo { double, int } // 12 byte size, wants 8-byte alignment.
about.
align(1): struct Foo { char c; double d; short s; bool b; }
[snip]so that Foo.d.alignof == 8. Align(1) is still necessary so that Foo.sizeof == 12.
Sergey is correct to the extent that in DMD, x.alignof <= x.sizeof for any x, and also x.sizeof is always an integer multiple of x.alignof. When you assume that DMD is correct, then the simple ordering by .alignof indeed gives an optimal solution. But these values *don't* reflect the machine behaviour. real.alignof is 2. But it's significantly faster (factor of 2) on most x86 machines to have real aligned to 16. These effects are not captured by the .alignof property for structs. To capture it in the Foo example, you'd need (for example) a Foo.memberalignof property, and a Foo.memberalignoffsetof property. But you could reasonably argue that if you're specifying align(1) then alignment is not important. The simple algorithm may well be good enough. (And note that you can use radix sort -- alignof can only be 1, 2, 4, 8, or 16 -- so it's in O(n) not O(n lg n)). Interestingly, this 'internal alignment' applies to function alignment, as well. D allows you to specify that a function be aligned to (for example) a 16-byte boundary. This is hardly ever useful; usually what you want is for the innermost loop to be aligned. And instead of a pile of nops before the loop, you'd like the function start address to be adjusted.
That's cool! I think the way to the templates AlignForSpeed!(Foo) and AlignForSize!(Foo) is paved. Don, now all you have to do is a simple matter of coding :o). Andrei
Here's a very simple implementation that should solve the problem described in the original post. It doesn't deal with the obscure and difficult cases of align(1) structs, or 80-bit reals. Implementation includes workarounds for FOUR compiler bugs. Works without modification on both D1 and D2. ---- /// Order the provided members to minimize size while preserving alignment /// BUG: bugzilla 2029 prevents the signature from being (string[] names...), /// so we need to use an ugly array literal instead. char [] alignForSize(E...)(string[E.length] names) { // Sort all of the members by .alignof. // BUG: Alignment is not always optimal for align(1) structs // or 80-bit reals. // TRICK: Use the fact that .alignof is always a power of 2, // and maximum 16 on extant systems. Thus, we can perform // a very limited radix sort. int [][] alignlist; // workaround for bugzilla 2569 // alignof = 1, 2, 4, 8, 16, 32, 64 alignlist = [ [],[],[],[],[],[],[]]; // workaround for bugzilla 2562 char[][] declaration; foreach(int i_bug,T; E) { int i = i_bug; // workaround for bugzilla 2564 (D2 only) declaration ~= T.stringof ~ " " ~ names[i].dup ~ ";\n"; int a = T.alignof; int k = a==2? 1 : a==4? 2 : a==8? 3 : a==16? 4 : a==32? 5 : a>=64? 6 : 0; alignlist[k]~=i; } char [] s; foreach_reverse(q; alignlist) { foreach(int i; q) { s ~= declaration[i]; } } return s; } // Example: struct Foo { mixin(alignForSize!(int[], char[13], short, double[5])(["x", "y","z", "w"])); } is equivalent to: struct Foo{ double[5u] w; // aligned to 8 bytes int[] x; // aligned to 4 short z; // aligned to 2 char[13u] y; // aligned to 1 } which will have a size of 63, followed by 1 byte of padding.
andrei:~$ grep unittest donscode.d andrei:~$ echo $? 1 andrei:~$ _ Other than that, I'd be glad if you included it in Phobos :o).
But this looks like something that really should be done by the compiler. This is in the compiler's area of responsibility, and using Don's template isn't very elegant either. Just look how the types and field names are separate, unlike in normal struct declarations. And the names are string literals. Instead, this should be implemented directly in the compiler. Some syntax is needed to mark structs, that should use an optimal layout. What about: align("optimal") struct Foo { int[] x; char[13] y; short z; double[5] w; } For classes, the compiler can optimize the field layout by default.
Jan 09 2009
grauzone wrote:Andrei Alexandrescu wrote:Don wrote:Andrei Alexandrescu wrote:Don wrote:Denis Koroskin wrote:On Thu, 18 Dec 2008 01:38:32 +0300, Sergey GromovThu, 18 Dec 2008 00:21:58 +0300, Denis Koroskin wrote:On Thu, 18 Dec 2008 00:12:18 +0300, Sergey GromovTue, 16 Dec 2008 10:09:41 +0100, Don wrote:struct Foo { double, int } // 12 byte size, wants 8-byte alignment.
about.
align(1): struct Foo { char c; double d; short s; bool b; }
[snip]so that Foo.d.alignof == 8. Align(1) is still necessary so that Foo.sizeof == 12.
Sergey is correct to the extent that in DMD, x.alignof <= x.sizeof for any x, and also x.sizeof is always an integer multiple of x.alignof. When you assume that DMD is correct, then the simple ordering by .alignof indeed gives an optimal solution. But these values *don't* reflect the machine behaviour. real.alignof is 2. But it's significantly faster (factor of 2) on most x86 machines to have real aligned to 16. These effects are not captured by the .alignof property for structs. To capture it in the Foo example, you'd need (for example) a Foo.memberalignof property, and a Foo.memberalignoffsetof property. But you could reasonably argue that if you're specifying align(1) then alignment is not important. The simple algorithm may well be good enough. (And note that you can use radix sort -- alignof can only be 1, 2, 4, 8, or 16 -- so it's in O(n) not O(n lg n)). Interestingly, this 'internal alignment' applies to function alignment, as well. D allows you to specify that a function be aligned to (for example) a 16-byte boundary. This is hardly ever useful; usually what you want is for the innermost loop to be aligned. And instead of a pile of nops before the loop, you'd like the function start address to be adjusted.
That's cool! I think the way to the templates AlignForSpeed!(Foo) and AlignForSize!(Foo) is paved. Don, now all you have to do is a simple matter of coding :o). Andrei
Here's a very simple implementation that should solve the problem described in the original post. It doesn't deal with the obscure and difficult cases of align(1) structs, or 80-bit reals. Implementation includes workarounds for FOUR compiler bugs. Works without modification on both D1 and D2. ---- /// Order the provided members to minimize size while preserving alignment /// BUG: bugzilla 2029 prevents the signature from being (string[] names...), /// so we need to use an ugly array literal instead. char [] alignForSize(E...)(string[E.length] names) { // Sort all of the members by .alignof. // BUG: Alignment is not always optimal for align(1) structs // or 80-bit reals. // TRICK: Use the fact that .alignof is always a power of 2, // and maximum 16 on extant systems. Thus, we can perform // a very limited radix sort. int [][] alignlist; // workaround for bugzilla 2569 // alignof = 1, 2, 4, 8, 16, 32, 64 alignlist = [ [],[],[],[],[],[],[]]; // workaround for bugzilla 2562 char[][] declaration; foreach(int i_bug,T; E) { int i = i_bug; // workaround for bugzilla 2564 (D2 only) declaration ~= T.stringof ~ " " ~ names[i].dup ~ ";\n"; int a = T.alignof; int k = a==2? 1 : a==4? 2 : a==8? 3 : a==16? 4 : a==32? 5 : a>=64? 6 : 0; alignlist[k]~=i; } char [] s; foreach_reverse(q; alignlist) { foreach(int i; q) { s ~= declaration[i]; } } return s; } // Example: struct Foo { mixin(alignForSize!(int[], char[13], short, double[5])(["x", "y","z", "w"])); } is equivalent to: struct Foo{ double[5u] w; // aligned to 8 bytes int[] x; // aligned to 4 short z; // aligned to 2 char[13u] y; // aligned to 1 } which will have a size of 63, followed by 1 byte of padding.
andrei:~$ grep unittest donscode.d andrei:~$ echo $? 1 andrei:~$ _ Other than that, I'd be glad if you included it in Phobos :o).
But this looks like something that really should be done by the compiler. This is in the compiler's area of responsibility, and using Don's template isn't very elegant either. Just look how the types and field names are separate, unlike in normal struct declarations. And the names are string literals. Instead, this should be implemented directly in the compiler. Some syntax is needed to mark structs, that should use an optimal layout. What about: align("optimal") struct Foo { int[] x; char[13] y; short z; double[5] w; } For classes, the compiler can optimize the field layout by default.
Well, it's very obscure, really. It only makes a difference when you want to reduce the size of the struct, since DMD already assigns padding to give optimal alignment. And you'd only use it in cases when you care about the size AND you don't think it's important enough to order the fields yourself (or where you can't, because you don't know the types) AND where you don't care that the compiler will add a few bytes of padding at the end. So I'm pretty much certain the compiler shouldn't include support for limited-interest stuff like this. I'm not even sure that it's useful enough to be in a standard library. It was a fun exercise though.
Jan 09 2009
== Quote from Don (nospam nospam.com)'s articleFor classes, the compiler can optimize the field layout by default.
want to reduce the size of the struct, since DMD already assigns padding to give optimal alignment. And you'd only use it in cases when you care about the size AND you don't think it's important enough to order the fields yourself (or where you can't, because you don't know the types) AND where you don't care that the compiler will add a few bytes of padding at the end. So I'm pretty much certain the compiler shouldn't include support for limited-interest stuff like this. I'm not even sure that it's useful enough to be in a standard library. It was a fun exercise though.
The thing is, those few bytes of padding really matter when you're working with large arrays of templated structs, and they can turn into tens of megabytes, or possibly even if they can just turn into kilobytes and kill cache performance. A perfect use for it (and the one I had in mind) was to build more space-efficient generic hash tables.
Jan 09 2009
Thu, 18 Dec 2008 17:08:12 +0100, Don wrote:On Thu, 18 Dec 2008 00:12:18 +0300, Sergey GromovTue, 16 Dec 2008 10:09:41 +0100, Don wrote:struct Foo { double, int } // 12 byte size, wants 8-byte alignment.
Sergey is correct to the extent that in DMD, x.alignof <= x.sizeof for any x, and also x.sizeof is always an integer multiple of x.alignof. When you assume that DMD is correct, then the simple ordering by .alignof indeed gives an optimal solution.
I think this is not something you can assume or not assume. The set of conditions you mention is required and sufficient to respect alignment requirements of array elements while obeying the rules of pointer math. You cannot change them until you drop either pointer math or alignment guarantees.But these values *don't* reflect the machine behaviour. real.alignof is 2. But it's significantly faster (factor of 2) on most x86 machines to have real aligned to 16.
If you want size, you can use align(): struct ReallySmall { int flags; align(2) real value; byte flags2; align(2) real value2; } Now ReallySmall.value.alignof == 2, and sorting will give you struct ReallySmallSorted { int flags; align(2) real value; align(2) real value2; byte flags2; } with ReallySmallSorted.sizeof == 28 and .alignof == 4 on Windows.These effects are not captured by the .alignof property for structs. To capture it in the Foo example, you'd need (for example) a Foo.memberalignof property, and a Foo.memberalignoffsetof property.
I don't understand this part. Do you say that fields in different elements of the same array should be aligned differently?
Dec 18 2008
Sergey Gromov wrote:I think this is not something you can assume or not assume. The set of conditions you mention is required and sufficient to respect alignment requirements of array elements while obeying the rules of pointer math. You cannot change them until you drop either pointer math or alignment guarantees.
You could split the sizeof property into two separate: real.alignof = 16 real.unpaddedsizeof = 12 real.paddedsizeof = 16 T.paddedsizeof = (T.unpaddedsizeof + T.alignof - 1) & ~T.alignof; Arrays would always use paddedsizeof to calculate addresses. Structs could use unpaddedsizeof and squeeze one or more additional variables into the padding space. The same applies to structs: struct C { int a; byte b; } C.alignof = 4 C.unpaddedsizeof = 5 C.paddedsizeof = 8 There is one problem with this technique. Because the padding space of a variable may contain another variable, when the variable is copied, only unpaddedsizeof bytes may be copied or the other variable will be clobbered. I expect that this partially negates the advantage of properly aligning the variable. -- Rainer Deyke
Dec 18 2008
Sergey Gromov wrote:Thu, 18 Dec 2008 17:08:12 +0100, Don wrote:On Thu, 18 Dec 2008 00:12:18 +0300, Sergey GromovTue, 16 Dec 2008 10:09:41 +0100, Don wrote:struct Foo { double, int } // 12 byte size, wants 8-byte alignment.
any x, and also x.sizeof is always an integer multiple of x.alignof. When you assume that DMD is correct, then the simple ordering by .alignof indeed gives an optimal solution.
I think this is not something you can assume or not assume. The set of conditions you mention is required and sufficient to respect alignment requirements of array elements while obeying the rules of pointer math. You cannot change them until you drop either pointer math or alignment guarantees.But these values *don't* reflect the machine behaviour. real.alignof is 2. But it's significantly faster (factor of 2) on most x86 machines to have real aligned to 16.
If you want size, you can use align(): struct ReallySmall { int flags; align(2) real value; byte flags2; align(2) real value2; } Now ReallySmall.value.alignof == 2, and sorting will give you struct ReallySmallSorted { int flags; align(2) real value; align(2) real value2; byte flags2; } with ReallySmallSorted.sizeof == 28 and .alignof == 4 on Windows.These effects are not captured by the .alignof property for structs. To capture it in the Foo example, you'd need (for example) a Foo.memberalignof property, and a Foo.memberalignoffsetof property.
I don't understand this part. Do you say that fields in different elements of the same array should be aligned differently?
No. It only applies in this situation where you have a struct which contains another struct which is align(1). Given align(1): struct Foo { int a; double b; } (A) struct Bar { int c; Foo d; } (B) struct Bar { Foo d; int c; } (A) is better than (B) because it aligns Bar.d.b correctly. It's a trick, really -- it's using the other elements of Bar as padding for Foo. I can't think of any other cases where this trick applies. As you say, an array of Foo[] cannot have all of its elements aligned. So probably, the 'ideal solution' for the proposed template would be probe the insides of each struct to see if the trick can be used. real80 is another case where the trick can be applied. float[4] may also benefit from being aligned to a 16-byte boundary. With Intel's AVX instructions, something as large as float[16] might like to be on a 256-byte boundary, but all such cases are easy, since they involve x.sizeof == pow(2,k). align(1) structs and real80 are the only non-trivial ones.
Dec 19 2008
Reply to Andrei,BCS wrote:would "align 1" work?
(in first approximation) to sort the members in decreasing order of size. Odd-sized arrays of char foil this plan to some extent, which is where the fun begins. Andrei
?? http://en.wikipedia.org/wiki/Bin_packing_problem
Dec 15 2008
== Quote from BCS (ao pathlink.com)'s article
http://en.wikipedia.org/wiki/Bin_packing_problem
Yes, but most structs are small enough that the asymptotic complexity really isn't important. For structs of maybe 4 or less elements, trying every possible permutation in O(N!) seems perfectly reasonable to me. For larger structs, using heuristics might be necessary.
Dec 15 2008
dsimcha wrote:== Quote from BCS (ao pathlink.com)'s article?? http://en.wikipedia.org/wiki/Bin_packing_problem
Yes, but most structs are small enough that the asymptotic complexity really isn't important. For structs of maybe 4 or less elements, trying every possible permutation in O(N!) seems perfectly reasonable to me. For larger structs, using heuristics might be necessary.
You're only interested in the values of x.sizeof&(x.alignof-1), and x.alignof is only ever 16,8,4,2, or 1. So there are only 65(?) possible elements. I'm pretty sure it can be done in linear time, with the calculation maybe even done in constant time.
Dec 15 2008
BCS wrote:Reply to Andrei,BCS wrote:would "align 1" work?
(in first approximation) to sort the members in decreasing order of size. Odd-sized arrays of char foil this plan to some extent, which is where the fun begins. Andrei
?? http://en.wikipedia.org/wiki/Bin_packing_problem
It's not a bin packing problem because the restrictions are very different. Clearly it's not a simple problem either! I wonder if it's NP-hard, and I highly doubt it (in fact I'm almost sure it isn't) because it can be easily decomposed into smaller subproblems. Andrei
Dec 15 2008
On Thu, 18 Dec 2008 00:12:18 +0300, Sergey Gromov <snake.scaly gmail.com> wrote:Tue, 16 Dec 2008 10:09:41 +0100, Don wrote:Example 2: struct Foo { double, int } // 12 byte size, wants 8-byte alignment.
Foo.sizeof is 16.
It is 12 with align(1) (I see no problem with it).The thing is, array of Foo's must be properly aligned, and &foo[1] must be cast(byte*) &foo[0] + Foo.sizeof. This means that Foo.sizeof must be itself 8-aligned. The solution is { Foo, Foo, int, int }.
Stop right there. You can't access &foo[1] no matter what align or structure layout is used. Example: align(default): struct Data { int i1; short s2; char c1; int 12; } What is &i1[1]?
Dec 17 2008
On Thu, 18 Dec 2008 01:38:32 +0300, Sergey Gromov <snake.scaly gmail.com> wrote:Thu, 18 Dec 2008 00:21:58 +0300, Denis Koroskin wrote:On Thu, 18 Dec 2008 00:12:18 +0300, Sergey Gromov <snake.scaly gmail.com> wrote:Tue, 16 Dec 2008 10:09:41 +0100, Don wrote:Example 2: struct Foo { double, int } // 12 byte size, wants 8-byte alignment.
Foo.sizeof is 16.
It is 12 with align(1) (I see no problem with it).
With align(1) the Foo.alignof is 1 so there is no problem to talk about. The problem is when you have elements with non-trivial alignment requirements and want to pack them as tightly as possible.
No, there is. You should have structure as follows: align(1): struct Foo { char c; double d; short s; bool b; } it should be reordered to (one of the solutions): align(1): struct Foo { char c; bool b; short s; double d; } so that Foo.d.alignof == 8. Align(1) is still necessary so that Foo.sizeof == 12.The thing is, array of Foo's must be properly aligned, and &foo[1] must be cast(byte*) &foo[0] + Foo.sizeof. This means that Foo.sizeof must be itself 8-aligned. The solution is { Foo, Foo, int, int }.
Stop right there. You can't access &foo[1] no matter what align or structure layout is used. Example: align(default): struct Data { int i1; short s2; char c1; int 12; } What is &i1[1]?
i1 is not an array. Sorry I wasn't clear enough. I was talking about an imaginary array of Foo's: Foo[] foo; You must admit that foo[1] and &foo[1] makes perfect sense for such construct. And that cast(byte*) &foo[1] - cast(byte*) &foo[0] == Foo.sizeof must hold.
This will *always* be true no matter what align/data layout is used.
Dec 18 2008









Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> 