Thread overview
StructType.init and StructType() cause a allocation
Jun 30, 2012
Benjamin Thaut
Jun 30, 2012
bearophile
Jun 30, 2012
bearophile
Jun 30, 2012
Benjamin Thaut
June 30, 2012
If T is a struct both of the following statements will lead to a call of the _d_arrayliteral function which will allocate a array of the size of the struct just to initialize it!!

void T[] data = ...;

data[0] = T.init;
data[0] = T();

This has proven to be the biggest performance bottleneck in my current codebase, replacing this statement with a unneccessary workaround speeds my code up by factor 100. This is the cause because all of my container classes tend to reinitialize the contents of the data arrays they are holding. Also this bug makes it very hard to write non leaking code when not using a GC. The replacement code could be

T temp;
data[0] = temp;

Which works correctly as long as T is publicly accessible, if it is a private type this will not compile. Then you have to do some more fancy stuff like:

void[T.sizeof] temp;
void[] initMem = typeid(T).init();
if(initMem.ptr is null)
  memset(temp.ptr, 0, temp.length);
else
  temp[] = initMem[];
data[0] = *cast(T*)temp.ptr;

How hard would it be to fix this?

It is really a shame that reinitalizing a struct
a) is a major performance bottleneck
b) leaks memory

I created a bug ticket for this 6 months ago, but it has been ignored so far: http://d.puremagic.com/issues/show_bug.cgi?id=7271

Kind Regards
Benjamin Thaut
June 30, 2012
Benjamin Thaut:

> I created a bug ticket for this 6 months ago, but it has been ignored so far: http://d.puremagic.com/issues/show_bug.cgi?id=7271

A similar bug was fixed very recently. D used to allocate a dynamic array of length 1 when you write "new T" where T is a struct. I don't know if that bug fix (in dmd 2.060alpha) has fixed your problem too. Such kind of bugs do get fixed, eventually :-)

Bye,
bearophile
June 30, 2012
> I don't know if that bug fix (in dmd 2.060alpha) has fixed your problem too.

I have compiled this code from your issue 7271 with the latest beta:


struct MemoryBlockInfo {
    size_t size;
    long[10] backtrace;
    int backtraceSize;

    this(size_t size) {
        this.size = size;
    }
}
void main() {
    MemoryBlockInfo info;
    info = MemoryBlockInfo.init; //array allocation here
}


Compiling it with no optimization it gives:


_D4temp15MemoryBlockInfo6__ctorMFkZS4temp15MemoryBlockInfo
        enter   4,0
        mov ECX,8[EBP]
        mov [EAX],ECX
        leave
        ret 4

__Dmain comdat
        enter   060h,0
        push    ESI
        push    EDI
        mov ECX,018h
        xor EAX,EAX
        lea EDI,-060h[EBP]
        rep
        stosd
        mov ESI,offset FLAT:_D4temp15MemoryBlockInfo6__initZ
        lea EDI,-060h[EBP]
        mov CL,018h
        rep
        movsd
        pop EDI
        pop ESI
        leave
        ret


With -O -release -inline it becomes:


_D4temp15MemoryBlockInfo6__ctorMFkZS4temp15MemoryBlockInfo  comdat
        push    EAX
        mov ECX,8[ESP]
        mov [EAX],ECX
        pop ECX
        ret 4

__Dmain comdat
        sub ESP,064h
        mov ECX,018h
        xor EAX,EAX
        push    EDI
        lea EDI,4[ESP]
        rep
        stosd
        pop EDI
        add ESP,064h
        ret


In both cases I don't see a memory allocation.

Bye,
bearophile
June 30, 2012
Am 30.06.2012 13:52, schrieb bearophile:
>> I don't know if that bug fix (in dmd 2.060alpha) has fixed your
>> problem too.
>
> I have compiled this code from your issue 7271 with the latest beta:
>
>
> struct MemoryBlockInfo {
>      size_t size;
>      long[10] backtrace;
>      int backtraceSize;
>
>      this(size_t size) {
>          this.size = size;
>      }
> }
> void main() {
>      MemoryBlockInfo info;
>      info = MemoryBlockInfo.init; //array allocation here
> }
>
>
> Compiling it with no optimization it gives:
>
>
> _D4temp15MemoryBlockInfo6__ctorMFkZS4temp15MemoryBlockInfo
>          enter   4,0
>          mov ECX,8[EBP]
>          mov [EAX],ECX
>          leave
>          ret 4
>
> __Dmain comdat
>          enter   060h,0
>          push    ESI
>          push    EDI
>          mov ECX,018h
>          xor EAX,EAX
>          lea EDI,-060h[EBP]
>          rep
>          stosd
>          mov ESI,offset FLAT:_D4temp15MemoryBlockInfo6__initZ
>          lea EDI,-060h[EBP]
>          mov CL,018h
>          rep
>          movsd
>          pop EDI
>          pop ESI
>          leave
>          ret
>
>
> With -O -release -inline it becomes:
>
>
> _D4temp15MemoryBlockInfo6__ctorMFkZS4temp15MemoryBlockInfo  comdat
>          push    EAX
>          mov ECX,8[ESP]
>          mov [EAX],ECX
>          pop ECX
>          ret 4
>
> __Dmain comdat
>          sub ESP,064h
>          mov ECX,018h
>          xor EAX,EAX
>          push    EDI
>          lea EDI,4[ESP]
>          rep
>          stosd
>          pop EDI
>          add ESP,064h
>          ret
>
>
> In both cases I don't see a memory allocation.
>
> Bye,
> bearophile

Thank you, Its very nice to know that this got fixed. Someone might want to close the ticket as duplicate then.

Kind Regards
Benjamin Thaut