続・FreeBSDの割り込み周りに足りないと思う機能
この記事に対して、さとうせんせいから”intr_event_bind() の本質的な部分は ie->ie_assign_cpu() を呼んでいるとこで、IRQ-CPU の binding は、そのハンドラ経由で呼ばれる PIC を操作する MD なコードでやっているはずですよ。(CPU単位の統計をとる機能がないのは確かですが)”とコメントを頂いた。
コードを読み違えていたようです。
intr_setaffinityで呼んでるintr_event_bindがie->ie_assign_cpuを最終的に呼んでいて、これが割り込みコントローラに設定を行なっているはず、という指摘でした。
ie->ie_assign_cpuはどこを指しているのだろう?と探してみると、intr_event_createの引数assign_cpuとして渡され設定されており、これはintr_register_sourceで呼ばれてます。
ここで渡してる関数はintr_assign_cpuで、isrc->is_pic->pic_assign_cpuを呼びます。
また関数ポインタだ。今度はどこを呼んでる?
intr_register_sourceがintr_event_createを呼んでいて、ここへisrcが渡されてきている事がわかる。
intr_register_sourceはx86/x86/io_apic.cやx86/x86/msi.cで渡されているが、今回はMSI割り込みの場合だけ見てみよう。msi_create_sourceでは、isrc->is_picにmsi_picを設定している。
msi_picはここに定義されていて、msi_assign_cpuをpic_assign_cpuに指定している。
msi_assign_cpuをみると、BUS_REMAP_INTRを呼んでいる。
pci.cではDEVMETHODでBUS_REMAP_INTRをpci_remap_intr_methodにmapしていて、pci_remap_intr_methodではPCIB_MAP_MSIを呼んでいる。
これはnexus.cでDEVMETHODでnexus_map_msiにmapされている。
nexus_map_msiはmsi_mapを呼ぶだけの関数で、これは以下のマクロ関数を実行している。
*addr = INTEL_ADDR(msi); *data = INTEL_DATA(msi);
これの定義をみてみると、
/* * Build Intel MSI message and data values from a source. AMD64 systems * seem to be compatible, so we use the same function for both. */ #define INTEL_ADDR(msi) \ (MSI_INTEL_ADDR_BASE | (msi)->msi_cpu << 12 | \ MSI_INTEL_ADDR_RH_OFF | MSI_INTEL_ADDR_DM_PHYSICAL) #define INTEL_DATA(msi) \ (MSI_INTEL_DATA_TRGREDG | MSI_INTEL_DATA_DELFIXED | (msi)->msi_vector)
こうなっている。
もう見れば一目瞭然かなと思うが、Physical Destination ModeでFixedな割り込みだ。
何の話かわからない人はぼくのスライドを読みなおして欲しい。
ってことは、誰かがどこかでこのremap処理を呼んでいない限りは、いつも初期化時に指定された同じCPUに割り込み続けられるわけだ。
初期化時に指定されるCPUが偏らないようになっていれば良いが、それでも各割り込みの割り込み量というのはNICとかNICとかのせいで偏りがちになるので、どうしても偏っているであろう。
まぁFreeBSDには割り込みスレッドがあるので負荷の偏りをだいぶ軽減するかもしれないけど。
ここまで出来ているなら、後は可視化(cat /proc/interrupts相当)とirqbalanced的なものがあるともう少しかっこよくなるのでは?