Как узнать, почему g++ занимает очень много времени в определенном файле?

Я создаю много автоматически сгенерированного кода, включая один особенно большой файл (~ 15K строк), используя кросс-компилятор mingw32 на linux. Большинство файлов очень быстрые, но для этого большого файла требуется неожиданно большое время (~ 15 минут) для компиляции.

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

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

Что в файле:

  • куча включает
  • набор строк сравнения
  • куча проверок if-then и вызовов конструктора

Файл представляет собой factory для создания тонны различных определенных подклассов определенного родительского класса. Большинство из них, однако, ничего страшного не представляют.


Результаты -ft-report, как предложил Нил Баттерворт, показывают, что фаза "жизненного анализа" занимает 921 секунду, что занимает большую часть 15 минут.

Похоже, что это происходит во время анализа потока данных. Сам файл представляет собой набор условных сопоставлений строк, создавая объект по имени класса, представленному в виде строки.

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


Действительно, создавая связку функций factory (для каждого объекта) и создавая карту из имени строки объекта указателю на ее функцию factory, сокращенное время компиляции от первоначальных 15 минут до примерно 25 секунд, который сэкономит все тонны времени на своих сборках.

Еще раз спасибо Нилу Баттерворту за отзыв о -ft-report.

Ответ 1

Не укажу все нужные сведения, но попробуйте запустить флаги -v (verbose) и -ftime-report. Последний дает краткое описание того, что было в компиляторе.

Ответ 2

Это, скорее всего, включает TONNES of includes. Я считаю, что -MD будет перечислять все включенные файлы в данном CPP файле (который включает в себя include включает и т.д.).

Ответ 3

Что замедляет g++ в целом, это шаблоны. Например, Boost любит их использовать. Это хороший код, отличные характеристики, но низкая скорость компиляции.

С другой стороны, 15мин кажется чрезвычайно длинным. После быстрого поиска в Google кажется, что это обычная проблема с mingw

Ответ 4

Другой процесс, который нужно попробовать, - добавить к вашему маркеру "маркер прогресса" pragma, чтобы уловить часть кода, который занимает много времени. Компилятор Visual Studio предоставляет #pragma message(), хотя для этого нет стандартной прагмы.

Поместите один маркер в начало кода и маркер в конце кода. Конечный маркер может быть #error, так как вы не заботитесь о оставшейся части исходного файла. Переместите маркеры соответственно, чтобы захватить часть кода, занимая самое длинное время.

Просто мысль...

Ответ 5

Я бы использовал #if 0/#endif, чтобы исключить большие части исходного файла из компиляции. Повторяйте с разными блоками кода, пока не укажете, какой блок работает медленно. Во-первых, вы можете увидеть, является ли ваша проблема #include с помощью #if 0/#endif, чтобы исключить все, кроме #include.

Ответ 6

Связанный с @Goz и @Josh_Kelley, вы можете получить gcc/g++, чтобы выплевывать предварительно обработанный источник (С#includes inline) с использованием -E. Это один из способов определить, насколько велико ваш источник.

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

Ответ 7

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

15K строк в одном источнике довольно много, но даже если они разделены, весь этот код еще нужно скомпилировать; однако использование инкрементной сборки может означать, что все это не нужно компилировать все время. В действительности нет необходимости в большом файле; его просто плохая практика/дизайн. Я начинаю думать о лучшей модуляции, когда файл достигает 500 строк (хотя я не догматичен об этом)

Ответ 8

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

Если вы видите, что это происходит, легко решить, установить больше ОЗУ... или просто разделить файл на несколько частей, которые могут быть скомпилированы отдельно.