digitalmars.D - Large .init for class containing void-initialized struct
- =?UTF-8?Q?Ali_=c3=87ehreli?= (63/63) Dec 06 2016 tl;dr; go to the TLDR section below. :)
- Stefan Koch (4/10) Dec 06 2016 I think this is a bug.
- ketmar (6/10) Dec 06 2016 https://issues.dlang.org/show_bug.cgi?id=11331
- Johan Engelen (11/23) Dec 07 2016 I think what's blocking things is:
- Basile B. (24/48) Dec 06 2016 Non initialized classes just don't work. Because of the hidden
- =?UTF-8?Q?Ali_=c3=87ehreli?= (17/54) Dec 07 2016 Understood. Please confirm whether the following is a bug. Just because
- Basile B. (11/72) Dec 07 2016 I've said bullshit here. In case of manual init, gaps couldn't be
- =?UTF-8?Q?Ali_=c3=87ehreli?= (4/5) Dec 07 2016 https://issues.dlang.org/show_bug.cgi?id=16956
tl;dr; go to the TLDR section below. :) I use the following command line to identify large symbols. Given a binary named 'deneme', the following command line (at least on Linux) produces the 30 largest symbols in the 'deneme' binary that actually take space in application's memory: nm --print-size --size-sort --radix=d deneme | tail -30 | grep -v " B " A test program: struct S { int i; double d; ubyte[10_000] a; } void main() { } According to the command line above, the largest symbol in that program is S.init: [...] 0000000004446100 0000000000003633 T _D4core4time8Duration13_toStringImplMxFNaNbNfZAya 0000000004504980 0000000000003707 T _d_arraysetlengthiT 0000000004511312 0000000000010016 R _D6deneme1S6__initZ So, the S.init object in that binary is 10016 bytes and that makes sense. Now, request S.init not be generated by initializing the members with void: struct S { int i = void; // (Actually, this =void is not required) double d = void; ubyte[10_000] a = void; } void main() { } Great: Now the large S.init is not a part of the binary: (Well, I think it's still in the BSS section but it does not take space in the memory): [...] 0000000004446100 0000000000003633 T _D4core4time8Duration13_toStringImplMxFNaNbNfZAya 0000000004504980 0000000000003707 T _d_arraysetlengthiT The largest symbol is now something else: _d_arraysetlengthiT. Here comes the trouble... TLDR: Use the void-initialized struct as a class member and that class gets a huge C.init: struct S { int i = void; double d = void; ubyte[10_000] a = void; } class C { S s = void; // (Same result even without the =void) } void main() { } [...] 0000000004446260 0000000000003633 T _D4core4time8Duration13_toStringImplMxFNaNbNfZAya 0000000004505140 0000000000003707 T _d_arraysetlengthiT 0000000006681456 0000000000010032 V _D6deneme1C6__initZ Now we have a 10032 byte C.init. Is there a rationale for this or is this an implementation quality issue? Is there a bug already? I could not find one. Also, I failed to find the "= void" documentation e.g. not on the struct spec page. Thank you, Ali
Dec 06 2016
On Wednesday, 7 December 2016 at 00:20:11 UTC, Ali Çehreli wrote:tl;dr; go to the TLDR section below. :) I use the following command line to identify large symbols. Given a binary named 'deneme', the following command line (at least on Linux) produces the 30 largest symbols in the 'deneme' binary that actually take space in application's memory: [...]I think this is a bug. Why is the classInit generated at all ? We don't guarantee blit construction of classes./////////////
Dec 06 2016
On Wednesday, 7 December 2016 at 00:20:11 UTC, Ali Çehreli wrote:Is there a rationale for this or is this an implementation quality issue? Is there a bug already? I could not find one. Also, I failed to find the "= void" documentation e.g. not on the struct spec page.https://issues.dlang.org/show_bug.cgi?id=11331 https://issues.dlang.org/show_bug.cgi?id=11817 at least. i.e.: known inefficiency, but nobody feels that it is important enough to get to the top of the list.
Dec 06 2016
On Wednesday, 7 December 2016 at 00:35:21 UTC, ketmar wrote:On Wednesday, 7 December 2016 at 00:20:11 UTC, Ali Çehreli wrote:Yep, many bugs about it.Is there a rationale for this or is this an implementation quality issue? Is there a bug already? I could not find one. Also, I failed to find the "= void" documentation e.g. not on the struct spec page.https://issues.dlang.org/show_bug.cgi?id=11331 https://issues.dlang.org/show_bug.cgi?id=11817 at least.i.e.: known inefficiency, but nobody feels that it is important enough to get to the top of the list.I think what's blocking things is: ``` T a; T b; assert(a == b); ``` Someone noted that that's a language guarantee, which would have to be relaxed for aggregates with `= void`initialized fields. -Johan
Dec 07 2016
On Wednesday, 7 December 2016 at 00:20:11 UTC, Ali Çehreli wrote:tl;dr; go to the TLDR section below. :) [...] struct S { int i = void; double d = void; ubyte[10_000] a = void; } class C { S s = void; // (Same result even without the =void) } void main() { } [...] 0000000004446260 0000000000003633 T _D4core4time8Duration13_toStringImplMxFNaNbNfZAya 0000000004505140 0000000000003707 T _d_arraysetlengthiT 0000000006681456 0000000000010032 V _D6deneme1C6__initZ Now we have a 10032 byte C.init. Is there a rationale for this or is this an implementation quality issue? Is there a bug already? I could not find one. Also, I failed to find the "= void" documentation e.g. not on the struct spec page. Thank you, AliNon initialized classes just don't work. Because of the hidden classes fields an initializer is **always** needed. What happens in your example is that the initializer size is sub optimal. A naive make without emplace(): ==== import std.traits, std.c.stdlib; CT make(CT, A...)(A a) { auto memory = malloc(__traits(classInstanceSize, CT)); version(none) emplace!Foo(memory[0..__traits(classInstanceSize, CT)]); static if (__traits(hasMember, CT, "__ctor")) (cast(CT) (memory)).__ctor(a); return cast(CT) memory; } class Foo{void foo(){}} void main() { Foo foo = make!Foo; foo.foo; } ==== crashes with a segfault....
Dec 06 2016
On 12/06/2016 06:10 PM, Basile B. wrote:On Wednesday, 7 December 2016 at 00:20:11 UTC, Ali Çehreli wrote:Understood. Please confirm whether the following is a bug. Just because a class uses a *pointer* to a void-initialized struct, the struct gets a .init: struct MyStruct(T) { T[10_000] a = void; } // Same with struct class Outer { MyStruct!ubyte* s; } void main() { } 0000000006681728 0000000000010000 V _D6deneme15__T8MyStructThZ8MyStruct6__initZ Make the struct a non-template and MyStruct.init disappears as expected. Alitl;dr; go to the TLDR section below. :) [...] struct S { int i = void; double d = void; ubyte[10_000] a = void; } class C { S s = void; // (Same result even without the =void) } void main() { } [...] 0000000004446260 0000000000003633 T _D4core4time8Duration13_toStringImplMxFNaNbNfZAya 0000000004505140 0000000000003707 T _d_arraysetlengthiT 0000000006681456 0000000000010032 V _D6deneme1C6__initZ Now we have a 10032 byte C.init. Is there a rationale for this or is this an implementation quality issue? Is there a bug already? I could not find one. Also, I failed to find the "= void" documentation e.g. not on the struct spec page. Thank you, AliNon initialized classes just don't work. Because of the hidden classes fields an initializer is **always** needed. What happens in your example is that the initializer size is sub optimal.
Dec 07 2016
On Wednesday, 7 December 2016 at 08:46:13 UTC, Ali Çehreli wrote:On 12/06/2016 06:10 PM, Basile B. wrote:I've said bullshit here. In case of manual init, gaps couldn't be handled easily anyway. We have the aggregate size, we have a pointer to its initializer, that's all.On Wednesday, 7 December 2016 at 00:20:11 UTC, Ali Çehreliwrote:qualitytl;dr; go to the TLDR section below. :) [...] struct S { int i = void; double d = void; ubyte[10_000] a = void; } class C { S s = void; // (Same result even without the =void) } void main() { } [...] 0000000004446260 0000000000003633 T _D4core4time8Duration13_toStringImplMxFNaNbNfZAya 0000000004505140 0000000000003707 T _d_arraysetlengthiT 0000000006681456 0000000000010032 V _D6deneme1C6__initZ Now we have a 10032 byte C.init. Is there a rationale for this or is this an implementationon theissue? Is there a bug already? I could not find one. Also, I failed to find the "= void" documentation e.g. nothidden classesstruct spec page. Thank you, AliNon initialized classes just don't work. Because of thefields an initializer is **always** needed. What happens inyour exampleis that the initializer size is sub optimal.Understood. Please confirm whether the following is a bug. Just because a class uses a *pointer* to a void-initialized struct, the struct gets a .init: struct MyStruct(T) { T[10_000] a = void; } // Same with struct class Outer { MyStruct!ubyte* s; } void main() { } 0000000006681728 0000000000010000 V _D6deneme15__T8MyStructThZ8MyStruct6__initZ Make the struct a non-template and MyStruct.init disappears as expected. AliI wouldn't say it's a bug rather an enhancement request. Unfortunately with my expertise level I can't say more. I think that one of the GDC member expressed some interest into making initialization of aggregates better. It was when A.Alexandrescu worked on RCString, I can't find the link anymore, it was about RCString init being slow, in comparison to a cpp equivalent. It looks like this discussion is highly related.
Dec 07 2016
On 12/07/2016 02:56 AM, Basile B. wrote:rather an enhancement requesthttps://issues.dlang.org/show_bug.cgi?id=16956 Thank you, Ali
Dec 07 2016