Kompilacja z g ++ przy użyciu wielu rdzeni


174

Szybkie pytanie: jaka jest flaga kompilatora, która pozwala g ++ na tworzenie wielu własnych instancji w celu szybszego kompilowania dużych projektów (na przykład 4 pliki źródłowe naraz dla wielordzeniowego procesora)?


Czy to naprawdę pomoże? Wszystkie moje zadania kompilacji są powiązane we / wy, a nie z procesorem.
Brian Knoblauch

5
Nawet jeśli są one ograniczone we / wy, prawdopodobnie można utrzymać większe obciążenie we / wy, gdy występują ciężkie bity procesora (przy tylko jednej instancji g ++ wystąpią przerwy) i prawdopodobnie zwiększyć wydajność we / wy, jeśli harmonogram ma większy wybór co dalej czytać z dysku. Z mojego doświadczenia wynika, że ​​rozsądne stosowanie make -jprawie zawsze prowadzi do pewnej poprawy.
Flexo

1
@BrianKnoblauch Ale na mojej maszynie (prawdziwej lub w VirtualBox), jest ona związana z procesorem, zauważyłem, że procesor jest zajęty przez polecenie „top” podczas kompilacji.
大 宝剑

1
Nawet jeśli są one związane we / wy, możemy użyć flagi gcc '-pipe', aby zmniejszyć ból.
大 宝剑

właśnie zobaczyłem to w google: gcc.gnu.org/onlinedocs/libstdc++/manual/…
Jim Michaels,

Odpowiedzi:


240

Możesz to zrobić za pomocą make - za pomocą gnu make jest to flaga -j (pomoże to również na komputerze jednoprocesorowym).

Na przykład, jeśli chcesz, aby marka miała 4 równoległe zadania:

make -j 4

Możesz także uruchomić gcc w potoku z

gcc -pipe

Spowoduje to potokowanie etapów kompilacji, co również pomoże utrzymać zajęcie rdzeni.

Jeśli masz również dodatkowe maszyny, możesz sprawdzić distcc , który będzie kompilował również do nich.


36
Twoja liczba -j powinna być 1,5 razy większa od liczby posiadanych rdzeni.
Mark Beckwith

2
Dzięki. Wciąż próbowałem przekazać „-j #” do gcc przez CFLAGS / CPPFLAGS / CXXFLAGS. Zupełnie zapomniałem, że "-j #" jest parametrem dla make GNU (a nie dla GCC).
chriv

33
Dlaczego opcja -j dla GNU Make musi być 1,5 razy większa od liczby rdzeni procesora?
bitek

28
Liczba 1.5 jest spowodowana zauważonym problemem związanym z we / wy . To praktyczna zasada. Około 1/3 zadań będzie czekała na operacje we / wy, więc pozostałe zadania będą wykorzystywać dostępne rdzenie. Liczba większa niż liczba rdzeni jest lepsza i możesz nawet osiągnąć nawet 2x . Zobacz także: Gnu -jargumentuje
bezartowy hałas

4
@JimMichaels Może tak być, ponieważ zależności są źle ustawione w projekcie (cel zaczyna budować, nawet jeśli jego zależności nie są jeszcze gotowe), tak że tylko kompilacja sekwencyjna kończy się sukcesem.
Antonio

42

Nie ma takiej flagi, a posiadanie jednej jest sprzeczne z filozofią Uniksa, zgodnie z którą każde narzędzie wykonuje tylko jedną funkcję i wykonuje ją dobrze. Tworzenie procesów kompilatora jest koncepcyjnie zadaniem systemu kompilacji. To, czego prawdopodobnie szukasz, to flaga -j (praca) do GNU make, a la

zrobić -j4

Lub możesz użyć pmake lub podobnych systemów do tworzenia równoległych.



3
„Unixowa pedanteria nie jest pomocna” Dobrze, że to nie była wtedy pedanteria, anonimowy redaktorze. Wycofana. Recenzenci powinni zwracać większą uwagę na to, co robisz.
Wyścigi lekkości na orbicie

12

Ludzie wspominali o podobnej koncepcji, makeale bjamteż ją popierają. Korzystanie z bjam -jxinstrukcji bjam do zbudowaniax współbieżnych poleceń.

Używamy tych samych skryptów kompilacji w systemach Windows i Linux, a użycie tej opcji skraca o połowę czas kompilacji na obu platformach. Miły.


9

makezrobi to za Ciebie. Zbadaj przełączniki -ji -lna stronie podręcznika. Nie sądzę, aby g++można go było równolegle.


