¿Cómo determinar el número máximo para pasar a la opción -j?

31

Quiero compilar lo más rápido posible. Imagínate. Y me gustaría automatizar la elección del número que sigue a la -jopción. ¿Cómo puedo elegir programáticamente ese valor, por ejemplo, en un script de shell?

¿La salida es nprocequivalente a la cantidad de hilos que tengo disponibles para compilar?

make -j1 make -j16

tarabyte
fuente

Respuestas:

34

nprocproporciona la cantidad de núcleos / subprocesos de CPU disponibles, por ejemplo , 8 en una CPU de cuatro núcleos que admite SMT bidireccional.

El número de trabajos que puede ejecutar en paralelo con el makeuso de la -jopción depende de varios factores:

  • la cantidad de memoria disponible
  • la cantidad de memoria utilizada por cada maketrabajo
  • la medida en que los maketrabajos están vinculados a E / S o CPU

make -j$(nproc) es un lugar decente para comenzar, pero generalmente puede usar valores más altos, siempre que no agote su memoria disponible y comience a agitarse.

Para compilaciones realmente rápidas, si tiene suficiente memoria, le recomiendo usar a tmpfs, de esa manera la mayoría de los trabajos estarán vinculados a la CPU y make -j$(nproc)funcionarán lo más rápido posible.

Stephen Kitt
fuente
3
y ccachepara la reconstrucción posterior, pero esto es OT
solSTiCe
1
¿Valdría la pena usar algo como GNU paralelo aquí?
terdon
Si uso a tmpfs, ¿estaré limitado a un tamaño de directorio que siempre sea más pequeño que el tamaño de mi RAM física?
tarabyte
2
No es una gran respuesta, pero en el espíritu estricto de la cuestión de determinar mediante programación el valor "j" más rápido, puede hacer un bucle j desde 1 hasta un límite superior razonable (2x nproc ??) y ajustar la marca en una timellamada. Limpie los resultados, repita el enjuague de espuma y termine ordenando los valores de tiempos / j.
Jeff Schaller
3
@terdon No. Make se trata de resolver dependencias, lo que significa que los trabajos aún deben ejecutarse en un cierto orden. GNU paralelo no se preocupa por eso. En una nota al margen, decidir qué trabajos son seguros para ejecutar en paralelo y cuáles no es un problema difícil. Todos los programas de creación que ofrecían compilaciones paralelas tomaron años hasta que se volvieron algo utilizables.
lcd047
6

Desafortunadamente, incluso diferentes partes de la misma compilación pueden ser óptimas con valores de factor j en conflicto, dependiendo de lo que se está construyendo, cómo, cuáles de los recursos del sistema son el cuello de botella en ese momento, qué más está sucediendo en la máquina de compilación, qué está sucediendo en la red (si usa técnicas de compilación distribuidas), estado / ubicación / rendimiento de los muchos sistemas de almacenamiento en caché involucrados en una compilación, etc.

Compilar 100 archivos C pequeños puede ser más rápido que compilar uno solo, o viceversa. La creación de código pequeño muy complicado puede ser más lento que la creación de grandes cantidades de código directo / lineal.

Incluso el contexto de la compilación es importante: el uso de un factor aj optimizado para compilaciones en servidores dedicados ajustados para compilaciones exclusivas y no superpuestas puede producir resultados muy decepcionantes cuando los desarrolladores lo usan en paralelo en el mismo servidor compartido (cada compilación puede tomar más tiempo que todos ellos combinados si se serializan) o en servidores con diferentes configuraciones de hardware o virtualizados.

También está el aspecto de la corrección de la especificación de compilación. Las construcciones muy complejas pueden tener condiciones de carrera que causan fallas de construcción intermitentes con tasas de ocurrencia que pueden variar enormemente con el aumento o disminución del factor j.

Puedo seguir y seguir. El punto es que debe evaluar realmente su compilación en el contexto en el que desea optimizar el factor j. Se aplica el comentario de @Jeff Schaller: itera hasta que encuentres tu mejor ajuste. Personalmente, comenzaría desde el valor nproc, intente hacia arriba primero y hacia abajo solo si los intentos hacia arriba muestran una degradación inmediata.

Puede ser una buena idea medir primero varias construcciones idénticas en contextos supuestamente idénticos solo para tener una idea de la variabilidad de sus mediciones; si es demasiado alta, podría poner en peligro todo su esfuerzo de optimización (una variabilidad del 20% eclipsaría por completo una mejora del 10% / lectura de degradación en la búsqueda del factor j).

Por último, en mi humilde opinión, es mejor usar un servidor de trabajo (adaptativo) si es compatible y está disponible en lugar de un factor j fijo: proporciona un mejor rendimiento de compilación en un rango más amplio de contextos.

Dan Cornilescu
fuente
Bien puesto en relación con las dependencias de la compilación subyacente. ¿Puedes comentar sobre pasar ningún número fijo con el -jparámetro? por ejemplomake -j
tarabyte
44
make -jgenerará tantos trabajos como lo permitan las dependencias, como una bomba tenedor ( superuser.com/questions/927836/… ); la compilación se arrastrará, en el mejor de los casos, gastando la mayor parte de la CPU en la gestión de los procesos en lugar de ejecutarlos ( superuser.com/questions/934685/… ) y en compilaciones altamente paralelas, el sistema se quedará sin memoria / intercambio o pid #s y la compilación fallará .
Dan Cornilescu
3

La forma más directa es usar nprocasí:

make -j`nproc`

El comando nprocdevolverá el número de núcleos en su máquina. Al envolverlo en los ticks, el nproccomando se ejecutará primero, devolverá un número y ese número se pasará make.

Es posible que tenga alguna experiencia anecdótica en la que hacer un conteo de núcleos + 1 resulte en tiempos de compilación más rápidos. Esto tiene más que ver con factores como los retrasos de E / S, otros retrasos de recursos y otra disponibilidad de limitaciones de recursos.

Para hacer esto nproc+1, intente esto:

make -j$((`nproc`+1))
010110110101
fuente
0

Si desea escribir un makecomando para usar tantos trabajadores paralelos como CPU virtuales, sugiero usar:

nproc | xargs -I % make -j%

Que se puede escribir como un comando independiente o como una RUNdirectiva dentro Dockerfile(ya que Docker no admite comandos anidados)

Maksym Ganenko
fuente