94 votes

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

Quelle est votre expérience avec le drapeau make -j ?

Il semble y avoir une controverse quant à savoir si les tâches sont censées être égales au nombre de cœurs, ou si vous pouvez maximiser la construction en ajoutant une tâche supplémentaire qui peut être activée pendant que les autres "travaillent".

La question est de savoir s'il est préférable d'utiliser -j4 ou -j5 sur un système à quatre cœurs ?

Et avez-vous vu (ou fait) des analyses comparatives qui soutiennent l'une ou l'autre de ces options ?

59voto

David Gelhar Points 20703

Je dirais que la meilleure chose à faire est de l'évaluer vous-même sur votre environnement particulier et votre charge de travail. Il semble qu'il y ait trop de variables (taille/nombre de fichiers sources, mémoire disponible, mise en cache sur le disque, si votre répertoire source et les en-têtes du système sont situés sur des disques différents, etc.

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

59voto

dascandy Points 2818

J'ai exécuté mon projet personnel sur mon ordinateur portable à 4 cœurs avec hyperthreading et j'ai enregistré les résultats. Il s'agit d'un projet assez lourd en termes de compilation, mais il comprend un test unitaire de 17,7 secondes à la fin. Les compilations ne sont pas très gourmandes en entrées-sorties ; il y a beaucoup de mémoire disponible et si ce n'est pas le cas, 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 façon presque linéaire. Le temps réel est passé de 2,5 minutes à 1 minute (2,5 fois plus rapide), mais le temps de compilation est passé de 2,11 à 2,50 minutes. Le système n'a pratiquement pas remarqué de charge supplémentaire dans cette partie.
  • Le passage du nombre de cœurs au nombre de threads a considérablement augmenté la charge utilisateur, de 2,50 minutes à 4,38 minutes. Ce quasi-doublement est très probablement dû au fait que les autres instances du compilateur ont voulu utiliser les mêmes ressources CPU au même moment. Le système est un peu plus chargé en requêtes et en changement de tâches, ce qui fait que le temps d'utilisation est passé à 17,7 secondes. L'avantage est d'environ 6,5 secondes sur un temps de compilation de 53,5 secondes, soit une accélération de 12%.
  • Le passage du nombre de fils au double nombre de fils n'a pas donné d'accélération significative. Les temps à 12 et 15 sont très probablement des anomalies statistiques que vous pouvez ignorer. Le temps total nécessaire augmente très légèrement, tout comme le temps système. Ces deux phénomènes sont très probablement dus à l'augmentation du changement de tâche. Il n'y a aucun avantage à cela.

A mon avis, maintenant : Si vous faites autre chose sur votre ordinateur, utilisez le comptage des noyaux. Si vous ne le faites pas, utilisez le nombre de fils. Dépasser ce nombre ne présente aucun avantage. À un moment donné, ils deviendront limités en mémoire et s'effondreront pour cette raison, rendant la compilation beaucoup plus lente. La ligne "inf" a été ajoutée à une date beaucoup plus tardive, ce qui me fait penser qu'il y a eu un étranglement thermique pour les travaux de 8+. Cela montre que pour cette taille de projet, il n'y a pas de limite de mémoire ou de débit en vigueur. Il s'agit cependant d'un petit projet, avec 8 Go de mémoire pour la compilation.

31voto

ereOn Points 18624

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

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

Quoi qu'il en soit, il faut être prudent car certaines chaînes de fabrication ne sont tout simplement pas compatibles avec le système d'information de l'UE. --jobs et peut conduire à des résultats inattendus. Si vous rencontrez d'étranges erreurs de dépendance, essayez simplement de make sans --jobs .

7voto

ijprest Points 1629

En fin de compte, vous devrez faire quelques tests pour déterminer le meilleur chiffre à utiliser pour votre construction, mais n'oubliez pas que le CPU n'est pas la seule ressource qui compte !

Si vous avez une construction qui dépend fortement du disque, par exemple, alors le lancement de nombreux travaux sur un système multicœur peut être une bonne solution. plus lent En effet, le disque devra faire un travail supplémentaire en déplaçant la tête du disque dans les deux sens pour servir les différents travaux (en fonction de nombreux facteurs, comme la façon dont le système d'exploitation gère le cache du disque, la prise en charge native de la file d'attente des commandes par le disque, etc.)

Et puis il y a les "vrais" cœurs par rapport à l'hyper-threading. Vous pouvez bénéficier ou non de la création de tâches pour chaque hyperthread. Encore une fois, vous devrez faire un benchmark 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 hyperthreadés, beaucoup de RAM et des disques VelociRaptor) et notre compilation (compilation C++ à grande échelle qui est alternativement liée au CPU et aux E/S), il y a très peu de différence entre -j4 et -j8. (C'est peut-être 15% mieux... mais loin d'être deux fois mieux).

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

5voto

sloMoses Points 21

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

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

uname -a on default slackware 14.0 kernel is 3.2.45.

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

l'a extrait ( tar -xjvf linux-3.2.46.tar.bz2 ) ;

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

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

utilisé make oldconfig pour préparer la configuration du noyau 3.2.46 ;

puis a couru faire avec diverses incantations de -jX.

J'ai testé les temps de chaque exécution en lançant make après la commande time, par exemple, 'time make -j2'. Entre chaque exécution, j'ai 'rm -rf' l'arbre de linux-3.2.46 et je l'ai réextrait, j'ai copié la configuration par défaut /usr/src/linux/.config dans le répertoire, j'ai lancé make oldconfig et j'ai refait mon test 'make -jX'.

plaine "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' produit :

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

Les rendements "gratuits" :

bob@Moses:/archive4$ free
             total       used       free     shared    buffers     cached
Mem:       3991304    3834564     156740          0     519220    2515308

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X