Co może powodować zawieszanie się make podczas kompilacji na wielu rdzeniach?

17

Wczoraj próbowałem skompilować pakiet ROOT ze źródła. Ponieważ kompilowałem go na 6-rdzeniowej maszynie z potworami, postanowiłem zacząć budować za pomocą wielu rdzeni make -j 6. Kompilacja przebiegła początkowo płynnie i naprawdę szybko, ale w pewnym momencie makezawiesiła się przy użyciu 100% procesora tylko na jednym rdzeniu.

Zrobiłem trochę googlingu i znalazłem ten post na forach dyskusyjnych ROOT. Ponieważ sam zbudowałem ten komputer, martwiłem się, że nie zastosowałem prawidłowo radiatora, a procesor się przegrzał. Niestety nie mam tu w pracy lodówki, w której mogłabym ją włożyć. ;-)

Zainstalowałem lm-sensorspakiet i uruchomiłem make -j 6ponownie, tym razem monitorując temperaturę procesora. Chociaż stał się wysoki (blisko 60 ° C), nigdy nie przekroczył wysokiej lub krytycznej temperatury.

Próbowałem biegać, make -j 4ale ponownie makezawiesiłem się podczas kompilacji, tym razem w innym miejscu.

W końcu skompilowałem tylko działający makei działało dobrze. Moje pytanie brzmi: dlaczego zwisało? Z uwagi na fakt, że zatrzymał się w dwóch różnych miejscach, sądzę, że było to spowodowane jakimś stanem wyścigowym, ale uważam, że makepowinno być wystarczająco sprytne, aby wszystko ułożyć we właściwej kolejności, ponieważ oferuje taką -jopcję.

użytkownik545424
źródło
4
To brzmi jak wyścig. Jedną rzeczą, którą możesz zrobić, to dołączyć do działającego procesu make (ten, który się kręci), używając np. strace -p <pid>I sprawdzić, czy możesz dowiedzieć się, na co on patrzy / na co. strace pokaże tylko wywołania systemowe (nie wywołania funkcji), ale nadal może dostarczyć cennych informacji, jeśli obraca się podczas przeglądania lub określonego pliku.
jlp
Wątek znaleziony przez Google prowadzi do wniosku, że nikt nie był w stanie go skompilować -j >1.
Nils
Nie związany z kompilacją równoległą, ale miałem wiszący makefile, którego debugowanie trwało wieczność. Okazuje się, że była to po prostu inicjalizacja zmiennej, $(shell ...)ostatecznie uruchomiono polecenie, które czekało na dane wejściowestdin . Stało się tak, gdy zmienna była pusta i do komendy nie przekazano argumentów pliku.
jozxyqk

Odpowiedzi:

13

Nie mam odpowiedzi na ten konkretny problem, ale mogę spróbować dać ci wskazówkę, co może się dziać: brak zależności w plikach Makefiles.

Przykład:

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

Jeśli zadzwonisz, make targetwszystko skompiluje się poprawnie. Kompilacja a.sourcejest wykonywana (arbitralnie, ale deterministycznie) w pierwszej kolejności. Następnie b.sourcewykonywana jest kompilacja .

Ale jeśli make -j2 targetobie compilekomendy będą uruchamiane równolegle. I faktycznie zauważysz, że zależności twojego Makefile są zepsute. Zakłada a.bytecodesię, że druga kompilacja jest już skompilowana, ale nie pojawia się w zależnościach. Prawdopodobnie wystąpi błąd. Prawidłową linią zależności dla b.bytecodepowinno być:

b.bytecode: b.source a.bytecode

Aby powrócić do problemu, jeśli nie masz szczęścia, możliwe jest zawieszenie się polecenia w 100% pętli procesora z powodu braku zależności. Prawdopodobnie tak się dzieje tutaj, brakująca zależność nie mogła zostać ujawniona przez kompilację sekwencyjną, ale została ujawniona przez kompilację równoległą.

Stéphane Gimenez
źródło
Ciekawy. Czy wiesz, czy są dostępne narzędzia, które mogą uruchomić plik makefile i sprawdzić te zależności?
user545424
Nie znam żadnego. W każdym razie takie narzędzie może znaleźć tylko oczywiste błędy. Chyba że rozumie składnię każdego polecenia pojawiającego się w Makefile i wie, jakie są (potencjalnie niejawne) zależności.
Stéphane Gimenez
2

Nie wiem, jak długo masz maszynę, ale moim pierwszym zaleceniem byłoby przetestowanie pamięci i sprawdzenie, czy pamięć działa poprawnie. Wiem, że często problemem nie jest pamięć, ale jeśli tak, to najlepiej jest ją najpierw wyeliminować, zanim spróbujesz wyśledzić inne prawdopodobne problemy.

killermist
źródło
1

Zdaję sobie sprawę, że to naprawdę stare pytanie, ale wciąż pojawia się na górze wyników wyszukiwania, więc oto moje rozwiązanie:

GNU make posiada mechanizm serwera zadań, aby zapewnić make i jego rekurencyjne dzieci nie zużywają więcej niż określona liczba rdzeni: http://make.mad-scientist.net/papers/jobserver-implementation/

Opiera się na potoku wspólnym dla wszystkich procesów. Każdy proces, który chce rozwidlić dodatkowe elementy potomne, musi najpierw zużyć tokeny z potoku, a następnie zrezygnować z nich po zakończeniu. Jeśli proces potomny nie zwróci zużytych tokenów, najwyższy poziom sprawia, że ​​podczas zawieszenia na zawsze czeka na ich zwrot.

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

Napotkałem ten błąd podczas budowania binutils z GNU make na moim komputerze Solaris, gdzie „sed” nie jest GNU sed. Poprawienie PATH, aby sed == gsed miało pierwszeństwo przed sedem systemowym, rozwiązało problem. Nie wiem jednak, dlaczego sed zużywał żetony z fajki.

Fazal Majid
źródło
0

Twój system może być w porządku, ale może to być sytuacja wyścigu makepodczas równoległego uruchamiania kompilacji.

Jeśli coś jest nie tak z twoim systemem, zawiesiłoby się / zawiesiło w innych scenariuszach, nie tylko podczas wykonywania równoległych kompilacji.

fduff
źródło
0

Może to być warunek wyścigu, ale także jeśli wszystkie niezbędne kompilacje są wykonywane równolegle i czekają na innych, łączenie zajmuje dużo czasu na twoim komputerze. Myślę, że jeśli linkowanie czeka na poprzednią konieczną kompilację równolegle, to uzyskujesz wysoką częstotliwość procesora przy łączeniu wątku, co skompilujesz.

MahmutBulut
źródło