2015-04-02 8 views
14

Ho letto in più punti che lo scheduler predefinito di Linux è con conoscenza hyperthreading su macchine multi-core, il che significa che se si dispone di una macchina con 2 core reali (4 HT), non pianifica due thread occupati su logico core in modo che entrambi funzionino con gli stessi core fisici (il che comporterebbe in genere un aumento dei costi di 2x).Perché lo scheduler di Linux mette due thread sullo stesso core fisico sui processori con HyperThreading?

Ma quando corro stress -c 2 (genera due thread per eseguire sul 100% della CPU) sul mio Intel i5-2520M, spesso orari (e mantiene) i due fili sul core HT 1 e 2, che mappa a lo stesso nucleo fisico. Anche se il sistema è inattivo altrimenti.

Questo succede anche con i programmi reali (sto usando stress qui perché rende facile la riproduzione), e quando ciò accade, il mio programma richiede comprensibilmente il doppio del tempo per l'esecuzione. L'impostazione manuale dell'affinità con le correzioni taskset per il mio programma, ma mi aspetto che lo scheduler di HT consapevole lo faccia da solo.

È possibile trovare il numero HT-> nucleo fisico con egrep "processor|physical id|core id" /proc/cpuinfo | sed 's/^processor/\nprocessor/g'.

Quindi la mia domanda è: Perché lo scheduler ha messo i miei thread sullo stesso nucleo fisico qui?


Note:

  • Questa domanda è molto simile a questo other question, le cui risposte dire che Linux ha abbastanza di un sofisticato schedulatore thread che è a conoscenza HT. Come descritto sopra, non posso osservare questo fatto (controlla te stesso con stress -c) e vorrei sapere perché.
  • So che posso impostare manualmente l'affinità dei processori per i miei programmi, ad es. con lo strumento taskset o con la funzione sched_setaffinity. Non è quello che sto cercando, mi aspetto che lo scheduler sappia da solo che mappare due thread occupati a un core fisico e lasciare un core fisico completamente vuoto non è una buona idea.
  • Sono consapevole che ci sono some situations in cui preferireste che i thread siano programmati sullo stesso core fisico e lasciano l'altro core libero, ma sembra assurdo che lo scheduler faccia circa 1/4 dei casi. Mi sembra che i core HT che seleziona siano completamente casuali, o forse quei core HT che hanno avuto meno attività al momento della pianificazione, ma che non sarebbero molto consapevoli di hyperthreading, data la chiarezza dei programmi con le caratteristiche del vantaggio stress da eseguire su core fisici separati.
+0

Quali distro e la versione ti riferisci? –

+0

