NVMe驱动中断绑定

本文讨论了NVMe驱动中断绑定的问题,指出在CentOS 6.6及之前的版本中,NVMe设备默认绑定在NUMA节点的第一个core,可能导致CPU锁。而在CentOS 7.1中,NVMe设备会绑定到所有NUMA节点的core上。通过查看中断分布,可以分析和优化NVMe设备的性能。
摘要由CSDN通过智能技术生成


NVMe驱动中断绑定

1. 要想理清绑定先把irqbalance关闭

2.  Kernel 和NVMe 驱动都可以和中断绑定相关

a. CentOS 6.6 之前的版本,NVMe 设备默认是绑定在最近的NUMA node的的第一个core,. 如果有多个强悍的PCIe SSD 在一个core上就有问题啦(CPU lock),哈哈!

[root@memblaze-lyk2 wa-script]# cat /etc/issue
CentOS release 6.6 (Final)

[root@memblaze-lyk2 wa-script]# fio --rw=write --iodepth=64 --numjobs=12 --loop=1 --bs=4k --ioengine=libaio --output=precond-1.log --name=preCondJob --filename=/dev/nvme0n1 --direct=1

[root@memblaze-lyk2 wa-script]# cat /proc/interrupts | grep nvme
109: 524206 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge nvme0q0, nvme0q1
110: 301 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-MSI-edge nvme0q2
111: 297792 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 IR-PCI-

在 Linux 5.17.12 内核版本中,可以通过修改 `pci_alloc_irq_vectors_affinity()` 函数的 `affinity_hint` 参数来绑定 NVMe 驱动的所有 I/O 队列到同一 CPU 核心上。 以下是示例代码: ```c static int nvme_setup_io_queues(struct nvme_dev *dev) { int err, qid; cpumask_var_t mask; // 分配 CPU 核心亲和性掩码 mask = alloc_cpumask_var(GFP_KERNEL); if (!mask) return -ENOMEM; // 将所有 CPU 核心添加到掩码中 cpumask_setall(mask); // 为每个 I/O 队列分配中断向量 for (qid = 0; qid < dev->ctrl.queue_count; qid++) { struct nvme_queue *nvmeq = &dev->queues[qid]; struct nvme_q_vector *q = &dev->q_vectors[qid]; struct pci_dev *pdev = to_pci_dev(dev->dev); irqreturn_t (*irq_fn)(int, void *); // 设置中断处理函数 irq_fn = nvme_irq; // 分配中断向量 err = pci_alloc_irq_vectors_affinity(pdev, 1, 1, PCI_IRQ_MSIX, q->num_vecs, mask, &q->affinity_hint); if (err < 0) { dev_err(dev->ctrl.device, "Failed to allocate IRQ vectors\n"); goto err_irq_vectors; } // 绑定 I/O 队列和中断向量 nvmeq->cq_vector = q->cq_vector = q->affinity_hint; nvmeq->sq_vector = q->sq_vector = q->affinity_hint; err = request_irq(pci_irq_vector(pdev, q->affinity_hint), irq_fn, IRQF_SHARED, dev_name(dev->dev), nvmeq); if (err < 0) { dev_err(dev->ctrl.device, "Failed to request IRQ %d\n", pci_irq_vector(pdev, q->affinity_hint)); goto err_request_irq; } } free_cpumask_var(mask); return 0; err_request_irq: for (; qid >= 0; qid--) { struct nvme_q_vector *q = &dev->q_vectors[qid]; struct pci_dev *pdev = to_pci_dev(dev->dev); free_irq(pci_irq_vector(pdev, q->affinity_hint), &dev->queues[qid]); } err_irq_vectors: for (; qid >= 0; qid--) { struct nvme_q_vector *q = &dev->q_vectors[qid]; struct pci_dev *pdev = to_pci_dev(dev->dev); if (q->affinity_hint >= 0) pci_free_irq_vectors(pdev); } free_cpumask_var(mask); return err; } ``` 在此示例代码中,我们使用 `alloc_cpumask_var()` 函数来分配一个 CPU 核心亲和性掩码,然后使用 `cpumask_setall()` 函数将所有 CPU 核心添加到掩码中。接下来,我们使用 `pci_alloc_irq_vectors_affinity()` 函数为每个 I/O 队列分配中断向量,并将 `affinity_hint` 参数设置为掩码,以绑定所有 I/O 队列到同一 CPU 核心。最后,我们使用 `request_irq()` 函数将每个 I/O 队列和中断向量绑定在一起,以便在中断处理程序中处理 I/O 完成事件。 请注意,NVMe 驱动的代码可能因版本而异,因此请根据您使用的内核版本和驱动版本进行适当的修改。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值