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 "travaillent".
Est-il préférable d'utiliser -j4
ou -j5
sur un système quad core?
Avez-vous vu (ou fait) des analyses comparatives qui soutiennent l'un ou l'autre?
Je dirais que la meilleure chose à faire est de le comparer vous-même à votre environnement et à votre charge de travail. Il semble qu'il y ait 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 du système sont situés sur différents disques, 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)
J'ai exécuté mon projet personnel sur mon ordinateur à 4 coeurs avec hyperthreading et enregistré les résultats. C'est un projet assez lourd à compiler mais il inclut un test unitaire de 17,7 secondes à la fin. Les compilations ne sont pas très IO intensive; 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:
Ma conjecture en ce moment: si vous faites autre chose sur votre ordinateur, utilisez le nombre de cœurs. Si ce n'est pas le cas, utilisez le nombre de threads. Le dépasser ne montre aucun avantage. À un moment donné, ils deviendront mémoire limitée et s'effondreront à cause de cela, ce qui rend la compilation beaucoup plus lente. La ligne "inf" a été ajoutée à une date beaucoup plus tardive, ce qui me fait soupçonner qu'il y avait un étranglement 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, avec 8 Go de mémoire à compiler.
Personnellement, j'utilise make -j n
où n est "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é de très bons résultats jusqu'à présent.
Quoi qu'il en soit, vous devez être prudent car certaines chaînes de création ne sont tout simplement pas compatibles avec le --jobs
option, et peut conduire à des résultats inattendus. Si vous rencontrez des erreurs de dépendance étranges, essayez simplement de make
sans --jobs
.
En fin de compte, vous devrez faire quelques repères pour déterminer le meilleur nombre à utiliser pour votre build, mais n'oubliez pas que le CPU n'est pas la seule ressource qui compte!
Si vous avez une version qui dépend fortement du disque, par exemple, la génération de nombreuses tâches sur un système multicœur peut en fait être plus lente, car le disque devra faire un travail supplémentaire pour déplacer le disque aller et venir pour servir toutes les différentes tâches (en fonction de nombreux facteurs, comme la façon dont le système d'exploitation gère le cache de disque, la prise en charge de la mise en file d'attente des commandes natives par le disque, etc.).
Et puis vous avez des "vrais" cœurs contre l'hyper-threading. Vous pouvez ou non bénéficier des tâches de génération pour chaque hyper-thread. Encore une fois, vous devrez comparer 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 disques VelociRaptor) et notre build (à grande échelle Version C++ 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 plus bon.)
Si je pars pour le déjeuner, j'utiliserai -j8, mais si je veux utiliser mon système pour autre chose pendant la construction, j'utiliserai un nombre inférieur. :)
Je viens de recevoir un processeur 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. Il s'agit d'un Athlon II x2 double cœur 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 du noyau par défaut sur (cp /usr/src/linux/.config .
);
utilisé make oldconfig
pour préparer la configuration du noyau 3.2.46;
puis exécuté make avec diverses incantations de -jX.
J'ai testé les temps de chaque exécution en émettant make après la commande time, par exemple, 'time make -j2'. Entre chaque exécution, je 'rm -rf' l'arborescence linux-3.2.46 et la réextrait, copiais le /usr/src/linux/.config par défaut dans le répertoire, exécutais make oldconfig puis refaisais mon test 'make -jX' .
"make" simple:
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
Tout comme une référence:
De Spawning Multiple Build Jobs
section dans LKD :
où n est le nombre d'emplois à générer. La pratique habituelle consiste à générer un ou deux travaux par processeur. Par exemple, sur une machine à double processeur, on pourrait faire
$ make j4
Les deux n'ont pas tort. 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: nproc
est une commande linux qui retournera le nombre de cœurs/threads (CPU modernes) disponibles sur le système. Le placer sous des ticks `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 le logiciel peut littéralement étouffer votre boîte à mort (ne répondant pas) et peut même prendre plus de temps que d'utiliser moins de cœurs. Comme j'ai vu un utilisateur Slackware ici posté, il avait un processeur dual core mais fournissait toujours des tests jusqu'à j 8, qui cessaient d'être différents en j 2 (seulement 2 cœurs matériels que le CPU peut utiliser). Donc, pour éviter une boîte qui ne répond pas, je vous suggère de l'exécuter comme ceci:
make -j`nproc --ignore=2`
Cela passera la sortie de nproc
à make
et soustraira 2 cœurs de son résultat.
D'après mon expérience, il doit y avoir des avantages en termes de performances lors de l'ajout de travaux supplémentaires. C'est simplement parce que les E/S 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 disques utilisés.