Compiler avec g ++ en utilisant plusieurs cœurs

174

Question rapide: quel est le drapeau du compilateur pour permettre à g ++ de générer plusieurs instances de lui-même afin de compiler plus rapidement de grands projets (par exemple 4 fichiers source à la fois pour un processeur multicœur)?

bsofman
la source
Cela aidera-t-il vraiment? Tous mes travaux de compilation sont liés aux E / S plutôt qu'au CPU.
Brian Knoblauch le
5
Même s'ils sont liés aux E / S, vous pouvez probablement maintenir la charge d'E / S plus élevée lorsque les bits lourds du processeur se produisent (avec une seule instance g ++, il y aura des accalmies) et éventuellement gagner en efficacité d'E / S si le planificateur a plus de choix sur que lire ensuite sur le disque. Mon expérience a été que l'utilisation judicieuse de make -jaboutit presque toujours à une certaine amélioration.
Flexo
1
@BrianKnoblauch Mais sur ma machine (vraie ou dans VirtualBox), elle est liée au processeur, j'ai trouvé que le processeur est occupé via la commande «top» lors de la compilation.
大 宝剑
1
Même s'ils sont liés aux E / S, nous pouvons utiliser le drapeau de gcc '-pipe' pour réduire la douleur.
大 宝剑
je viens de voir ça dans google: gcc.gnu.org/onlinedocs/libstdc++/manual/…
Jim Michaels

Réponses:

240

Vous pouvez le faire avec make - avec gnu make it est le drapeau -j (cela aidera également sur une machine monoprocesseur).

Par exemple, si vous voulez 4 jobs parallèles de make:

make -j 4

Vous pouvez également exécuter gcc dans un tube avec

gcc -pipe

Cela acheminera les étapes de compilation, ce qui aidera également à garder les cœurs occupés.

Si vous disposez également de machines supplémentaires, vous pouvez consulter distcc , qui les compilera également.

Frankodwyer
la source
36
Votre nombre -j doit être 1,5x le nombre de cœurs que vous avez.
Mark Beck avec le
2
Merci. J'ai continué à essayer de passer "-j #" à gcc via CFLAGS / CPPFLAGS / CXXFLAGS. J'avais complètement oublié que "-j #" était un paramètre pour GNU make (et pas pour GCC).
chriv
33
Pourquoi l' option -j de GNU Make doit-elle être égale à 1,5 fois le nombre de cœurs de processeur?
bitek
28
Le nombre 1.5 est dû au problème de liaison d'E / S noté . C'est une règle de base. Environ 1/3 des travaux seront en attente d'E / S, les travaux restants utiliseront donc les cœurs disponibles. Un nombre supérieur aux cœurs est meilleur et vous pouvez même aller jusqu'à 2x . Voir aussi: Gnu make -jarguments
artless noise
4
@JimMichaels Cela peut être dû au fait que les dépendances sont mal définies dans votre projet (une cible commence à se construire même si ses dépendances ne sont pas encore prêtes) de sorte que seule une construction séquentielle aboutit.
Antonio
42

Il n'y a pas de tel drapeau, et en avoir un va à l'encontre de la philosophie Unix qui veut que chaque outil exécute une seule fonction et l'exécute correctement. La création de processus de compilation est conceptuellement le travail du système de construction. Ce que vous recherchez probablement, c'est l'indicateur -j (jobs) pour GNU make, a la

faire -j4

Ou vous pouvez utiliser pmake ou des systèmes de fabrication parallèles similaires.

Mihai Limbășan
la source
3
"Le pédantisme Unix n'est pas utile" Heureusement que ce n'était pas du pédantisme alors, éditeur anonyme. Annulées. Les évaluateurs doivent prêter plus d'attention à ce que vous faites.
Courses de légèreté en orbite
12

Les gens ont mentionné makemais bjamsoutiennent également un concept similaire. L'utilisation bjam -jxindique à bjam de créer xdes commandes simultanées.

Nous utilisons les mêmes scripts de construction sur Windows et Linux et l'utilisation de cette option réduit de moitié nos temps de construction sur les deux plates-formes. Agréable.

MattyT
la source
9

makefera cela pour vous. Examinez les commutateurs -jet -ldans la page de manuel. Je ne pense pas que ce g++soit parallélisable.

rmeador
la source
+1 pour mentionner l' -loption (ne démarre pas un nouvel emploi à moins que tous les emplois précédents ne se terminent) Sinon, il semble que le travail de l'éditeur de liens ne commence pas avec tous les fichiers objets créés (car certaines compilations sont toujours en cours), de sorte que le travail de l'éditeur de liens échoue.
NGI
8

Si vous utilisez make, sortez avec -j. De 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.

Et plus particulièrement, si vous souhaitez créer un script ou identifier le nombre de cœurs dont vous disposez (en fonction de votre environnement, et si vous exécutez dans de nombreux environnements, cela peut beaucoup changer), vous pouvez utiliser la fonction Python omniprésente cpu_count():

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

Comme ça:

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

Si vous demandez pourquoi 1.5je citerai l'utilisateur artless-noise dans un commentaire ci-dessus:

Le nombre 1.5 est dû au problème de liaison d'E / S noté. C'est une règle de base. Environ 1/3 des travaux seront en attente d'E / S, les travaux restants utiliseront donc les cœurs disponibles. Un nombre supérieur aux cœurs est meilleur et vous pouvez même aller jusqu'à 2x.

Havok
la source
5
La plupart des utilisateurs de Linux préféreront probablement le plus court: make -j`nproc` avec nprocdans GNU Coreutils.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Si vous utilisez un SSD, les E / S ne seront pas autant un problème. Juste pour construire sur le commentaire de Ciro ci-dessus, vous pouvez faire ceci: make -j $(( $(nproc) + 1 ))(assurez-vous de mettre des espaces là où je les ai).
Ed K
Belle suggestion utilisant python, sur les systèmes où il nprocn'est pas disponible, par exemple dans les manylinux1conteneurs, cela permet de gagner du temps en évitant d'exécuter yum update/ yum install.
hoefling
7

distcc peut également être utilisé pour distribuer des compilations non seulement sur la machine actuelle, mais également sur d'autres machines d'une ferme sur lesquelles distcc est installé.

Jason
la source
+1, distcc est un outil utile à avoir dans son arsenal pour les grosses constructions.
Flexo
On dirait qu'il y en a quelques-uns qui fonctionnent "comme" distcc aussi: stackoverflow.com/questions/5374106/distributed-make/…
rogerdpack
3

Je ne suis pas sûr de g ++, mais si vous utilisez GNU Make alors "make -j N" (où N est le nombre de threads que peut créer) permettra à make d'exécuter plusieurs tâches g ++ en même temps (si longtemps car les fichiers ne dépendent pas les uns des autres).

Andy
la source
2
no N ist pas le nombre de threads! Beaucoup de gens comprennent mal cela, mais -j Ndisent à make combien de processus à la fois doivent être générés, pas de threads. C'est la raison pour laquelle il n'est pas aussi performant que MS cl -MT(vraiment multithread).
Sebi2020
2

GNU parallèle

Je faisais un benchmark de compilation synthétique et je ne pouvais pas être dérangé d'écrire un Makefile, alors j'ai utilisé:

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

Explication:

  • {.} prend l'argument d'entrée et supprime son extension
  • -t imprime les commandes en cours d'exécution pour nous donner une idée de la progression
  • --will-cite supprime la demande de citer le logiciel si vous publiez des résultats en l'utilisant ...

parallel est si pratique que je pourrais même faire une vérification d'horodatage moi-même:

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

xargs -Ppeut également exécuter des tâches en parallèle, mais il est un peu moins pratique de faire la manipulation d'extension ou d'exécuter plusieurs commandes avec: Appel de plusieurs commandes via xargs

La liaison parallèle a été posée à l' adresse suivante : gcc peut-il utiliser plusieurs cœurs lors de la liaison?

TODO: Je pense avoir lu quelque part que la compilation peut être réduite à la multiplication matricielle, donc il est peut-être également possible d'accélérer la compilation d'un seul fichier pour les gros fichiers. Mais je ne trouve pas de référence maintenant.

Testé dans Ubuntu 18.10.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source