web-dev-qa-db-fra.com

Définir automatiquement l'indicateur de travaux (-j) pour une machine multicœur?

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?

57
KarateSnowMachine

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.

34
Jeremiah Willcock

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.

37
Sam Miller

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
27
jcoffland

Je fais généralement cela comme suit dans mes scripts bash:

make -j$(nproc)
15
Bl00dh0und

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.)

6
Sdaz MacSkibbons

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` "$@"
6
svlasov

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
2
golvok

Sur Ubuntu 16.4 utilisant tous les cœurs de CPU:

export MAKEFLAGS='-j$(nproc)'

ou

export MAKEFLAGS='-j 2'
2
mwweb

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.

1
sanmai