Was kann dazu führen, dass make beim Kompilieren auf mehreren Kernen hängen bleibt?

17

Gestern habe ich versucht, das ROOT- Paket aus dem Quellcode zu kompilieren . Da ich es auf einem 6-Kern-Monstercomputer kompilierte, entschied ich mich, mit mehreren Kernen zu bauen make -j 6. Die Kompilierung verlief zunächst reibungslos und sehr schnell, aber irgendwann makehing die Verwendung von 100% CPU auf nur einem Kern.

Ich habe ein bisschen gegoogelt und diesen Beitrag in den ROOT- Foren gefunden . Da ich diesen Computer selbst gebaut habe, war ich besorgt, dass ich den Kühlkörper nicht richtig angebracht habe und die CPU überhitzt ist oder so. Leider habe ich hier bei der Arbeit keinen Kühlschrank, in den ich ihn stecken kann ;-)

Ich installierte das lm-sensorsPaket und lief make -j 6erneut, diesmal mit Überwachung der CPU-Temperatur. Obwohl es hoch wurde (nahe 60 ° C), überschritt es nie die hohe oder kritische Temperatur.

Ich habe versucht zu rennen, habe make -j 4aber makeirgendwann während des Kompilierens wieder aufgehängt, diesmal an einer anderen Stelle.

Am Ende habe ich nur das Laufen kompiliert makeund es hat gut funktioniert. Meine Frage ist: Warum hing es? Aufgrund der Tatsache, dass es an zwei verschiedenen Stellen anhielt, würde ich vermuten, dass es an einer Art Rennbedingung lag, aber ich würde denken, makedass es klug genug sein sollte, um alles in die richtige Reihenfolge zu bringen, da es die -jOption bietet .

user545424
quelle
4
Es klingt wie eine Rennbedingung. Eine Sache, die Sie tun können, ist das Anhängen an den laufenden Make-Prozess (den, der sich dreht), indem Sie z. B. strace -p <pid>prüfen, ob Sie herausfinden können, wonach er sucht. strace zeigt Ihnen nur Systemaufrufe (keine Funktionsaufrufe), aber es kann Ihnen trotzdem wertvolle Informationen geben, wenn es sich dreht, während Sie nach einer bestimmten Datei suchen.
jlp
Der Thread, den Sie über Google gefunden haben, lässt den Schluss zu, dass es niemandem gelungen ist, ihn zu kompilieren -j >1.
Nils
Nicht im Zusammenhang mit der parallelen Kompilierung, aber ich hatte ein hängendes Makefile, dessen Debugging ewig gedauert hat. Es stellte sich heraus, dass es sich einfach um die Initialisierung einer Variablen handelte, $(shell ...)die letztendlich einen Befehl ausführte, der auf die Eingabe von wartetestdin . Dies wurde verursacht, wenn eine Variable leer war und keine Dateiargumente an den Befehl übergeben wurden.
Jozxyqk

Antworten:

13

Ich habe keine Antwort auf dieses präzise Problem, aber ich kann versuchen, Ihnen einen Hinweis darauf zu geben, was möglicherweise passiert: Fehlende Abhängigkeiten in Makefiles.

Beispiel:

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

Wenn Sie aufrufen, wird make targetalles korrekt kompiliert. Die Kompilierung von a.sourcewird zuerst (willkürlich, aber deterministisch) durchgeführt. Dann wird die Kompilierung von b.sourcedurchgeführt.

Aber wenn Sie make -j2 targetbeide compileBefehle parallel ausgeführt werden. Und Sie werden feststellen, dass die Abhängigkeiten Ihres Makefiles beschädigt sind. Die zweite Kompilierungsannahme a.bytecodeist bereits kompiliert, wird jedoch nicht in Abhängigkeiten angezeigt. Es ist also wahrscheinlich, dass ein Fehler auftritt. Die richtige Abhängigkeitszeile für b.bytecodesollte sein:

b.bytecode: b.source a.bytecode

Um auf Ihr Problem zurückzukommen: Wenn Sie kein Glück haben, kann es sein, dass ein Befehl aufgrund einer fehlenden Abhängigkeit in einer 100% -CPU-Schleife hängen bleibt. Das ist wahrscheinlich das, was hier passiert. Die fehlende Abhängigkeit konnte nicht durch einen sequentiellen Build aufgedeckt werden, sondern wurde durch Ihren parallelen Build aufgedeckt.

Stéphane Gimenez
quelle
Interessant. Wissen Sie, ob Tools verfügbar sind, die ein Makefile durchlaufen und diese Abhängigkeiten überprüfen können?
user545424
Ich kenne keine In jedem Fall konnte ein solches Tool nur offensichtliche Fehler finden. Es sei denn, es versteht die Syntax für jeden Befehl, der im Makefile angezeigt wird, und kennt die (möglicherweise impliziten) Abhängigkeiten.
Stéphane Gimenez
2

Ich weiß nicht, wie lange Sie den Computer schon haben, aber meine erste Empfehlung wäre, einen Speichertest durchzuführen und zu überprüfen, ob der Speicher ordnungsgemäß funktioniert. Ich weiß, es ist oft nicht der Speicher, der das Problem ist, aber wenn ja, ist es am besten, ihn zuerst als Ursache zu beseitigen, bevor Sie versuchen, andere mögliche Probleme aufzuspüren.

Killermist
quelle
1

Mir ist klar, dass dies eine sehr alte Frage ist, aber sie taucht immer noch oben in den Suchergebnissen auf. Hier ist meine Lösung:

GNU make verfügt über einen Jobserver-Mechanismus, der sicherstellt, dass make und seine rekursiven Kinder nicht mehr als die angegebene Anzahl von Kernen verbrauchen: http://make.mad-scientist.net/papers/jobserver-implementation/

Es basiert auf einer Pipe, die von allen Prozessen gemeinsam genutzt wird. Jeder Prozess, bei dem zusätzliche Kinder gezählt werden sollen, muss zuerst Token aus der Pipe konsumieren und diese anschließend wieder abgeben. Wenn ein untergeordneter Prozess die verbrauchten Token nicht zurückgibt, bleibt die Ausführung auf oberster Ebene für immer hängen und wartet darauf, dass sie zurückgegeben werden.

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

Ich bin auf diesen Fehler gestoßen, als ich Binutils mit GNU make auf meiner Solaris-Box erstellt habe, wobei "sed" nicht GNU sed ist. Das Fummeln mit PATH, damit sed == gsed Vorrang vor dem System hat, hat das Problem behoben. Ich weiß allerdings nicht, warum sed Token aus der Pipe verbraucht hat.

Fazal Majid
quelle
0

Ihr System mag in Ordnung sein, aber es könnte eine Racebedingung sein, makewenn Sie Builds parallel ausführen.

Wenn etwas mit Ihrem System nicht stimmt, kann es in anderen Szenarien zum Absturz kommen, nicht nur bei parallelen Builds.

fduff
quelle
0

Dies kann eine Racebedingung sein, aber auch, wenn alle erforderlichen Kompilierungen parallel durchgeführt werden und auf andere gewartet wird. Das Verknüpfen kostet Ihre Zeit auf Ihrem Computer. Ich denke, dass, wenn das Verknüpfen auf vorherige notwendige Kompilierung parallel wartet, Sie hohe CPU-Frequenz auf dem Verknüpfen des Threads erhalten, was auch immer Sie kompilieren.

MahmutBulut
quelle