GNU make: le nombre de tâches doit-il être égal au nombre de cœurs de processeur dans un système?

87

Il semble y avoir une certaine controverse quant à savoir si le nombre de travaux dans GNU make est censé être égal au nombre de cœurs, ou si vous pouvez optimiser le temps de construction en ajoutant un travail supplémentaire qui peut être mis en file d'attente pendant que les autres "fonctionnent" .

Vaut-il mieux utiliser -j4ou -j5sur un système quad core?

Avez-vous vu (ou fait) une analyse comparative qui soutient l'un ou l'autre?

Johan
la source
8
Juste pour le conseil, vous pouvez utiliser make `nproc`pour créer un script indépendant du processeur :)
VivienG
Si vous avez un mélange de recettes liées à io et liées au processeur, vous en voudrez potentiellement beaucoup plus que des NCPU. Pensez également à ajouter des options -lX. Ce n'est pas vraiment une question à laquelle il faut répondre, à part "cela dépend de votre matériel et de vos tâches".
James Moore
Il est techniquement possible de voir une amélioration. Vous avez besoin d'un disque lent, pas assez de RAM et de nombreux petits fichiers de code source. Plus facile à trouver il y a dix ans.
Hans Passant

Réponses:

56

Je dirais que la meilleure chose à faire est de le comparer vous-même à votre environnement et à votre charge de travail particuliers. On dirait qu'il y a trop de variables (taille / nombre de fichiers source, mémoire disponible, mise en cache du disque, si votre répertoire source et les en-têtes système sont situés sur des disques différents, etc.) pour une réponse unique.

Mon expérience personnelle (sur un MacBook Pro 2 cœurs) est que -j2 est nettement plus rapide que -j1, mais au-delà (-j3, -j4 etc.), il n'y a pas d'accélération mesurable. Donc pour mon environnement "jobs == nombre de cœurs" semble être une bonne réponse. (YMMV)

David Gelhar
la source
57

J'ai exécuté mon projet domestique sur mon ordinateur portable 4 cœurs avec hyperthreading et enregistré les résultats. C'est un projet assez lourd en compilateur mais il inclut un test unitaire de 17,7 secondes à la fin. Les compilations ne sont pas très gourmandes en E / S; il y a beaucoup de mémoire disponible et sinon le reste est sur un SSD rapide.

1 job        real   2m27.929s    user   2m11.352s    sys    0m11.964s    
2 jobs       real   1m22.901s    user   2m13.800s    sys    0m9.532s
3 jobs       real   1m6.434s     user   2m29.024s    sys    0m10.532s
4 jobs       real   0m59.847s    user   2m50.336s    sys    0m12.656s
5 jobs       real   0m58.657s    user   3m24.384s    sys    0m14.112s
6 jobs       real   0m57.100s    user   3m51.776s    sys    0m16.128s
7 jobs       real   0m56.304s    user   4m15.500s    sys    0m16.992s
8 jobs       real   0m53.513s    user   4m38.456s    sys    0m17.724s
9 jobs       real   0m53.371s    user   4m37.344s    sys    0m17.676s
10 jobs      real   0m53.350s    user   4m37.384s    sys    0m17.752s
11 jobs      real   0m53.834s    user   4m43.644s    sys    0m18.568s
12 jobs      real   0m52.187s    user   4m32.400s    sys    0m17.476s
13 jobs      real   0m53.834s    user   4m40.900s    sys    0m17.660s
14 jobs      real   0m53.901s    user   4m37.076s    sys    0m17.408s
15 jobs      real   0m55.975s    user   4m43.588s    sys    0m18.504s
16 jobs      real   0m53.764s    user   4m40.856s    sys    0m18.244s
inf jobs     real   0m51.812s    user   4m21.200s    sys    0m16.812s

Résultats de base:

  • La mise à l'échelle du nombre de cœurs augmente les performances de manière presque linéaire. Le temps réel est passé de 2,5 minutes à 1,0 minute (2,5 fois plus vite), mais le temps pris pendant la compilation est passé de 2,11 à 2,50 minutes. Le système n'a remarqué pratiquement aucune charge supplémentaire dans ce bit.
  • La mise à l'échelle du nombre de cœurs au nombre de threads a considérablement augmenté la charge de l'utilisateur, de 2,50 minutes à 4,38 minutes. Ce quasi-doublement est probablement dû au fait que les autres instances du compilateur souhaitaient utiliser les mêmes ressources de processeur en même temps. Le système est un peu plus chargé avec les demandes et le changement de tâche, ce qui le fait passer à 17,7 secondes de temps d'utilisation. L'avantage est d'environ 6,5 secondes sur un temps de compilation de 53,5 secondes, soit une accélération de 12%.
  • La mise à l'échelle du nombre de threads au double nombre de threads n'a donné aucune accélération significative. Les heures 12 et 15 sont des anomalies statistiques les plus probables que vous pouvez ignorer. Le temps total pris augmente très légèrement, tout comme le temps système. Les deux sont probablement dus à un changement de tâche accru. Il n'y a aucun avantage à cela.

Je suppose maintenant: si vous faites autre chose sur votre ordinateur, utilisez le nombre de cœurs. Si vous ne le faites pas, utilisez le nombre de threads. Le dépasser ne montre aucun avantage. À un moment donné, ils deviendront limités en mémoire et s'effondreront à cause de cela, rendant la compilation beaucoup plus lente. La ligne "inf" a été ajoutée à une date beaucoup plus tardive, me donnant le soupçon qu'il y avait une certaine limitation thermique pour les 8+ travaux. Cela montre que pour cette taille de projet, il n'y a pas de limite de mémoire ou de débit en vigueur. C'est un petit projet cependant, avec 8 Go de mémoire pour compiler.

Dascandy
la source
Selon stackoverflow.com/questions/56272639/… , vous pouvez obtenir un avantage en exécutant plus de tâches que vous n'avez de processeurs, mais seulement si vos tâches passent une part importante de temps à attendre les E / S réseau. Pour les tâches de compilation, ce n'est cependant pas le cas.
ivan_pozdeev
30

Personnellement, j'utilise make -j noù n est "nombre de cœurs" + 1.

Je ne peux cependant pas donner une explication scientifique: j'ai vu beaucoup de gens utiliser les mêmes paramètres et ils m'ont donné de très bons résultats jusqu'à présent.

Quoi qu'il en soit, vous devez faire attention car certaines chaînes de fabrication ne sont tout simplement pas compatibles avec l' --jobsoption et peuvent entraîner des résultats inattendus. Si vous rencontrez d'étranges erreurs de dépendance, essayez simplement de le faire makesans --jobs.

ereOn
la source
19
L'explication (ne peut pas garantir son caractère scientifique cependant) est que "+ 1" donne un travail supplémentaire qui s'exécute pendant que n'importe lequel des n autres travaux effectue des E / S.
Laurynas Biveinis
@LaurynasBiveinis: Mais alors les jobs s'exécutent sur différents cœurs tout le temps, au moins plus souvent qu'avec un cadre plus conservateur où un job a la possibilité de rester sur le même cœur pendant une période de temps plus longue. Il y a des avantages et des inconvénients ici ...
krlmlr
1
Le nombre de cœurs + 1 est également mon paramètre par défaut. Un problème est que, dans tout système raisonnablement grand, make semble retarder la liaison et effectuer toutes les étapes de liaison ensemble. À ce stade, vous manquez de RAM. Bah!
bobbogo
4
certaines chaînes de fabrication ne sont tout simplement pas compatibles avec l'option --jobs -> Cela signifie que vous avez des dépendances manquantes. Corrigez vos makefiles si jamais vous obtenez cela.
dascandy le
7

En fin de compte, vous devrez faire quelques tests pour déterminer le meilleur nombre à utiliser pour votre build, mais rappelez-vous que le processeur n'est pas la seule ressource qui compte!

Si vous avez une version qui dépend fortement du disque, par exemple, la création de nombreux travaux sur un système multicœur peut en fait être plus lente , car le disque devra faire un travail supplémentaire en déplaçant la tête de disque d'avant en arrière pour servir tous. les différents travaux (en fonction de nombreux facteurs, comme la façon dont le système d'exploitation gère le cache disque, la prise en charge de la mise en file d'attente de commandes native par le disque, etc.).

