LinuxでIRQの割り込みを複数CPUに分散する方法

2019年4月4日

マルチプロセッサ

周辺ハードウェアは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)といった負荷分散の仕組みがあります。

これらについてはまた別の機会に解説していこうかと思いますので、今後ともこのアカスブログを宜しくお願い致します。