CPU0 è sommerso da interruzioni eth1


12

Ho una macchina virtuale Ubuntu, in esecuzione all'interno di Xen XCP basato su Ubuntu. Ospita un servizio HTTP personalizzato basato su FCGI, dietro nginx.

Sotto carico dal ab primo core della CPU è saturo e il resto è sotto-caricato.

In /proc/interruptsVedo che CPU0 serve un ordine di grandezza più interrupt di qualsiasi altro core. Molti di loro vengono eth1.

C'è qualcosa che posso fare per migliorare le prestazioni di questa VM? C'è un modo per bilanciare gli interrupt in modo più uniforme?


Dettagli Gory:

$ uname -a
Linux MYHOST 2.6.38-15-virtual # 59-Ubuntu SMP ven 27 apr 16:40:18 UTC 2012 i686 i686 i386 GNU / Linux

$ lsb_release -a
Non sono disponibili moduli LSB.
ID distributore: Ubuntu
Descrizione: Ubuntu 11.04
Rilascio: 11.04
Nome in codice: natty

$ cat / proc / interrupt 
           CPU0 CPU1 CPU2 CPU3 CPU4 CPU5 CPU6 CPU7       
283: 113720624 0 0 0 0 0 0 0 xen-dyn-event eth1
284: 1 0 0 0 0 0 0 0 xen-dyn-event eth0
285: 2254 0 0 3873799 0 0 0 0 xen-dyn-event blkif
286: 23 0 0 0 0 0 0 0 xen-dyn-event hvc_console
287: 492 42 0 0 0 0 0 295324 xenbus xen-dyn-event
288: 0 0 0 0 0 0 0 222294 xen-percpu-ipi callfuncsingle7
289: 0 0 0 0 0 0 0 0 debug xen-percpu-virq7
290: 0 0 0 0 0 0 0 151302 xen-percpu-ipi callfunc7
291: 0 0 0 0 0 0 0 3236015 xen-percpu-ipi riprogrammato7
292: 0 0 0 0 0 0 0 60064 xen-percpu-ipi spinlock7
293: 0 0 0 0 0 0 0 12355510 xen-percpu-virq timer7
294: 0 0 0 0 0 0 803174 0 xen-percpu-ipi callfuncsingle6
295: 0 0 0 0 0 0 0 0 debug xen-percpu-virq6
296: 0 0 0 0 0 0 60027 0 xen-percpu-ipi callfunc6
297: 0 0 0 0 0 0 5374762 0 xen-percpu-ipi riprogrammato6
298: 0 0 0 0 0 0 64976 0 xen-percpu-ipi spinlock6
299: 0 0 0 0 0 0 15294870 0 timer xen-percpu-virq6
300: 0 0 0 0 0 264441 0 0 xen-percpu-ipi callfuncsingle5
301: 0 0 0 0 0 0 0 0 debug xen-percpu-virq5
302: 0 0 0 0 0 79324 0 0 xen-percpu-ipi callfunc5
303: 0 0 0 0 0 3468144 0 0 xen-percpu-ipi riprogrammato5
304: 0 0 0 0 0 66269 0 0 xen-percpu-ipi spinlock5
305: 0 0 0 0 0 12778464 0 0 xen-percpu-virq timer5
306: 0 0 0 0 844591 0 0 0 xen-percpu-ipi callfuncsingle4
307: 0 0 0 0 0 0 0 0 debug xen-percpu-virq4
308: 0 0 0 0 75293 0 0 0 xen-percpu-ipi callfunc4
309: 0 0 0 0 3482146 0 0 0 xen-percpu-ipi riprogrammato4
310: 0 0 0 0 79312 0 0 0 xen-percpu-ipi spinlock4
311: 0 0 0 0 21642424 0 0 0 xen-percpu-virq timer4
312: 0 0 0 449141 0 0 0 0 xen-percpu-ipi callfuncsingle3
313: 0 0 0 0 0 0 0 0 debug xen-percpu-virq3
314: 0 0 0 95405 0 0 0 0 xen-percpu-ipi callfunc3
315: 0 0 0 3802992 0 0 0 0 xen-percpu-ipi riprogrammato3
316: 0 0 0 76607 0 0 0 0 xen-percpu-ipi spinlock3
317: 0 0 0 16439729 0 0 0 0 xen-percpu-virq timer3
318: 0 0 876383 0 0 0 0 0 xen-percpu-ipi callfuncsingle2
319: 0 0 0 0 0 0 0 0 debug xen-percpu-virq2
320: 0 0 76416 0 0 0 0 0 xen-percpu-ipi callfunc2
321: 0 0 3422476 0 0 0 0 0 xen-percpu-ipi riprogrammato2
322: 0 0 69217 0 0 0 0 0 xen-percpu-ipi spinlock2
323: 0 0 10247182 0 0 0 0 0 xen-percpu-virq timer2
324: 0 393514 0 0 0 0 0 0 xen-percpu-ipi callfuncsingle1
325: 0 0 0 0 0 0 0 0 debug xen-percpu-virq1
326: 0 95773 0 0 0 0 0 0 xen-percpu-ipi callfunc1
327: 0 3551629 0 0 0 0 0 0 xen-percpu-ipi riprogrammato1
328: 0 77823 0 0 0 0 0 0 xen-percpu-ipi spinlock1
329: 0 13784021 0 0 0 0 0 0 xen-percpu-virq timer1
330: 730435 0 0 0 0 0 0 0 xen-percpu-ipi callfuncsingle0
331: 0 0 0 0 0 0 0 0 debug xen-percpu-virq0
332: 39649 0 0 0 0 0 0 0 xen-percpu-ipi callfunc0
333: 3607120 0 0 0 0 0 0 0 xen-percpu-ipi riprogrammato0
334: 348740 0 0 0 0 0 0 0 xen-percpu-ipi spinlock0
335: 89912004 0 0 0 0 0 0 0 xen-percpu-virq timer0
NMI: 0 0 0 0 0 0 0 0 Interrupt non mascherabili
LOC: 0 0 0 0 0 0 0 0 Il timer locale si interrompe
SPU: 0 0 0 0 0 0 0 0 Interruzioni spurie
PMI: 0 0 0 0 0 0 0 0 Interruzione del monitoraggio delle prestazioni
IWI: 0 0 0 0 0 0 0 0 Interrupt di lavoro IRQ
RES: 3607120 3551629 3422476 3802992 3482146 3468144 5374762 3236015 Riprogrammazione degli interrupt
CAL: 770084 489287 952799 544546 919884 343765 863201 373596 Interrupt di chiamata funzione
TLB: 0 0 0 0 0 0 0 0 Shooting TLB
TRM: 0 0 0 0 0 0 0 0 Interruzioni di eventi termici
THR: 0 0 0 0 0 0 0 0 Soglia APIC interrotta
MCE: 0 0 0 0 0 0 0 0 Eccezioni controllo macchina
MCP: 0 0 0 0 0 0 0 0 Sondaggi controllo macchina
ERR: 0
MIS: 0

Domanda bonus: c'è un modo per ridurre il numero di interruzioni da eth1?
Alexander Gladysh,

Risposte:


10

Cerca nella /proc/irq/283directory. C'è un smp_affinity_listfile che mostra quali CPU otterranno l'interruzione 283. Per te questo file probabilmente contiene "0" (e smp_affinityprobabilmente contiene "1").

È possibile scrivere l'intervallo di CPU nel smp_affinity_listfile:

echo 0-7 | sudo tee /proc/irq/283/smp_affinity_list

Oppure puoi scrivere una maschera di bit, dove ogni bit corrisponde a una CPU, a smp_affinity:

printf %x $((2**8-1)) | sudo tee /proc/irq/283/smp_affinity

Tuttavia, è noto che irqbalance ha la propria idea di quale affinità dovrebbe avere ciascun interrupt e potrebbe ripristinare gli aggiornamenti. Quindi è meglio disinstallare completamente irqbalance. O almeno fermalo e disabilita il riavvio.

Se anche senza irqbalance stai diventando dispari smp_affinityper l'interruzione 283 dopo un riavvio, dovrai aggiornare manualmente l'affinità della CPU in uno dei tuoi script di avvio.


irqbalanceè già in esecuzione. Forse non è configurato correttamente? Come controllarlo?
Alexander Gladysh,

Forse dovresti semplicemente disabilitare irqbalance, riavviare, vedere se questo aiuta. Gli interrupt sono abbastanza ben bilanciati di default.
Chutz

Cordiali saluti: ora /proc/irq/283/smp_affinityè 01in esso (nessuno ha cambiato quella roba su questa macchina per quanto ne so - quindi questo deve essere il sistema predefinito).
Alexander Gladysh,

Mi dispiace, ho aggiornato la mia risposta. l'irqbalance è probabilmente il colpevole. Liberatene. Non so quale dovrebbe essere il valore predefinito, ma per esperienza l'ho visto predefinito su "TUTTE LE CPU".
Chutz

La disabilitazione irqbalance(tramite ENABLED=0in /etc/default/irqbalance) non aiuta. Dopo il riavvio irqbalanceè stop/waiting, ma /proc/irq/283/smp_affinityè ancora 01.
Alexander Gladysh,

2

