Compilar con g ++ usando múltiples núcleos

174

Pregunta rápida: ¿cuál es el indicador del compilador para permitir que g ++ genere múltiples instancias de sí mismo para compilar proyectos grandes más rápido (por ejemplo, 4 archivos fuente a la vez para una CPU de múltiples núcleos)?

bsofman
fuente
¿Realmente ayudará? Todos mis trabajos de compilación están vinculados a E / S en lugar de a CPU.
Brian Knoblauch el
55
Incluso si están vinculados a E / S, probablemente pueda mantener la carga de E / S más alta cuando ocurran los bits pesados ​​de la CPU (con solo una instancia de g ++ habrá interrupciones) y posiblemente gane eficiencia de E / S si el planificador tiene más opciones sobre qué leer del disco a continuación. Mi experiencia ha sido que el uso juicioso de make -jcasi siempre resulta en alguna mejora.
Flexo
1
@BrianKnoblauch Pero en mi máquina (real o en VirtualBox), está vinculada a la CPU, descubrí que la CPU está ocupada a través del comando 'superior' al compilar.
大 宝剑
1
Incluso si están unidos a E / S, podemos usar la bandera 'gpi' de gcc para reducir el dolor.
大 宝剑
acabo de ver esto en google: gcc.gnu.org/onlinedocs/libstdc++/manual/…
Jim Michaels

Respuestas:

240

Puede hacer esto con make - con gnu make es la bandera -j (esto también ayudará en una máquina de un solo procesador).

Por ejemplo, si desea 4 trabajos paralelos de make:

make -j 4

También puede ejecutar gcc en una tubería con

gcc -pipe

Esto canalizará las etapas de compilación, lo que también ayudará a mantener ocupados los núcleos.

Si también tiene máquinas adicionales disponibles, puede consultar distcc , que también compilará compilaciones para ellos.

frankodwyer
fuente
36
Tu número -j debe ser 1,5 veces el número de núcleos que tienes.
Mark Beckwith el
2
Gracias. Seguí intentando pasar "-j #" a gcc a través de CFLAGS / CPPFLAGS / CXXFLAGS. Había olvidado por completo que "-j #" era un parámetro para la creación de GNU (y no para GCC).
chriv
33
¿Por qué la opción -j para GNU Make necesita ser 1.5 veces el número de núcleos de CPU?
bitek
28
El número 1.5 se debe al problema vinculado de E / S observado . Es una regla de oro. Aproximadamente 1/3 de los trabajos estarán esperando E / S, por lo que los trabajos restantes utilizarán los núcleos disponibles. Un número mayor que los núcleos es mejor e incluso podría llegar hasta 2x . Ver también: Gnu hace -jargumentos
ruido sin sentido
44
@ JimMichaels Podría deberse a que las dependencias están mal configuradas dentro de su proyecto (un objetivo comienza a construirse incluso si sus dependencias aún no están listas) de modo que solo una compilación secuencial termina siendo exitosa.
Antonio
42

No existe ese indicador, y tener uno va en contra de la filosofía de Unix de hacer que cada herramienta realice solo una función y lo haga bien. Generar procesos del compilador es conceptualmente el trabajo del sistema de compilación. Lo que probablemente esté buscando es la bandera -j (empleos) a GNU make, a la

make -j4

O puede usar pmake o sistemas similares de creación paralela.

Mihai Limbășan
fuente
3
"La pedantería de Unix no es útil" Lo bueno no fue la pedantería entonces, editor anónimo. Retrotraído. Los revisores, por favor, presten más atención a lo que están haciendo.
Carreras de ligereza en órbita
12

La gente ha mencionado makepero bjamtambién apoya un concepto similar. El uso bjam -jxinstruye a bjam para que se acumule en xcomandos simultáneos.

Usamos los mismos scripts de compilación en Windows y Linux y esta opción reduce a la mitad nuestros tiempos de compilación en ambas plataformas. Agradable.

MattyT
fuente
9

makeHará esto por ti. Investigue -jy -lcambie en la página del manual. No creo que g++sea ​​paralelizable.

rmeador
fuente
+1 por mencionar la -lopción (no inicia un nuevo trabajo a menos que todos los trabajos anteriores hayan terminado). De lo contrario, parece que el trabajo del vinculador comienza con no todos los archivos de objetos creados (ya que algunas compilaciones aún están en curso), por lo que el trabajo del vinculador falla.
NGI
8

