Wie bestimme ich die maximale Anzahl, die an die Option make -j übergeben werden soll?

31

Ich möchte so schnell wie möglich kompilieren. Stelle dir das vor. Und möchte die Wahl der Nummer nach der -jOption automatisieren . Wie kann ich diesen Wert programmatisch auswählen, z. B. in einem Shell-Skript?

nprocEntspricht die Ausgabe von der Anzahl der Threads, mit denen ich kompilieren kann?

make -j1 make -j16

Tarabyte
quelle

Antworten:

34

nprocgibt die Anzahl der verfügbaren CPU-Kerne / Threads an, z. B. 8 auf einer Vierkern-CPU, die Zweiwege-SMT unterstützt.

Die Anzahl der Jobs, die Sie mit makeder -jOption parallel ausführen können, hängt von einer Reihe von Faktoren ab:

  • die Menge des verfügbaren Speichers
  • die Menge an Speicher, die von jedem makeJob verwendet wird
  • das Ausmaß, in dem makeJobs E / A- oder CPU-gebunden sind

make -j$(nproc) Es ist ein anständiger Ort, um anzufangen, aber Sie können normalerweise höhere Werte verwenden, solange Sie den verfügbaren Speicher nicht ausschöpfen und mit dem Dröhnen beginnen.

Für wirklich schnelle Builds empfehle ich die Verwendung von, wenn Sie über genügend Arbeitsspeicher verfügen. Auf tmpfsdiese Weise sind die meisten Jobs CPU-gebunden und make -j$(nproc)arbeiten so schnell wie möglich.

Stephen Kitt
quelle
3
und ccachefür den späteren
umbau
1
Wäre es hier sinnvoll, so etwas wie GNU parallel zu verwenden?
Terdon
Wenn ich a verwende tmpfs, bin ich dann auf eine Verzeichnisgröße beschränkt, die immer kleiner als meine physische RAM-Größe ist?
Tarabyte
2
Es ist keine gute Antwort, aber im strengen Sinne der Frage, programmgesteuert den schnellsten "j" -Wert zu bestimmen, könnten Sie j von 1 bis zu einer vernünftigen Obergrenze (2x nproc ??) schleifen und make in einen timeAufruf einschließen . Bereinigen Sie die Ergebnisse, schäumen Sie die Spülwiederholung ein - und sortieren Sie am Ende die Zeiten / j-Werte.
Jeff Schaller
3
@terdon Nein. Bei Make dreht sich alles um das Auflösen von Abhängigkeiten. Das bedeutet, dass die Jobs immer noch in einer bestimmten Reihenfolge ausgeführt werden müssen. GNU parallel kümmert sich nicht darum. Nebenbei bemerkt ist es ein schwieriges Problem, zu entscheiden, welche Jobs sicher parallel ausgeführt werden können und welche nicht. Alle make-Programme, die parallele Builds anboten, brauchten Jahre, bis sie einigermaßen brauchbar wurden.
lcd047
6

Leider können sogar unterschiedliche Teile desselben Builds mit widersprüchlichen j-Faktor-Werten optimal sein, je nachdem, was gerade erstellt wird, wie, welche der Systemressourcen zu diesem Zeitpunkt den Engpass darstellen, was sonst noch auf der Build-Maschine passiert und was gerade passiert das Netzwerk (bei Verwendung verteilter Build-Techniken), Status / Standort / Leistung der vielen an einem Build beteiligten Caching-Systeme usw.

Das Kompilieren von 100 winzigen C-Dateien ist möglicherweise schneller als das Kompilieren einer einzelnen großen Datei oder umgekehrt. Das Erstellen von kleinem, stark verschachteltem Code kann langsamer sein als das Erstellen großer Mengen von direktem / linearem Code.

