Как мне узнать, почему g ++ занимает очень много времени на конкретном файле? - PullRequest
17 голосов
/ 15 января 2010

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

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

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

Что в файле:

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

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


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

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

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


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

Еще раз спасибо Нилу Баттеруорту за подсказку о -ftime-report.

Ответы [ 8 ]

25 голосов
/ 15 января 2010

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

3 голосов
/ 15 января 2010

Скорее всего, включает в себя тонны включает. Я полагаю, что -MD перечислит все файлы включений в данном файле CPP (включая включения включений и т. Д.).

2 голосов
/ 15 января 2010

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

2 голосов
/ 15 января 2010

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

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

1 голос
/ 15 января 2010

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

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

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

0 голосов
/ 19 января 2010

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

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

0 голосов
/ 15 января 2010

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

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

0 голосов
/ 15 января 2010

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

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

...