* Re: [PATCH] sched: Further restrict the preemption modes
[not found] <20251219101502.GB1132199@noisy.programming.kicks-ass.net>
@ 2026-02-24 15:45 ` Ciunas Bennett
2026-02-24 17:11 ` Sebastian Andrzej Siewior
2026-02-25 2:30 ` Ilya Leoshkevich
0 siblings, 2 replies; 11+ messages in thread
From: Ciunas Bennett @ 2026-02-24 15:45 UTC (permalink / raw)
To: Peter Zijlstra, mingo, Thomas Gleixner, Sebastian Andrzej Siewior
Cc: juri.lelli, vincent.guittot, dietmar.eggemann, rostedt, bsegall,
mgorman, vschneid, clrkwllms, linux-kernel, linux-rt-devel,
Linus Torvalds, linux-s390
On 19/12/2025 10:15, Peter Zijlstra wrote:
Hi Peter,
We are observing a performance regression on s390 since enabling PREEMPT_LAZY.
Test Environment
Architecture: s390
Setup:
Single KVM host running two identical guests
Guests are connected virtually via Open vSwitch
Workload: uperf streaming read test with 50 parallel connections
One guest acts as the uperf client, the other as the server
Open vSwitch configuration:
OVS bridge with two ports
Guests attached via virtio‑net
Each guest configured with 4 vhost‑queues
Problem Description
When comparing PREEMPT_LAZY against full PREEMPT, we see a substantial drop in throughput—on some systems up to 50%.
Observed Behaviour
By tracing packets inside Open vSwitch (ovs_do_execute_action), we see:
Packet drops
Retransmissions
Reductions in packet size (from 64K down to 32K)
Capturing traffic inside the VM and inspecting it in Wireshark shows the following TCP‑level differences between PREEMPT_FULL and PREEMPT_LAZY:
|--------------------------------------+--------------+--------------+------------------|
| Wireshark Warning / Note | PREEMPT_FULL | PREEMPT_LAZY | (lazy vs full) |
|--------------------------------------+--------------+--------------+------------------|
| D-SACK Sequence | 309 | 2603 | ×8.4 |
| Partial Acknowledgement of a segment | 54 | 279 | ×5.2 |
| Ambiguous ACK (Karn) | 32 | 747 | ×23 |
| (Suspected) spurious retransmission | 205 | 857 | ×4.2 |
| (Suspected) fast retransmission | 54 | 1622 | ×30 |
| Duplicate ACK | 504 | 3446 | ×6.8 |
| Packet length exceeds MSS (TSO/GRO) | 13172 | 34790 | ×2.6 |
| Previous segment(s) not captured | 9205 | 6730 | -27% |
| ACKed segment that wasn't captured | 7022 | 8272 | +18% |
| (Suspected) out-of-order segment | 436 | 303 | -31% |
|--------------------------------------+--------------+--------------+------------------|
This pattern indicates reordering, loss, or scheduling‑related delays, but it is still unclear why PREEMPT_LAZY is causing this behaviour in this workload.
Additional observations:
Monitoring the guest CPU run time shows that it drops from 16% with PREEMPT_FULL to 9% with PREEMPT_LAZY.
The workload is dominated by voluntary preemption (schedule()), and PREEMPT_LAZY is, as far as I understand, mainly concerned with forced preemption.
It is therefore not obvious why PREEMPT_LAZY has an impact here.
Changing guest configuration to disable mergeable RX buffers:
<host mrg_rxbuf="off"/>
had a clear effect on throughput:
PREEMPT_LAZY: throughput improved from 40 Gb/s → 60 Gb/s
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] sched: Further restrict the preemption modes
2026-02-24 15:45 ` [PATCH] sched: Further restrict the preemption modes Ciunas Bennett
@ 2026-02-24 17:11 ` Sebastian Andrzej Siewior
2026-02-25 9:56 ` Ciunas Bennett
2026-02-25 2:30 ` Ilya Leoshkevich
1 sibling, 1 reply; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2026-02-24 17:11 UTC (permalink / raw)
To: Ciunas Bennett
Cc: Peter Zijlstra, mingo, Thomas Gleixner, juri.lelli,
vincent.guittot, dietmar.eggemann, rostedt, bsegall, mgorman,
vschneid, clrkwllms, linux-kernel, linux-rt-devel, Linus Torvalds,
linux-s390
On 2026-02-24 15:45:39 [+0000], Ciunas Bennett wrote:
> Monitoring the guest CPU run time shows that it drops from 16% with
> PREEMPT_FULL to 9% with PREEMPT_LAZY.
>
> The workload is dominated by voluntary preemption (schedule()), and
> PREEMPT_LAZY is, as far as I understand, mainly concerned with forced
> preemption.
> It is therefore not obvious why PREEMPT_LAZY has an impact here.
PREEMPT_FULL schedules immediately if there is a preemption request
either due to a wake up of a task, or because the time slice is used up
(while in kernel).
PREEMPT_LAZY delays the preemption request, caused by the scheduling
event, either until the task returns to userland or the next HZ tick.
The voluntary schedule() invocation shouldn't be effected by FULL-> LAZY
but I guess FULL scheduled more often after a wake up which is in
favour.
> Changing guest configuration to disable mergeable RX buffers:
> <host mrg_rxbuf="off"/>
> had a clear effect on throughput:
> PREEMPT_LAZY: throughput improved from 40 Gb/s → 60 Gb/s
>
Brings this the workload/ test to PREEMPT_FULL level?
Sebastian
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] sched: Further restrict the preemption modes
2026-02-24 15:45 ` [PATCH] sched: Further restrict the preemption modes Ciunas Bennett
2026-02-24 17:11 ` Sebastian Andrzej Siewior
@ 2026-02-25 2:30 ` Ilya Leoshkevich
2026-02-25 16:33 ` Christian Borntraeger
1 sibling, 1 reply; 11+ messages in thread
From: Ilya Leoshkevich @ 2026-02-25 2:30 UTC (permalink / raw)
To: Ciunas Bennett, Peter Zijlstra, mingo, Thomas Gleixner,
Sebastian Andrzej Siewior, Christian Borntraeger
Cc: juri.lelli, vincent.guittot, dietmar.eggemann, rostedt, bsegall,
mgorman, vschneid, clrkwllms, linux-kernel, linux-rt-devel,
Linus Torvalds, linux-s390
On 2/24/26 16:45, Ciunas Bennett wrote:
>
>
> On 19/12/2025 10:15, Peter Zijlstra wrote:
>
>
> Hi Peter,
> We are observing a performance regression on s390 since enabling
> PREEMPT_LAZY.
> Test Environment
> Architecture: s390
> Setup:
>
> Single KVM host running two identical guests
> Guests are connected virtually via Open vSwitch
> Workload: uperf streaming read test with 50 parallel connections
> One guest acts as the uperf client, the other as the server
>
> Open vSwitch configuration:
>
> OVS bridge with two ports
> Guests attached via virtio‑net
> Each guest configured with 4 vhost‑queues
>
> Problem Description
> When comparing PREEMPT_LAZY against full PREEMPT, we see a substantial
> drop in throughput—on some systems up to 50%.
>
> Observed Behaviour
> By tracing packets inside Open vSwitch (ovs_do_execute_action), we see:
> Packet drops
> Retransmissions
> Reductions in packet size (from 64K down to 32K)
>
> Capturing traffic inside the VM and inspecting it in Wireshark shows
> the following TCP‑level differences between PREEMPT_FULL and
> PREEMPT_LAZY:
> |--------------------------------------+--------------+--------------+------------------|
>
> | Wireshark Warning / Note | PREEMPT_FULL | PREEMPT_LAZY |
> (lazy vs full) |
> |--------------------------------------+--------------+--------------+------------------|
>
> | D-SACK Sequence | 309 | 2603 |
> ×8.4 |
> | Partial Acknowledgement of a segment | 54 | 279 |
> ×5.2 |
> | Ambiguous ACK (Karn) | 32 | 747 |
> ×23 |
> | (Suspected) spurious retransmission | 205 | 857 |
> ×4.2 |
> | (Suspected) fast retransmission | 54 | 1622 |
> ×30 |
> | Duplicate ACK | 504 | 3446 |
> ×6.8 |
> | Packet length exceeds MSS (TSO/GRO) | 13172 | 34790 |
> ×2.6 |
> | Previous segment(s) not captured | 9205 | 6730 |
> -27% |
> | ACKed segment that wasn't captured | 7022 | 8272 |
> +18% |
> | (Suspected) out-of-order segment | 436 | 303 |
> -31% |
> |--------------------------------------+--------------+--------------+------------------|
>
> This pattern indicates reordering, loss, or scheduling‑related delays,
> but it is still unclear why PREEMPT_LAZY is causing this behaviour in
> this workload.
>
> Additional observations:
>
> Monitoring the guest CPU run time shows that it drops from 16% with
> PREEMPT_FULL to 9% with PREEMPT_LAZY.
>
> The workload is dominated by voluntary preemption (schedule()), and
> PREEMPT_LAZY is, as far as I understand, mainly concerned with forced
> preemption.
> It is therefore not obvious why PREEMPT_LAZY has an impact here.
>
> Changing guest configuration to disable mergeable RX buffers:
> <host mrg_rxbuf="off"/>
> had a clear effect on throughput:
> PREEMPT_LAZY: throughput improved from 40 Gb/s → 60 Gb/s
When I look at top sched_switch kstacks on s390 with this workload, 20%
of them are worker_thread() -> schedule(), both with CONFIG_PREEMPT and
CONFIG_PREEMPT_LAZY. The others are vhost and idle.
On x86 I see only vhost and idle, but not worker_thread().
According to runqlat.bt, average run queue latency goes up from 4us to
18us when switching from CONFIG_PREEMPT to CONFIG_PREEMPT_LAZY.
I modified the script to show per-comm latencies, and it shows
that worker_thread() is disproportionately penalized: the latency
increases from 2us to 60us!
For vhost it's better: 5us -> 2us, and for KVM it's better too: 8us -> 2us.
Finally, what is the worker doing? I looked at __queue_work() kstacks,
and they all come from irqfd_wakeup().
irqfd_wakeup() calls arch-specific kvm_arch_set_irq_inatomic(), which is
implemented on x86 and not implemented on s390.
This may explain why we on s390 are the first to see this.
Christian, do you think if it would make sense to
implement kvm_arch_set_irq_inatomic() on s390?
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] sched: Further restrict the preemption modes
2026-02-24 17:11 ` Sebastian Andrzej Siewior
@ 2026-02-25 9:56 ` Ciunas Bennett
0 siblings, 0 replies; 11+ messages in thread
From: Ciunas Bennett @ 2026-02-25 9:56 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: Peter Zijlstra, mingo, Thomas Gleixner, juri.lelli,
vincent.guittot, dietmar.eggemann, rostedt, bsegall, mgorman,
vschneid, clrkwllms, linux-kernel, linux-rt-devel, Linus Torvalds,
linux-s390
On 24/02/2026 17:11, Sebastian Andrzej Siewior wrote:
> On 2026-02-24 15:45:39 [+0000], Ciunas Bennett wrote:
>> Changing guest configuration to disable mergeable RX buffers:
>> <host mrg_rxbuf="off"/>
>> had a clear effect on throughput:
>> PREEMPT_LAZY: throughput improved from 40 Gb/s → 60 Gb/s
>>
>
> Brings this the workload/ test to PREEMPT_FULL level?
>
Sorry was not clear here, so when I enable this there is also an improvement in PREEMPT_FULL
from 55Gb/s -> 60Gb/s
So I see an improvement in both test cases.
PREEMPT_LAZY: throughput improved from 40 Gb/s → 60 Gb/s
PREEMPT_FULL: throughput improved from 55 Gb/s → 60 Gb/s
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] sched: Further restrict the preemption modes
2026-02-25 2:30 ` Ilya Leoshkevich
@ 2026-02-25 16:33 ` Christian Borntraeger
2026-02-25 18:30 ` Douglas Freimuth
0 siblings, 1 reply; 11+ messages in thread
From: Christian Borntraeger @ 2026-02-25 16:33 UTC (permalink / raw)
To: Ilya Leoshkevich, Ciunas Bennett, Peter Zijlstra, mingo,
Thomas Gleixner, Sebastian Andrzej Siewior
Cc: juri.lelli, vincent.guittot, dietmar.eggemann, rostedt, bsegall,
mgorman, vschneid, clrkwllms, linux-kernel, linux-rt-devel,
Linus Torvalds, linux-s390, Douglas Freimuth, Matthew Rosato,
Hendrik Brueckner
Am 24.02.26 um 21:30 schrieb Ilya Leoshkevich:
> Finally, what is the worker doing? I looked at __queue_work() kstacks, and they all come from irqfd_wakeup().
>
> irqfd_wakeup() calls arch-specific kvm_arch_set_irq_inatomic(), which is implemented on x86 and not implemented on s390.
>
>
> This may explain why we on s390 are the first to see this.
>
>
> Christian, do you think if it would make sense to implement kvm_arch_set_irq_inatomic() on s390?
So in fact Doug is working on that at the moment. There are some corner
cases where we had concerns as we have to pin the guest pages holding
the interrupt bits. This was secure execution, I need to followup if
we have already solved those cases. But we can try if the current patch
will help this particular problem.
If yes, then we can try to speed up the work on this.
Christian
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] sched: Further restrict the preemption modes
2026-02-25 16:33 ` Christian Borntraeger
@ 2026-02-25 18:30 ` Douglas Freimuth
2026-03-03 9:15 ` Ciunas Bennett
0 siblings, 1 reply; 11+ messages in thread
From: Douglas Freimuth @ 2026-02-25 18:30 UTC (permalink / raw)
To: Christian Borntraeger, Ilya Leoshkevich, Ciunas Bennett,
Peter Zijlstra, mingo, Thomas Gleixner, Sebastian Andrzej Siewior
Cc: juri.lelli, vincent.guittot, dietmar.eggemann, rostedt, bsegall,
mgorman, vschneid, clrkwllms, linux-kernel, linux-rt-devel,
Linus Torvalds, linux-s390, Matthew Rosato, Hendrik Brueckner
On 2/25/26 11:33 AM, Christian Borntraeger wrote:
> Am 24.02.26 um 21:30 schrieb Ilya Leoshkevich:
>> Finally, what is the worker doing? I looked at __queue_work() kstacks,
>> and they all come from irqfd_wakeup().
>>
>> irqfd_wakeup() calls arch-specific kvm_arch_set_irq_inatomic(), which
>> is implemented on x86 and not implemented on s390.
>>
>>
>> This may explain why we on s390 are the first to see this.
>>
>>
>> Christian, do you think if it would make sense to
>> implement kvm_arch_set_irq_inatomic() on s390?
>
> So in fact Doug is working on that at the moment. There are some corner
> cases where we had concerns as we have to pin the guest pages holding
> the interrupt bits. This was secure execution, I need to followup if
> we have already solved those cases. But we can try if the current patch
> will help this particular problem.
>
> If yes, then we can try to speed up the work on this.
>
> Christian
Christian, the patch is very close to ready. The last step, I rebased on
Master today to pickup the latest changes to interrupt.c. I am building
that now and will test for non-SE and SE environments. I have been
testing my solution for SE environments for a few weeks and it seems to
cover the use cases I have tested.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] sched: Further restrict the preemption modes
2026-02-25 18:30 ` Douglas Freimuth
@ 2026-03-03 9:15 ` Ciunas Bennett
2026-03-03 11:52 ` Peter Zijlstra
0 siblings, 1 reply; 11+ messages in thread
From: Ciunas Bennett @ 2026-03-03 9:15 UTC (permalink / raw)
To: Douglas Freimuth, Christian Borntraeger, Ilya Leoshkevich,
Peter Zijlstra, mingo, Thomas Gleixner, Sebastian Andrzej Siewior
Cc: juri.lelli, vincent.guittot, dietmar.eggemann, rostedt, bsegall,
mgorman, vschneid, clrkwllms, linux-kernel, linux-rt-devel,
Linus Torvalds, linux-s390, Matthew Rosato, Hendrik Brueckner
A quick update on the issue.
Introducing kvm_arch_set_irq_inatomic() appears to make the problem go away on my setup.
That said, this still begs the question: why does irqfd_wakeup behave differently (or poorly) in this scenario compared to the in-atomic IRQ injection path?
Is there a known interaction with workqueues, contexts, or locking that would explain the divergence here?
Observations:
irqfd_wakeup: triggers the problematic behaviour.
Forcing in-atomic IRQ injection (kvm_arch_set_irq_inatomic): issue not observed.
@Peter Zijlstra — Peter, do you have thoughts on how the workqueue scheduling context here could differ enough to cause this regression?
Any pointers on what to trace specifically in irqfd_wakeup and the work item path would be appreciated.
Thanks,
Ciunas Bennett
On 25/02/2026 18:30, Douglas Freimuth wrote:
>
> Christian, the patch is very close to ready. The last step, I rebased on Master today to pickup the latest changes to interrupt.c. I am building that now and will test for non-SE and SE environments. I have been testing my solution for SE environments for a few weeks and it seems to cover the use cases I have tested.
>
>
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] sched: Further restrict the preemption modes
2026-03-03 9:15 ` Ciunas Bennett
@ 2026-03-03 11:52 ` Peter Zijlstra
2026-06-05 10:43 ` Ciunas Bennett
0 siblings, 1 reply; 11+ messages in thread
From: Peter Zijlstra @ 2026-03-03 11:52 UTC (permalink / raw)
To: Ciunas Bennett
Cc: Douglas Freimuth, Christian Borntraeger, Ilya Leoshkevich, mingo,
Thomas Gleixner, Sebastian Andrzej Siewior, juri.lelli,
vincent.guittot, dietmar.eggemann, rostedt, bsegall, mgorman,
vschneid, clrkwllms, linux-kernel, linux-rt-devel, Linus Torvalds,
linux-s390, Matthew Rosato, Hendrik Brueckner
On Tue, Mar 03, 2026 at 09:15:55AM +0000, Ciunas Bennett wrote:
> A quick update on the issue.
> Introducing kvm_arch_set_irq_inatomic() appears to make the problem go away on my setup.
> That said, this still begs the question: why does irqfd_wakeup behave differently (or poorly) in this scenario compared to the in-atomic IRQ injection path?
> Is there a known interaction with workqueues, contexts, or locking that would explain the divergence here?
>
> Observations:
> irqfd_wakeup: triggers the problematic behaviour.
> Forcing in-atomic IRQ injection (kvm_arch_set_irq_inatomic): issue not observed.
>
> @Peter Zijlstra — Peter, do you have thoughts on how the workqueue scheduling context here could differ enough to cause this regression?
> Any pointers on what to trace specifically in irqfd_wakeup and the work item path would be appreciated.
So the thing that LAZY does different from FULL is that it delays
preemption a bit.
This has two ramifications:
1) some ping-pong workloads will turn into block+wakeup, adding
overhead.
FULL: running your task A, an interrupt would come in, wake task B and
set Need Resched and the interrupt return path calls schedule() and
you're task B. B does its thing, 'wakes' A and blocks.
LAZY: running your task A, an interrupt would come in, wake task B (no
NR set), you continue running A, A blocks for it needs something of B,
now you schedule() [*] B runs, does its thing, does an actual wakeup of
A and blocks.
The distinct difference here is that LAZY does a block of A and
consequently B has to do a full wakeup of A, whereas FULL doesn't do a
block of A, and hence the wakeup of A is NOP as well.
2) Since the schedule() is delayed, it might happen that by the time it
does get around to it, your task B is no longer the most eligible
option.
Same as above, except now, C is also woken, and the schedule marked with
[*] picks C, this then results in a detour, delaying things further.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] sched: Further restrict the preemption modes
2026-03-03 11:52 ` Peter Zijlstra
@ 2026-06-05 10:43 ` Ciunas Bennett
2026-06-05 10:52 ` Sebastian Andrzej Siewior
0 siblings, 1 reply; 11+ messages in thread
From: Ciunas Bennett @ 2026-06-05 10:43 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Douglas Freimuth, Christian Borntraeger, Ilya Leoshkevich, mingo,
Thomas Gleixner, Sebastian Andrzej Siewior, juri.lelli,
vincent.guittot, dietmar.eggemann, rostedt, bsegall, mgorman,
vschneid, clrkwllms, linux-kernel, linux-rt-devel, Linus Torvalds,
linux-s390, Matthew Rosato, Hendrik Brueckner
On 03/03/2026 11:52, Peter Zijlstra wrote:
> This has two ramifications:
>
> 1) some ping-pong workloads will turn into block+wakeup, adding
> overhead.
>
> FULL: running your task A, an interrupt would come in, wake task B and
> set Need Resched and the interrupt return path calls schedule() and
> you're task B. B does its thing, 'wakes' A and blocks.
>
> LAZY: running your task A, an interrupt would come in, wake task B (no
> NR set), you continue running A, A blocks for it needs something of B,
> now you schedule() [*] B runs, does its thing, does an actual wakeup of
> A and blocks.
>
> The distinct difference here is that LAZY does a block of A and
> consequently B has to do a full wakeup of A, whereas FULL doesn't do a
> block of A, and hence the wakeup of A is NOP as well.
>
>
> 2) Since the schedule() is delayed, it might happen that by the time it
> does get around to it, your task B is no longer the most eligible
> option.
>
> Same as above, except now, C is also woken, and the schedule marked with
> [*] picks C, this then results in a detour, delaying things further.
>
>
>
Hi Peter,
I wanted to share an update/findings from the investigations that I carried out for the issue mentioned above.
Quick refresh:
Workload: uperf sending TCP data between two VMs (client and server), each configured with a single vhost queue (min vhost ques for testing)
Issue: With lazy preemption as the default preemption mode where previously it was full preemption, there is a significant drop in performance for this workload
Simplification of the issue
We have two tasks:
TaskA produces data
TaskB consumes the data produced by TaskA
Notification path: TaskA informs TaskB that new data is available by adding a new item to a workqueue. This triggers a kworker which runs and notifies TaskB.
Issue
TaskA is configured to use schedule_work(). Internally, schedule_work() uses system_percpu_wq, which is configured as:
<WQ_PERCPU = 1 << 8, /* bound to a specific cpu */>
This means the workqueue item will be woken up and executed on the same CPU that queued the work.
If the task that queues the work (TaskA) is a long-running task with limited opportunities to call schedule(), then the kworker may be delayed significantly before it gets CPU time.
In our scenario:
TaskA continuously produces data
There is no dependency requiring TaskA to yield due to TaskB
As a result, TaskA can occupy the CPU for an entire tick before being preempted by the kworker
Observed behavior
This is exactly what we observe in practice:
TaskB corresponds to the VM consuming data generated by our vhost task
When running uperf, this behavior leads to a significant drop in throughput (Gb/s)
The VM is unable to consume data in a timely manner
When it is finally notified of new data, the delayed signaling introduces jitter
This causes TCP issues, including retransmissions and out-of-order packets
Results:
|--------------+-----+------------------+------------------------|
| preempt mode | Gbs | workqueue pool | kworker latency avg ms |
|--------------+-----+------------------+------------------------|
| full | ~50 | system_percpu_wq | 0.002 |
| lazy | ~13 | system_percpu_wq | 0.721 |
| lazy | ~50 | system_dfl_wq | 0.005 |
|--------------+-----+------------------+------------------------|
So I did some more testing and if I use a different workqueue pool the system_dfl_wq the TP was good again, as you can see in the results table.
Since the kworker is not CPU-bound, the scheduler has flexibility to select a more suitable CPU for execution.
/* system_dfl_wq is unbound workqueue. Workers are not bound to
* any specific CPU, not concurrency managed, and all queued works are
* executed immediately as long as max_active limit is not reached and
* resources are available. */
Given this understanding, what would be the best approach here? Should we consider changing the workqueue usage in the KVM code, or do you see an alternative way to address this issue?
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] sched: Further restrict the preemption modes
2026-06-05 10:43 ` Ciunas Bennett
@ 2026-06-05 10:52 ` Sebastian Andrzej Siewior
2026-06-05 11:01 ` Ciunas Bennett
0 siblings, 1 reply; 11+ messages in thread
From: Sebastian Andrzej Siewior @ 2026-06-05 10:52 UTC (permalink / raw)
To: Ciunas Bennett
Cc: Peter Zijlstra, Douglas Freimuth, Christian Borntraeger,
Ilya Leoshkevich, mingo, Thomas Gleixner, juri.lelli,
vincent.guittot, dietmar.eggemann, rostedt, bsegall, mgorman,
vschneid, clrkwllms, linux-kernel, linux-rt-devel, Linus Torvalds,
linux-s390, Matthew Rosato, Hendrik Brueckner, Marco Crivellari
On 2026-06-05 11:43:24 [+0100], Ciunas Bennett wrote:
…
> Quick refresh:
> Workload: uperf sending TCP data between two VMs (client and server), each configured with a single vhost queue (min vhost ques for testing)
> Issue: With lazy preemption as the default preemption mode where previously it was full preemption, there is a significant drop in performance for this workload
>
> Simplification of the issue
> We have two tasks:
>
> TaskA produces data
> TaskB consumes the data produced by TaskA
>
> Notification path: TaskA informs TaskB that new data is available by
> adding a new item to a workqueue. This triggers a kworker which runs
> and notifies TaskB.
>
> Issue
> TaskA is configured to use schedule_work(). Internally, schedule_work() uses system_percpu_wq, which is configured as:
> <WQ_PERCPU = 1 << 8, /* bound to a specific cpu */>
>
> This means the workqueue item will be woken up and executed on the same CPU that queued the work.
> If the task that queues the work (TaskA) is a long-running task with
> limited opportunities to call schedule(), then the kworker may be
> delayed significantly before it gets CPU time.
There is some work done by Marco to rework the API to explicitly state
if a per-CPU workqueue is mandatory _or_ if an CPU unbound workqueue can
be used instead. (Rather than having schedule_work() not knowing the
implications).
> In our scenario:
>
> TaskA continuously produces data
> There is no dependency requiring TaskA to yield due to TaskB
> As a result, TaskA can occupy the CPU for an entire tick before being preempted by the kworker
>
> Observed behavior
> This is exactly what we observe in practice:
>
> TaskB corresponds to the VM consuming data generated by our vhost task
> When running uperf, this behavior leads to a significant drop in throughput (Gb/s)
> The VM is unable to consume data in a timely manner
> When it is finally notified of new data, the delayed signaling introduces jitter
> This causes TCP issues, including retransmissions and out-of-order packets
>
> Results:
> |--------------+-----+------------------+------------------------|
> | preempt mode | Gbs | workqueue pool | kworker latency avg ms |
> |--------------+-----+------------------+------------------------|
> | full | ~50 | system_percpu_wq | 0.002 |
> | lazy | ~13 | system_percpu_wq | 0.721 |
> | lazy | ~50 | system_dfl_wq | 0.005 |
> |--------------+-----+------------------+------------------------|
>
> So I did some more testing and if I use a different workqueue pool the system_dfl_wq the TP was good again, as you can see in the results table.
> Since the kworker is not CPU-bound, the scheduler has flexibility to select a more suitable CPU for execution.
>
> /* system_dfl_wq is unbound workqueue. Workers are not bound to
> * any specific CPU, not concurrency managed, and all queued works are
> * executed immediately as long as max_active limit is not reached and
> * resources are available. */
>
> Given this understanding, what would be the best approach here? Should
> we consider changing the workqueue usage in the KVM code, or do you
> see an alternative way to address this issue?
It seems that using an unbound worker would avoid the problem at hand,
correct?
Sebastian
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH] sched: Further restrict the preemption modes
2026-06-05 10:52 ` Sebastian Andrzej Siewior
@ 2026-06-05 11:01 ` Ciunas Bennett
0 siblings, 0 replies; 11+ messages in thread
From: Ciunas Bennett @ 2026-06-05 11:01 UTC (permalink / raw)
To: Sebastian Andrzej Siewior
Cc: Peter Zijlstra, Douglas Freimuth, Christian Borntraeger,
Ilya Leoshkevich, mingo, Thomas Gleixner, juri.lelli,
vincent.guittot, dietmar.eggemann, rostedt, bsegall, mgorman,
vschneid, clrkwllms, linux-kernel, linux-rt-devel, Linus Torvalds,
linux-s390, Matthew Rosato, Hendrik Brueckner, Marco Crivellari
>> delayed significantly before it gets CPU time.
>
> There is some work done by Marco to rework the API to explicitly state
> if a per-CPU workqueue is mandatory _or_ if an CPU unbound workqueue can
> be used instead. (Rather than having schedule_work() not knowing the
> implications).
Oh, that is good some work already being done here.
I had a small patch ready to go, but possibly the solution needs to be more robust.
- schedule_work(&irqfd->inject);
+ queue_work(system_dfl_wq, &irqfd->inject);
> It seems that using an unbound worker would avoid the problem at hand,
> correct?
>
> Sebastian
Yeah, changing to an unbound kworker avoids the issue in any of the testing I have done.
Ciunas
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-06-05 11:02 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20251219101502.GB1132199@noisy.programming.kicks-ass.net>
2026-02-24 15:45 ` [PATCH] sched: Further restrict the preemption modes Ciunas Bennett
2026-02-24 17:11 ` Sebastian Andrzej Siewior
2026-02-25 9:56 ` Ciunas Bennett
2026-02-25 2:30 ` Ilya Leoshkevich
2026-02-25 16:33 ` Christian Borntraeger
2026-02-25 18:30 ` Douglas Freimuth
2026-03-03 9:15 ` Ciunas Bennett
2026-03-03 11:52 ` Peter Zijlstra
2026-06-05 10:43 ` Ciunas Bennett
2026-06-05 10:52 ` Sebastian Andrzej Siewior
2026-06-05 11:01 ` Ciunas Bennett
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox