Re: [PATCH v10 00/14] Allow preemption during IPI completion waiting to improve real-time performance

From: Chuyi Zhou

Date: Tue Aug 11 2026 - 23:56:48 EST


On 2026-07-24 3:26 a.m., Borislav Petkov wrote:
> On Thu, Jul 09, 2026 at 08:29:19PM +0800, Chuyi Zhou wrote:
>> In our production environments, latency-sensitive workloads (DPDK) are
>> configured with the highest priority to preempt lower-priority tasks at any
>> time. We discovered that DPDK's wake-up latency is primarily caused by the
>> current CPU having preemption disabled. Therefore, we collected the maximum
>> preemption disabled events within every 30-second interval and then
>> calculated the P50/P99 of these max preemption disabled events:
>
> Out of curiosity, can you run your workloads on AMD Zen3 and newer which have
> TLBI support (this does away with the TLB flush IPIs). Do you see any
> improvement there?
>
> Thx.
>

Hi Boris,

Thanks! I think this can be tested without setting up DPDK. DPDK was
only the latency-sensitive workload which exposed the problem in our
production environment.

The direct effect of this series is to shorten the preemption-disabled
section around a synchronous TLB-shootdown IPI. A more direct test would
therefore be to generate TLB flushes and compare the maximum preempt-off
latency between the baseline and patched kernels.

I have not tested the following setup on INVLPGB-capable hardware
myself. I have only checked it against the kernel and stress-ng code, so
please treat this as a suggested starting point rather than a known-good
reproducer. The workload or tracing may need some adjustment if it does
not hit the expected paths.

Two stress-ng stressors appear useful for separating the INVLPGB and IPI
cases.

1. INVLPGB/global-ASID path

A recent stress-ng, starting with v0.21.01, has the tlb-numa
stressor:

stress-ng --tlb-numa 1 --timeout 5m --metrics-brief

One stressor instance runs a main thread and three pthreads sharing
the same mm. The threads move between CPUs and repeatedly perform
mmap(), munmap(), madvise(), and mbind() operations.

If the same mm is observed active on at least four CPUs
simultaneously, the kernel should initially use the IPI path, assign
a global ASID, and then switch to INVLPGB broadcast invalidation.

It would be better to let this workload warm up before starting the
trace. Once it reaches the global-ASID steady state, I would expect
little or no difference between the baseline and patched kernels,
since there is no remote IPI completion wait. The INVLPGB/TLBSYNC
sequence itself still has to remain within the CPU-pinned section.

2. IPI fallback path

The older tlb-shootdown stressor can be used separately:

stress-ng --tlb-shootdown 1 --timeout 5m --metrics-brief

This stressor forks several processes. Each process has a separate mm
and periodically migrates between CPUs while repeatedly executing
mprotect() and madvise(). Since each mm is normally active on only
one CPU at a time, it should not acquire a global ASID.

The mprotect()-generated flushes should therefore continue to use
the ordinary IPI path, even when INVLPGB is available. This is the
case where the reduction in the preemption-disabled section should
be visible.

With CONFIG_PREEMPT_TRACER=y, the test can simply compare the
preemption-disabled intervals attributed to the TLB flush paths on the
baseline and patched kernels. For the IPI case, the baseline interval
should include the remote IPI completion wait in csd_lock_wait(), while
the patched kernel should re-enable preemption before that wait.