digitalmars.D - Delegate Memory Usage & Optimization
- Maxime Chevalier-Boisvert (12/12) Dec 11 2013 I have a use case where I will need to generate millions
- Walter Bright (9/20) Dec 11 2013 No. It'll be a pointer to the enclosing stack frame, even if it is never...
- Maxime Chevalier-Boisvert (8/13) Dec 11 2013 The delegate will escape the enclosing scope. I'm wondering if
- Manu (13/24) Dec 11 2013 If you have no use for the context pointer, then it sounds like what you
- Manu (14/41) Dec 11 2013 Oh sorry, I see. you just mean in some cases functions that don't access
- Timon Gehr (2/6) Dec 12 2013 std.functional.toDelegate
- Orvid King (6/51) Dec 11 2013 Actually, you could simply use function pointers rather than delegates, ...
- Maxime Chevalier-Boisvert (36/36) Dec 11 2013 I went ahead and wrote a little test program:
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
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
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
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 theIf 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 thescope 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.result to confirm.I'll look into that.
Dec 11 2013
On 12 December 2013 14:06, Manu <turkeyman gmail.com> wrote:On 12 December 2013 13:45, Maxime Chevalier-Boisvert < maximechevalierb gmail.com> wrote: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?It only allocates a closure if (1) it thinks the delegate may escape theIf 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.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 theresult to confirm.I'll look into that.
Dec 11 2013
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
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: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.On 12 December 2013 13:45, Maxime Chevalier-Boisvert <maximechevalierb gmail.com> wrote: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.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.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.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
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