Si usa make, emita con -j. De man make:

  -j [jobs], --jobs[=jobs]
       Specifies the number of jobs (commands) to run simultaneously.  
       If there is more than one -j option, the last one is effective.
       If the -j option is given without an argument, make will not limit the
       number of jobs that can run simultaneously.

Y lo más notable, si desea escribir o identificar la cantidad de núcleos que tiene disponibles (dependiendo de su entorno, y si se ejecuta en muchos entornos, esto puede cambiar mucho) puede usar la función ubicua de Python cpu_count():

https://docs.python.org/3/library/multiprocessing.html#multiprocessing.cpu_count

Me gusta esto:

make -j $(python3 -c 'import multiprocessing as mp; print(int(mp.cpu_count() * 1.5))')

Si está preguntando por qué 1.5citaré al usuario artless-noise en un comentario anterior:

El número 1.5 se debe al problema vinculado de E / S observado. Es una regla de oro. Aproximadamente 1/3 de los trabajos estarán esperando E / S, por lo que los trabajos restantes utilizarán los núcleos disponibles. Un número mayor que los núcleos es mejor e incluso podría llegar hasta 2x.

Havok
fuente
55
La mayoría de los usuarios de Linux probablemente preferirán el más corto: make -j`nproc` con nprocGNU Coreutils.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Si está utilizando una SSD, la E / S no será un problema tan grave. Solo para construir sobre el comentario anterior de Ciro, puedes hacer esto: make -j $(( $(nproc) + 1 ))(asegúrate de poner espacios donde los tengo).
Ed K
Buena sugerencia usando python, en sistemas donde nprocno está disponible, por ejemplo, en manylinux1contenedores, ahorra tiempo adicional al evitar ejecutar yum update/ yum install.
hoefling
7

distcc también se puede usar para distribuir compilaciones no solo en la máquina actual, sino también en otras máquinas en una granja que tienen instalado distcc.

Jason
fuente
+1, distcc es una herramienta útil para tener en el arsenal para grandes construcciones.
Flexo
Parece que hay algunos que también funcionan como "distcc": stackoverflow.com/questions/5374106/distributed-make/…
rogerdpack
3

No estoy seguro acerca de g ++, pero si está usando GNU Make, entonces "make -j N" (donde N es el número de hilos que puede crear make) permitirá que make ejecute trabajos multple g ++ al mismo tiempo (tanto tiempo ya que los archivos no dependen el uno del otro).

Andy
fuente
2
no N no es el número de hilos! Mucha gente lo malinterpreta, pero -j Nle dice a cuántos procesos a la vez se deben generar, no hilos. Esa es la razón por la cual no es tan eficiente como MS cl -MT(realmente multiproceso).
Sebi2020
2

GNU paralelo

Estaba haciendo un punto de referencia de compilación sintética y no podía molestarme en escribir un Makefile, así que usé:

sudo apt-get install parallel
ls | grep -E '\.c$' | parallel -t --will-cite "gcc -c -o '{.}.o' '{}'"

Explicación:

  • {.} toma el argumento de entrada y elimina su extensión
  • -t imprime los comandos que se ejecutan para darnos una idea del progreso
  • --will-cite elimina la solicitud de citar el software si publica resultados utilizándolo ...

parallel es tan conveniente que incluso podría hacer una comprobación de marca de tiempo yo mismo:

ls | grep -E '\.c$' | parallel -t --will-cite "\
  if ! [ -f '{.}.o' ] || [ '{}' -nt '{.}.o' ]; then
    gcc -c -o '{.}.o' '{}'
  fi
"

xargs -Ptambién puede ejecutar trabajos en paralelo, pero es un poco menos conveniente hacer la manipulación de la extensión o ejecutar múltiples comandos con él: llamar a múltiples comandos a través de xargs

Se solicitó la vinculación paralela en: ¿Puede gcc usar múltiples núcleos al vincular?

TODO: Creo que leí en alguna parte que la compilación se puede reducir a la multiplicación de matrices, por lo que tal vez también sea posible acelerar la compilación de un solo archivo para archivos grandes. Pero no puedo encontrar una referencia ahora.

Probado en Ubuntu 18.10.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente