Почему компиляция D занимает так много времени?
D - один из самых быстрых языков программирования для компиляции, если не самый быстрый, но это не всегда так. Когда unittest
включается, все становится очень медленным. Мой текущий проект имеет 6-7 модулей (~ 2000 LOC), причем каждый из них имеет unittests, который также содержит контрольные показатели. Вот некоторые цифры из моего текущего проекта:
dmd -O -noboundscheck
принимает 0m1.287s
dmd -O -release -noboundscheck
принимает 0m1.382s
dmd -O -inline -noboundscheck
принимает 0m1.499s
dmd -O -inline -release -noboundscheck
принимает 0m3.477s
добавление -unittest
к любому из вышеперечисленных действий приведет к резкому увеличению времени компиляции:
dmd -O -inline -release -noboundscheck -unittest
принимает 0m21.918s
и иногда он сбрасывает DMD:
time dmd -O t1.d -inline -noboundscheck -version=Double -unittest
принимает 0m2.297s
Internal error: ../ztc/gdag.c 776
Очевидно, unittest является ошибкой, но в то же время он стал важной частью моего проекта. Я хотел бы знать, нормальное ли замедление или это то, над чем работали? Мой проект растет, и с каждым новым unittest компиляция занимает больше времени и дольше. Единственное решение, которое я знаю, - отключить -release
и -inline
, но это не всегда желательно.
Ответы
Ответ 1
У DMD есть известная проблема с оптимизацией: длинные блоки кода оптимизируются с помощью алгоритма O (n ^ 2), поэтому длинные функции долгое время для компиляции с оптимизацией.
Попробуйте разбить код на более мелкие функции, и вы должны получить лучшее время компиляции. Вы можете сделать это довольно легко, используя встроенные функции:
void foo()
{
// lots of code
// more code
}
Включите это:
void foo()
{
void block1()
{
// lots of code
}
block1();
void block2()
{
// more code
}
block2();
}
Это сработало для меня.
Ответ 2
Очень небольшим улучшением производительности может быть перемещение экземпляра шаблона в область видимости модуля с помощью version(unittest) block
, например:
auto foo(T)(T t) { return t; }
version(unittest) {
alias foo!int fooInt;
}
unittest {
auto x = fooInt(1);
}
Профилируя это, я оборачиваюсь с повышением скорости ~30msec
, если я использую экземпляр шаблона aliased в 5000 эквивалентных блоках unittest через auto x = fooInt(1)
, по сравнению с его экземпляром непосредственно в каждом блоке unittest через auto x = foo(1)
(это фактически расширяет до auto x = foo!int(1)
).
Это, скорее всего, будет работать только в случаях, когда у вас много unittests, которые создают один и тот же экземпляр шаблона.
Ответ 3
Я заменил большую часть моего общего кода, но сократил время компиляции на 4-5 секунд. Все ухудшилось, и я считаю, что компилятор, вероятно, проблема:
time dmd -O -inline -release -noboundscheck -unittest
принимает 0m30.388s
time dmd -O -inline -release -noboundscheck
принимает 0m11.597s
time dmd -inline -release -noboundscheck -unittest
принимает 0m1.884s
Когда -O
, -inline
, -release
и -unittest
все установлены, компиляция занимает самое длинное. Отбрасывание -O
резко сокращает время компиляции. Поэтому, чтобы сократить время компиляции во время unittesting, снимите флаг оптимизации. Для обычных компиляций вы можете использовать любой из трех (-inline
, -release
, -unittest
) без проблем. По моему опыту, это комбинация всех трех, из-за чего компиляция занимает второе место и самая длинная, когда также устанавливается -unittest
.