Автоматически устанавливать флаг заданий (-j) для многоядерной машины?

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

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

10 ответов


получается, что MAKEFLAGS переменная окружения может передавать флаги, которые являются частью каждого make run (по крайней мере, для GNU make). Мне не очень повезло с этим, но это может быть возможно использовать -l, а не -j для автоматического запуска столько заданий, сколько подходит для количества доступных ядер.


Я предполагаю, что вы используете Linux. Это от моего ~/.bashrc

# parallel make
export NUMCPUS=`grep -c '^processor' /proc/cpuinfo`
alias pmake='time nice make -j$NUMCPUS --load-average=$NUMCPUS'

пример использования

samm@host src> echo $NUMCPUS
8
samm@host src> pmake

становится time nice make -j8 --load-average=8.

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


как сказал Иеремия Уиллкок, используйте MAKEFLAGS, но вот как это сделать:

export MAKEFLAGS="-j $(grep -c ^processor /proc/cpuinfo)"

или вы можете просто установить фиксированное значение, как это:

export MAKEFLAGS="-j 8"

если вы действительно хотите, чтобы повысить производительность, вы должны использовать ccache добавлять что-то вроде следующего в ваш Makefile:

CCACHE_EXISTS := $(shell ccache -V)
ifdef CCACHE_EXISTS
    CC := ccache $(CC)
    CXX := ccache $(CXX)
endif

Я обычно делаю это следующим образом в моих сценариях bash:

make -j$(nproc)

вы можете добавить строку в свой Makefile, аналогичную следующей:

NUMJOBS=${NUMJOBS:-" -j4 "}

добавить ${NUMJOBS} строка в ваших правилах или добавьте ее в другую Makefile var (like MAKEFLAGS). Это будет использовать NUMJOBS envvar, если он существует; если это не так, автоматически используйте -j4. Вы можете настроить или переименовать его на свой вкус.

(N. B.: лично я бы предпочел, чтобы по умолчанию было -j1 или "", особенно если он будет распространяться среди других, потому что, хотя у меня есть несколько ядер также я компилирую на разных платформах и часто забываю СОП-возможность -jX настройка.)


псевдонимы не разворачиваются внутри скриптов. Лучше создать отдельный make скрипт и поместите его в один из $PATH каталоги:

#!/bin/sh

if [ -f /proc/cpuinfo ]; then
    CPUS=`grep processor /proc/cpuinfo | wc -l`
else
    CPUS=1
fi
/usr/bin/make -j`expr $CPUS + 1` "$@"

на Ubuntu 16.4 с использованием всех ядер процессора:

export MAKEFLAGS='-j$(nproc)'

или

export MAKEFLAGS='-j 2'

пока где-то в прошлом году вы не смогли сделать это в своем makefile: (GNU make tested)

MAKEFLAGS += "-j$(NUM_CORES) -l$(NUM_CORES)

(где NUM_PPROCS рассчитывается или устанавливается в соответствии с одним из многих других ответов здесь) и, бац! у вас идет многопроцессное строительство.

учитывая, что это перестало работать, лучшее, что я мог придумать, это то, где makefile называет себя, но с -jX и -lX.

# add parallelism equal to number of cores every time.
# it seems that adding -jX to MAKEFLAGS directly doesn't work any more.
# included some "random" strings to ensure uniqueness
ifneq ($(PARALELL_WRAPPER_ABXCOEOEKCOEBMQJKHTOEUB),done)

NUM_CORES ?= $(shell grep -c "vendor_id" /proc/cpuinfo)
MAKEFLAGS +=" -j$(NUM_CORES) -l$(NUM_CORES) "

# for the default target case
parallel_wrapper_default_target_anthsqjkshbeohcbmeuthnoethoaeou:
    $(MAKE) PARALELL_WRAPPER_ABXCOEOEKCOEBMQJKHTOEUB=done

# catches everything else
% :
    $(MAKE) $@ PARALELL_WRAPPER_ABXCOEOEKCOEBMQJKHTOEUB=done

# the match for this else is at the end of the file
else

##### rest of makefile here #####
all: ...
   ...

other_target: ...
    ...

##### etc. #####

endif

В начале файла Makefile:

MAKEFLAGS+="j"

он не будет принимать числовые аргументы для любой версии GNU Make до 4.2.

если у вас есть некоторые задания, у которых заканчивается память, вы можете заставить их работать только по одному с flock из util-linux-ng. Например,convert утилита от ImageMagick будет использовать все ресурсы, которые она может получить при использовании оптимизация изображений в соответствии с рекомендациями Google, так что нет смысла пусть он работает параллельно.

%.min.jpg: %.jpg
    @flock --wait 600 Makefile convert $< -sampling-factor 4:2:0 -strip $@

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

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


Я бы просто поставил

alias make='make -j'

на ~/.profile или ~/.bashrc.

По словам руководство:

Если после опции ‘-j’ нет ничего похожего на целое число, нет ограничения на количество слотов заданий.