Как я могу улучшить скорость моего Makefile? - PullRequest
1 голос
/ 30 июня 2011

Я строю несколько двоичных файлов в C ++ и CUDA с парой файлов в Fortran. Я нашел этот вопрос , и у меня возникла похожая проблема. Пользователь недавно попросил меня перестроить трехлетнюю версию хранилища (до того, как мы выполнили масштабную миграцию и переименование), и я был потрясен, увидев, как быстро он построил . Было бы невозможно / невероятно трудоемко определить, какие именно изменения между этой версией и теперь заставили сборку занимать так долго.

Однако я заметил в комментарии к ответу на вышеупомянутый вопрос:

В частности, не забудьте использовать: = вместо =, так как: = выполняет расширение немедленно, что экономит время. - Джек Келли 23 марта в 22: 38

Есть ли другие предложения, о которых мне следует знать?

Примечание:

  • Я использую парадигму «include», в которой каждый каталог, который я хочу создать, имеет файл module.mk, который непосредственно включен в один-единственный Makefile.
  • Я использую несколько функций, таких как:

(уценки ..)

#
# CUDA Compilation Rules
#

define cuda-compile-rule
  $1: $(call generated-source,$2) \
    $(call source-dir-to-build-dir, $(subst .cu,.cubin, $2)) \
    $(call source-dir-to-build-dir, $(subst .cu,.ptx, $2))
    $(NVCC) $(CUBIN_ARCH_FLAG) $(NVCCFLAGS) $(INCFLAGS) $(DEFINES) -o $$@ -c $$<

  $(call source-dir-to-build-dir, $(subst .cu,.cubin, $2)): $(call generated-source,$2)
    $(NVCC) -cubin -Xptxas -v $(CUBIN_ARCH_FLAG) $(NVCCFLAGS) $(INCFLAGS) $(DEFINES) $(SMVERSIONFLAGS) -o $$@ $$<

  $(call source-dir-to-build-dir, $(subst .cu,.ptx, $2)): $(call generated-source,$2)
    $(NVCC) -ptx $(CUBIN_ARCH_FLAG) $(NVCCFLAGS) $(INCFLAGS) $(DEFINES) $(SMVERSIONFLAGS) -o $$@ $$<

  $(subst .o,.d,$1): $(call generated-source,$2)
    $(NVCC) $(CUBIN_ARCH_FLAG) $(NVCCFLAGS) $3 $(TARGET_ARCH) $(INCFLAGS) $(DEFINES) -M $$< | \
    $(SED) 's,\($$(notdir $$*)\.o\) *:,$$(dir $$@)\1 $$@: ,' > $$@.tmp
    $(MV) $$@.tmp $$@
endef
  • Но большинство этих функций я использовал в более старой версии ...

И наконец: Как я могу определить, действительно ли время компиляции или make действительно замедляет процесс?

Я не хотел добавлять весь Makefile. Это 914 строк, но я был бы рад обновить вопрос с помощью фрагментов кода, если это поможет.

Обновление: Вот мое правило генерации зависимостей и правило компиляции:

#
# Dependency Generation Rules
#

define dependency-rules

  $(subst .o,.d,$1): $2
    $(CC) $(CFLAGS) $(DEFINES) $(INCFLAGS) $3 $(TARGET_ARCH) -M $$< | \
    $(SED) 's,\($$(notdir $$*)\.o\) *:,$$(dir $$@)\1 $$@: ,' > $$@.tmp
    $(MV) $$@.tmp $$@

endef

%.d: %.cpp
    $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -M $< | \
    $(SED) 's,\($(notdir $*)\.o\) *:,$(dir $@)\1 $@: ,' > $@.tmp
    $(MV) $@.tmp $@

Обновление 2: Используя предложение @ Beta, я смог разложить генерацию зависимостей, и время создания файла составило примерно 14,2% от общего времени компиляции. Поэтому я собираюсь сосредоточиться на минимизации включения заголовка в мой код C ++. Спасибо вам обоим за ваши предложения !!

Ответы [ 3 ]

3 голосов
/ 01 июля 2011
  1. Не должно быть так сложно определить, какие изменения замедлили все. У вас есть все версии за последние три года (я надеюсь), и вы говорите, что разница существенная. Так что попробуйте версию от двух лет назад. Если это занимает слишком много времени, выполните бинарный поиск . Вы могли бы даже автоматизировать этот процесс, запустить его на ночь и дать вам график утром, время построения выборки каждый месяц за последние 36 месяцев.
  2. Если вы используете GNUMake (как я надеюсь), `make -n` распечатает команды, которые выполнит , без фактического их выполнения. Это даст вам все время Make без времени компиляции.
  3. Один из самых больших источников ненужного времени сборки (даже больше, чем рекурсия, которую вы не используете) - это ненужная перестройка, перекомпиляция / перекомпоновка / что угодно, когда вам это действительно не нужно. Это может быть из-за того, что ваш make-файл неправильно обрабатывает зависимости, или из-за того, что ваши C ++ файлы `# include` опрометчиво заголовки, или из-за чего-то о CUDA или FORTRAN, чего я не знаю. Запустите Make дважды подряд и посмотрите, что он сделает во втором проходе. Просмотрите подозрительно огромные списки предварительных требований в make-файле. Попросите опытного программиста взглянуть на несколько исходных файлов, особенно на новые, и проверить наличие ненужных зависимостей.
3 голосов
/ 01 июля 2011

ElectricMake (emake) - это заменитель gmake, который позволяет очень и очень легко отвечать на подобные вопросы. emake может сгенерировать аннотированный журнал сборки, который включает подробную информацию о времени каждой работы в сборке, а затем вы можете загрузить ее в ElectricInsight для генерации, например, Job Time по типу Докладываю:

Job Time by Type example

Если вы хотите попробовать, вы можете получить пробную копию .

(отказ от ответственности: я архитектор и ведущий разработчик ElectricMake и ElectricInsight!)

1 голос
/ 01 июля 2011

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

VAR := $(shell ...)

Могут быть другие скрытые процессы потребления, которые не очевидны.Например, в нашей среде стандартный временный каталог Windows был на сетевом диске.Таким образом, когда делали сохраненные / обновленные файлы на этом диске (даже с 1G LAN) - это было очень медленно.Что вам нужно, это отладить make-файл (ы). Это может быть полезно .

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...