Sogar der Kontext des Builds spielt eine Rolle - die Verwendung eines für Builds auf dedizierten Servern optimierten Aj-Faktors, der für exklusive, nicht überlappende Builds optimiert ist, kann zu sehr enttäuschenden Ergebnissen führen, wenn Entwickler parallel auf demselben gemeinsam genutzten Server bauen (für jeden solchen Build ist möglicherweise mehr erforderlich) Zeit als alle von ihnen kombiniert, wenn serialisiert) oder auf Servern mit unterschiedlichen Hardware-Konfigurationen oder virtualisiert.

Es gibt auch den Aspekt der Richtigkeit der Build-Spezifikation. Sehr komplexe Builds können Race-Zustände aufweisen, die zu intermittierenden Build-Fehlern führen. Die Auftrittsraten können je nach Zunahme oder Abnahme des j-Faktors stark variieren.

Ich kann weiter und weiter gehen. Der Punkt ist, dass Sie Ihren Build tatsächlich in Ihrem Kontext bewerten müssen , für den Sie den Faktor j optimieren möchten. Es gilt der Kommentar von @Jeff Schaller: iterieren Sie, bis Sie die beste Anpassung gefunden haben. Persönlich würde ich vom nproc-Wert ausgehen und erst nach oben und dann nach unten probieren, wenn die Versuche nach oben eine sofortige Verschlechterung anzeigen.

Es könnte eine gute Idee sein, zunächst mehrere identische Builds in vermeintlich identischen Kontexten zu messen, um sich einen Eindruck von der Variabilität Ihrer Messungen zu verschaffen. Wenn dies zu hoch ist, kann dies Ihren gesamten Optimierungsaufwand gefährden (eine Variabilität von 20% würde eine Verbesserung von 10% vollständig in den Schatten stellen). Verschlechterungswert in der j-Faktorsuche).

Schließlich ist es meiner Meinung nach besser, einen (adaptiven) Jobserver zu verwenden, sofern dieser unterstützt wird und verfügbar ist, als einen festen J-Faktor. Er bietet konsistent eine bessere Build-Leistung in einem breiteren Bereich von Kontexten.

Dan Cornilescu
quelle
Gut ausgedrückt in Bezug auf die Abhängigkeiten des zugrunde liegenden Builds. kannst du kommentieren, dass mit dem -jparameter keine feste nummer übergeben wird? zBmake -j
tarabyte
4
make -jwird so viele Jobs erzeugen, wie die Abhängigkeiten erlauben wie eine Gabelbombe ( superuser.com/questions/927836/… ); Der Build wird im besten Fall crawlen und die meiste CPU für die Verwaltung der Prozesse aufwenden als für deren Ausführung ( superuser.com/questions/934685/… ). Bei hochparallelen Builds geht dem System der Speicher / Swap oder die PID-Nummern aus, und der Build schlägt fehl .
Dan Cornilescu
3

Der direkteste Weg ist, nprocwie folgt zu verfahren :

make -j`nproc`

Der Befehl nprocgibt die Anzahl der Kerne auf Ihrem Computer zurück. Wenn Sie es in die Häkchen setzen, wird der nprocBefehl zuerst ausgeführt, es wird eine Zahl zurückgegeben und diese Zahl wird übergeben make.

Möglicherweise verfügen Sie über einige anekdotische Erfahrungen, bei denen Core-Count + 1 zu schnelleren Kompilierzeiten führt. Dies hat mehr mit Faktoren wie E / A-Verzögerungen, anderen Ressourcenverzögerungen und der Verfügbarkeit von Ressourcenbeschränkungen zu tun.

Um dies zu tun mit nproc+1, versuchen Sie dies:

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

Wenn Sie einen makeBefehl schreiben möchten, um so viele parallele Worker wie virtuelle CPUs zu verwenden, empfehle ich:

nproc | xargs -I % make -j%

Dies kann entweder als eigenständiger Befehl oder als RUNDirektive innerhalb von geschrieben werden Dockerfile(da Docker keine verschachtelten Befehle unterstützt).

Maksym Ganenko
quelle