digitalmars.D.learn - GC allocation
- Alex (13/13) Apr 21 2016 Hi all!
- QAston (10/23) Apr 21 2016 Closure (delegate type) objects have to allocate because they're
- Alex (18/27) Apr 21 2016 Ok. So, does this mean, that they just allocate on
- QAston (9/25) Apr 21 2016 Instead of using a delegate you can use a Struct with opCall.
- via Digitalmars-d-learn (10/12) Apr 21 2016 Heap closures are actually allocated on declaration. The compiler
- Alex (22/38) Apr 21 2016 Ok... I make slices of them, carefully avoiding to make copies...
- Adam D. Ruppe (7/19) Apr 21 2016 Can you post any more of your code?
- Alex (38/57) Apr 22 2016 Wait, wait... I try to make slices of the array of delegates,
- Alex (13/39) Apr 21 2016 Yes, I can. I even used a struct before. But then, all properties
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
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
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#closuresyeah... have seen the link already, thanks!
Apr 21 2016
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
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
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:Ok... I make slices of them, carefully avoiding to make copies...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.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.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.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
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 viaCan 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
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: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.Ok... I make slices of them, carefully avoiding to make copies...Yeah, that shouldn't make a difference..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.Huh? I think, this is the place, where I lack some background... So, I bind my delegates viaCan you post any more of your code?Cool :) Thanks!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 22 2016
On Thursday, 21 April 2016 at 19:37:59 UTC, QAston wrote:On Thursday, 21 April 2016 at 17:27:09 UTC, Alex wrote: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.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