Почему компиляция D занимает так много времени? - PullRequest
10 голосов
/ 26 декабря 2011

D - один из самых быстрых языков программирования для компиляции, если не самый быстрый, но это не всегда так. Вещи становятся мучительно медленными, когда unittest включен. Мой текущий проект состоит из 6-7 модулей (~ 2000 LOC), каждый из которых имеет юнит-тесты, которые также содержат тесты. Вот некоторые цифры из моего текущего проекта:

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 содержит ошибки, но в то же время он стал важной частью моего проекта. Я хотел бы знать, является ли замедление нормальным или это что-то над чем работает? Мой проект растет, и с каждым новым юнит-тестом сборка занимает все больше и больше времени. Единственное известное мне решение - отключить -release и -inline, но это не всегда желательно.

Ответы [ 3 ]

4 голосов
/ 26 декабря 2011

У DMD есть известная проблема с оптимизацией: длинные блоки кода оптимизируются с помощью алгоритма O (n ^ 2) , поэтому длинные функции компилируются с оптимизацией очень долго.

Попробуйте разбить ваш код на более мелкие функции, и тем временем вы получите лучшее время компиляции.Вы можете сделать это довольно легко, используя встроенные функции:

void foo()
{
    // lots of code
    // more code
}

Превратите это в:

void foo()
{
    void block1()
    {
        // lots of code
    }
    block1();

    void block2()
    {
        // more code
    }
    block2();
}

Это сработало для меня.

1 голос
/ 26 декабря 2011

Очень маленьким улучшением производительности может быть перемещение экземпляра шаблона в область видимости модуля через version(unittest) block, например ::

auto foo(T)(T t) { return t; }

version(unittest) {
    alias foo!int fooInt;
}

unittest {
    auto x = fooInt(1);
}

Профилируя это, я получаю ~30msec улучшение скорости, если я использую экземпляр шаблона с псевдонимом в 5000 эквивалентных блоков юнит-теста через auto x = fooInt(1), по сравнению с его экземпляром непосредственно в каждом блоке юнит-теста через auto x = foo(1) (это фактически расширяется до auto x = foo!int(1)).

Скорее всего, это будет работать только в тех случаях, когда у вас много юнит-тестов, которые создают один и тот же экземпляр шаблона.

0 голосов
/ 31 декабря 2011

Я заменил большую часть своего общего кода, но это только сократило время компиляции на 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 значительно сокращает время компиляции.Поэтому, чтобы сократить время компиляции при тестировании модулей, сбросьте флаг (ы) оптимизации.Для обычных компиляций вы можете без проблем использовать любой из трех (-inline, -release, -unittest).По моему опыту, именно комбинация всех трех приводит к тому, что компиляция занимает второе по длине и самое длинное, когда также установлен -unittest.

...