J'ai un Makefile sur une machine qui contient une tonne de cœurs, mais j'ai toujours l'impression d'écrire -jX
lors de la compilation de mon projet et cela prend beaucoup plus de temps que prévu.
Existe-t-il un moyen de définir le -j
drapeau à travers une variable d'environnement ou un autre fichier de configuration persistant afin que make exécute automatiquement plusieurs travaux en parallèle sur cette machine?
Il semble que la variable d'environnement MAKEFLAGS
puisse passer des indicateurs qui font partie de chaque make
exécution (au moins pour GNU make). Je n'ai pas eu beaucoup chance avec moi-même, mais il pourrait être possible d'utiliser -l
plutôt que -j
pour exécuter automatiquement autant de travaux que nécessaire en fonction du nombre de cœurs disponibles.
Je suppose que vous utilisez Linux. C'est de mon ~/.bashrc
# parallel make
export NUMCPUS=`grep -c '^processor' /proc/cpuinfo`
alias pmake='time Nice make -j$NUMCPUS --load-average=$NUMCPUS'
exemple d'utilisation
samm@Host src> echo $NUMCPUS
8
samm@Host src> pmake
devient time Nice make -j8 --load-average=8
.
Pour répondre à votre question spécifique à propos de la mise dans un Makefile
, je ne trouve pas pratique de saupoudrer cette logique partout dans mes Makefiles. Mettre cela dans un Makefile de haut niveau n'est pas non plus une excellente solution car je construis souvent à partir de sous-répertoires et je souhaite également les construire en parallèle. Cependant, si vous avez une hiérarchie source assez plate, cela peut fonctionner pour vous.
Comme l'a dit Jeremiah Willcock, utilisez MAKEFLAGS
, mais voici comment procéder:
export MAKEFLAGS="-j $(grep -c ^processor /proc/cpuinfo)"
ou vous pouvez simplement définir une valeur fixe comme celle-ci:
export MAKEFLAGS="-j 8"
Si vous voulez vraiment augmenter les performances, vous devez utiliser ccache
en ajoutant quelque chose comme ceci à votre Makefile
:
CCACHE_EXISTS := $(Shell ccache -V)
ifdef CCACHE_EXISTS
CC := ccache $(CC)
CXX := ccache $(CXX)
endif
Je fais généralement cela comme suit dans mes scripts bash:
make -j$(nproc)
Vous pouvez ajouter une ligne à votre Makefile semblable à la suivante:
NUMJOBS=${NUMJOBS:-" -j4 "}
Ajoutez ensuite un ${NUMJOBS}
ligne dans vos règles, ou ajoutez-la dans une autre Makefile
var (comme MAKEFLAGS
). Cela utilisera l'envvar NUMJOBS, s'il existe; si ce n'est pas le cas, utilisez automatiquement -j4
. Vous pouvez le régler ou le renommer à votre goût.
(N.B .: Personnellement, je préférerais que la valeur par défaut soit -j1
ou ""
, surtout si elle va être distribuée à d'autres, car même si j'ai plusieurs cœurs également, je compile sur de nombreuses plates-formes différentes et oublie souvent dis - capable de -jX
réglage.)
Les alias ne sont pas développés dans les scripts . Il est préférable de créer un script make
séparé et de le placer dans l'un des $PATH
répertoires:
#!/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` "$@"
Jusqu'en 2016, vous pourriez mettre ceci dans votre makefile: (GNU make testé)
MAKEFLAGS += "-j$(NUM_CORES) -l$(NUM_CORES)
(où NUM_PPROCS
est calculé ou défini selon l'une des nombreuses autres réponses ici) Et, bam! vous avez la construction multi-processus en cours.
Étant donné que cela a cessé de fonctionner, la meilleure chose que j'ai pu trouver est celle-ci, où le makefile s'appelle lui-même, mais avec -jX
et -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
Sur Ubuntu 16.4 utilisant tous les cœurs de CPU:
export MAKEFLAGS='-j$(nproc)'
ou
export MAKEFLAGS='-j 2'
Au début d'un Makefile:
MAKEFLAGS+="j"
Il ne prendra pas d'arguments numériques pour toute version de GNU Make avant 4.2 . Après 4.2 vous pouvez le faire :
MAKEFLAGS+="j2"
Pour les versions antérieures à 4.2 s'il vous arrive que certains travaux manquent de mémoire, vous pouvez les exécuter uniquement un à la fois avec flock
à partir d'util-linux-ng. Par exemple, un utilitaire convert
d'ImageMagick utilisera toutes les ressources qu'il peut obtenir lorsqu'il est utilisé pour optimiser les images selon les recommandations de Google , il est donc inutile de le faire fonctionner en parallèle.
%.min.jpg: %.jpg
@flock --wait 600 Makefile convert $< -sampling-factor 4:2:0 -strip $@
Il est important de définir un long temps d'attente car make exécutera toujours la plupart de ces commandes en parallèle. Par conséquent, le temps d'attente doit être tel que le temps d'exécution de la file d'attente le plus profond. Si vous disposez de huit cœurs et que huit grandes images prennent une minute pour être optimisées, vous devez définir le temps d'attente sur au moins une minute.
Avec des centaines de cœurs et d'énormes images, six cents secondes définies ci-dessus pourraient ne pas suffire.