www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Delegate Memory Usage & Optimization

reply "Maxime Chevalier-Boisvert" <maximechevalierb gmail.com> writes:
I have a use case where I will need to generate millions 
(possibly hundreds of millions) of delegates with the same type 
signature. I'd like to know more about the memory usage 
characteristics. I have two questions:

1. Delegates have environment/context pointer. If the delegate 
does not capture/access any variables from the englobing function 
(if it behaves like a static nested function), will a context 
object be allocated anyways, or will this pointer be null? Does 
DMD optimize this case?

2. Delegates are a function pointer and an environment pointer. 
Are they passed/stored by value, as a struct would be, or heap 
allocated and passed by reference?
Dec 11 2013
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 12/11/2013 6:27 PM, Maxime Chevalier-Boisvert wrote:
 I have a use case where I will need to generate millions (possibly hundreds of
 millions) of delegates with the same type signature. I'd like to know more
about
 the memory usage characteristics. I have two questions:

 1. Delegates have environment/context pointer. If the delegate does not
 capture/access any variables from the englobing function (if it behaves like a
 static nested function), will a context object be allocated anyways,
No.
 or will this pointer be null?
No. It'll be a pointer to the enclosing stack frame, even if it is never used.
 Does DMD optimize this case?
Yes. It only allocates a closure if (1) it thinks the delegate may escape the scope and (2) uplevel references are used in the delegate.
 2. Delegates are a function pointer and an environment pointer. Are they
 passed/stored by value, as a struct would be,
Yes.
 or heap allocated and passed by reference?
No. I strongly suggest trying out a couple examples, and disassembling the result to confirm.
Dec 11 2013
next sibling parent reply "Maxime Chevalier-Boisvert" <maximechevalierb gmail.com> writes:
 It only allocates a closure if (1) it thinks the delegate may 
 escape the scope and (2) uplevel references are used in the 
 delegate.
The delegate will escape the enclosing scope. I'm wondering if there will still be some kind of scope object allocated to represent escaping values in the englobing stack frame, even when there are no escaping values. I don't mind paying the small cost of an extraneous null context pointer, but having a whole unnecessary context object allocated seems wasteful.
 I strongly suggest trying out a couple examples, and 
 disassembling the result to confirm.
I'll look into that.
Dec 11 2013
next sibling parent Manu <turkeyman gmail.com> writes:
On 12 December 2013 13:45, Maxime Chevalier-Boisvert <
maximechevalierb gmail.com> wrote:

 It only allocates a closure if (1) it thinks the delegate may escape the
 scope and (2) uplevel references are used in the delegate.
