我正在尝试将所有中断移至核心 0-3,以保持其余核心空闲,以实现高速、低延迟的虚拟化。
我写了一个快速脚本来将 IRQ 亲和性设置为 0-3:
#!/bin/bash
while IFS= read -r LINE; do
echo "0-3 -> \"$LINE\""
sudo bash -c "echo 0-3 > \"$LINE\""
done <<< "$(find /proc/irq/ -name smp_affinity_list)"
这似乎适用于 USB 设备和网络设备,但不适用于 NVME 设备。他们都产生这个错误:
bash: line 1: echo: write error: Input/output error
他们顽固地继续在我几乎所有的核心上均匀地产生中断。
如果我检查这些设备的当前亲和力:
$ cat /proc/irq/81/smp_affinity_list
0-1,16-17
$ cat /proc/irq/82/smp_affinity_list
2-3,18-19
$ cat /proc/irq/83/smp_affinity_list
4-5,20-21
$ cat /proc/irq/84/smp_affinity_list
6-7,22-23
...
似乎“某事”正在完全控制跨核心传播 IRQ,而不是让我改变它。
将这些移到其他内核是完全关键的,因为我在这些内核上的虚拟机中执行大量 IO,并且 NVME 驱动器正在产生大量的中断负载。这不是 Windows,我应该能够决定我的机器做什么。
什么是控制这些设备的 IRQ 亲和性以及如何覆盖它?
我在 Gigabyte Auros X570 Master 主板上使用 Ryzen 3950X CPU,3 个 NVME 驱动器连接到主板上的 M.2 端口。
(更新:我现在使用的是 5950X,仍然有完全相同的问题)
内核:5.12.2-arch1-1
lspci -v
与 NVME 相关的输出:
01:00.0 Non-Volatile memory controller: Phison Electronics Corporation E12 NVMe Controller (rev 01) (prog-if 02 [NVM Express])
Subsystem: Phison Electronics Corporation E12 NVMe Controller
Flags: bus master, fast devsel, latency 0, IRQ 45, NUMA node 0, IOMMU group 14
Memory at fc100000 (64-bit, non-prefetchable) [size=16K]
Capabilities: [80] Express Endpoint, MSI 00
Capabilities: [d0] MSI-X: Enable+ Count=9 Masked-
Capabilities: [e0] MSI: Enable- Count=1/8 Maskable- 64bit+
Capabilities: [f8] Power Management version 3
Capabilities: [100] Latency Tolerance Reporting
Capabilities: [110] L1 PM Substates
Capabilities: [128] Alternative Routing-ID Interpretation (ARI)
Capabilities: [200] Advanced Error Reporting
Capabilities: [300] Secondary PCI Express
Kernel driver in use: nvme
04:00.0 Non-Volatile memory controller: Phison Electronics Corporation E12 NVMe Controller (rev 01) (prog-if 02 [NVM Express])
Subsystem: Phison Electronics Corporation E12 NVMe Controller
Flags: bus master, fast devsel, latency 0, IRQ 24, NUMA node 0, IOMMU group 25
Memory at fbd00000 (64-bit, non-prefetchable) [size=16K]
Capabilities: [80] Express Endpoint, MSI 00
Capabilities: [d0] MSI-X: Enable+ Count=9 Masked-
Capabilities: [e0] MSI: Enable- Count=1/8 Maskable- 64bit+
Capabilities: [f8] Power Management version 3
Capabilities: [100] Latency Tolerance Reporting
Capabilities: [110] L1 PM Substates
Capabilities: [128] Alternative Routing-ID Interpretation (ARI)
Capabilities: [200] Advanced Error Reporting
Capabilities: [300] Secondary PCI Express
Kernel driver in use: nvme
05:00.0 Non-Volatile memory controller: Phison Electronics Corporation E12 NVMe Controller (rev 01) (prog-if 02 [NVM Express])
Subsystem: Phison Electronics Corporation E12 NVMe Controller
Flags: bus master, fast devsel, latency 0, IRQ 40, NUMA node 0, IOMMU group 26
Memory at fbc00000 (64-bit, non-prefetchable) [size=16K]
Capabilities: [80] Express Endpoint, MSI 00
Capabilities: [d0] MSI-X: Enable+ Count=9 Masked-
Capabilities: [e0] MSI: Enable- Count=1/8 Maskable- 64bit+
Capabilities: [f8] Power Management version 3
Capabilities: [100] Latency Tolerance Reporting
Capabilities: [110] L1 PM Substates
Capabilities: [128] Alternative Routing-ID Interpretation (ARI)
Capabilities: [200] Advanced Error Reporting
Capabilities: [300] Secondary PCI Express
Kernel driver in use: nvme
$ dmesg | grep -i nvme
[ 2.042888] nvme nvme0: pci function 0000:01:00.0
[ 2.042912] nvme nvme1: pci function 0000:04:00.0
[ 2.042941] nvme nvme2: pci function 0000:05:00.0
[ 2.048103] nvme nvme0: missing or invalid SUBNQN field.
[ 2.048109] nvme nvme2: missing or invalid SUBNQN field.
[ 2.048109] nvme nvme1: missing or invalid SUBNQN field.
[ 2.048112] nvme nvme0: Shutdown timeout set to 10 seconds
[ 2.048120] nvme nvme1: Shutdown timeout set to 10 seconds
[ 2.048127] nvme nvme2: Shutdown timeout set to 10 seconds
[ 2.049578] nvme nvme0: 8/0/0 default/read/poll queues
[ 2.049668] nvme nvme1: 8/0/0 default/read/poll queues
[ 2.049716] nvme nvme2: 8/0/0 default/read/poll queues
[ 2.051211] nvme1n1: p1
[ 2.051260] nvme2n1: p1
[ 2.051577] nvme0n1: p1 p2
这个问题最简单的解决方案可能只是从使用 IRQ/中断模式切换到 NVMe 驱动程序的轮询模式。
将此添加到
/etc/modprobe.d/nvme.conf
:然后运行
update-initramfs -u
,重新启动,您应该会看到 NVMe 设备的 IRQ 大大减少。您还可以在 sysfs 和其他 NVMe 驱动程序可调整项中使用轮询队列计数(modinfo NVMe
应该为您提供可以调整的参数列表)也就是说,这完全取决于您正在运行的内核版本......
自v4.8以来的Linux 内核在 NVMe 驱动程序中自动使用MSI/MSI-X中断屏蔽;和
IRQD_AFFINITY_MANAGED
, 自动管理内核中的 MSI/MSI-X 中断。查看这些提交:
90c9712fbb388077b5e53069cae43f1acbb0102a
- NVMe:始终使用 MSI/MSI-X 中断9c2555835bb3d34dfac52a0be943dcc4bedd650f
- genirq:引入IRQD_AFFINITY_MANAGED
标志通过输出查看您的内核版本和设备功能
lspci -v
,显然是这样。除了禁用标志和重新编译内核之外,还可能禁用 MSI/MSI-X 到您的 PCI 桥接器(而不是设备):
请注意,禁用 MSI/MSI-X 会对性能产生影响。有关更多详细信息,请参阅此内核文档。
除了禁用 MSI/MSI-X,更好的方法是保留 MSI-X,同时在 NVMe 驱动程序中启用轮询模式。请参阅Andrew H 的回答。
那是故意的。
NVMe 设备应该有多个带有相关中断的命令队列,因此可以将中断传递给请求操作的 CPU。
对于模拟虚拟磁盘,这是运行 I/O 线程的 CPU,然后决定是否需要中断 VM CPU 以传递模拟中断。
对于PCIe直通磁盘,这是VM CPU,它离开VM,进入主机中断处理程序,它注意到中断是针对虚拟CPU的,并将其入队以便在VM进入后交付给VM处理程序返回,因此我们仍然只获得一次 VM 上下文中断。
这几乎是最佳的。您可以通过将 IRQ 传递给另一个 CPU 来对此感到悲观,然后它会注意到 VM 需要中断,并将处理器间中断排队以将其引导到需要去的地方。
对于不属于 VM 的 I/O,中断应该转到与 VM 无关的 CPU。
为了使其正常工作,VM 的 CPU 映射需要保持一定程度的静态。
您还可以查看CPU 隔离框架,但这可能过于严厉。