Se hai il modello giusto di Intel NIC puoi migliorare significativamente le prestazioni.

Per citare il primo paragrafo:

I processori multicore e gli adattatori Ethernet più recenti (inclusi 82575, 82576, 82598 e 82599) consentono di ottimizzare i flussi di inoltro TCP assegnando i flussi di esecuzione ai singoli core. Per impostazione predefinita, Linux assegna automaticamente gli interrupt ai core del processore. Esistono attualmente due metodi per assegnare automaticamente gli interrupt, un bilanciamento IRQ del kernel e il daemon di bilanciamento IRQ nello spazio utente. Entrambi offrono compromessi che potrebbero ridurre l'utilizzo della CPU ma non massimizzare le velocità di inoltro IP. Il throughput ottimale può essere ottenuto bloccando manualmente le code dell'adattatore Ethernet su core del processore specifici.

Per l'inoltro IP, una coppia di code di trasmissione / ricezione deve utilizzare lo stesso core del processore e ridurre l'eventuale sincronizzazione della cache tra diversi core. Ciò può essere eseguito assegnando interruzioni di trasmissione e ricezione a core specifici. A partire dal kernel 2.6.27 di Linux, è possibile utilizzare più code su 82575, 82576, 82598 e 82599. Inoltre, sono state abilitate più code di trasmissione in Interruzioni segnalate di messaggistica estesa (MSI-X). MSI-X supporta un numero maggiore di interrupt che è possibile utilizzare, consentendo un controllo più preciso e il targeting degli interrupt su CPU specifiche.

Vedere: Assegnazione di interrupt ai core del processore mediante un controller Ethernet Intel® 82575/82576 o 82598/82599


2

In realtà si raccomanda, soprattutto quando si tratta di processi ripetitivi di breve durata, che tutte le interruzioni generate da una coda di dispositivi siano gestite dalla stessa CPU, invece del bilanciamento IRQ e quindi si vedranno prestazioni migliori se una singola CPU gestisse l'interruzione eth1 *** eccezione fornita di seguito

La fonte, collegata sopra, proviene dal Linux Symposium e ti consiglio di leggere i paragrafi di coppia su SMP IRQ Affinity perché ti convincerà in modo più efficace di questo post.

Perché?

Richiama ogni processore ha la sua cache oltre a poter accedere alla memoria principale, controlla questo diagramma . Quando viene attivato un interrupt, un core della CPU dovrà recuperare le istruzioni per gestire l'interrupt dalla memoria principale, che impiega molto più tempo rispetto alle istruzioni nella cache. Una volta che un processore ha eseguito un'attività, avrà quelle istruzioni nella cache. Ora supponiamo che lo stesso core della CPU gestisca lo stesso interrupt quasi sempre, la funzione del gestore degli interrupt difficilmente lascerà la cache del core della CPU, migliorando le prestazioni del kernel.

In alternativa, quando IRQ è bilanciato, può assegnare l'interruzione da gestire costantemente da CPU diverse, quindi il nuovo core della CPU probabilmente non avrà la funzione di gestore di interrupt nella cache e sarà necessario molto tempo per ottenere il gestore corretto da main memoria.

Eccezione : se stai raramente usando l'interruzione eth1, significa che passa abbastanza tempo da sovrascrivere la cache eseguendo altre attività, il che significa che hai dati che arrivano su quell'interfaccia in modo intermittente con lunghi periodi tra ... quindi molto probabilmente non vedrai questi vantaggi perché lo sono quando si utilizza un processo ad alta frequenza.

Conclusione

Se l'interruzione si verifica molto frequentemente, è sufficiente associare tale interruzione per essere gestita solo da una CPU specifica. Questa configurazione vive a

 /proc/'IRQ number'/smp_affinity

o

/proc/irq/'IRQ number'/smp_affinity

Vedi l'ultimo paragrafo nella sezione Affinità IRP SMP dalla fonte collegata sopra, contiene istruzioni.

In alternativa

È possibile modificare la frequenza con cui viene generato il flag di interruzione aumentando la dimensione MTU (frame jumbo) se la rete lo consente o modificare il rilancio del flag dopo che viene ricevuto un numero maggiore di pacchetti anziché in ogni pacchetto OPPURE modificare il timeout, quindi aumentare l'interrupt dopo un certo periodo di tempo. Attenzione all'opzione time perché la dimensione del buffer potrebbe essere piena prima che scada il tempo. Questo può essere fatto usando l' ethtool che è delineato nella fonte collegata.

questa risposta si avvicina alla lunghezza con cui la gente non la leggerà, quindi non entrerò nei dettagli, ma a seconda della tua situazione ci sono molte soluzioni ... controlla la fonte :)

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.