Как ускорить время компиляции g++ (при использовании большого количества шаблонов)



этот вопрос, возможно, как-то странно, но как я могу ускорить время компиляции g++? Мой код на C++ сильно использует boost и шаблоны. Я уже переместил как можно больше файлов заголовков и использовал опцию-j, но все же для компиляции (и ссылки) требуется довольно много времени.



есть ли какие-либо инструменты, которые анализируют мой код и указывают на бутылочные горлышки для компилятора? Или можно как-то профилировать компилятор, работающий на моем коде? Это было бы очень приятно, потому что иногда я у меня сложилось впечатление, что я слишком много времени смотрел на журнал консоли компилятора ...

750   11  

11 ответов:

что было для меня самым полезным:

  • построить на RAM файловой системы. Это тривиально на Linux. Вы можете сохранить копию общих заголовочных файлов (предварительно скомпилированных или фактических .H файлы) и в файловой системе ОЗУ.
  • предварительно скомпилированные заголовки. У меня есть одна (основная) библиотека (например, Boost, Qt, stdlib).
  • объявить вместо включения классов, где это возможно. Это уменьшает зависимости, таким образом, уменьшает количество файлов, которые нужно быть перекомпилированы при изменении файла заголовка.
  • распараллелить make. Обычно это помогает в каждом конкретном случае, но у меня -j3 во всем мире для. Однако убедитесь, что ваши графики зависимостей верны в вашем файле Makefile, или у вас могут возникнуть проблемы.
  • использовать -O0 Если вы не тестируете скорость выполнения или размер кода (и ваш компьютер достаточно быстр, чтобы вы не заботились о (вероятно, небольшом) хите производительности).
  • компилировать каждый раз вы экономите. Некоторым людям это не нравится, но это позволяет видеть ошибки рано и может быть сделано в фоновом режиме, сокращая время, которое вам нужно ждать, когда вы закончите писать и готовы к тестированию.

вот что я сделал, чтобы ускорить сборки по очень похожему сценарию, который вы описываете (boost, templates, gcc)

  • построить на локальном диске вместо сетевой файловой системы, как NFS
  • обновление до более новой версии gcc
  • расследование distcc
  • быстрее строить системы, особенно больше оперативной памяти

Я предполагаю, что мы говорим о минут для компиляции файла, т. е. предварительно скомпилированные заголовки или проблемы с локальным диском не являются проблемой.

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

вот документ, который называет сокращенное время компиляции в качестве мотивация для вариативных шаблонов:

У cpptruths была статья о том, как gcc-4.5 намного лучше в этом отношении и как он блестяще справляется со своими вариативными шаблонами:

IIRC тогда BOOST имеет способ ограничить генерацию параметры шаблона по умолчанию для псевдо-вариадики, я думаю, что' g++ -DBOOST_MPL_LIMIT_LIST_SIZE=10 ' должен работать (по умолчанию 20)

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

обновление: речь идет о проблемах производительности при компиляции шаблоны, принятый ответ рекомендует gcc-4.5 тоже, также clang упоминается в качестве положительного примера:

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

дополнительная идея: если ваш код компилируется с лязгом вместо того, чтобы использовать его. Это обычно быстрее, чем gcc.

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

// ClsWithNoTemplates.h file, included everywhere

class ClsWithTemplates
{
    ComplicatedTemplate<abc> member;
    // ...

public:
    void FunctionUsingYourMember();
};

вы должны:

// ClsWithNoTemplates.h file:

class ClsWithTemplatesImplementation; // forward declaration
  // definition included in the ClsWithNoTemplates.cpp file
  // this class will have a ComplicatedTemplate<abc> member, but it is only 
  // included in your ClsWithNoTemplates definition file (that is only included once)


class ClsWithNoTemplates
{
     ClsWithTemplatesImplementation * impl; // no templates mentioned anywhere here
public:
    void FunctionUsingYourMember(); // call impl->FunctionUsingYourMember() internally
};

Это немного меняет ваш дизайн ООП, но это к лучшему: в том числе определение "ClsWithNoTemplates" теперь быстро и вы только (заранее)составить определение из ClsWithNoTemplates раз.

Aditionally, если вы измените код реализации, любой код, который включал ClsWithNoTemplates.h, вероятно, не нужно будет переопределять.

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

попробуйте технику PIMPL, этот вопрос:какие методы можно использовать для ускорения компиляции C++?

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

Если есть много файлов, вы можете ускорить компиляцию много, просто имея один .cpp файл, который #включает в себя все остальные .cpp-файлы. Это, конечно, требует от вас быть более осторожными с макросами и такими, что вы уже определили для каждого файла, поскольку теперь они будут видны другим cpp-файлам.

Если есть много файлов, это может значительно сократить время компиляции.

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

однако, это простой факт, что C++ является невероятно сложным языком и компиляция занимает довольно много времени.

этой статье описывает метод для компиляции кода шаблона так же, как" традиционные " файлы объектов без шаблонов. Экономит время компиляции и компоновки, имея только одну строку накладных расходов кода на экземпляр шаблона.

обычно самыми дорогими частями компиляции являются (a) чтение исходных файлов (все из них) и (Б) загрузка компилятора в память для каждого исходного файла.

Если у вас есть 52 исходных файла (.cc), каждый из которых #включает в себя 47 #include (.h) файлы, вы собираетесь загрузить компилятор 52 раза, и вы собираетесь пахать через 2496 файлов. В зависимости от плотности комментариев в файлах, вы можете потратить изрядный кусок времени, поедая бесполезные символы. (В одной организации, которую я видел, заголовочные файлы варьировались от 66% до 90% комментариев, причем только 10% -33% файла были "значимыми". Единственное лучшее, что можно было сделать для повышения читаемости этих файлов, - это удалить все последние комментарии, оставив только код.)

внимательно посмотрите, как физически организована ваша программа. Смотрите, можно ли объединить исходные файлы и упростить иерархию #include файлов.

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

компиляция с g++ с использованием нескольких ядер

компиляция с g++ с использованием нескольких ядер

Comments

    Ничего не найдено.