Forum: PC-Programmierung Problem mit Multithread-make in Linux


von Vancouver (Gast)


Lesenswert?

Moin,

größere Pakete (z.B den Kernel) übersetze ich in Linux mit make -j6, um 
alle Cores zu auszulasten. Hin und wieder bricht make jedoch mit einem 
Fehler ab (mit einer unverständlichen Fehlermeldung). Bei einem weiteren 
Aufruf macht make dann an dieser Stelle weiter, und fast immer läuft es 
dann durch. Wird nur ein Core verwendet, tritt der Fehler nicht auf. Das 
Problem tritt bei allen Versionen und Backends des gcc auf, die ich 
bisher verwendet habe.

Ist kein Weltuntergang, nervt aber. Kennt jemand das Problem?

von proggen (Gast)


Lesenswert?

Vancouver schrieb:
> (mit einer unverständlichen Fehlermeldung)

mit der könnte man dir hier vll. helfen, aber so bleibt nur die 
Glaskugel...

von Blubb (Gast)


Lesenswert?

Warum denn nicht einfach mal die Fehlermeldung hier posten?

von Sven B. (scummos)


Lesenswert?

proggen schrieb:
> Vancouver schrieb:
>> (mit einer unverständlichen Fehlermeldung)
>
> mit der könnte man dir hier vll. helfen, aber so bleibt nur die
> Glaskugel...

Ich bezweifle es.

Das passiert hin und wieder, weiß auch nicht woran es liegt. Den 
QtWebKit-Build muss man auch grundsätzlich zweimal starten ...

von Kaj (Gast)


Lesenswert?

Das Problem ist, dass schon ein Modul gebaut werden soll, wofuer die 
abhaengigkeit vielleicht noch gar nicht gebaut ist.

Das kann bei -j1 nicht passieren.

Beispiel:
Du hast Modul A und Modul B. A braucht 30 Sekunden zum compilieren und B 
nur 10 Sekunden. B ist aber abhaengig von A.

Bei -j1 wird brav Modul A gebaut und dann Modul B. Somit ist die 
Abhaengigkeit fuer B vorhanden.

Bei -j6 ist das aber nicht mehr gegeben. Jetzt werden A und B 
gleichzeitig compiliert und das compilieren schlaegt natuerlich fehl, 
weil die abhaengigkeit fuer B noch nicht vorhanden ist.

Ja, es gibt tatsaechlich faelle, wo sowas auftreten kann. Es gibt Pakete 
die mit -j1 gebaut werden muessen.

Das kann z.B. auftreten, wenn Modul A zu einer Lib gebaut wird, und 
Modul B auf diese Lib zugreifen will. Ist die Lib nicht vorhanden kann 
es nicht compiliert werden.

von Kaj (Gast)


Lesenswert?

Nachtrag:
Deswegen geht es dann beim zweitenmal Compilieren, dann ist die 
Abhengigkeit vorhanden.

von Oliver S. (oliverso)


Lesenswert?

Das sollte dann aber zu aussagekräftigen Fehlermeldungen führen.

Und eigentlich deutet sowas auf Fehler im makefile hin.

Oliver

von Vancouver (Gast)


Lesenswert?

> mit der könnte man dir hier vll. helfen, aber so bleibt nur die
> Glaskugel...

Ja, da hast Du grundsätzlich recht. Aber ich habe die Fehlermeldung 
nicht parat, da müsste ich das ganze nochmal ausprobieren. Ich habe 
gehofft, das jemand das Problem kennt.

@Kaj: Ich habe auch schon orakelt, dass es ein Dependency-Problem ist, 
aber eigentlich sollte make solche Abhängigkeiten doch auflösen.

Also gut, dann eben Neustarten. Das geht immernoch schneller als 
Singlethreaded.

Danke für Eure Hilfe!

von Daniel A. (daniel-a)


Lesenswert?

Vancouver schrieb:
> @Kaj: Ich habe auch schon orakelt, dass es ein Dependency-Problem ist,
> aber eigentlich sollte make solche Abhängigkeiten doch auflösen.

Aber nur, wenn diese im Makefile auch angegeben sind, stelle dir 
volgendes (ungetestetes) szenario vor:
1
all: a b
2
    cat a b > all
3
a: c
4
    cat c > a
5
b: c
6
    cat a c > b
7
c:
8
    echo test > c

In diesem Beispiel braucht b a, aber a ist nicht als dependency 
angegeben. "make all -j1" wird zuerst a und dann b erstellen, aber "make 
all -j2" wird es gleichzeitig versuchen, weil es von der Abhängigkeit, 
die nicht richtig angegeben wurde, nichts weiss.

von Oliver S. (oliverso)


Lesenswert?

Daniel A. schrieb:
> In diesem Beispiel braucht b a, aber a ist nicht als dependency
> angegeben.