The delegate will escape the enclosing scope. I'm wondering if there will still be some kind of scope object allocated to represent escaping values in the englobing stack frame, even when there are no escaping values. I don't mind paying the small cost of an extraneous null context pointer, but having a whole unnecessary context object allocated seems wasteful.
If you have no use for the context pointer, then it sounds like what you want is a function pointer, not a delegate. A delegate is just a function-ptr+context-ptr pair, it is a trivial struct that is passed by value, the same as a dynamic array. The context pointer may be to a stack frame (in case of a closure), or a class object (in the case of a class method pointer). If you intend a null context pointer (ie, function doesn't reference any state), than what you really have is a function pointer, not a delegate. You should use a function pointer instead. Can you show your usage? I strongly suggest trying out a couple examples, and disassembling the
 result to confirm.
I'll look into that.
Dec 11 2013
prev sibling next sibling parent reply Manu <turkeyman gmail.com> writes:
On 12 December 2013 14:06, Manu <turkeyman gmail.com> wrote:

 On 12 December 2013 13:45, Maxime Chevalier-Boisvert <
 maximechevalierb gmail.com> wrote:

 It only allocates a closure if (1) it thinks the delegate may escape the
 scope and (2) uplevel references are used in the delegate.
The delegate will escape the enclosing scope. I'm wondering if there will still be some kind of scope object allocated to represent escaping values in the englobing stack frame, even when there are no escaping values. I don't mind paying the small cost of an extraneous null context pointer, but having a whole unnecessary context object allocated seems wasteful.
If you have no use for the context pointer, then it sounds like what you want is a function pointer, not a delegate. A delegate is just a function-ptr+context-ptr pair, it is a trivial struct that is passed by value, the same as a dynamic array. The context pointer may be to a stack frame (in case of a closure), or a class object (in the case of a class method pointer). If you intend a null context pointer (ie, function doesn't reference any state), than what you really have is a function pointer, not a delegate. You should use a function pointer instead.
Oh sorry, I see. you just mean in some cases functions that don't access state will be bound to your delegate. It seems unusual to me for a function that doesn't access any state to produce a delegate. Wouldn't it be static, or a free function in that case? There are tricks to bind a free function to a delegate using a little call-through stub. It sets the delegate function to a callthrough-stub which internally casts 'this' to a 'function' and calls it with the same arguments. Don does it to bind static functions to delegates in his C++ FastDelegate library. I wonder if there's a helper in phobos? You can be sure when assigning functions to delegates in this way that there will never be any associated state. Can you show your usage?
  I strongly suggest trying out a couple examples, and disassembling the
 result to confirm.
I'll look into that.
Dec 11 2013
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 12/12/2013 05:16 AM, Manu wrote:
 Don does it to bind static functions to delegates in his C++
 FastDelegate library. I wonder if there's a helper in phobos?
 You can be sure when assigning functions to delegates in this way that
 there will never be any associated state.
std.functional.toDelegate
Dec 12 2013
prev sibling parent "Orvid King" <blah38621 gmail.com> writes:
On Wed, 11 Dec 2013 22:16:08 -0600, Manu <turkeyman gmail.com> wrote:

 On 12 December 2013 14:06, Manu <turkeyman gmail.com> wrote:
 On 12 December 2013 13:45, Maxime Chevalier-Boisvert  
 <maximechevalierb gmail.com> wrote:
 It only allocates a closure if (1) it thinks the delegate may escape  
 the scope and (2) uplevel references are used in the delegate.
The delegate will escape the enclosing scope. I'm wondering if there will still be some kind of scope object allocated to represent escaping values in >>>the englobing stack frame, even when there are no escaping values. I don't mind paying the small cost of an extraneous null context pointer, but having a whole unnecessary context object allocated seems wasteful.
If you have no use for the context pointer, then it sounds like what you want is a function pointer, not a delegate. A delegate is just a function-ptr+context-ptr pair, it is a trivial struct that is passed by value, the same as a dynamic array. The context pointer may be >>to a stack frame (in case of a closure), or a class object (in the case of a class method pointer). If you intend a null context pointer (ie, function doesn't reference any state), than what you really have is a function pointer, not a delegate. You >>should use a function pointer instead.
Oh sorry, I see. you just mean in some cases functions that don't access state will be bound to your delegate. It seems unusual to me for a function that doesn't access any state to produce a delegate. Wouldn't it be static, or a free function in that case? There are tricks to bind a free function to a delegate using a little call-through stub. It sets the delegate function to a callthrough-stub which internally >casts 'this' to a 'function' and calls it with the same arguments. Don does it to bind static functions to delegates in his C++ FastDelegate library. I wonder if there's a helper in phobos? You can be sure when assigning functions to delegates in this way that there will never be any associated state.
 Can you show your usage?

 I strongly suggest trying out a couple examples, and disassembling  
 the result to confirm.
I'll look into that.
Actually, you could simply use function pointers rather than delegates, and when you need to pass them as a delegate, pass them through std.functional.toDelegate, which, for a function pointer at least, utilizes a union to set the delegate's context pointer to null, and sets the function pointer to the one you've passed in.
Dec 11 2013
prev sibling parent "Maxime Chevalier-Boisvert" <maximechevalierb gmail.com> writes:
I went ahead and wrote a little test program:

---------

import std.stdio;

alias int delegate() Dg;

Dg[] dgList;

Dg foo()
{
     auto f = delegate int()
     {
         return 0;
     };

     return f;
}

Dg bar()
{
     int n = 0;

     auto f = delegate int()
     {
         return n++;
     };

     return f;
}

void main()
{
     auto d0 = foo();
     writeln(d0.ptr);
     dgList ~= d0;

     auto d1 = bar();
     writeln(d1.ptr);
     dgList ~= d1;
}

---------

This outputs:

null
7F37305DDFF0

So it seems DMD optimizes this well, as I had hoped.
Dec 11 2013