2011-01-24 5 views
51

Tengo un Makefile en una máquina que tiene una tonelada de núcleos, pero siempre me olvido de escribir -jX al compilar mi proyecto y toma más tiempo de lo que debería.¿Indicador de configuración automática de trabajos (-j) para una máquina multinúcleo?

¿Hay alguna manera de establecer el indicador -j a través de una variable de entorno u otro archivo de configuración persistente para que make ejecute automáticamente varias tareas en paralelo en esta máquina?

+0

Relacionado: http: // stackoverflow.com/questions/2527496/how-can-i-write-a-makefile-to-auto-detect-and-parallelize-the-build-with-gnu-make –

+0

@sanmai, ¿para qué sistema operativo lo necesita? ¿Y por qué 'alias make = 'make -j $ (getconf _NPROCESSORS_ONLN)' 'no funciona para usted? –

+0

Alias ​​no será suficiente porque necesito publicar el Makefile y que siga funcionando. Necesito esto para GNU Make 4.1. @TarunLalwani – sanmai

Respuesta

29

Parece que la variable de entorno MAKEFLAGS puede pasar indicadores que forman parte de cada ejecución make (al menos para la marca GNU). No he tenido mucha suerte con esto, pero podría ser posible usar -l en lugar de -j para ejecutar automáticamente tantos trabajos como sea apropiado para la cantidad de núcleos que tenga disponibles.

+0

Bueno, puedes pasar '-l' o' -j' pero sin argumentos. Pruébelo usted mismo: https://gist.github.com/sanmai/dcc31ae20afa6e8ba4721f174fe05fd9 – sanmai

6

Puede añadir una línea a su Makefile similares a lo siguiente:

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

Luego añada una línea ${NUMJOBS} en sus reglas, o añadirlo a otro Makefile var (como MAKEFLAGS). Esto usará el envvar NUMJOBS, si existe; si no lo hace, use automáticamente -j4. Puede sintonizar o cambiar el nombre a su gusto.

(NB: En lo personal, yo prefiero el defecto de ser -j1 o "", especialmente si va a ser distribuido a los demás, porque aunque tengo varios núcleos también, lo compile en muchas plataformas diferentes, ya menudo se olvide de dis -posible la configuración -jX.)

+0

Gracias por esta respuesta. Fui con la respuesta de Jeremiah porque es un poco más fácil de entender y no tengo que modificar el archivo MAKE en absoluto (permitir que las personas que descarguen el proyecto establezcan el marcador -j que quieran como quieran). Informativo, sin embargo. – KarateSnowMachine

+0

Por lo que puedo decir, agregar -jX a MAKEFLAGS ha dejado de funcionar en la última versión de GNU en algún momento del año pasado. Alguien más ha experimentado esto? – golvok

33

Supongo que está utilizando Linux. Esto es de mi ejemplos de uso ~/.bashrc

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

[email protected] src> echo $NUMCPUS 
8 
[email protected] src> pmake 

convierte time nice make -j8 --load-average=8.

Para responder a su pregunta específica sobre cómo poner esto en un Makefile, no me parece práctico rociar esta lógica en todos mis archivos Makefiles. Poner esto en un Makefile de nivel superior tampoco es una gran solución ya que a menudo construyo desde subdirectorios y deseo construirlos en paralelo también. Sin embargo, si tiene una jerarquía de fuente bastante plana, puede funcionar para usted.

+1

Buena idea autodetección de la cantidad de núcleos. Aunque terminé yendo con $ ((NUMCPUS * 2)) ya que normalmente compilo con eso. ¡Gracias! – KarateSnowMachine

+1

% NUMBER_OF_PROCESSORS% se puede usar con gnu make en sistemas de Windows – davenpcj

+2

También puede tener el número de cpus con el comando 'nproc'. – Soullivaneuh

-1

Me acaba de poner

alias make='make -j' 

en ~/.profile o ~/.bashrc.

De acuerdo con la manual:

Si no hay nada que parece un número entero después de la opción ‘j’, no hay límite en el número de plazas de trabajo.

+9

En mi máquina de 2 núcleos, una' -j' no calificada rápidamente consume toda mi memoria en una construcción grande. No recomendado. – ntc2

+0

Sí, esto parece algo que causaría una bomba de tenedor en su computadora con un Makefile grande. – gib

24

Como dijo Jeremías Willcock, utilice MAKEFLAGS, pero aquí es cómo hacerlo:

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

o usted podría establecer un valor fijo como esto:

export MAKEFLAGS="-j 8" 

Si realmente desea aumentar el rendimiento, debe usar ccache agregando algo como lo siguiente a su Makefile:

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

no funciona para osx (y también para Windows) – bibi

+0

No funcionará para GNU Make 4.1 - [ver ejemplo aquí] (https://gist.github.com/sanmai/dcc31ae20afa6e8ba4721f174fe05fd9) – sanmai

+0

@sanmai, estoy usando MAKEFLAGS aquí no MAKEOPTS como se usa en su ejemplo. Creo que GNU Make 4.1 todavía tiene MAKEFLAGS. – jcoffland

9

Yo suelo hacer esto de la siguiente manera en mis scripts bash:

make -j$(nproc) 
1

Hasta que en algún momento del año pasado, usted puede hacer esto en su archivo MAKE: (GNU make probado)

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

(donde se calcula NUM_PPROCS o conjunto de acuerdo con una de las muchas de las otras respuestas aquí) ¡Y, bam! usted tiene una construcción multiproceso en marcha.

Dado que esto ha dejado de funcionar, lo mejor que se me ocurre es esto, donde se llama el archivo MAKE, pero con -jX y -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) [email protected] 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 
1

En Ubuntu 16.4 utilizando todos los núcleos de la CPU:

export MAKEFLAGS='-j$(nproc)' 

o

export MAKEFLAGS='-j 2' 
1

Al comienzo de un Makefile:

MAKEFLAGS+="j" 

No va a tomar argumentos numéricos para cualquier ver sion de GNU Make before 4.2.

Si tiene algunos trabajos que se quedan sin memoria, puede hacer que se ejecuten solo uno a la vez con flock de util-linux-ng. Por ejemplo, una utilidad convert de ImageMagick utilizará todos los recursos que pueda obtener cuando se use en optimize images according to Google's recommendations, por lo que no tiene sentido que se ejecute en paralelo.

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

Es importante establecer un tiempo de espera largo porque make seguirá ejecutando la mayoría de estos comandos en paralelo. Por lo tanto, el tiempo de espera debe ser como el tiempo de ejecución de cola más profundo. Si tiene ocho núcleos y ocho imágenes grandes tardan un minuto en optimizar, debe establecer el tiempo de espera en al menos un minuto.

Con cientos de núcleos e imágenes enormes, seiscientos segundos establecidos anteriormente podrían no ser suficientes.

Cuestiones relacionadas