Re: Closures and memory allocation

2019-06-22 Thread kinke via Digitalmars-d-learn

On Saturday, 22 June 2019 at 16:52:07 UTC, Anonymouse wrote:

When entering the following function, does it allocate:

1. 0 times, because while there are closures defined, none is 
ever called?

2. 2 times, because there are closures over two variables?
3. 20 times, because there are 20 unique closures?


4. One time, allocating a single closure for all variables 
referenced in nested functions. Easy to check by inspecting the 
generated asm (https://run.dlang.io/is/qO3JxO):


void receive(void delegate() a, void delegate() b) {}

void foo()
{
int i;
long l;

void foo1() { i += 1; }
void foo2() { l += 1; }

receive(, );
}

When adding `scope` to the `receive()` params, the closure is 
allocated on the stack.


Re: Closures and memory allocation

2019-06-22 Thread Cym13 via Digitalmars-d-learn

On Saturday, 22 June 2019 at 19:26:13 UTC, Cym13 wrote:

On Saturday, 22 June 2019 at 16:52:07 UTC, Anonymouse wrote:

[...]


Clearly this is a good time for you to learn about the tools D 
offers to profile allocations. There is the --profile=gc DMD 
argument that you can use but here there's something better: 
DMD's GC has a few hooks that are directly inside druntime and 
therefore available to any D program.


[...]


Ooops, sorry I went a bit fast there, --DRT-gcopt gives you the 
number of collections, not allocations.


Re: Closures and memory allocation

2019-06-22 Thread Cym13 via Digitalmars-d-learn

On Saturday, 22 June 2019 at 16:52:07 UTC, Anonymouse wrote:
I'm looking into why my thing does so many memory allocations. 
Profiling with kcachegrind shows _d_allocmemory being called 
upon entering a certain function, lots and lots of times.


It's a function that receives concurrency messages, so it 
contains nested functions that close over local variables. 
Think receiveTimeout(0.seconds, , , , 
...) with 13 pointers to nested functions passed.


When entering the following function, does it allocate:

1. 0 times, because while there are closures defined, none is 
ever called?

2. 2 times, because there are closures over two variables?
3. 20 times, because there are 20 unique closures?



Clearly this is a good time for you to learn about the tools D 
offers to profile allocations. There is the --profile=gc DMD 
argument that you can use but here there's something better: 
DMD's GC has a few hooks that are directly inside druntime and 
therefore available to any D program.


Putting your above code in test.d you can then do:

$ dmd test.d
$ ./test --DRT-gcopt=profile:1
Number of collections:  2
Total GC prep time:  0 milliseconds
Total mark time:  0 milliseconds
Total sweep time:  0 milliseconds
Max Pause Time:  0 milliseconds
Grand total GC time:  0 milliseconds
GC summary:1 MB,2 GC0 ms, Pauses0 ms <0 ms

And here is your answer: two allocations. More information about 
--DRT-gcopt there: https://dlang.org/spec/garbage.html


Closures and memory allocation

2019-06-22 Thread Anonymouse via Digitalmars-d-learn
I'm looking into why my thing does so many memory allocations. 
Profiling with kcachegrind shows _d_allocmemory being called upon 
entering a certain function, lots and lots of times.


It's a function that receives concurrency messages, so it 
contains nested functions that close over local variables. Think 
receiveTimeout(0.seconds, , , , ...) with 
13 pointers to nested functions passed.


When entering the following function, does it allocate:

1. 0 times, because while there are closures defined, none is 
ever called?

2. 2 times, because there are closures over two variables?
3. 20 times, because there are 20 unique closures?

void foo()
{
int i;
long l;

void foo01(bool b_) { i += 1; }
void foo02(string s) { i += 2; }
void foo03(int n) { i += 3; }
void foo04(float f) { i += 4; }
void foo05(double d) { i += 5; }
void foo06() { i += 6; }
void foo07() { i += 7; }
void foo08() { i += 8; }
void foo09() { i += 9; }
void foo10() { i += 10; }
void foo11() { l += 11; }
void foo12() { l += 12; }
void foo13() { l += 13; }
void foo14() { l += 14; }
void foo15() { l += 15; }
void foo16() { l += 16; }
void foo17() { l += 17; }
void foo18() { l += 18; }
void foo19() { l += 19; }
void foo20() { l += 20; }

auto f01 = 
auto f02 = 
auto f03 = 
auto f04 = 
auto f05 = 
auto f06 = 
auto f07 = 
auto f08 = 
auto f09 = 
auto f10 = 
auto f11 = 
auto f12 = 
auto f13 = 
auto f14 = 
auto f15 = 
auto f16 = 
auto f17 = 
auto f18 = 
auto f19 = 
auto f20 = 
}