计算 SMP IRQ Affinity

前天我们讨论了如何绑定特定的硬件中断到特定的 CPU 上,分散和平衡各个中断到不同的 CPU 上以获取更大性能的处理能力。上篇限于篇幅的关系,没有来得及进一步说明 “echo 2 > /proc/irq/90/smp_affinity” 中的 ”2“ 是怎么来的,这其实是个二进制数字,代表 00000010,00000001 代表 CPU0 的话,00000010 就代表 CPU1, “echo 2 > /proc/irq/90/smp_affinity” 的意思就是说把 90 中断绑定到 00000010(CPU1)上。所以各个 CPU 用二进制和十六进制表示就是:

               Binary       Hex 
    CPU 0    00000001         1 
    CPU 1    00000010         2
    CPU 2    00000100         4
    CPU 3    00001000         8

如果我想把 IRQ 绑定到 CPU2 上就是 00000100=4:

# echo "4" > /proc/irq/90/smp_affinity

如果我想把 IRQ 同时平衡到 CPU0 和 CPU2 上就是 00000001+00000100=00000101=5

# echo "5" > /proc/irq/90/smp_affinity

需要注意的是,在手动绑定 IRQ 到 CPU 之前需要先停掉 irqbalance 这个服务,irqbalance 是个服务进程、是用来自动绑定和平衡 IRQ 的:

# /etc/init.d/irqbalance stop

还有一个限制就是,IO-APIC 有两种工作模式:logic 和 physical,在 logic 模式下 IO-APIC 可以同时分布同一种 IO 中断到8颗 CPU (core) 上(受到 bitmask 寄存器的限制,因为 bitmask 只有8位长。);在 physical 模式下不能同时分布同一中断到不同 CPU 上,比如,不能让 eth0 中断同时由 CPU0 和 CPU1 处理,这个时候只能定位 eth0 到 CPU0、eth1 到 CPU1,也就是说 eth0 中断不能像 logic 模式那样可以同时由多个 CPU 处理。

评论 (17 Comments)

  1. 说的很详细.昨天晚上我也给我的同学演示了如何将一个网卡中断在单独的一个CPU上,昨天在16核的CPU测试中照上述方法计算感觉好像有点我问题. 今天我在测试下 但是在8核以下的CPU没有遇到问题

  2. CPU 0 00000001 1
    CPU 1 00000010 2
    CPU 2 00000100 4
    CPU 3 00001000 8
    CPU 4 00010000 16
    CPU 5 00100000 32

    请教下 我这么理解对么?

  3. 好东西呀。。
    转载了。

  4. 嗯,可以这样理解。

  5. 嗯,IO-APIC 在 logical 模式下只能支持到8核。

  6. 刚刚测试在16核的情况下按上方法计算没有问题。下面给大家提供一个计算小脚本值提供中断在单CPU上
    #!/bin/bash
    #Author Jiaion MSN:Jiaion@msn.com
    [ $# -ne 1 ] && echo ‘$1 is Cpu core number’ && exit 1

    CCN=$1
    echo “Print eth0 affinity”
    for((i=0; i<${CCN}; i++))
    do
    echo ==============================
    echo "Cpu Core $i is affinity"
    ((affinity=(1<<i)))
    echo "obase=16;${affinity}" | bc
    echo ==============================
    done

  7. IO-APIC两种工作模式logic 和 physical,请问我怎么才能知道他工作在哪种模式呢?

  8. 直接在 /proc/interrupts 就可以看到,下面的 Phys-irq 和 Dynamic-irq 就是 Physical/Fixed 和 Logical/Dynamic 两种工作模式:
    $ cat /proc/interrupts
    CPU0 CPU1
    1: 2 0 Phys-irq i8042
    8: 0 0 Phys-irq rtc
    9: 0 0 Phys-irq acpi

    256: 425649090 0 Dynamic-irq timer0
    257: 6986967 0 Dynamic-irq resched0
    258: 44 0 Dynamic-irq callfunc0

  9. “00000001 代表 CPU0 的话,00000010 就代表 CPU0”
    一句有误.
    另请问能更改IO-APIC的两种工作模式吗?

  10. 嗯,谢谢,已经更正。
    有的 BIOS 支持关闭和开启 IO-APIC,不能更改工作模式。

  11. 刚看到这篇文章,讲的很清楚,只是在我的服务器上 cat /proc/interrupts的结果是:
    CPU0 CPU1
    0: 199129585 0 IO-APIC-edge timer
    8: 1 0 IO-APIC-edge rtc
    9: 0 0 IO-APIC-level acpi
    14: 4039669 3090365 IO-APIC-edge ide0
    50: 180979 156252 IO-APIC-level libata, ehci_hcd:usb1, uhci_hcd:usb2
    107: 131753 0 PCI-MSI eth0
    169: 5959191 155732875 IO-APIC-level eth1
    177: 0 0 IO-APIC-level uhci_hcd:usb3
    185: 16906 3776 IO-APIC-level uhci_hcd:usb4

    比如我的网卡eth1为IO-APIC-level,那么它应该是physical模式还是logic模式呢?
    谢谢!

  12. 2楼是错误的,应该是hex,16进制哦。
    1
    2
    4
    8
    10
    20
    40
    80
    100
    。。。

  13. 受益匪浅,支持&感谢

  14. 同一个队列貌似不支持分配给多个CPU核心,不知道是否与操作系统有关。多余的核心空闲怎么办呢?比如我现在是万兆网卡有16个队列,CPU为24核,有8个核始终空闲。请楼主支招。

  15. hi 博主,请教下

    >> 一种 IO 中断到8颗 CPU (core) 上(受到 bitmask 寄存器的限制,因为 bitmask 只有8位长。)

    /proc/irq/IRQ#/smp_affinity的值最大是ffffffff,那一个IO中断应该不止绑定到8个CPU上?

    如果按上面的算法,一个io中断是不可能绑定到第9个以后的CPU?
    如果我理解错误,请指正

  16. @Mr_Zh
    嗯嗯,好问题。我们现在用的 APIC (Advanced Programmable Interrupt Controller) 只能支持前8个 cpu cores,也就是说第9个 cpu core 开始不再接受中断了,所有中断都由前8个 cpu cores 完成。

  17. @Jessi
    请问你的问题解决了吗,我的输出也是和你一样的

发表评论