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


¿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.
大 宝剑

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.


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.



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.


9

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


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


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


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


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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.