Compilazione con g ++ usando più core


174

Domanda rapida: qual è il flag del compilatore per consentire a g ++ di generare più istanze di se stesso al fine di compilare più rapidamente progetti di grandi dimensioni (ad esempio 4 file sorgente alla volta per una CPU multi-core)?


Aiuterà davvero? Tutti i miei processi di compilazione sono associati a I / O anziché a CPU.
Brian Knoblauch,

5
Anche se sono associati a I / O, è possibile che il carico di I / O sia più alto quando si verificano i bit pesanti della CPU (con solo un'istanza g ++ ci saranno delle pause) e possibilmente ottenere efficienze di I / O se lo scheduler ha più scelta cosa leggere dal disco successivo. La mia esperienza è stata che l'uso giudizioso di make -jquasi sempre porta a qualche miglioramento.
Flexo

1
@BrianKnoblauch Ma sul mio computer (quello reale o in VirtualBox), è associato alla CPU, ho scoperto che la CPU è occupata tramite il comando 'top' durante la compilazione.
宝剑 宝剑

1
Anche se sono associati agli I / O, possiamo usare la flag '-pipe' di gcc per ridurre il dolore.
宝剑 宝剑

ho appena visto questo su Google: gcc.gnu.org/onlinedocs/libstdc++/manual/…
Jim Michaels,

Risposte:


240

Puoi farlo con make - con gnu make è il flag -j (questo aiuterà anche su una macchina uniprocessore).

Ad esempio, se si desidera creare 4 lavori paralleli da:

make -j 4

Puoi anche eseguire gcc in una pipe con

gcc -pipe

Questo condurrà le fasi di compilazione, contribuendo anche a mantenere occupati i core.

Se hai anche macchine aggiuntive disponibili, potresti controllare distcc , che verrà compilato anche su quelle.


36
Il numero -j dovrebbe essere 1,5 volte il numero di core che hai.
Mark Beckwith

2
Grazie. Ho continuato a provare a passare "-j #" a gcc tramite CFLAGS / CPPFLAGS / CXXFLAGS. Avevo completamente dimenticato che "-j #" era un parametro per GNU make (e non per GCC).
chriv,

33
Perché l' opzione -j per GNU Make deve essere 1,5 volte il numero di core della CPU?
Bitek,

28
Il numero 1.5 è a causa del noto problema associato I / O. È una regola empirica. Circa 1/3 dei lavori saranno in attesa di I / O, quindi i lavori rimanenti utilizzeranno i core disponibili. Un numero maggiore dei core è migliore e potresti persino arrivare fino a 2 volte . Vedi anche: Gnu fa -jargomentazioni
rumore senza arte

4
@JimMichaels Potrebbe essere perché le dipendenze sono impostate male nel progetto (una destinazione inizia a costruire anche se le sue dipendenze non sono ancora pronte) in modo che solo una build sequenziale abbia successo.
Antonio,

42

Non esiste tale flag e avere una corsa contro la filosofia Unix secondo cui ogni strumento esegue una sola funzione e la esegue bene. La generazione dei processi del compilatore è concettualmente il lavoro del sistema di compilazione. Quello che probabilmente stai cercando è il flag -j (jobs) di GNU make, a la

make -j4

Oppure puoi usare pmake o simili sistemi di creazione parallela.



3
"La pedanteria Unix non è utile" Meno male che non era la pedanteria allora, editore anonimo. Tornato alla situazione precedente. I revisori prestano maggiore attenzione a ciò che si sta facendo.
Razze di leggerezza in orbita,

12

Le persone hanno menzionato makema bjamsupporta anche un concetto simile. L'utilizzo bjam -jxindica a bjam di creare xcomandi simultanei.

Usiamo gli stessi script di build su Windows e Linux e l'utilizzo di questa opzione dimezza i nostri tempi di compilazione su entrambe le piattaforme. Bello.


9

makelo farà per te. Indaga sugli interruttori -je -lnella pagina man. Non credo g++sia parallelizzabile.


+1 per menzionare l' -lopzione (non avvia un nuovo lavoro a meno che tutti i lavori precedenti non siano terminati). Altrimenti sembra che il lavoro del linker inizi con non tutti i file oggetto creati (poiché alcune compilazioni sono ancora in corso), quindi il lavoro del linker ha esito negativo.
NGI,

8

Se si utilizza make, rilasciare con -j. Da 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.

E in particolare, se vuoi scrivere script o identificare il numero di core che hai a disposizione (a seconda del tuo ambiente, e se corri in molti ambienti, questo può cambiare molto) puoi usare l'onnipresente funzione Python cpu_count():

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

Come questo:

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

Se stai chiedendo perché 1.5citerò l'utente senza rumore in un commento sopra:

Il numero 1.5 è a causa del noto problema associato I / O. È una regola empirica. Circa 1/3 dei lavori saranno in attesa di I / O, quindi i lavori rimanenti utilizzeranno i core disponibili. Un numero maggiore dei core è migliore e potresti persino arrivare fino a 2 volte.


5
La maggior parte degli utenti Linux preferirà probabilmente i più brevi: make -j`nproc` con nprocin GNU Coreutils.
Ciro Santilli 25 冠状 病 六四 事件 法轮功

Se si utilizza un SSD, l'I / O non sarà un grosso problema. Solo per basarti sul commento di Ciro sopra, puoi farlo: make -j $(( $(nproc) + 1 ))(assicurati di mettere gli spazi dove li ho).
Ed K

Bel suggerimento usando python, su sistemi dove nprocnon è disponibile, ad es. In manylinux1contenitori, si risparmia tempo aggiuntivo evitando l'esecuzione yum update/ yum install.
hoefling


3

Non sono sicuro di g ++, ma se stai usando GNU Make, allora "make -j N" (dove N è il numero di thread che può creare) consentirà a make di eseguire più lavori g ++ contemporaneamente (così a lungo poiché i file non dipendono l'uno dall'altro).


2
no N non è il numero di thread! Molte persone lo fraintendono, ma -j Ndicono che quanti processi contemporaneamente dovrebbero essere generati, non thread. Questo è il motivo per cui non è così performante come MS cl -MT(realmente multithread).
Sebi2020,

2

Parallelo GNU

Stavo facendo un benchmark di compilazione sintetico e non potevo preoccuparmi di scrivere un Makefile, quindi ho usato:

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

Spiegazione:

  • {.} accetta l'argomento input e ne rimuove l'estensione
  • -t stampa i comandi in esecuzione per darci un'idea del progresso
  • --will-cite rimuove la richiesta di citare il software se si pubblicano risultati utilizzandolo ...

parallel è così conveniente che potrei anche fare un controllo del timestamp da solo:

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

xargs -Ppuò anche eseguire lavori in parallelo, ma è un po 'meno conveniente eseguire la manipolazione dell'estensione o eseguire più comandi con esso: chiamata di più comandi tramite xargs

È stato chiesto il collegamento parallelo su: gcc può usare più core durante il collegamento?

TODO: Penso di aver letto da qualche parte che la compilazione può essere ridotta alla moltiplicazione di matrici, quindi forse è anche possibile velocizzare la compilazione di singoli file per file di grandi dimensioni. Ma non riesco a trovare un riferimento ora.

Testato su Ubuntu 18.10.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.