GNU make: il numero di lavori dovrebbe essere uguale al numero di core della CPU in un sistema?


88

Sembra esserci qualche controversia sul fatto che il numero di lavori in GNU make debba essere uguale al numero di core, o se puoi ottimizzare il tempo di compilazione aggiungendo un lavoro extra che può essere messo in coda mentre gli altri "funzionano" .

È meglio usare -j4o -j5su un sistema quad core?

Hai visto (o fatto) qualche benchmarking che supporti l'uno o l'altro?


8
Solo per un suggerimento, puoi usare make `nproc`per creare script indipendenti dalla CPU :)
VivienG

Se hai un mix di ricette che sono legate a io e alla cpu, allora potenzialmente vorrai molte più delle NCPU. Considera anche l'aggiunta delle opzioni -lX. Questa non è davvero una domanda a cui rispondere, a parte "dipende dal tuo hardware e dai compiti".
James Moore

È tecnicamente possibile vedere un miglioramento. Hai bisogno di un disco lento, non abbastanza ram e molti piccoli file di codice sorgente. Più facile da trovare dieci anni fa.
Hans Passant

Risposte:


57

Direi che la cosa migliore da fare è fare un benchmark tu stesso sul tuo particolare ambiente e carico di lavoro. Sembra che ci siano troppe variabili (dimensione / numero di file sorgente, memoria disponibile, memorizzazione nella cache del disco, se la directory di origine e le intestazioni di sistema si trovano su dischi diversi, ecc.) Per una risposta valida per tutti.

La mia esperienza personale (su un MacBook Pro a 2 core) è che -j2 è significativamente più veloce di -j1, ma oltre a ciò (-j3, -j4 ecc.) Non c'è velocità misurabile. Quindi per il mio ambiente "lavori == numero di core" sembra essere una buona risposta. (YMMV)


58

Ho eseguito il mio progetto casalingo sul mio laptop a 4 core con hyperthreading e ho registrato i risultati. Questo è un progetto abbastanza impegnativo per il compilatore ma include uno unit test di 17,7 secondi alla fine. Le compilazioni non richiedono molta IO; c'è molta memoria disponibile e se no il resto è su un veloce SSD.

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

Risultati di base:

  • Il ridimensionamento al numero di core aumenta le prestazioni in modo quasi lineare. Il tempo reale è passato da 2,5 minuti a 1,0 minuto (2,5 volte più veloce), ma il tempo impiegato durante la compilazione è passato da 2,11 a 2,50 minuti. Il sistema ha notato a malapena alcun carico aggiuntivo in questo bit.
  • Il ridimensionamento dal numero di core al numero di thread ha aumentato immensamente il carico dell'utente, da 2,50 minuti a 4,38 minuti. Questo quasi raddoppio è molto probabile perché le altre istanze del compilatore volevano utilizzare le stesse risorse della CPU allo stesso tempo. Il sistema si sta caricando un po 'di più con le richieste e il cambio di attività, portando il tempo a 17,7 secondi. Il vantaggio è di circa 6,5 ​​secondi su un tempo di compilazione di 53,5 secondi, con un aumento della velocità del 12%.
  • Il passaggio dal numero di thread al doppio numero di thread non ha dato alcun aumento significativo della velocità. I tempi a 12 e 15 sono molto probabilmente anomalie statistiche che puoi ignorare. Il tempo totale impiegato aumenta leggermente, così come il tempo di sistema. Entrambi sono molto probabilmente dovuti a un maggiore cambio di attività. Non c'è alcun vantaggio in questo.

La mia ipotesi in questo momento: se fai qualcos'altro sul tuo computer, usa il conteggio dei core. Se non lo fai, usa il conteggio thread. Superarlo non mostra alcun vantaggio. Ad un certo punto diventeranno limitati dalla memoria e collasseranno a causa di ciò, rendendo la compilazione molto più lenta. La riga "inf" è stata aggiunta molto più tardi, dandomi il sospetto che ci fosse qualche limitazione termica per i lavori 8+. Questo mostra che per questa dimensione del progetto non esiste alcun limite di memoria o velocità effettiva. È un piccolo progetto, dato 8 GB di memoria per compilare.


Secondo stackoverflow.com/questions/56272639/… , puoi ottenere un vantaggio eseguendo più attività di quante ne hai CPU, ma solo se le tue attività trascorrono una parte significativa del tempo in attesa dell'I / O di rete. Per le attività di compilazione, però, non è così.
ivan_pozdeev

30

Personalmente, uso make -j ndove n è "numero di core" + 1.

Tuttavia, non posso fornire una spiegazione scientifica: ho visto molte persone usare le stesse impostazioni e finora mi hanno dato risultati piuttosto buoni.