Oliver S. schrieb:
> Und eigentlich deutet sowas auf Fehler im makefile hin.

Qed

Oliver

von Vancouver (Gast)


Lesenswert?

> Und eigentlich deutet sowas auf Fehler im makefile hin.

Ich würde das nicht einen Fehler nennen. Die Abhängigkeit ist implizit 
gegeben durch die Reihenfolge der Regeln im Makefile. Eigentlich wäre es 
die Aufgabe vom make, die Regeln beim Multithreading so zu schedulen, 
dass bei -jN das Gleiche herauskommt wie bei -j1, aber dazu müsste make 
die Regeln tiefer analysieren, sonst wäre alles wieder sequenziell. Das 
ist vermutlich viel zu aufwändig, schließlich ist make kein 
parallelisierender Compiler.

von Bernhard M. (boregard)


Lesenswert?

Vancouver schrieb:
> Die Abhängigkeit ist implizit
> gegeben durch die Reihenfolge der Regeln im Makefile. Eigentlich wäre es
> die Aufgabe vom make, die Regeln beim Multithreading so zu schedulen,
> dass bei -jN das Gleiche herauskommt wie bei -j1,

Wie soll das denn gehen?
Er muß ja dann  die Reihenfolge einhalten, und damit geht nichts mehr 
parallel...
Nein, patrallele Builds (das ist doch eher Multi-Processing als 
Multi-Threading, oder?) gehen nur problemlos mit komplett sauberen 
Abhängigkeiten. Ansonsten muß man halt restarten...

von Vancouver (Gast)


Lesenswert?

Bernhard M. schrieb:
> Er muß ja dann  die Reihenfolge einhalten, und damit geht nichts mehr
> parallel...

Das nicht, aber er muss die Abhängigkeiten selbst analysieren um 
herauszufinden, was parallel machbar ist. Parallelisierende Compiler tun 
genau das, aber make nicht, deswegen muss der Anwender die 
Abhängigkeiten explizit angeben.

>(das ist doch eher Multi-Processing als Multi-Threading, oder?)

Ja, richtig.

von Rolf M. (rmagnus)


Lesenswert?

Kaj schrieb:
> Das Problem ist, dass schon ein Modul gebaut werden soll, wofuer die
> abhaengigkeit vielleicht noch gar nicht gebaut ist.
>
> Das kann bei -j1 nicht passieren.

Ja, genau so ist es.

Vancouver schrieb:
>> Und eigentlich deutet sowas auf Fehler im makefile hin.
>
> Ich würde das nicht einen Fehler nennen. Die Abhängigkeit ist implizit
> gegeben durch die Reihenfolge der Regeln im Makefile.

Nein. Der ganze Sinn hinter einem Makefile ist, dass man ihm die 
Abhängigkeiten explizit nennt. Die Reihenfolge der Regeln ist dabei 
völlig egal.

> Eigentlich wäre es die Aufgabe vom make, die Regeln beim Multithreading
> so zu schedulen, dass bei -jN das Gleiche herauskommt wie bei -j1, aber
> dazu müsste make die Regeln tiefer analysieren, sonst wäre alles wieder
> sequenziell.

Nein, die Regeln müssen korrekt angegeben sein. Wie soll make durch 
"tieferes Analysieren" der Regeln wissen, was wovon abhängig ist? Genau 
damit make das weiß, gibt man die Abhängigkeiten doch an.

> Das ist vermutlich viel zu aufwändig, schließlich ist make kein
> parallelisierender Compiler.

Make kümmert sich vor allem nicht darum, was da überhaupt erzeugt wird. 
Man sagt ihm nur: "Ich will eine Datei x haben. Die wird von Kommando k 
erzeugt, und dafür muss Datei y schon vorhanden sein". Und das kann man 
dann wiederum rekursiv machen, um z.B. wiederum Datei y zu erzeugen, 
wenn dafür eine Regel vorhanden ist.
Ob k jetzt ein C-Compiler oder ein xslt-Konverter oder ein mp3-Encoder 
ist und wie der Erzeugungsvorgang funktioniert, ist make dabei völlig 
wurscht. Dementsprechend kann es da auch nix analysieren, um auf 
magische Weise die Abhängigkeiten zu finden.

Vancouver schrieb:
>>(das ist doch eher Multi-Processing als Multi-Threading, oder?)
>
> Ja, richtig.

Es ist ein "parallel build". Make führt einfach mehrere Regeln 
gleichzeitig aus, wenn die nicht von einander abhängen.

Übrigens wirken sich solche fehlenden Abhängigkeiten nicht nur beim 
parallelen Bauen aus, sondern auch, wenn man was am Code ändert. Dann 
werden ggf. Teile nicht gebaut, weil make nicht weiß, dass die von der 
geänderten Datei abhängig sind.

