Thread overview | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
December 12, 2013 Delegate Memory Usage & Optimization | ||||
---|---|---|---|---|
| ||||
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? |
December 12, 2013 Re: Delegate Memory Usage & Optimization | ||||
---|---|---|---|---|
| ||||
Posted in reply to Maxime Chevalier-Boisvert | 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. |
December 12, 2013 Re: Delegate Memory Usage & Optimization | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | > 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. |
December 12, 2013 Re: Delegate Memory Usage & Optimization | ||||
---|---|---|---|---|
| ||||
Posted in reply to Maxime Chevalier-Boisvert Attachments:
| 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. > |
December 12, 2013 Re: Delegate Memory Usage & Optimization | ||||
---|---|---|---|---|
| ||||
Attachments:
| 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. >> > > |
December 12, 2013 Re: Delegate Memory Usage & Optimization | ||||
---|---|---|---|---|
| ||||
Attachments:
| 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.
|
December 12, 2013 Re: Delegate Memory Usage & Optimization | ||||
---|---|---|---|---|
| ||||
Posted in reply to Walter Bright | 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. |
December 12, 2013 Re: Delegate Memory Usage & Optimization | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manu | 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
|
Copyright © 1999-2021 by the D Language Foundation