LinuxでIRQの割り込みを複数CPUに分散する方法
周辺ハードウェアはCPUに処理して欲しい出来事があるとCPUに割り込みをかけて処理してもらいます。
例えばネットワークインターフェースカード(NIC)にパケットが到着した時などです。
パケットが到着するごとにCPUに割り込みが入ると効率が悪いので、ここでは割愛しますが現在のLinuxには割り込みを緩やかにする仕組みがあります。
デフォルトではこの割り込み処理は先頭のCPUが受け持つ事になるので、トラフィックが多いサーバ等では先頭のCPUだけ負荷が高くなることがあります。
IRQごとに担当CPUを割り当てることによって、複数NICを搭載した環境では複数のCPUに負荷を分散することができます。
割り込み数の確認方法
procファイルシステムのinterruptsを見ると現在の割り込み数の統計を確認することができます。
$ cat /proc/interrupts
CPU0 CPU1
0: 25 0 IO-APIC 2-edge timer
8: 1 0 IO-APIC 8-edge rtc0
9: 0 0 IO-APIC 9-fasteoi acpi
14: 1640643 0 IO-APIC 14-edge pata_sch
15: 0 0 IO-APIC 15-edge pata_sch
18: 0 0 IO-APIC 18-fasteoi uhci_hcd:usb4
19: 0 0 IO-APIC 19-fasteoi uhci_hcd:usb3
21: 18 0 IO-APIC 21-fasteoi ehci_hcd:usb1
23: 0 0 IO-APIC 23-fasteoi uhci_hcd:usb2
24: 12368433 0 PCI-MSI 1048576-edge eth0
25: 36473102 0 PCI-MSI 1572864-edge eth1
NMI: 0 0 Non-maskable interrupts
LOC: 226472199 217458810 Local timer interrupts
SPU: 0 0 Spurious interrupts
PMI: 0 0 Performance monitoring interrupts
IWI: 0 0 IRQ work interrupts
RTR: 0 0 APIC ICR read retries
RES: 421745 436286 Rescheduling interrupts
CAL: 651056 16002572 Function call interrupts
TLB: 89231 73300 TLB shootdowns
ERR: 0
MIS: 0
PIN: 0 0 Posted-interrupt notification event
NPI: 0 0 Nested posted-interrupt event
PIW: 0 0 Posted-interrupt wakeup event
上は現在の私の自宅サーバのinterruptsを表示したものになります。
IRQ24と25がeth0と1ということが分かると思います。
私の環境でCPUは0と1の2つあるように見えますが、残念ながら32bitのATOMプロセッサでHyper Threadingを有効にしてあるのでそう見えているだけです。
Hyper Threadingに分散することはできませんが、2コア以上の環境であればそれぞれのIRQの割り込み処理を別々のCPUに割り当てて負荷を分散することが可能です。
割り込みを処理するCPUの割り当て
現在のCPU割り当ての設定はprocファイルシステムのsmp_affinityを読み出す事で確認できます。
$ cat /proc/irq/IRQ番号/smp_affinity
ex. IRQ24の設定値の確認
$ cat /proc/irq/24/smp_affinity
1
smp_affinityはビットごとのフラグになっており、下位ビットから順番に1ビット目が1番目のCPU、2ビット目が2番目のCPU、・・・と対応しています。
3番目のCPUは2進数で100の4、4番目のCPUは2進数で1000の8となることに注意して下さい。
そして以下のようにIRQごとに処理するCPUを割り当てることができます。
# echo 設定値 >/proc/irq/IRQ番号/smp_affinity
ex. IRQ25を5番目のCPUに割り当てる場合
# echo 16 >/proc/irq/25/smp_affinity
まとめ
物理的に複数のNICとCPUを搭載したマシンで、システムの負荷が1つのCPUに偏っている場合は状況をみて適切に設定してあげるとシステム全体のパフォーマンスが改善する事があります。
このIRQによる物理的な負荷分散以外にもLinuxのネットワークについてはRSS(Receive Side Scaling)やRPS(Receive Packet Steering)、RFS(Receive Flow Steering)といった負荷分散の仕組みがあります。
これらについてはまた別の機会に解説していこうかと思いますので、今後ともこのアカスブログを宜しくお願い致します。