: Bearbeitet durch User
von Vancouver (Gast)


Lesenswert?

Rolf M. schrieb:
> Nein. Der ganze Sinn hinter einem Makefile ist, dass man ihm die
> Abhängigkeiten explizit nennt. Die Reihenfolge der Regeln ist dabei
> völlig egal.

Unabhängige Regeln werden bei -j1 in der Reihenfolge abgearbeitet, wie 
sie im Makefile stehen, richtig? Damit werden implizit Abhängigkeiten 
aufgelöst, wie im cat-Beispiel oben. Das ist nicht schön, aber erlaubt 
und es funktioniert zuverlässig bei Single-processing.

> Wie soll make durch  "tieferes Analysieren" der Regeln wissen, was wovon 
abhängig ist?

make könnte sich diese Regel anschauen:

b: c
    cat a c > b

und erkennen, dass neben der expliziten Abhängigkeit von c 
offensichtlich auch noch a verwendet wird.  make selbst kann übrigens 
selbst Dependencies erkennen, wenn man es ihm sagt, siehe 
http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/

Oder viel einfacher, wenn eine Regel wegen einer fehlenden Abhängigkeit 
einen Fehler liefert, könnte man sie zu einem späteren Zeitpunkt 
wiederholen. Genau das tue ich, wenn ich einen abgebrochen make-Lauf neu 
starte. Erst wenn am Schluss noch Regeln übrigbleiben, die nicht 
bearbeitet werden können, gibt es wirklich einen Fehler. Auf diese Weise 
gehen viele andere Build-Tools vor, z.B. für FPGA-Synthese, die die 
gesamte Dependency-Analyse selbst duchführen.
Mir ist (jetzt) schon klar, dass make explizite Abhängigkeiten braucht, 
um immer korrekt zu funktionieren. Aber leider ist das bei vielen großen 
Projekten nicht der Fall (Kernel, GNURadio, um nur zwei zu nennen), und 
ich verspüre relativ wenig Lust, hunderte verschachtelte Makefiles zu 
durchforsten.

von Oliver S. (oliverso)


Lesenswert?

Vancouver schrieb:
> Das ist nicht schön, aber erlaubt
> und es funktioniert zuverlässig bei Single-processing.

und geht bei Multithreading halt in die Hose.

Ist wie mit jedem Stück Software: nur, weil es unter ganz bestimmten 
Randbedingungen den Anschein hat, daß es tut, was es soll, ist es noch 
lange nicht fehlerfrei.

Oliver

von Daniel A. (daniel-a)


Lesenswert?

Vancouver schrieb:
> make könnte sich diese Regel anschauen:
>
> b: c
>     cat a c > b
>
> und erkennen, dass neben der expliziten Abhängigkeit von c
> offensichtlich auch noch a verwendet wird.

Das ist einfach unrealistisch. Make würde dafür wissen müssen, was der 
Befehl tut. Wäre da z.B. echo stat cat, brauchte man weder a noch c. 
Make kann unmöglich jedes Kommando kennen.

Vancouver schrieb:
> make selbst kann übrigens
> selbst Dependencies erkennen, wenn man es ihm sagt, siehe
> http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/

Die methode scheint mir eher alles komplizierter zu machen.

Vancouver schrieb:
> Oder viel einfacher, wenn eine Regel wegen einer fehlenden Abhängigkeit
> einen Fehler liefert, könnte man sie zu einem späteren Zeitpunkt
> wiederholen.

Dazu müsste aber make von jeder Anwendung jede Fehlermeldung kennen, was 
nicht möglich ist, oder die Dateizugriffs syscalls abfangen, und einer 
Abhängigkeit zuordnen, was auch nicht möglich ist.

von Vancouver (Gast)


Lesenswert?

Daniel A. schrieb:

> Die methode scheint mir eher alles komplizierter zu machen.

Ist sie auch, das gibt die absolut kryptischen makefiles. Aber sie 
funktioniert.

> Dazu müsste aber make von jeder Anwendung jede Fehlermeldung kennen, was

Nein, wenn eine Regel irgendeinen Fehler liefert, wird sie später 
wiederholt. Wenn der Fehler nicht durch eine Dependency ausgelöst wurde, 
wird er dann wieder auftreten.

Aber das wird jetzt alles sehr hypothetisch. Lassen wir make so wie es 
ist.
Schönes Wochenende :-)

von hink (Gast)


Lesenswert?

Vancouver schrieb:
> Das
> Problem tritt bei allen Versionen und Backends des gcc auf, die ich
> bisher verwendet habe.
Das hat nichts mit dem GCC/Compiler ansich zutun.
Wo kommen die Makefiles her? Die sind offensichtlich nicht richtig 
konfiguriert.

von Rene H. (Gast)


Lesenswert?

