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.