Ad ogni modo, devi stare attento perché alcune catene di fabbricazione semplicemente non sono compatibili con l' --jobsopzione e possono portare a risultati inaspettati. Se riscontri strani errori di dipendenza, prova a farne a makemeno --jobs.


19
La spiegazione (non posso garantire per la sua scientificità) è che "+ 1" fornisce un lavoro extra che viene eseguito mentre uno degli altri n lavori sta facendo I / O.
Laurynas Biveinis

@LaurynasBiveinis: Ma poi i lavori vengono eseguiti su core diversi tutto il tempo, almeno più spesso che con un'impostazione più conservativa in cui un lavoro ha la possibilità di rimanere sullo stesso core per un periodo di tempo più lungo. Ci sono pro e contro qui ...
krlmlr

1
Anche il numero di core + 1 è la mia impostazione predefinita. Un problema è che, in qualsiasi sistema ragionevolmente grande, make sembra ritardare il collegamento ed eseguire tutti i passaggi di collegamento insieme. A questo punto si esaurisce la RAM. Bah!
bobbogo

4
alcune make-chain semplicemente non sono compatibili con l'opzione --jobs -> Ciò significa che mancano le dipendenze. Correggi i tuoi makefile se mai ottieni questo.
dascandy,

7

Alla fine, dovrai fare alcuni benchmark per determinare il numero migliore da utilizzare per la tua build, ma ricorda che la CPU non è l'unica risorsa che conta!