Weshalb nimmst Du nicht cmake? Das baut Dir ein funktionierendes 
makefile mit allem drum und dran.

Grüsse,
René

von hink (Gast)


Lesenswert?

Vancouver schrieb:
>> Dazu müsste aber make von jeder Anwendung jede Fehlermeldung kennen, was
> Nein, wenn eine Regel irgendeinen Fehler liefert, wird sie später
> wiederholt.
Make wiederholt nichts.

von hink (Gast)


Lesenswert?

Rene H. schrieb:
> Weshalb nimmst Du nicht cmake? Das baut Dir ein funktionierendes
> makefile mit allem drum und dran.
Weil cmake auch kein Selbstläufer ist und falsche nicht eingetragenen 
Abhängigkeiten (falsche Konfigurationen) führen auch hier zu Fehlern. 
;-)

von Mikro 7. (mikro77)


Lesenswert?

Daniel A. schrieb:

> Vancouver schrieb:
>> make selbst kann übrigens
>> selbst Dependencies erkennen, wenn man es ihm sagt, siehe
>> http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/

> Die methode scheint mir eher alles komplizierter zu machen.

Die Dependencies macht make da auch nicht. Das sind nur "clever" 
geschriebene Regeln, die bspw. auf sed oder gcc -M basieren, und so 
Dependencies "automatisch" erstellen.

Bspw. durch Durchsuchen der C Files nach #includes, Schreiben einer 
neuen Datei mit den gefundenen Abhängigkeiten; und diese Datei wird 
wiederum vom Makefile geladen. Funktioniert. :-)

Das hat aber nix mit speziellen Fähigkeiten von make zu tun, wie 
@Vancouver behauptet. Wie auch? Make ist einfach nur ein Regelwerk das 
nichts von C oder welcher Sprache auch immer weiß.

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

Kann es eventuell sein daß das verwendete Dateisystem eine von einem 
Prozess neu erzeugte Datei für einem anderen Prozess erst mit etwas 
Verzögerung sichtbar werden lässt? Vielleicht kann man irgendwelche 
Speicherbarrieren in den mount options abschalten um es performanter zu 
machen, vielleicht ist das der Fall?

von Rolf M. (rmagnus)


Lesenswert?

Vancouver schrieb:
> Unabhängige Regeln werden bei -j1 in der Reihenfolge abgearbeitet, wie
> sie im Makefile stehen, richtig?

Nein. Sie werden in der Reihenfolge ausgeführt, in der sie benötigt 
werden. Die Reihenfolge im Makefile spielt wie schon gesagt keine Rolle. 
Ein Makefile definiert keinen Sequenziellen Ablauf, auch nicht bei 
-j1.
Beispiel:
1
a: b c
2
3
b: d
4
5
c:
6
  @echo "c"
7
8
d:
9
  @echo "d"
c und d sind nicht von einander abhängig. Die Ausgabe ist aber:
1
d
2
c

>> Wie soll make durch  "tieferes Analysieren" der Regeln wissen, was wovon
> abhängig ist?
>
> make könnte sich diese Regel anschauen:
>
> b: c
>     cat a c > b
>
> und erkennen, dass neben der expliziten Abhängigkeit von c
> offensichtlich auch noch a verwendet wird.

Dazu müßte es wissen, dass an dieser Stelle a ein Dateiname sein soll. 
Das heißt, es müsste wissen, was die Kommandozeilenparameter von cat 
bedeuten. Anderes sehr änliches Beispiel:
1
 b: c
2
     grep a c > b

hier ist a keine Datei, sondern das Pattern, nach dem mit grep gesucht 
werden soll. Also müßte make auch grep kennen. Als nächstes kommt dann:
1
 b: c
2
     meintollestool a c > b

Und jetzt? Was ist a?

> Oder viel einfacher, wenn eine Regel wegen einer fehlenden Abhängigkeit
> einen Fehler liefert, könnte man sie zu einem späteren Zeitpunkt
> wiederholen.

Das ist Murks.

> Mir ist (jetzt) schon klar, dass make explizite Abhängigkeiten braucht,
> um immer korrekt zu funktionieren. Aber leider ist das bei vielen großen
> Projekten nicht der Fall (Kernel, GNURadio, um nur zwei zu nennen), und
> ich verspüre relativ wenig Lust, hunderte verschachtelte Makefiles zu
> durchforsten.

Natürlich nicht. Aber es ist dennoch kein Fehler in make, sondern einer 
in den Makefiles des Projekts.

von Sven B. (scummos)


Lesenswert?

Rene H. schrieb:
> Weshalb nimmst Du nicht cmake? Das baut Dir ein funktionierendes
> makefile mit allem drum und dran.

Und dann lässt du cmake am besten noch ein ninja file generieren statt 
make (-GNinja), dann ist make ganz raus und alles ein gutes Stück 
schneller ;)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.