www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - GC allocation

reply Alex <sascha.orlov gmail.com> writes:
Hi all!
timing my program with valgrind/cachegrind and using -vgc option 
of the compiler found the message:
"using closure causes GC allocation"

The question is:
does the usage of the closure causes the GC allocation on every 
usage of the closure or only on creation/assigning of it? If the 
former, why?

I'm not sure, if the context of my problem (say: context of the 
closure) is relevant, but have some thoughts about and a working 
implementation of it, so if any information is needed, just give 
me a sign.

Thanks in advance :)
Apr 21 2016
parent reply QAston <qaston gmail.com> writes:
On Thursday, 21 April 2016 at 15:22:15 UTC, Alex wrote:
 Hi all!
 timing my program with valgrind/cachegrind and using -vgc 
 option of the compiler found the message:
 "using closure causes GC allocation"

 The question is:
 does the usage of the closure causes the GC allocation on every 
 usage of the closure or only on creation/assigning of it? If 
 the former, why?

 I'm not sure, if the context of my problem (say: context of the 
 closure) is relevant, but have some thoughts about and a 
 working implementation of it, so if any information is needed, 
 just give me a sign.

 Thanks in advance :)
Closure (delegate type) objects have to allocate because they're reference types and have state. For stateful reference types to be safe they have to be put on the GC allocated heap. In other words - closures work just like classes. The allocation is done for each instance of closure you create and stores the variables you captured from the stack. When you don't capture you can use plain functions which don't use GC. See also: https://dlang.org/spec/function.html#closures
Apr 21 2016
parent reply Alex <sascha.orlov gmail.com> writes:
On Thursday, 21 April 2016 at 15:44:56 UTC, QAston wrote:
 Closure (delegate type) objects have to allocate because 
 they're reference types and have state. For stateful reference 
 types to be safe they have to be put on the GC allocated heap.
Ok. So, does this mean, that they just allocate on creation/binding them? If so, there is no problem and there are no questions any more.
 In other words - closures work just like classes. The 
 allocation is done for each instance of closure you create and 
 stores the variables you captured from the stack. When you 
 don't capture you can use plain functions which don't use GC.
I have an unusual caption... On creation I capture an immutable id for my delegates, which are stored in an array. Indeed, the id of the delegate is just the position of it in its array. Then, I call my delegate as a function with a parameter, depending on it, the call is delegated to another objects (with the stored id, of course :) ) Another possibility, which I could imagine is: not to store the id and let the delegate calculate it by some pointer arithmetic from the array wherein it is stored. Then, no independent data would be stored at all. This would assume however, that different function pointers won't be merged, although the one and only distinction between them would be the fact of storing them at different array indices.
 See also:
 https://dlang.org/spec/function.html#closures
yeah... have seen the link already, thanks!
Apr 21 2016
parent reply QAston <qaston gmail.com> writes:
On Thursday, 21 April 2016 at 17:27:09 UTC, Alex wrote:
 Ok. So, does this mean, that they just allocate on 
 creation/binding them? If so, there is no problem and there are 
 no questions any more.
Just like classes - when closure expression is executed.
 I have an unusual caption... On creation I capture an immutable 
 id for my delegates, which are stored in an array. Indeed, the 
 id of the delegate is just the position of it in its array.
 Then, I call my delegate as a function with a parameter, 
 depending on it, the call is delegated to another objects (with 
 the stored id, of course :) )
 Another possibility, which I could imagine is: not to store the 
 id and let the delegate calculate it by some pointer arithmetic 
 from the array wherein it is stored. Then, no independent data 
 would be stored at all. This would assume however, that 
 different function pointers won't be merged, although the one 
 and only distinction between them would be the fact of storing 
 them at different array indices.
Instead of using a delegate you can use a Struct with opCall. Pass what you want to copy to the struct by using a constructor and put your function code in opCall method. An example here: https://github.com/QAston/transducers-dlang/blob/master/source/transduced/transducers.d#L797 you can see there various variants of doing the same operation, using closure, function and struct.
Apr 21 2016
next sibling parent reply via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
I'm on mobile so I will be brief now and expand later

On Thu, Apr 21, 2016 at 07:37:59PM +0000, QAston via Digitalmars-d-learn wrote:
 Just like classes - when closure expression is executed.
Heap closures are actually allocated on declaration. The compiler looks to see if it will need to be copied and if so, avoids it by just using the heap to begin with.
 Instead of using a delegate you can use a Struct with opCall.
Indeed, though delegates do not necessarily allocate. If they come from &obj.member, they never do. If the usage point calls them scope, they never do. If the usage is an alias arg and it can be inlined, it might not. However, if you do &obj.member you do need to be sure obj stays alive while the delegate is in use, so struct w/ opCall may make lifetime management easier.
Apr 21 2016
parent reply Alex <sascha.orlov gmail.com> writes:
On Thursday, 21 April 2016 at 19:54:10 UTC, via 
Digitalmars-d-learn wrote:
 I'm on mobile so I will be brief now and expand later

 On Thu, Apr 21, 2016 at 07:37:59PM +0000, QAston via 
 Digitalmars-d-learn wrote:
 Just like classes - when closure expression is executed.
Heap closures are actually allocated on declaration. The compiler looks to see if it will need to be copied and if so, avoids it by just using the heap to begin with.
Ok... I make slices of them, carefully avoiding to make copies...
 Instead of using a delegate you can use a Struct with opCall.