Se hai una build che fa molto affidamento sul disco, ad esempio, la generazione di molti lavori su un sistema multicore potrebbe effettivamente essere più lenta , poiché il disco dovrà fare del lavoro extra spostando la testina del disco avanti e indietro per servire tutti i diversi lavori (a seconda di molti fattori, come il modo in cui il sistema operativo gestisce la cache del disco, il supporto nativo dell'accodamento dei comandi da parte del disco, ecc.).

E poi hai core "reali" contro hyper-threading. Puoi o meno trarre vantaggio dalla generazione di processi per ogni hyper-thread. Ancora una volta, dovrai fare un benchmark per scoprirlo.

Non posso dire di aver provato specificamente #cores + 1 , ma sui nostri sistemi (Intel i7 940, 4 core hyperthread, molta RAM e unità VelociRaptor) e la nostra build (build C ++ su larga scala che è alternativamente CPU e io / O bound) c'è poca differenza tra -j4 e -j8. (È forse il 15% migliore ... ma neanche lontanamente il doppio.)

Se vado a pranzo, userò -j8, ma se voglio usare il mio sistema per qualcos'altro durante la costruzione, userò un numero inferiore. :)


1
Sembra fantastico, ma sono confuso sul motivo per cui non dovresti prendere quel + 15% ogni volta usando-j 8
sg

1
@sg: j8 era davvero faticoso sul sistema che ho descritto nel mio post originale ... la macchina era ancora utilizzabile , ma era decisamente meno reattiva. Quindi, se volessi ancora utilizzarlo in modo interattivo per altre attività (in genere lavorando su altro codice e forse la build occasionale di una singola DLL), riserverei un paio di core per i bit interattivi.
ijprest

@sg: Questo è un problema minore sui nostri sistemi più recenti ... Sospetto che sia principalmente perché ora eseguiamo SSD. (Penso che siamo completamente vincolati alla CPU ora che andremo agli SSD ... abbiamo provato a costruire interamente su un'unità RAM senza quasi alcun miglioramento.) Ma lascerò ancora un paio di core liberi se lo faccio fare qualcosa di più della semplice modifica del testo in primo piano.
ijprest

5

Ho appena ricevuto un processore Athlon II X2 Regor con un Foxconn M / B e 4 GB di memoria G-Skill.

Ho messo i miei "cat / proc / cpuinfo" e "free" alla fine di questo in modo che gli altri possano vedere le mie specifiche. È un Athlon II x2 dual core con 4 GB di RAM.

uname -a on default slackware 14.0 kernel is 3.2.45.

Ho scaricato il sorgente del kernel del passaggio successivo (linux-3.2.46) in / archive4;

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

cd nella directory ( cd linux-3.2.46);

e copiato la configurazione del kernel predefinito su ( cp /usr/src/linux/.config .);

usato make oldconfigper preparare la configurazione del kernel 3.2.46;

poi ha eseguito make con vari incantesimi di -jX.

Ho testato i tempi di ogni esecuzione immettendo make dopo il comando time, ad esempio "time make -j2". Tra ogni esecuzione ho 'rm -rf' l'albero linux-3.2.46 e l'ho estratto di nuovo, ho copiato il file /usr/src/linux/.config predefinito nella directory, ho eseguito make oldconfig e poi ho fatto di nuovo il mio test 'make -jX' .

semplice "make":

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

come sopra ma con make -j2

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

come sopra ma con make -j3

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

come sopra ma con make -j4

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

come sopra ma con make -j8

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

'cat / proc / cpuinfo' restituisce:

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

rendimenti 'gratuiti':

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

1
Cosa fa solo make -jsu quel sistema? Make dovrebbe controllare il carico e ridimensionare il numero di processi in base al carico.
docwhat

1
make -jnon limita affatto il numero di lavori. Questo di solito è disastroso su un progetto di medie o grandi dimensioni poiché vengono rapidamente biforcati più lavori di quelli che possono essere supportati dalla RAM. L'opzione che devi limitare in base al carico è -l [load], in combinazione con-j
Matt G

5

Entrambi non hanno torto. Per essere in pace con te stesso e con l'autore del software che stai compilando (a livello di software stesso si applicano diverse restrizioni multi-thread / single-thread), ti suggerisco di utilizzare:

make -j`nproc`

Note: nprocè un comando Linux che restituirà il numero di core / thread (CPU moderna) disponibili sul sistema. Mettendolo sotto le zecche `come sopra passerà il numero al comando make.

Informazioni aggiuntive: come qualcuno ha menzionato, l'utilizzo di tutti i core / thread per compilare software può letteralmente soffocare la tua scatola fino quasi alla morte (non rispondendo) e potrebbe anche richiedere più tempo rispetto all'utilizzo di meno core. Come ho visto un utente Slackware qui pubblicato, aveva una CPU dual core ma continuava a fornire test fino a j 8, che ha smesso di essere diverso a j 2 (solo 2 core hardware che la CPU può utilizzare). Quindi, per evitare che la scatola non risponda, ti suggerisco di eseguirlo in questo modo:

make -j`nproc --ignore=2`

Questo passerà l'uscita nprocper makee sottrarre 2 core dal suo risultato.


3

Proprio come un riferimento:

Dalla Spawning Multiple Build Jobssezione in LKD :

dove n è il numero di posti di lavoro da generare. La pratica abituale consiste nel generare uno o due lavori per processore. Ad esempio, su una macchina a doppio processore, si potrebbe fare

$ make j4


collegamento interrotto, è questa citazione da Linux Kernel Development di Robert Love?
Behrooz

Sì, è da quel libro.
Nan Xiao

1

Dalla mia esperienza, ci devono essere alcuni vantaggi in termini di prestazioni quando si aggiungono lavori extra. È semplicemente perché l'I / O del disco è uno dei colli di bottiglia oltre alla CPU. Tuttavia non è facile decidere il numero di lavori extra in quanto è altamente interconnesso con il numero di core e tipi di disco utilizzati.


1

Molti anni dopo, la maggior parte di queste risposte è ancora corretta. Tuttavia, c'è stato un piccolo cambiamento: l'utilizzo di più lavori rispetto ai core fisici ora offre una velocità davvero significativa. Come aggiunta al tavolo di Dascandy, ecco i miei tempi per compilare un progetto su un AMD Ryzen 5 3600X su Linux. (The Powder Toy, commit c6f653ac3cef03acfbc44e8f29f11e1b301f1ca2)

Consiglio di controllare te stesso, ma ho scoperto con il contributo di altri che l'utilizzo del conteggio logico del core per il conteggio dei lavori funziona bene su Zen. Inoltre, il sistema non sembra perdere la reattività. Immagino che questo si applichi anche alle recenti CPU Intel. Tieni presente che ho anche un SSD, quindi potrebbe valere la pena provare tu stesso la tua CPU.

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.)

Test effettuati su Ubuntu 19.10 con Ryzen 5 3600X, Samsung 860 Evo SSD (SATA) e 32 GB di RAM

Nota finale: altre persone con un 3600X potrebbero avere tempi migliori di me. Durante questo test, avevo abilitato la modalità Eco, riducendo leggermente la velocità della CPU.


0

SÌ! Sul mio 3950x, eseguo -j32 e mi fa risparmiare ore di tempo di compilazione! Posso ancora guardare YouTube, navigare sul web, ecc. Durante la compilazione senza alcuna differenza. Il processore non è sempre ancorato nemmeno con un 970 PRO nvme da 1 TB o Auros Gen4 nvme da 1 TB e 64 GB di 3200C14. Anche quando lo è, non noto l'interfaccia utente saggia. Ho intenzione di testare con -j48 nel prossimo futuro su alcuni grandi progetti in arrivo. Mi aspetto, come probabilmente fai tu, di vedere qualche miglioramento impressionante. Quelli ancora con un quad-core potrebbero non ottenere gli stessi guadagni ...

Lo stesso Linus è appena passato a un 3970x e puoi scommettere il tuo dollaro inferiore, sta almeno eseguendo -j64.

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.