DMD and GDC are unnecessarily using heap allocations for closures
Siarhei Siamashka
siarhei.siamashka at gmail.com
Mon May 30 06:47:24 UTC 2022
Consider the following example:
```D
import std.algorithm, std.range, std.stdio;
long binary_search(long n, long val, long i) {
return iota(1, i + 1).map!(x => n / x ==
val).assumeSorted.upperBound(false).length;
}
// A solution for
https://atcoder.jp/contests/abc230/tasks/abc230_e
long solve(long n) {
long ans = 0, i = n;
while (i != 0) {
long val = n / i;
auto cnt = binary_search(n, val, i);
ans += cnt * val;
i -= cnt;
}
return ans;
}
void main() {
long ans = 0;
foreach (n ; 1 .. 100000)
ans += solve(n);
writeln(ans);
}
```
Benchmarks with GDC 11.2.0, LDC 1.27.1 (LLVM 12.0.0) and DMD
2.091.1:
```
$ dmd -O -g -release -inline test.d && time ./test
55836809328
real 0m10.654s
user 0m11.001s
sys 0m0.052s
$ gdc-11.2.0 -O3 -g -frelease -flto test.d && time ./a.out
55836809328
real 0m6.520s
user 0m6.519s
sys 0m0.000s
$ ldc2 -O -g -release test.d && time ./test
55836809328
real 0m1.904s
user 0m1.903s
sys 0m0.000s
```
LDC produces significantly faster code here and one of the major
contributing factors is that LDC is able to avoid heap
allocations (as can be confirmed by running a profiler). It is
possible to force LDC to also use heap allocations via adding
'--disable-gc2stack' option and the performance drops:
```
$ ldc2 -O -g -release --disable-gc2stack test.d && time ./test
55836809328
real 0m3.621s
user 0m3.620s
sys 0m0.000s
```
So only LDC is doing a proper job and lives up to its state of
the art optimizing compiler reputation. But not everything is
perfect even with LDC. In another thread
https://forum.dlang.org/thread/t6rijv$nlb$1@digitalmars.com
Steven Schveighoffer mentioned @nogc annotations. Now if I add
@nogc attribute to 'binary_search' function, then LDC refuses to
compile the source code:
```
$ ldc2 -O -g -release test.d && time ./test
test.d(3): Error: function `test.binary_search` is `@nogc` yet
allocates closures with the GC
test.d(4): test.binary_search.__lambda4 closes over
variable n at test.d(3)
```
What do you think about all of this?
More information about the Digitalmars-d
mailing list