Re: [PATCH v1 1/1] nvme-pci: adaptive interrupt coalescing
Andy Shevchenko <[email protected]>
| Newsgroups | org.infradead.lists.linux-nvme,org.kernel.vger.linux-kernel |
|---|---|
| Organization | Intel Finland Oy - BIC 0357606-4 - c/o Alberga Business Park, 6 krs, Bertel Jungin Aukio 5, 02600 Espoo |
| Message-ID | <[email protected]> |
On Tue, Jul 21, 2026 at 04:37:39PM +0800, Fengnan Chang wrote: > The patch is included below. The above in this case can be moved to cover letter, in this form it's harder for maintainers to apply this. ... > From 1c84b5afc906e780e1dbd2ee186251f9de2716b5 Mon Sep 17 00:00:00 2001 > From: Fengnan Chang <[email protected]> > Date: Tue, 21 Jul 2026 12:31:46 +0800 > Subject: [PATCH] nvme-pci: adaptively poll busy queues from threaded > interrupts > > On systems with multiple fast NVMe devices, hard IRQ completion > processing can become CPU-bound and cap 4K random-read throughput > before the devices are saturated. > > Add adaptive polling for busy interrupt-driven queues. Track the SQ head > reported by completions while the CQE is still owned by the host. After > the hard IRQ reaps pending CQEs, wake the IRQ thread and mask the queue > interrupt when the number of SQ entries not yet consumed reaches a high > watermark. Poll in the IRQ thread until the queue drops below a low > watermark or a bounded loop count is reached, then reenable the > interrupt. > > Only enable adaptive polling when the controller has independent > vectors, as masking a shared single vector could suppress unrelated > queues. Expose the enable switch, watermarks, loop bound, and sleep > interval as module parameters. ... > +static irqreturn_t nvme_adaptive_poll(int irq, void *data) > { > struct nvme_queue *nvmeq = data; > + unsigned int loops = 0; Unneeded. See below how. > + unsigned int max_loops = READ_ONCE(adaptive_poll_max_loops); > + unsigned int sleep_min = READ_ONCE(adaptive_poll_sleep_min_us); > + unsigned int sleep_max = READ_ONCE(adaptive_poll_sleep_max_us); > > - if (nvme_cqe_pending(nvmeq)) > - return IRQ_WAKE_THREAD; > - return IRQ_NONE; > + do { > + if (nvme_cqe_pending(nvmeq)) > + nvme_irq(irq, data); > + if (nvme_adaptive_poll_should_stop(nvmeq)) > + break; > + usleep_range(sleep_min, sleep_max); fsleep() ? This automatically makes the upper bound ~25% of the requested value. Supplying max in this situation makes not much sense. > + } while (++loops < max_loops); } while (--max_loops); > + enable_irq(irq); > + return IRQ_HANDLED; > +} -- With Best Regards, Andy Shevchenko