Indeed, though delegates do not necessarily allocate. If they come from &obj.member, they never do. If the usage point calls them scope, they never do. If the usage is an alias arg and it can be inlined, it might not.
Huh? I think, this is the place, where I lack some background... So, I bind my delegates via auto initDelegates(uint delegatesAmount) { return iota(delegatesAmount).map!(a => (MM p) => .dDelegate(a, p)); } and in a class constructor I call this method .delegates = .initDelegates(delegateAmount); and .dDelegate = &this.delegateDefinition; where delegateDefinition is a member function of an uint and the MM type.
 However, if you do &obj.member you do need to be sure obj stays 
 alive while
 the delegate is in use, so struct w/ opCall may make lifetime 
 management easier.
Yes. I'm sure the object is alive till the very end. As mentioned above, do you think it is worth to make a struct to save a result from iota? Nevertheless, my intention here is speed, so a fast solution is much better, then any slow one, even if the speed gain is 10% only... But the construction effort is almost negligible.
Apr 21 2016
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Thursday, 21 April 2016 at 22:59:58 UTC, Alex wrote:
 Ok... I make slices of them, carefully avoiding to make 
 copies...
Yeah, that shouldn't make a difference..
 Huh? I think, this is the place, where I lack some 
 background... So, I bind my delegates via
Can you post any more of your code?
     return iota(delegatesAmount).map!(a => (MM p) => 
 .dDelegate(a, p));
This would indeed allocate a new heap block for each one, but there might be other ways to do it.
 Yes. I'm sure the object is alive till the very end. As 
 mentioned above, do you think it is worth to make a struct to 
 save a result from iota?
 Nevertheless, my intention here is speed, so a fast solution is 
 much better, then any slow one, even if the speed gain is 10% 
 only... But the construction effort is almost negligible.
I don't know yet, if construction is allowed to be slower, what you have is fine though.
Apr 21 2016
parent Alex <sascha.orlov gmail.com> writes:
On Friday, 22 April 2016 at 01:55:36 UTC, Adam D. Ruppe wrote:
 On Thursday, 21 April 2016 at 22:59:58 UTC, Alex wrote:
 Ok... I make slices of them, carefully avoiding to make 
 copies...
Yeah, that shouldn't make a difference..
Wait, wait... I try to make slices of the array of delegates, because I thought the slicing operation is cheaper, then another possibilities... And I try to make them as little as possible.
 Huh? I think, this is the place, where I lack some 
 background... So, I bind my delegates via
Can you post any more of your code?
Sure. Which part? ;) the delegate is defined directly in a model as uint dDelegate(uint id, MM p); and the method delegateDefinition inside the binding responsible class has a form like uint delegateDefinition(uint id, MM p) { uint retVal; final switch(p) with(MM) { case first: return callSomeFuncFromThisObject(id); break; case second: return id; break; // this the one and only case, which is unusual case third: return knownObjectByThisObject.callAnotherFunc(id); break; } } And a slice returning method inside the responsible class has a form like typeof(.delegates) getSlice(uint i) { uint first = someLogic(i); uint last = someOtherLogic(i); return .delegates[first .. last]; } Indeed, the getSlice operation is the slowest, because of the getting the first and the last operations. So I reduce the calls to slice returning methods to this one and only method. And I call it as rare as possible. But I hope the slicing itself does not copy anything which is seen anyway by every other object. The getSlice method should just return the proper, well, slice, based on the given input.
     return iota(delegatesAmount).map!(a => (MM p) => 
 .dDelegate(a, p));
This would indeed allocate a new heap block for each one, but there might be other ways to do it.
 Yes. I'm sure the object is alive till the very end. As 
 mentioned above, do you think it is worth to make a struct to 
 save a result from iota?
 Nevertheless, my intention here is speed, so a fast solution 
 is much better, then any slow one, even if the speed gain is 
 10% only... But the construction effort is almost negligible.
I don't know yet, if construction is allowed to be slower, what you have is fine though.
Cool :) Thanks!
Apr 22 2016
prev sibling parent Alex <sascha.orlov gmail.com> writes:
On Thursday, 21 April 2016 at 19:37:59 UTC, QAston wrote:
 On Thursday, 21 April 2016 at 17:27:09 UTC, Alex wrote:
 Ok. So, does this mean, that they just allocate on 
 creation/binding them? If so, there is no problem and there 
 are no questions any more.
Just like classes - when closure expression is executed.
 I have an unusual caption... On creation I capture an 
 immutable id for my delegates, which are stored in an array. 
 Indeed, the id of the delegate is just the position of it in 
 its array.
 Then, I call my delegate as a function with a parameter, 
 depending on it, the call is delegated to another objects 
 (with the stored id, of course :) )
 Another possibility, which I could imagine is: not to store 
 the id and let the delegate calculate it by some pointer 
 arithmetic from the array wherein it is stored. Then, no 
 independent data would be stored at all. This would assume 
 however, that different function pointers won't be merged, 
 although the one and only distinction between them would be 
 the fact of storing them at different array indices.
Instead of using a delegate you can use a Struct with opCall. Pass what you want to copy to the struct by using a constructor and put your function code in opCall method. An example here: https://github.com/QAston/transducers-dlang/blob/master/source/transduced/transducers.d#L797 you can see there various variants of doing the same operation, using closure, function and struct.
Yes, I can. I even used a struct before. But then, all properties of it were moved to other classes and I decided to not have a struct just for storing an id. Well, storing an id alone would maybe be ok for me, but I also have the knowledge, that the id has to be an ordinal number. And that is why I thought a struct would be not worth it. But the solution with the opCall is cool. Thanks for the hint. So my question was, if I messed up the speed of my code, by removing the struct. And if the allocation is done like classes - then it is no problem. I allocate them all once: at the beginning of my prog, then only use them as functions, so the allocating is just an initialization effort and nothing bad is happening.
Apr 21 2016