September 05, 2012
Benjamin Thaut wrote:
> I do object pooling in both versions, as in game developement you
> usually don't allocate during the frame. But still in the GC version you
> have the problem that way to many parts of the language allocate and you
> don't event notice it when using the GC.

There's one proposed solution to this problem: http://forum.dlang.org/thread/k1rlhn$19du$1@digitalmars.com
September 05, 2012
On Wednesday, 5 September 2012 at 12:27:05 UTC, Benjamin Thaut wrote:
> Then because they are const, TypeInfo_Const.toString() will be called:
>
>     override string toString()
>     {
>         return cast(string) ("const(" ~ base.toString() ~ ")");
>     }
>
> which allocates, due to array concardination.

Wow.
September 05, 2012
Am 05.09.2012 14:34, schrieb Peter Alexander:
> On Wednesday, 5 September 2012 at 12:27:05 UTC, Benjamin Thaut wrote:
>> Then because they are const, TypeInfo_Const.toString() will be called:
>>
>>     override string toString()
>>     {
>>         return cast(string) ("const(" ~ base.toString() ~ ")");
>>     }
>>
>> which allocates, due to array concardination.
>
> Wow.

I already have a fix for this.

https://github.com/Ingrater/druntime/commit/74713f7af496fd50fe4cfe60b3d9906b87efbdb6
https://github.com/Ingrater/druntime/commit/05c440b0322d39cf98425f50172c468c6659efb8

If I find a good description how to do pull requests, I might be able to do one.

Kind Regards
Benjamin Thaut
September 05, 2012
On 5 September 2012 13:27, Benjamin Thaut <code@benjamin-thaut.de> wrote:
> Am 05.09.2012 14:14, schrieb Alex Rønne Petersen:
>
>>
>> Where's the catch? From looking in druntime, I don't see where the allocation could occur.
>>
>
> Everything is in object_.d:
>
>     equals_t opEquals(Object lhs, Object rhs)
>     {
>         if (lhs is rhs)
>             return true;
>         if (lhs is null || rhs is null)
>             return false;
>         if (typeid(lhs) == typeid(rhs))
>             return lhs.opEquals(rhs);
>         return lhs.opEquals(rhs) &&
>                rhs.opEquals(lhs);
>     }
>
> Will trigger a comparison of the TypeInfo objects with
> if (typeid(lhs) == typeid(rhs))
>
> Which will after some function calls trigger opEquals of TypeInfo
>
>     override equals_t opEquals(Object o)
>     {
>         /* TypeInfo instances are singletons, but duplicates can exist
>          * across DLL's. Therefore, comparing for a name match is
>          * sufficient.
>          */
>         if (this is o)
>             return true;
>         TypeInfo ti = cast(TypeInfo)o;
>         return ti && this.toString() == ti.toString();
>     }
>

This got fixed.  Said code is now:

override equals_t opEquals(Object o)
{
    if (this is o)
        return true;
    auto c = cast(const TypeInfo_Class)o;
    return c && this.info.name == c.info.name;
}

Causing no hidden allocation.


Regards
-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';
September 05, 2012
On 5 September 2012 14:04, Iain Buclaw <ibuclaw@ubuntu.com> wrote:
> On 5 September 2012 13:27, Benjamin Thaut <code@benjamin-thaut.de> wrote:
>> Am 05.09.2012 14:14, schrieb Alex Rønne Petersen:
>>
>>>
>>> Where's the catch? From looking in druntime, I don't see where the allocation could occur.
>>>
>>
>> Everything is in object_.d:
>>
>>     equals_t opEquals(Object lhs, Object rhs)
>>     {
>>         if (lhs is rhs)
>>             return true;
>>         if (lhs is null || rhs is null)
>>             return false;
>>         if (typeid(lhs) == typeid(rhs))
>>             return lhs.opEquals(rhs);
>>         return lhs.opEquals(rhs) &&
>>                rhs.opEquals(lhs);
>>     }
>>
>> Will trigger a comparison of the TypeInfo objects with
>> if (typeid(lhs) == typeid(rhs))
>>
>> Which will after some function calls trigger opEquals of TypeInfo
>>
>>     override equals_t opEquals(Object o)
>>     {
>>         /* TypeInfo instances are singletons, but duplicates can exist
>>          * across DLL's. Therefore, comparing for a name match is
>>          * sufficient.
>>          */
>>         if (this is o)
>>             return true;
>>         TypeInfo ti = cast(TypeInfo)o;
>>         return ti && this.toString() == ti.toString();
>>     }
>>
>
> This got fixed.  Said code is now:
>
> override equals_t opEquals(Object o)
> {
>     if (this is o)
>         return true;
>     auto c = cast(const TypeInfo_Class)o;
>     return c && this.info.name == c.info.name;
> }
>
> Causing no hidden allocation.
>
>

Oops, let me correct myself.

This was hacked at to call the *correct* opEquals method above.


bool opEquals(const Object lhs, const Object rhs)
{
    // A hack for the moment.
    return opEquals(cast()lhs, cast()rhs);
}


Regards
-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';
September 05, 2012
On 9/5/12 1:03 PM, Benjamin Thaut wrote:
> http://3d.benjamin-thaut.de/?p=20#more-20

Smile, you're on reddit:

http://www.reddit.com/r/programming/comments/ze4cx/real_world_comparison_gc_vs_manual_memory/


Andrei
September 05, 2012
On Wednesday, 5 September 2012 at 12:22:52 UTC, Alex Rønne Petersen wrote:
> On 05-09-2012 13:03, Benjamin Thaut wrote:
>> I rewrote a 3d game I created during my studies with D 2.0 to manual
>> memory mangement. If I'm not studying I'm working in the 3d Engine
>> deparement of Havok. As I needed to pratice manual memory management and
>> did want to get rid of the GC in D for quite some time, I did go through
>> all this effort to create a GC free version of my game.
>>
>> The results are:
>>
>>     DMD GC Version: 71 FPS, 14.0 ms frametime
>>     GDC GC Version: 128.6 FPS, 7.72 ms frametime
>>     DMD MMM Version: 142.8 FPS, 7.02 ms frametime
>>
>> GC collection times:
>>
>>     DMD GC Version: 8.9 ms
>>     GDC GC Version: 4.1 ms
>>
>> As you see the manual managed version is twice as fast as the garbage
>> collected one. Even the highly optimized version created with GDC is
>> still slower the the manual memory management.
>>
>> You can find the full article at:
>>
>> http://3d.benjamin-thaut.de/?p=20#more-20
>>
>>
>> Feedback is welcome.
>>
>> Kind Regards
>> Benjamin Thaut
>
> BTW, your blog post appears to have comparison misspelled.

Also "development".

It was interesting to read it. What about GDC MMM?



September 05, 2012
Benjamin Thaut:

> http://3d.benjamin-thaut.de/?p=20#more-20

Regardind your issues list, most of them are fixable, like the one regarding array literals, and even the one regarding the invariant handler.

But I didn't know about this, and I don't know how and if this is fixable:

>The new statement will not free any memory if the constructor throws a exception.<

Insights welcome.

Bye,
bearophile
September 05, 2012
Am 05.09.2012 15:07, schrieb Iain Buclaw:
> On 5 September 2012 14:04, Iain Buclaw <ibuclaw@ubuntu.com> wrote:
>> On 5 September 2012 13:27, Benjamin Thaut <code@benjamin-thaut.de> wrote:
>>> Am 05.09.2012 14:14, schrieb Alex Rønne Petersen:
>>>
>>>>
>>>> Where's the catch? From looking in druntime, I don't see where the
>>>> allocation could occur.
>>>>
>>>
>>> Everything is in object_.d:
>>>
>>>      equals_t opEquals(Object lhs, Object rhs)
>>>      {
>>>          if (lhs is rhs)
>>>              return true;
>>>          if (lhs is null || rhs is null)
>>>              return false;
>>>          if (typeid(lhs) == typeid(rhs))
>>>              return lhs.opEquals(rhs);
>>>          return lhs.opEquals(rhs) &&
>>>                 rhs.opEquals(lhs);
>>>      }
>>>
>>> Will trigger a comparison of the TypeInfo objects with
>>> if (typeid(lhs) == typeid(rhs))
>>>
>>> Which will after some function calls trigger opEquals of TypeInfo
>>>
>>>      override equals_t opEquals(Object o)
>>>      {
>>>          /* TypeInfo instances are singletons, but duplicates can exist
>>>           * across DLL's. Therefore, comparing for a name match is
>>>           * sufficient.
>>>           */
>>>          if (this is o)
>>>              return true;
>>>          TypeInfo ti = cast(TypeInfo)o;
>>>          return ti && this.toString() == ti.toString();
>>>      }
>>>
>>
>> This got fixed.  Said code is now:
>>
>> override equals_t opEquals(Object o)
>> {
>>      if (this is o)
>>          return true;
>>      auto c = cast(const TypeInfo_Class)o;
>>      return c && this.info.name == c.info.name;
>> }
>>
>> Causing no hidden allocation.
>>
>>
>
> Oops, let me correct myself.
>
> This was hacked at to call the *correct* opEquals method above.
>
>
> bool opEquals(const Object lhs, const Object rhs)
> {
>      // A hack for the moment.
>      return opEquals(cast()lhs, cast()rhs);
> }
>
>
> Regards
>

Still, comparing two type info objects will result in one or multiple allocations most of the time.

Kind Regards
Benjamin Thaut
September 05, 2012
On 5 September 2012 15:57, bearophile <bearophileHUGS@lycos.com> wrote:
> Benjamin Thaut:
>
>> http://3d.benjamin-thaut.de/?p=20#more-20
>
>
> Regardind your issues list, most of them are fixable, like the one regarding array literals, and even the one regarding the invariant handler.
>

I have no clue what the issue with invariant handlers is...  Calls to them are not emitted in release code, and if you think they are, then you've probably built either your application, or the library you are using wrong.

Array literals are not so easy to fix.  I once thought that it would be optimal to make it a stack initialisation given that all values are known at compile time, this infact caused many strange SEGV's in quite a few of my programs  (most are parsers / interpreters, so things that go down *heavy* nested into itself, and it was under these circumstances that array literals on the stack would go corrupt in one way or another causing *huge* errors in perfectly sound code).



-- 
Iain Buclaw

*(p < e ? p++ : p) = (c & 0x0f) + '0';