Prova lo stress in esecuzione in due processi con un thread ciascuno. Non ho esaminato le specifiche dello scheduler di Linux (che potrebbe anche essere cambiato dall'ultima volta che lo stavo facendo ricerche). È possibile che il kernel preferisca pianificare i thread nello stesso processo sullo stesso processore fisico per ragioni come la localizzazione della cache. – joshperry

+0

Ubuntu 14.04, Linux 3.13.0. – nh2

risposta

4

Non riesco a riprodurlo su 3.13.0-48 con la mia CPU Intel (R) Xeon (R) E5-1650 0 @ 3.20 GHz.

Ho 6 core con hyperthreading, in cui il core logico N si associa al core N fisico 6.

Ecco un'uscita tipica top con stress -c 4 in due colonne, in modo che ogni riga è un core fisico (I tralasciato alcuni nuclei perché il mio sistema non è inattivo):

%Cpu0 :100.0 us, %Cpu6 : 0.0 us, 
%Cpu1 :100.0 us, %Cpu7 : 0.0 us, 
%Cpu2 : 5.9 us, %Cpu8 : 2.0 us, 
%Cpu3 :100.0 us, %Cpu9 : 5.7 us, 
%Cpu4 : 3.9 us, %Cpu10 : 3.8 us, 
%Cpu5 : 0.0 us, %Cpu11 :100.0 us, 

Qui è dopo uccidendo e riavviando stress:

%Cpu0 :100.0 us, %Cpu6 : 2.6 us, 
%Cpu1 :100.0 us, %Cpu7 : 0.0 us, 
%Cpu2 : 0.0 us, %Cpu8 : 0.0 us, 
%Cpu3 : 2.6 us, %Cpu9 : 0.0 us, 
%Cpu4 : 0.0 us, %Cpu10 :100.0 us, 
%Cpu5 : 2.6 us, %Cpu11 :100.0 us, 

ho fatto più volte, e non vedere le istanze dove 4 filoni all'interno di 12 core logici avrebbero pianificare sullo stesso nucleo fisico.

Con -c 6 Tendo a ottenere risultati come questo, in cui Linux sembra essere utile per pianificare altri processi sui propri core fisici. Anche così, sono distribuiti modo migliore di possibilità:

%Cpu0 : 18.2 us, %Cpu6 : 4.5 us, 
%Cpu1 : 0.0 us, %Cpu7 :100.0 us, 
%Cpu2 :100.0 us, %Cpu8 :100.0 us, 
%Cpu3 :100.0 us, %Cpu9 : 0.0 us, 
%Cpu4 :100.0 us, %Cpu10 : 0.0 us, 
%Cpu5 :100.0 us, %Cpu11 : 0.0 us, 
+0

L'ho appena testato su un Intel i7-2600 e su un Intel Xeon E5-1620, e in effetti ottengo il buon comportamento che descrivi. Ma sul mio Intel i5-2520M, ottengo il cattivo comportamento di programmazione. Una cosa che ho notato come differente è che su i7 e Xeon, ho una mappatura 'N mod 4' (12341234), proprio come descriveresti, ma sull'i5 ho una mappatura" accoppiata "(1122). Potrebbe essere questa la differenza? – nh2

+0

Inoltre, grazie per aver dedicato del tempo per rispondere in dettaglio! – nh2

-2

Citando la vostra esperienza con due processori aggiuntivi che sembravano funzionare correttamente, l'i7-2600 e Xeon E5-1620; Questo potrebbe essere un lungo periodo, ma che ne dite di un aggiornamento del microcodice della CPU? Potrebbe includere qualcosa per risolvere il problema se si tratta di un comportamento interno della CPU.

CPU Intel microcodice Download: http://intel.ly/1aku6ak

vedi anche qui: https://wiki.archlinux.org/index.php/Microcode

+0

Non ha nulla a che fare con il problema degli OP, le informazioni sulla relazione tra core e processore contenute nelle tabelle SRPI/SLIT ACPI fornite dal BIOS/UEFI. – myaut

6

penso che sia arrivato il momento di riassumere una certa conoscenza dai commenti.

Linux scheduler è a conoscenza di HyperThreading - informazioni su di esso devono essere lette dalle tabelle ACPI SRAT/fessura, che sono forniti da BIOS/UEFI - di Linux costruisce scheduler domains da questo.

Domini hanno gerarchia - cioè su server 2-CPU si ottengono tre strati di domini: tutte le CPU, per-cpu-pacchetto e per-cpu core dominio. Si può controllare da /proc/schedstat:

$ awk '/^domain/ { print $1, $2; } /^cpu/ { print $1; }' /proc/schedstat 
cpu0 
domain0 0000,00001001  <-- all cpus from core 0 
domain1 0000,00555555  <-- all cpus from package 0 
domain2 0000,00ffffff  <-- all cpus in the system 

Parte del CFS di pianificazione è di bilanciamento del carico - la bestia che deve rubare le attività dal vostro core occupato per un'altra anima. Ecco la sua descrizione della documentazione del kernel:

Mentre faceva tutto ciò, si controlla per vedere se il dominio attuale ha esaurito il suo intervallo di riequilibrio. In tal caso, viene eseguito load_balance() su quel dominio. Quindi controlla gen_store_programma (se esiste) e il genitore del genitore e quindi avanti.

Inizialmente, load_balance() trova il gruppo più occupato nel dominio di pianificazione corrente. Se riesce, cerca il runcoue più attivo di tutti i runscreens della CPU nel gruppo . Se riesce a trovare un tale runqueue, blocca sia il runqueue della CPU iniziale che quello appena trovato più affollato e inizia a spostare le attività da esso al nostro runqueue. Il numero esatto di attività equivale a uno squilibrio precedentemente calcolato con durante l'iterazione sui gruppi di questo dominio di pianificazione.

Da: https://www.kernel.org/doc/Documentation/scheduler/sched-domains.txt

È possibile monitorare per le attività di bilanciamento del carico, confrontando i numeri in /proc/schedstat. Ho scritto uno script per farlo: schedstat.py

contatore alb_pushed dimostra che di bilanciamento del carico è stato trasferito con successo compito:

Sun Apr 12 14:15:52 2015    cpu0 cpu1 ... cpu6 cpu7 cpu8 cpu9 cpu10 ... 
.domain1.alb_count         ...  1  1      1 
.domain1.alb_pushed         ...  1  1      1 
.domain2.alb_count        1  ...           
.domain2.alb_pushed        1  ... 

Tuttavia, la logica di bilanciamento del carico è complessa, quindi è difficile determinare quali ragioni può impedirgli di fare bene il suo lavoro e come sono collegati ai contatori di schedstat. Né io né @thatotherguy possiamo riprodurre il problema.

Vedo due possibilità per quel comportamento:

  • Avete qualche politica di risparmio potenza aggressiva che cerca di salvare un core per ridurre il consumo di CPU.
  • È davvero incontrato un bug con sottosistema di pianificazione, che si dovrebbe andare a LKML e con attenzione condividere le tue scoperte (tra cui mpstat e schedstat dati)
Problemi correlati