¿Qué podría estar causando que se bloquee al compilar en múltiples núcleos?

17

Ayer estaba tratando de compilar el paquete ROOT desde la fuente. Como lo estaba compilando en una máquina monstruo de 6 núcleos, decidí seguir adelante y construir usando múltiples núcleos make -j 6. La compilación se realizó sin problemas y realmente rápido al principio, pero en algún momento se makebloqueó usando 100% de CPU en un solo núcleo.

Busqué en Google y encontré esta publicación en los foros de ROOT. Desde que construí esta computadora, me preocupaba no haber aplicado correctamente el disipador de calor y la CPU se estaba sobrecalentando o algo así. Desafortunadamente, no tengo un refrigerador aquí en el trabajo en el que pueda meterlo. ;-)

Instalé el lm-sensorspaquete y corrí make -j 6nuevamente, esta vez monitoreando la temperatura de la CPU. Aunque se puso alto (cerca de 60 C), nunca pasó la temperatura alta o crítica.

Traté de correr, make -j 4pero nuevamente makecolgué en algún momento durante la compilación, esta vez en un lugar diferente.

Al final, compilé simplemente corriendo makey funcionó bien. Mi pregunta es: ¿por qué estaba colgando? Debido al hecho de que se detuvo en dos puntos diferentes, supongo que se debió a algún tipo de condición de carrera, pero creo que makedebería ser lo suficientemente inteligente como para tener todo en el orden correcto, ya que ofrece la -jopción.

usuario545424
fuente
44
Suena como una condición de carrera. Una cosa que puede hacer es adjuntarse al proceso de creación en ejecución (el que está girando) usando, por ejemplo, strace -p <pid>y ver si puede averiguar qué está mirando / buscando. strace solo le mostrará llamadas al sistema (no llamadas a funciones), pero aún podría brindarle información valiosa si está girando mientras mira o busca un archivo en particular.
jlp
El hilo que encontraste a través de google lleva a la conclusión de que nadie pudo compilarlo -j >1.
Nils
No relacionado con la compilación paralela, pero tenía un archivo MAKE colgante que demoró una eternidad en depurar. Resulta que fue simplemente en la inicialización de una variable, $(shell ...)finalmente estaba ejecutando un comando que estaba esperando la entrada destdin . Esto se produjo cuando una variable estaba vacía y no se pasaron argumentos de archivo al comando.
jozxyqk

Respuestas:

13

No tengo una respuesta a este problema preciso, pero puedo intentar darle una pista de lo que puede estar sucediendo: faltan dependencias en Makefiles.

Ejemplo:

target: a.bytecode b.bytecode
    link a.bytecode b.bytecode -o target

a.bytecode: a.source
    compile a.source -o a.bytecode

b.bytecode: b.source
    compile b.source a.bytecode -o a.bytecode

Si llamas make targettodo se compilará correctamente. La compilación de a.sourcese realiza (arbitrariamente, pero determinísticamente) primero. Luego b.sourcese realiza la compilación de .

Pero si tu make -j2 target ambos compilecomandos se ejecutarán en paralelo. Y realmente notará que las dependencias de su Makefile están rotas. La segunda compilación supone a.bytecodeque ya está compilada, pero no aparece en las dependencias. Por lo tanto, es probable que ocurra un error. La línea de dependencia correcta para b.bytecodedebería ser:

b.bytecode: b.source a.bytecode

Para volver a su problema, si no tiene suerte, es posible que un comando se bloquee en un ciclo de CPU 100%, debido a una dependencia que falta. Eso es probablemente lo que está sucediendo aquí, la dependencia faltante no pudo ser revelada por una compilación secuencial, pero ha sido revelada por su compilación paralela.

Stéphane Gimenez
fuente
Interesante. ¿Sabes si hay herramientas disponibles que puedan ejecutarse a través de un archivo MAKE y verificar estas dependencias?
user545424
No se ninguno. En cualquier caso, dicha herramienta solo podría encontrar errores obvios. A menos que comprenda la sintaxis de cada comando que aparece en el Makefile y sepa cuáles son las dependencias (potencialmente implícitas).
Stéphane Gimenez
2

No sé cuánto tiempo ha tenido la máquina, pero mi primera recomendación sería probar una prueba de memoria y verificar que la memoria funciona correctamente. Sé que a menudo el problema no es la memoria, pero si lo es, lo mejor es eliminarlo como causa antes de intentar localizar otros problemas probablemente.

asesino
fuente
1

Me doy cuenta de que esta es una pregunta muy antigua, pero aún aparece en la parte superior de los resultados de búsqueda, así que aquí está mi solución:

GNU make tiene un mecanismo de servidor de trabajo para garantizar que make y sus hijos recursivos no consuman más que el número especificado de núcleos: http://make.mad-scientist.net/papers/jobserver-implementation/

Se basa en una tubería compartida por todos los procesos. Cada proceso que quiere bifurcar niños adicionales primero tiene que consumir fichas de la tubería, luego renunciar a ellas cuando haya terminado. Si un proceso secundario no devuelve los tokens que consumió, el nivel superior se realiza mientras se bloquea para siempre esperando que sean devueltos.

https://bugzilla.redhat.com/show_bug.cgi?id=654822

Encontré este error al construir binutils con GNU make en mi caja Solaris, donde "sed" no es GNU sed. Jugar con PATH para que sed == gsed tenga prioridad sobre el sistema sed solucionó el problema. Sin embargo, no sé por qué sed estaba consumiendo fichas de la tubería.

Fazal Majid
fuente
0

su sistema podría estar bien, pero podría ser una condición de carrera que ocurra con make cuando se ejecutan compilaciones en paralelo.

Si algo está mal con su sistema, se bloqueará / bloqueará para otros escenarios, no solo al hacer compilaciones paralelas.

fduff
fuente
0

Esta podría ser una condición de carrera, pero también si toda la compilación necesaria se realiza en paralelo y esperando a otros, la vinculación lleva su tiempo en su máquina. Creo que si el enlace espera la compilación necesaria previa en paralelo, entonces obtienes una alta frecuencia de CPU en el hilo de enlace, lo que sea que compiles.

MahmutBulut
fuente