+1 za -lmożliwość dodania wzmianki (nie rozpoczyna nowej pracy, chyba że wszystkie poprzednie prace zostały zakończone). W przeciwnym razie wydaje się, że zadanie konsolidatora nie rozpoczyna się od zbudowania wszystkich plików obiektowych (ponieważ niektóre kompilacje nadal trwają), więc zadanie konsolidatora kończy się niepowodzeniem.
NGI

8

Jeśli używasz make, problem z -j. Od man make:

  -j [jobs], --jobs[=jobs]
       Specifies the number of jobs (commands) to run simultaneously.  
       If there is more than one -j option, the last one is effective.
       If the -j option is given without an argument, make will not limit the
       number of jobs that can run simultaneously.

A przede wszystkim, jeśli chcesz napisać skrypt lub zidentyfikować liczbę dostępnych rdzeni (w zależności od środowiska i jeśli pracujesz w wielu środowiskach, może to bardzo się zmienić), możesz użyć wszechobecnej funkcji Pythona cpu_count():

https://docs.python.org/3/library/multiprocessing.html#multiprocessing.cpu_count

Lubię to:

make -j $(python3 -c 'import multiprocessing as mp; print(int(mp.cpu_count() * 1.5))')

Jeśli pytasz, dlaczego 1.5w komentarzu powyżej zacytuję bezartowy szum użytkownika:

Liczba 1.5 jest spowodowana zauważonym problemem związanym z we / wy. To praktyczna zasada. Około 1/3 zadań będzie czekała na operacje we / wy, więc pozostałe zadania będą wykorzystywać dostępne rdzenie. Liczba większa niż liczba rdzeni jest lepsza i możesz nawet osiągnąć nawet 2x.


5
Większość użytkowników Linuksa prawdopodobnie będzie wolała krótszy: make -j`nproc` z nprocw GNU Coreutils.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Jeśli używasz dysku SSD, we / wy nie będzie tak dużym problemem. Aby rozwinąć powyższy komentarz Ciro, możesz to zrobić: make -j $(( $(nproc) + 1 ))(upewnij się, że wstawiłeś spacje tam, gdzie je mam).
Ed K

Fajna sugestia użycia Pythona, na systemach, gdzie nprocnie jest dostępny, np. W manylinux1kontenerach, oszczędza dodatkowy czas, unikając uruchamiania yum update/ yum install.
hafling


3

Nie jestem pewien co do g ++, ale jeśli używasz GNU Make to "make -j N" (gdzie N to liczba wątków, które może utworzyć) pozwoli make na uruchomienie wielu zadań g ++ w tym samym czasie (tak długo ponieważ pliki nie są od siebie zależne).


2
nie Nie ma liczby wątków! Wiele osób źle to rozumie, ale -j Nmówi, że należy uruchomić liczbę procesów naraz, a nie wątków. To jest powód, dla którego nie jest tak wydajny jak MS cl -MT(naprawdę wielowątkowy).
Sebi2020

2

Równolegle z GNU

Robiłem test porównawczy kompilacji syntetycznej i nie mogłem zawracać sobie głowy pisaniem pliku Makefile, więc użyłem:

sudo apt-get install parallel
ls | grep -E '\.c$' | parallel -t --will-cite "gcc -c -o '{.}.o' '{}'"

Wyjaśnienie:

  • {.} pobiera argument wejściowy i usuwa jego rozszerzenie
  • -t wypisuje wykonywane polecenia, aby dać nam wyobrażenie o postępie
  • --will-cite usuwa prośbę o cytowanie oprogramowania, jeśli publikujesz przy jego użyciu wyniki ...

parallel jest tak wygodny, że mógłbym sam sprawdzić datownik:

ls | grep -E '\.c$' | parallel -t --will-cite "\
  if ! [ -f '{.}.o' ] || [ '{}' -nt '{.}.o' ]; then
    gcc -c -o '{.}.o' '{}'
  fi
"

xargs -P może również uruchamiać zadania równolegle, ale nieco mniej wygodne jest manipulowanie rozszerzeniami lub uruchamianie z nim wielu poleceń: wielu poleceń Wywoływanie wielu poleceń przez xargs

Poproszono o linkowanie równoległe pod adresem: Czy gcc może używać wielu rdzeni podczas łączenia?

DO ZROBIENIA: Myślę, że gdzieś przeczytałem, że kompilację można zredukować do mnożenia macierzy, więc być może jest też możliwe przyspieszenie kompilacji pojedynczego pliku dla dużych plików. Ale nie mogę teraz znaleźć odniesienia.

Testowane w Ubuntu 18.10.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.