Подтвердить что ты не робот

Профилирование профилей

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

Я вижу некоторые возможности для оптимизации -

  • Уменьшение количества раз, когда Makefile анализируется, и DAG пересчитывается из-за включения фрагмента Makefile.
  • Уменьшение количества переходов во внешний Makefile с помощью make -C
  • Уменьшение разложений переменных
  • и др.

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

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

... и просто для того, чтобы упредить часть возможного ответа. Я знаю, что могут быть более быстрые и лучшие системы сборки, чем GNU make - (Лично я с нетерпением жду, чтобы увидеть, что люди CMake придумают в отношении системы ниндзя) - но, к сожалению, система смены сборки не находится в карточках.

4b9b3361

Ответ 1

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

  • -q (вопрос) будет просто решить, что нужно сделать, ничего не делать, ничего не печатать, а вернуть код статуса выхода, указывающий, нужно ли что-то делать. Вы можете просто потратить это время на любую интересующую вас цель (включая "все" ).
  • -n (no-op) будет печатать рецепты, а не выполнять их. Наблюдение за их прокруткой даст вам общее представление о том, как Make тратит свое время, и если вам нравится, вы можете сделать умные трюки с трубами вовремя.
  • -t (touch) будет касаться целевых файлов, которые нужно перестроить, а не перестраивать их. A script мог бы посмотреть время обновления файлов, найти большие пробелы и рассказать вам, какие цели требуют много предусмотрительности.

РЕДАКТИРОВАТЬ:

Я НЕПРАВИЛЬНО.

Создайте конструкцию DAG и решите, какие цели необходимо перестроить, прежде чем восстанавливать любой из них. Поэтому, когда он начинает выполнять правила, печатает рецепты или трогательные файлы, часть интересующей нас работы заканчивается, и наблюдаемое время бесполезно. Таким образом, опции -n и -t не подходят, но -q по-прежнему полезен в качестве грубого инструмента. Также -d расскажет вам, что вы делаете мыслительный процесс; он не укажет вам время, но он укажет, какие цели требуют много шагов для рассмотрения.

Ответ 2

Я не думаю, что есть какой-либо способ профилировать Makefile.

Вы можете что-то сделать: для нулевой сборки (все в актуальном состоянии) запустите make файл верхнего уровня под strace -tt -fv и посмотрите, какие части дерева, какие рекурсивные подписи, какие файлы обращаются и т.д., неожиданно долго.

Вычисляемые переменные (var := $(shell ...)), повторяющиеся вызовы NFS stat и т.д. часто делают make медленными.

Ответ 3

Это работа, но я бы получил источник Make, построил его с помощью отладочной информации и запустил его под gdb и случайным образом-приостановить его в то время, когда вы его ждёте. Это покажет, что он делает и почему. Вероятно, нужно будет смотреть не столько на стек вызовов, сколько на внутреннюю структуру данных, потому что Make является интерпретатором. Поскольку Make называет себя подчиненным приложением, это может затруднить работу. Мне нужно было бы выяснить, как отлаживать подчиненный вызов.

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

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

Ответ 4

Это зависит от того, что вы пытаетесь измерить и насколько сложны ваши Makefile.

Если вы просто хотите измерить разбор, вызовите тривиальную цель без зависимостей. Но это не работает, если у вас есть целевые правила (например, из-за использования $(eval)).

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

Если вы также хотите включить разворот оболочки, которая выполняет команды, все станет проще: установите $(SHELL) на то, что окружает фактическое выполнение команды оболочки с информацией о времени.

Еще одна идея - запустить исходный код make непосредственно в профилировщике или добавить временные сообщения.

Ответ 5

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

Одно предупреждение. Опция -d вызывает make для получения непристойного объема вывода. Вы обязательно захотите перенаправить вывод в файл. Терминал вас поблагодарит позже.

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

Ответ 6

Было предпринято несколько попыток добавить профилирование в GNU make. См. Например https://github.com/eddyp/make-profiler

Моя недавняя запись на этот счет заключалась в том, чтобы расширить remake для вывода информации с помощью valgrind код callgrind; то можно использовать kcachegrind или gprof2dot для визуализации. Прямо сейчас, проверьте ветвь профилирования в github. Или посмотрите скриншот kcachegrind.

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

Ответ 7

Make не занимает времени, анализируя Makefile и не создавая DAG. Я использовал make файлы, которые $(eval...) тысячи строк make, создают dag со многими 100-м файлами и возвращаются почти мгновенно (ну хорошо, через секунду или два), когда нечего делать.

Итак, где ваша скорость идет?

  • Recurvsive make (т.е. запуск другого make в рецепте оболочки (${MAKE} blah...)) всегда медленный. (Это неизменно плохо тоже ИМХО.)
  • Вам следует избегать использования $(shell...) — использовать возможности по мере возможности
  • Ваши файлы Makefile должны корректно работать при использовании с -jn (n > 1). Убедитесь, что вы говорите, что именно то, что можно построить параллельно с чем. Не используйте оболочки оболочки, если это вообще возможно.