Et puis vous avez de "vrais" cœurs contre l'hyper-threading. Vous pouvez ou non bénéficier de la création d'emplois pour chaque hyper-thread. Encore une fois, vous devrez effectuer une analyse comparative pour le savoir.

Je ne peux pas dire que j'ai spécifiquement essayé #cores + 1 , mais sur nos systèmes (Intel i7 940, 4 cœurs hyperthreading, beaucoup de RAM et des disques VelociRaptor) et notre version (version C ++ à grande échelle qui est alternativement CPU et I / O lié) il y a très peu de différence entre -j4 et -j8. (C'est peut-être 15% mieux ... mais loin du double.)

Si je pars pour le déjeuner, j'utiliserai -j8, mais si je veux utiliser mon système pour autre chose pendant sa construction, j'utiliserai un nombre inférieur. :)

ijprest
la source
1
Ça a l'air génial, mais je ne comprends pas pourquoi vous ne prendriez pas simplement cela + 15% à chaque fois en utilisant-j 8
sg
1
@sg: j8 était vraiment pénible sur le système que j'ai décrit dans mon article d'origine ... la machine était toujours utilisable , mais elle était nettement moins réactive. Donc, si je voulais toujours l'utiliser de manière interactive pour d'autres tâches (travaillant généralement sur un autre code, et peut-être la construction occasionnelle d'une seule DLL), je réserverais quelques cœurs pour les bits interactifs.
ijprest
@sg: C'est moins un problème sur nos nouveaux systèmes ... Je suppose que c'est principalement parce que nous utilisons des SSD maintenant. (Je pense que nous sommes entièrement liés au processeur maintenant que nous allons aux SSD ... nous avons essayé de construire entièrement sur un lecteur RAM sans presque aucune amélioration.) Mais je laisserai toujours quelques cœurs libres si je suis faire autre chose qu'une simple édition de texte au premier plan.
ijprest
5

Je viens de recevoir un proc Athlon II X2 Regor avec un Foxconn M / B et 4 Go de mémoire G-Skill.

J'ai mis mon 'cat / proc / cpuinfo' et 'free' à la fin de ceci pour que les autres puissent voir mes spécifications. C'est un Athlon II x2 dual core avec 4 Go de RAM.

uname -a on default slackware 14.0 kernel is 3.2.45.

J'ai téléchargé la source du noyau de l'étape suivante (linux-3.2.46) dans / archive4;

extrait ( tar -xjvf linux-3.2.46.tar.bz2);

cd'd dans le répertoire (cd linux-3.2.46 );

et copié la configuration par défaut du noyau sur ( cp /usr/src/linux/.config .);

utilisé make oldconfigpour préparer la configuration du noyau 3.2.46;

puis a exécuté make avec diverses incantations de -jX.

J'ai testé le minutage de chaque exécution en exécutant make après la commande time, par exemple «time make -j2». Entre chaque exécution, j'ai 'rm -rf' l'arborescence linux-3.2.46 et je l'ai réextrait, copié la valeur par défaut /usr/src/linux/.config dans le répertoire, lancé make oldconfig puis refait mon test 'make -jX' .

simple "faire":

real    51m47.510s
user    47m52.228s
sys     3m44.985s
bob@Moses:/archive4/linux-3.2.46$

comme ci-dessus mais avec make -j2

real    27m3.194s
user    48m5.135s
sys     3m39.431s
bob@Moses:/archive4/linux-3.2.46$

comme ci-dessus mais avec make -j3

real    27m30.203s
user    48m43.821s
sys     3m42.309s
bob@Moses:/archive4/linux-3.2.46$

comme ci-dessus mais avec make -j4

real    27m32.023s
user    49m18.328s
sys     3m43.765s
bob@Moses:/archive4/linux-3.2.46$

comme ci-dessus mais avec make -j8

real    28m28.112s
user    50m34.445s
sys     3m49.877s
bob@Moses:/archive4/linux-3.2.46$

'cat / proc / cpuinfo' donne:

bob@Moses:/archive4$ cat /proc/cpuinfo
processor       : 0
vendor_id       : AuthenticAMD
cpu family      : 16
model           : 6
model name      : AMD Athlon(tm) II X2 270 Processor
stepping        : 3
microcode       : 0x10000c8
cpu MHz         : 3399.957
cache size      : 1024 KB
physical id     : 0
siblings        : 2
core id         : 0
cpu cores       : 2
apicid          : 0
initial apicid  : 0
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 5
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmo
v pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rd
tscp lm 3dnowext 3dnow constant_tsc nonstop_tsc extd_apicid pni monitor cx16 p
opcnt lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowpre
fetch osvw ibs skinit wdt npt lbrv svm_lock nrip_save
bogomips        : 6799.91
clflush size    : 64
cache_alignment : 64
address sizes   : 48 bits physical, 48 bits virtual
power management: ts ttp tm stc 100mhzsteps hwpstate

processor       : 1
vendor_id       : AuthenticAMD
cpu family      : 16
model           : 6
model name      : AMD Athlon(tm) II X2 270 Processor
stepping        : 3
microcode       : 0x10000c8
cpu MHz         : 3399.957
cache size      : 1024 KB
physical id     : 0
siblings        : 2
core id         : 1
cpu cores       : 2
apicid          : 1
initial apicid  : 1
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 5
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmo
v pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rd
tscp lm 3dnowext 3dnow constant_tsc nonstop_tsc extd_apicid pni monitor cx16 p
opcnt lahf_lm cmp_legacy svm extapic cr8_legacy abm sse4a misalignsse 3dnowpre
fetch osvw ibs skinit wdt npt lbrv svm_lock nrip_save
bogomips        : 6799.94
clflush size    : 64
cache_alignment : 64
address sizes   : 48 bits physical, 48 bits virtual
power management: ts ttp tm stc 100mhzsteps hwpstate

rendements 'gratuits':

bob@Moses:/archive4$ free
             total       used       free     shared    buffers     cached
Mem:       3991304    3834564     156740          0     519220    2515308
sloMoses
la source
1
Que fait juste make -jsur ce système? Make est censé vérifier la charge et mettre à l'échelle le nombre de processus en fonction de la charge.
docwhat
1
make -jne limite pas du tout le nombre d'emplois. Ceci est généralement désastreux sur un projet de taille moyenne ou grande, car plus de tâches sont rapidement fourchues que ce que peut prendre en charge la RAM. L'option que vous devez restreindre par charge est -l [load], en conjonction avec-j
Matt G
5

Les deux ne sont pas faux. Pour être en paix avec vous-même et avec l'auteur du logiciel que vous compilez (différentes restrictions multi-thread / single-thread s'appliquent au niveau du logiciel lui-même), je vous suggère d'utiliser:

