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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.