FreeBSDの割り込み周りに足りないと思う機能

ぼくは10GbEの割り込み周り(MSI-Xによりコア毎に独立したIRQを持つ)とかに興味を持っていたので、以前からこれがかなり気になってたんだが、まずはこれを見て欲しい。

Linux

IRQ毎に各CPUの割り込み回数が取れるよね。

$ cat /proc/interrupts 
            CPU0       CPU1       CPU2       CPU3       
   0:         55          0          0          0   IO-APIC-edge      timer
   1:         92          0          0          0   IO-APIC-edge      i8042
   5:          0          0          0          0   IO-APIC-edge      parport0
   6:          2          0          0          0   IO-APIC-edge      floppy
   8:          1          0          0          0   IO-APIC-edge      rtc0
   9:          0          0          0          0   IO-APIC-fasteoi   acpi
  12:        149          0          0          0   IO-APIC-edge      i8042
  14:          0          0          0          0   IO-APIC-edge      ata_piix
  15:        192          0          0          0   IO-APIC-edge      ata_piix
  16:          0          0          0          0   IO-APIC-fasteoi   vmwgfx, snd_ens1371
  17:       5088          0          0         50   IO-APIC-fasteoi   ehci_hcd:usb1, ioc0
  18:        149          0          0          0   IO-APIC-fasteoi   uhci_hcd:usb2
  19:        195          0          0          0   IO-APIC-fasteoi   eth0
  40:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  41:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  42:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  43:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  44:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  45:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  46:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  47:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  48:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  49:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  50:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  51:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  52:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  53:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  54:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  55:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  56:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  57:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  58:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  59:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  60:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  61:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  62:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  63:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  64:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  65:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  66:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  67:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  68:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  69:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  70:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  71:          0          0          0          0   PCI-MSI-edge      PCIe PME, pciehp
  72:          0          0          0          0   PCI-MSI-edge      vmci
  73:          0          0          0          0   PCI-MSI-edge      vmci
 NMI:          0          0          0          0   Non-maskable interrupts
 LOC:       3328       3158       2543       3122   Local timer interrupts
 SPU:          0          0          0          0   Spurious interrupts
 PMI:          0          0          0          0   Performance monitoring interrupts
 IWI:          0          0          0          0   IRQ work interrupts
 RTR:          0          0          0          0   APIC ICR read retries
 RES:       1626       2065       1404       1944   Rescheduling interrupts
 CAL:        457       2074        600       1412   Function call interrupts
 TLB:        471        521        388        505   TLB shootdowns
 TRM:          0          0          0          0   Thermal event interrupts
 THR:          0          0          0          0   Threshold APIC interrupts
 MCE:          0          0          0          0   Machine check exceptions
 MCP:          1          1          1          1   Machine check polls
 ERR:          0
 MIS:          0

IRQ毎の割り込み先CPUを設定出来るよね(この場合はIRQ72の設定を表示していて、0x4=cpu2に割り込み、と設定されてる。irqbalanceの仕業でしょうね。)。

$ sudo cat /proc/irq/72/smp_affinity
00000000,00000004

デフォルトで全CPUに公平に割り込みをまくようになっていて(値が0xffとかになってる)、CPU間の不公平がないようにしてあるし、irqbalanceってデーモンがCPU負荷を見ながらこの値をうまく調整してくれる。
10GbEMSI-XみたいにCPUごとにIRQを持つ場合は、そのNICIRQだけ特別扱いして、それぞれのIRQに割り込み先を設定出来るようになってる。
この辺は幾度と無く解説してるはずだから、皆もう知ってるよね。
参考資料

FreeBSD

IRQ毎の割り込み回数になっちゃってるよね。
どのCPUなのか、わかんないよねこれ。

$ sudo vmstat -i
interrupt                          total       rate
irq1: atkbd0                          56          0
irq6: fdc0                            95          0
irq14: ata0                       704289          3
irq15: ata1                       491895          2
irq16: uhci0                      400566          1
irq17: mpt0 ehci0                     16          0
irq18: em0                      22122134         96
cpu0:timer                      11350955         49
cpu1:timer                       5166995         22
Total                           40237001        175

割り込み先CPUの設定はどうすんねん、って思って調べた所、cpuset(1)でIRQとCPUを指定すれば出来そうである。
On-line Manual of "cpuset"

が…カーネル側のコードを良く見てみよう。
fxr.watson.org: sys/kern/kern_cpuset.c
CPU_LEVEL_ROOT(全CPU指定)・CPU_LEVEL_CPUSET(複数CPU指定)の時はEINVALである(このへん)。もうこの時点でアウツなんだが…
気を取り直してCPU_LEVEL_WITCH(1CPU指定)の場合をみてみる。
fxr.watson.org: sys/kern/kern_intr.c
あ〜…うん…これ…割り込み先CPUの設定じゃなくて、割り込みスレッドの実行先CPUの設定だね。似ているようで全然違うね。
つまり、割り込まれた後に起動するスレッドの実行先CPUは選べても、割り込み先CPUを変える術は用意されてないよね、これ。

あかんがな(完)