make -j`nproc`

Notes: nprocest une commande linux qui retournera le nombre de cœurs / threads (CPU moderne) disponibles sur le système. Le placer sous les coches `comme ci-dessus passera le numéro à la commande make.

Informations supplémentaires: comme quelqu'un l'a mentionné, l'utilisation de tous les cœurs / threads pour compiler des logiciels peut littéralement étouffer votre boîte à un point mort (ne pas répondre) et peut même prendre plus de temps que d'utiliser moins de cœurs. Comme j'ai vu un utilisateur de Slackware posté ici, il avait un processeur double cœur mais fournissait toujours des tests jusqu'à j 8, qui cessaient d'être différents à j 2 (seulement 2 cœurs matériels que le processeur peut utiliser). Donc, pour éviter que la boîte ne réponde, je vous suggère de l'exécuter comme ceci:

make -j`nproc --ignore=2`

Cela passera la sortie de nprocto makeet soustraira 2 cœurs de son résultat.

Lucifer numérique
la source
3

Tout comme un ref:

De la Spawning Multiple Build Jobssection dans LKD :

où n est le nombre d'emplois à générer. La pratique habituelle consiste à générer une ou deux tâches par processeur. Par exemple, sur une machine à double processeur, on peut faire

$ faire j4

Nan Xiao
la source
lien cassé, est-ce que cette citation de Linux Kernel Development par Robert Love?
Behrooz
Oui, c'est de ce livre.
Nan Xiao
1

D'après mon expérience, il doit y avoir des avantages en termes de performances lors de l'ajout d'emplois supplémentaires. C'est simplement parce que les E / S de disque sont l'un des goulots d'étranglement en plus du CPU. Cependant, il n'est pas facile de décider du nombre de travaux supplémentaires car il est fortement interconnecté avec le nombre de cœurs et les types de disque utilisés.

Mat
la source
1

Plusieurs années plus tard, la majorité de ces réponses sont toujours correctes. Cependant, il y a eu un petit changement: utiliser plus de travaux que de cœurs physiques donne désormais une accélération véritablement significative. En complément à la table de Dascandy, voici mes horaires pour compiler un projet sur un AMD Ryzen 5 3600X sous Linux. (Le jouet en poudre, commettez c6f653ac3cef03acfbc44e8f29f11e1b301f1ca2)

Je recommande de vous vérifier, mais j'ai trouvé avec les commentaires d'autres personnes que l'utilisation de votre nombre de cœurs logiques pour le nombre de tâches fonctionne bien sur Zen. Parallèlement, le système ne semble pas perdre de réactivité. J'imagine que cela s'applique également aux processeurs Intel récents. Notez que j'ai également un SSD, donc cela peut valoir la peine de tester votre processeur vous-même.

scons -j1 --release --native  120.68s user 9.78s system 99% cpu 2:10.60 total
scons -j2 --release --native  122.96s user 9.59s system 197% cpu 1:07.15 total
scons -j3 --release --native  125.62s user 9.75s system 292% cpu 46.291 total
scons -j4 --release --native  128.26s user 10.41s system 385% cpu 35.971 total
scons -j5 --release --native  133.73s user 10.33s system 476% cpu 30.241 total
scons -j6 --release --native  144.10s user 11.24s system 564% cpu 27.510 total
scons -j7 --release --native  153.64s user 11.61s system 653% cpu 25.297 total
scons -j8 --release --native  161.91s user 12.04s system 742% cpu 23.440 total
scons -j9 --release --native  169.09s user 12.38s system 827% cpu 21.923 total
scons -j10 --release --native  176.63s user 12.70s system 910% cpu 20.788 total
scons -j11 --release --native  184.57s user 13.18s system 989% cpu 19.976 total
scons -j12 --release --native  192.13s user 14.33s system 1055% cpu 19.553 total
scons -j13 --release --native  193.27s user 14.01s system 1052% cpu 19.698 total
scons -j14 --release --native  193.62s user 13.85s system 1076% cpu 19.270 total
scons -j15 --release --native  195.20s user 13.53s system 1056% cpu 19.755 total
scons -j16 --release --native  195.11s user 13.81s system 1060% cpu 19.692 total
( -jinf test not included, as it is not supported by scons.)

Tests effectués sur Ubuntu 19.10 avec Ryzen 5 3600X, Samsung 860 Evo SSD (SATA) et 32 ​​Go de RAM

Note finale: d'autres personnes avec un 3600X peuvent avoir de meilleurs temps que moi. Lors de ce test, j'ai activé le mode Eco, réduisant un peu la vitesse du processeur.

moonheart08
la source
0

OUI! Sur mon 3950x, j'exécute -j32 et cela économise des heures de compilation! Je peux toujours regarder YouTube, naviguer sur le Web, etc. pendant la compilation sans aucune différence. Le processeur n'est pas toujours lié, même avec un nvme 1 To 970 PRO ou 1 To Auros Gen4 nvme et 64 Go de 3200C14. Même quand c'est le cas, je ne remarque pas l'interface utilisateur. Je prévois de tester avec -j48 dans un proche avenir sur certains grands projets à venir. Je m'attends, comme vous le faites probablement, à voir une amélioration impressionnante. Ceux qui ont encore un quad-core pourraient ne pas obtenir les mêmes gains ...

Linus lui-même vient de passer à un 3970x et vous pouvez parier votre dernier dollar, il utilise au moins -j64.

lazyacevw
la source