Автоматически устанавливать флаг заданий (-j) для многоядерного компьютера? - PullRequest
56 голосов
/ 24 января 2011

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

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

Ответы [ 10 ]

37 голосов
/ 24 января 2011

Я предполагаю, что вы используете 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, я не считаю целесообразным распространять эту логику по всем моим Make-файлам. Помещение этого в Makefile верхнего уровня также не является хорошим решением, так как я часто собираю из подкаталогов и хочу построить их параллельно. Однако, если у вас достаточно плоская иерархия источников, она может работать на вас.

33 голосов
/ 24 января 2011

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

27 голосов
/ 06 декабря 2013

Как сказал Иеремия Уиллкок, используйте 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
15 голосов
/ 20 декабря 2016

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

make -j$(nproc)
6 голосов
/ 03 июня 2015

Псевдонимы не раскрываются внутри скриптов . Лучше создать отдельный скрипт 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` "$@"
6 голосов
/ 24 января 2011

Вы можете добавить строку в ваш Makefile, как показано ниже:

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

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

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

2 голосов
/ 08 сентября 2017

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

export MAKEFLAGS='-j$(nproc)'

или

export MAKEFLAGS='-j 2'
2 голосов
/ 11 июня 2017

До 2016 года вы можете поместить это в свой make-файл: (GNU make test)

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

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

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

ifeq ($(PARALELL_WRAPPER_ABXCOEOEKCOEBMQJKHTOEUB),done)

all: ...
   ...

other_target: ...
    ...

else
# add parallelism equal to number of cores every time.
# "random" strings are to ensure uniqueness
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

endif
1 голос
/ 27 декабря 2017

В начале Makefile:

MAKEFLAGS+="j"

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

MAKEFLAGS+="j2"

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

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

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

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

0 голосов
/ 05 июня 2013

Я бы просто положил

alias make='make -j'

в ~/.profile или ~/.bashrc.

В соответствии с руководством :

Если после параметра -j нет ничего, похожего на целое число, количество рабочих мест не ограничено.

...