如何覆盖 NVME 设备的 IRQ 亲和性

如何覆盖 NVME 设备的 IRQ 亲和性

我正在尝试将所有中断移至核心 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

答案1

什么控制着这些设备的 IRQ 亲和性?

Linux 内核自v4.8自动使用MSI/MSI-XNVMe 驱动程序中的中断屏蔽;并使用IRQD_AFFINITY_MANAGED,自动管理内核中的 MSI/MSI-X 中断。

查看这些提交:

  1. 90c9712fbb388077b5e53069cae43f1acbb0102a- NVMe:始终使用 MSI/MSI-X 中断
  2. 9c2555835bb3d34dfac52a0be943dcc4bedd650f- genirq:引入IRQD_AFFINITY_MANAGED标志

通过输出查看您的内核版本和设备功能lspci -v,显然确实如此。

我该如何覆盖它?

除了禁用标志并重新编译内核之外,还可能禁用 PCI 桥(而不是设备)的 MSI/MSI-X:

echo 1 > /sys/bus/pci/devices/$bridge/msi_bus

请注意,禁用 MSI/MSI-X 会对性能产生影响。请参阅这个内核文档更多细节。

与其禁用 MSI/MSI-X,更好的方法是保留 MSI-X,同时在 NVMe 驱动程序中启用轮询模式。请参阅Andrew H 的回答

答案2

解决此问题最简单的方法可能就是将 NVMe 驱动程序从使用 IRQ/中断模式切换到轮询模式。

将其添加到/etc/modprobe.d/nvme.conf

options nvme poll_queues=4

然后运行update-initramfs -u,重新启动,您应该会看到 NVMe 设备的 IRQ 大幅减少。您还可以尝试使用 sysfs 中的轮询队列计数和其他 NVMe 驱动程序可调整项(modinfo NVMe应该会为您提供可调整的参数列表)

也就是说,这完全取决于您所运行的内核版本……

答案3

这是故意的。

NVMe 设备应该有多个带有相关中断的命令队列,因此中断可以传送到请求操作的 CPU。

对于模拟虚拟磁盘,这是运行 I/O 线程的 CPU,然后决定是否需要中断 VM CPU 以传递模拟中断。

对于 PCIe 直通磁盘,这是 VM CPU,它离开 VM,进入主机中断处理程序,该处理程序注意到该中断发往虚拟 CPU,并将其入队,以便在处理程序返回后在 VM 进入时将其传送到 VM,所以我们仍然只得到一个 VM 上下文中断。

这几乎是最佳选择。您可以通过将 IRQ 传送给另一个 CPU 来实现悲观的结果,该 CPU 随后会注意到 VM 需要中断,并将处理器间中断排队以将其引导到需要去的地方。

对于不属于 VM 的 I/O,中断应该转到与 VM 不关联的 CPU。

为了使其正常工作,虚拟机的 CPU 映射需要有一定的静态性。

还有CPU 隔离您可以看一下框架,但这可能太过严厉了。

相关内容