D is one of the fastest programming languages to compile, if not the fastest, but this isn't always the case. Things become painfully slow when unittest
is turned on. My current project has 6-7 modules (~2000 LOC), with every single one of them having unittests that also contain benchmarks. Here are some numbers from my current project:
dmd -O -noboundscheck
takes 0m1.287s
dmd -O -release -noboundscheck
takes 0m1.382s
dmd -O -inline -noboundscheck
takes 0m1.499s
dmd -O -inline -release -noboundscheck
takes 0m3.477s
adding -unittest
to any one of the above will drastically increase compilation time:
dmd -O -inline -release -noboundscheck -unittest
takes 0m21.918s
and sometimes it crashes DMD:
time dmd -O t1.d -inline -noboundscheck -version=Double -unittest
takes 0m2.297s
Internal error: ../ztc/gdag.c 776
Evidentially, unittest is buggy but at the same time it has become an important part of my project. I would like to know if the slowdown is normal or is it something that's being worked on? My project is growing and with every new unittest the compilation is taking longer and longer. The only solution I know is to disable -release
and -inline
, but that's not always desirable.
DMD has a known issue with optimisations: long blocks of code optimise with an O(n^2) algorithm, so long functions take a long time to compile with optimisations.
Try splitting your code up into smaller functions and you should get better compile times in the meantime. You can do this quite easily by using inline functions:
void foo()
{
// lots of code
// more code
}
Turn this into:
void foo()
{
void block1()
{
// lots of code
}
block1();
void block2()
{
// more code
}
block2();
}
This worked for me.
A very tiny performance improvement could be to move template instantiation to module-scope, via a version(unittest) block
, e.g.:
auto foo(T)(T t) { return t; }
version(unittest) {
alias foo!int fooInt;
}
unittest {
auto x = fooInt(1);
}
Profiling this, I get around ~30msec
speed improvement if I use the aliased template instance in 5000 equivalent unittest blocks via auto x = fooInt(1)
, compared to instantiating it directly in each unittest block via auto x = foo(1)
(this actually expands to auto x = foo!int(1)
).
This will likely only work for cases where you have a lot of unittests that create the same template instance.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With