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,
Ali
Non 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









Stefan Koch <uplink.coder googlemail.com> 