* [PATCH v4 0/1] powerpc: Enable dynamic preemption @ 2025-02-10 18:43 Shrikanth Hegde 2025-02-10 18:43 ` [PATCH v4 1/1] powerpc: enable " Shrikanth Hegde 0 siblings, 1 reply; 35+ messages in thread From: Shrikanth Hegde @ 2025-02-10 18:43 UTC (permalink / raw) To: maddy, linuxppc-dev, christophe.leroy Cc: sshegde, mpe, npiggin, bigeasy, will, linux-kernel Now that preempt=lazy patches are merged upstream, sending out the patch to support dynamic preemption based on DYNAMIC_KEY. Once the arch supports static inline calls, it would be needed to evaluate to see if that gives better performance. This makes the same code for arm64 and powerpc. Will be sending an RFC patch to move this static key into sched/core. v3->v4: - Use static key instead of using preempt_model_preemptible (Sebastian Andrzej Siewior and Christophe Leroy) - Dropped printing the preemption model, since it is addressed in a patchset from Sebastian Andrzej Siewior v2->v3: - fixed a build error reported by linux test robot by including jump label header. v1->v2: - Instead of copying asm-generic preempt.h content include it in arch/asm preempt.h. (Christophe Leroy) - Merge the patches into one patch (Christophe Leroy) v3: https://lore.kernel.org/all/20250106051919.55020-1-sshegde@linux.ibm.com/ Shrikanth Hegde (1): powerpc: enable dynamic preemption arch/powerpc/Kconfig | 1 + arch/powerpc/include/asm/preempt.h | 16 ++++++++++++++++ arch/powerpc/kernel/interrupt.c | 6 +++++- arch/powerpc/lib/vmx-helper.c | 2 +- 4 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 arch/powerpc/include/asm/preempt.h -- 2.39.3 ^ permalink raw reply [flat|nested] 35+ messages in thread
* [PATCH v4 1/1] powerpc: enable dynamic preemption 2025-02-10 18:43 [PATCH v4 0/1] powerpc: Enable dynamic preemption Shrikanth Hegde @ 2025-02-10 18:43 ` Shrikanth Hegde 2026-07-26 18:33 ` Jirka Hladky 0 siblings, 1 reply; 35+ messages in thread From: Shrikanth Hegde @ 2025-02-10 18:43 UTC (permalink / raw) To: maddy, linuxppc-dev, christophe.leroy Cc: sshegde, mpe, npiggin, bigeasy, will, linux-kernel Once the lazy preemption is supported, it would be desirable to change the preemption models at runtime. So add support for dynamic preemption using DYNAMIC_KEY. ::Tested lightly on Power10 LPAR Performance numbers indicate that, preempt=none(no dynamic) and preempt=none(dynamic) are close. cat /sys/kernel/debug/sched/preempt (none) voluntary full lazy perf stat -e probe:__cond_resched -a sleep 1 Performance counter stats for 'system wide': 1,253 probe:__cond_resched echo full > /sys/kernel/debug/sched/preempt cat /sys/kernel/debug/sched/preempt none voluntary (full) lazy perf stat -e probe:__cond_resched -a sleep 1 Performance counter stats for 'system wide': 0 probe:__cond_resched Signed-off-by: Shrikanth Hegde <sshegde@linux.ibm.com> --- arch/powerpc/Kconfig | 1 + arch/powerpc/include/asm/preempt.h | 16 ++++++++++++++++ arch/powerpc/kernel/interrupt.c | 6 +++++- arch/powerpc/lib/vmx-helper.c | 2 +- 4 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 arch/powerpc/include/asm/preempt.h diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 424f188e62d9..364edaea1f88 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -275,6 +275,7 @@ config PPC select HAVE_PERF_EVENTS_NMI if PPC64 select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP + select HAVE_PREEMPT_DYNAMIC_KEY select HAVE_RETHOOK if KPROBES select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_RELIABLE_STACKTRACE diff --git a/arch/powerpc/include/asm/preempt.h b/arch/powerpc/include/asm/preempt.h new file mode 100644 index 000000000000..000e2b9681f3 --- /dev/null +++ b/arch/powerpc/include/asm/preempt.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASM_POWERPC_PREEMPT_H +#define __ASM_POWERPC_PREEMPT_H + +#include <asm-generic/preempt.h> + +#if defined(CONFIG_PREEMPT_DYNAMIC) +#include <linux/jump_label.h> +DECLARE_STATIC_KEY_TRUE(sk_dynamic_irqentry_exit_cond_resched); +#define need_irq_preemption() \ + (static_branch_unlikely(&sk_dynamic_irqentry_exit_cond_resched)) +#else +#define need_irq_preemption() (IS_ENABLED(CONFIG_PREEMPTION)) +#endif + +#endif /* __ASM_POWERPC_PREEMPT_H */ diff --git a/arch/powerpc/kernel/interrupt.c b/arch/powerpc/kernel/interrupt.c index 8f4acc55407b..e0c681d0b076 100644 --- a/arch/powerpc/kernel/interrupt.c +++ b/arch/powerpc/kernel/interrupt.c @@ -25,6 +25,10 @@ unsigned long global_dbcr0[NR_CPUS]; #endif +#if defined(CONFIG_PREEMPT_DYNAMIC) +DEFINE_STATIC_KEY_TRUE(sk_dynamic_irqentry_exit_cond_resched); +#endif + #ifdef CONFIG_PPC_BOOK3S_64 DEFINE_STATIC_KEY_FALSE(interrupt_exit_not_reentrant); static inline bool exit_must_hard_disable(void) @@ -396,7 +400,7 @@ notrace unsigned long interrupt_exit_kernel_prepare(struct pt_regs *regs) /* Returning to a kernel context with local irqs enabled. */ WARN_ON_ONCE(!(regs->msr & MSR_EE)); again: - if (IS_ENABLED(CONFIG_PREEMPTION)) { + if (need_irq_preemption()) { /* Return to preemptible kernel context */ if (unlikely(read_thread_flags() & _TIF_NEED_RESCHED)) { if (preempt_count() == 0) diff --git a/arch/powerpc/lib/vmx-helper.c b/arch/powerpc/lib/vmx-helper.c index 58ed6bd613a6..54340912398f 100644 --- a/arch/powerpc/lib/vmx-helper.c +++ b/arch/powerpc/lib/vmx-helper.c @@ -45,7 +45,7 @@ int exit_vmx_usercopy(void) * set and we are preemptible. The hack here is to schedule a * decrementer to fire here and reschedule for us if necessary. */ - if (IS_ENABLED(CONFIG_PREEMPTION) && need_resched()) + if (need_irq_preemption() && need_resched()) set_dec(1); return 0; } -- 2.39.3 ^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2025-02-10 18:43 ` [PATCH v4 1/1] powerpc: enable " Shrikanth Hegde @ 2026-07-26 18:33 ` Jirka Hladky 2026-07-27 4:18 ` Shrikanth Hegde 0 siblings, 1 reply; 35+ messages in thread From: Jirka Hladky @ 2026-07-26 18:33 UTC (permalink / raw) To: Shrikanth Hegde Cc: maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel, Jirka Hladky Hi Shrikanth, Christophe, I'm seeing a significant performance regression on ppc64le after this patch landed in 6.16, caused by CONFIG_PREEMPT_RCU becoming active once HAVE_PREEMPT_DYNAMIC_KEY is selected. Benchmark: stress-ng kill stressor (tight kill() syscall loop), single thread, POWER10 LPAR (8 vCPUs, 1 core SMT-8). Bisected across Fedora ELN kernel builds on ppc64le: kernel CONFIG_PREEMPT_RCU kill bogo-ops/sec --- 6.15-rc6 (eln148) no 103,207 6.16 (eln150) yes 70,281 (-32%) 6.18 (eln154) yes 72,552 (-30%) For comparison, x86_64 (AMD EPYC 9355P) with the same config change shows only a 2.8% regression: 6.12 x86_64 37,436 7.2 x86_64 36,392 (-2.8%) perf report shows the overhead comes from rcu_read_lock/unlock in the SELinux AVC path (check_kill_permission -> security_task_kill -> selinux_task_kill -> avc_has_perm -> avc_lookup): Function 6.15 (no PREEMPT_RCU) 6.16 (PREEMPT_RCU) --- avc_lookup 15.23% 24.79% __rcu_read_lock ~0% 4.52% __rcu_read_unlock ~0% 4.17% selinux_task_kill 6.23% 7.35% audit_signal_info* 0.94% 3.59% On x86_64, rcu_read_lock/unlock are cheap thanks to static calls (HAVE_PREEMPT_DYNAMIC_CALL). On ppc64le with the KEY-based implementation, the weak memory model requires real barriers (lwsync/isync) making each RCU read-side critical section significantly more expensive. This aligns with Christophe's earlier review comment that HAVE_PREEMPT_DYNAMIC_CALL should be more performant. Would implementing static calls for ppc64 be feasible to close this gap? Test details: - Machine: IBM POWER10 (pvr 0080 0200), pHyp virtualization - stress-ng 0.21.03, gcc 14.3.1, glibc 2.39 - Tuned profile: virtual-guest - SELinux: enforcing (permissive recovers only ~7%) Happy to run additional tests if needed. On Mon, Feb 10, 2025 at 7:46 PM Shrikanth Hegde <sshegde@linux.ibm.com> wrote: > > Once the lazy preemption is supported, it would be desirable to change > the preemption models at runtime. So add support for dynamic preemption > using DYNAMIC_KEY. > > ::Tested lightly on Power10 LPAR > Performance numbers indicate that, preempt=none(no dynamic) and > preempt=none(dynamic) are close. > > cat /sys/kernel/debug/sched/preempt > (none) voluntary full lazy > perf stat -e probe:__cond_resched -a sleep 1 > Performance counter stats for 'system wide': > 1,253 probe:__cond_resched > > echo full > /sys/kernel/debug/sched/preempt > cat /sys/kernel/debug/sched/preempt > none voluntary (full) lazy > perf stat -e probe:__cond_resched -a sleep 1 > Performance counter stats for 'system wide': > 0 probe:__cond_resched > > Signed-off-by: Shrikanth Hegde <sshegde@linux.ibm.com> > --- > arch/powerpc/Kconfig | 1 + > arch/powerpc/include/asm/preempt.h | 16 ++++++++++++++++ > arch/powerpc/kernel/interrupt.c | 6 +++++- > arch/powerpc/lib/vmx-helper.c | 2 +- > 4 files changed, 23 insertions(+), 2 deletions(-) > create mode 100644 arch/powerpc/include/asm/preempt.h > > diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig > index 424f188e62d9..364edaea1f88 100644 > --- a/arch/powerpc/Kconfig > +++ b/arch/powerpc/Kconfig > @@ -275,6 +275,7 @@ config PPC > select HAVE_PERF_EVENTS_NMI if PPC64 > select HAVE_PERF_REGS > select HAVE_PERF_USER_STACK_DUMP > + select HAVE_PREEMPT_DYNAMIC_KEY > select HAVE_RETHOOK if KPROBES > select HAVE_REGS_AND_STACK_ACCESS_API > select HAVE_RELIABLE_STACKTRACE > diff --git a/arch/powerpc/include/asm/preempt.h b/arch/powerpc/include/asm/preempt.h > new file mode 100644 > index 000000000000..000e2b9681f3 > --- /dev/null > +++ b/arch/powerpc/include/asm/preempt.h > @@ -0,0 +1,16 @@ > +/* SPDX-License-Identifier: GPL-2.0 */ > +#ifndef __ASM_POWERPC_PREEMPT_H > +#define __ASM_POWERPC_PREEMPT_H > + > +#include <asm-generic/preempt.h> > + > +#if defined(CONFIG_PREEMPT_DYNAMIC) > +#include <linux/jump_label.h> > +DECLARE_STATIC_KEY_TRUE(sk_dynamic_irqentry_exit_cond_resched); > +#define need_irq_preemption() \ > + (static_branch_unlikely(&sk_dynamic_irqentry_exit_cond_resched)) > +#else > +#define need_irq_preemption() (IS_ENABLED(CONFIG_PREEMPTION)) > +#endif > + > +#endif /* __ASM_POWERPC_PREEMPT_H */ > diff --git a/arch/powerpc/kernel/interrupt.c b/arch/powerpc/kernel/interrupt.c > index 8f4acc55407b..e0c681d0b076 100644 > --- a/arch/powerpc/kernel/interrupt.c > +++ b/arch/powerpc/kernel/interrupt.c > @@ -25,6 +25,10 @@ > unsigned long global_dbcr0[NR_CPUS]; > #endif > > +#if defined(CONFIG_PREEMPT_DYNAMIC) > +DEFINE_STATIC_KEY_TRUE(sk_dynamic_irqentry_exit_cond_resched); > +#endif > + > #ifdef CONFIG_PPC_BOOK3S_64 > DEFINE_STATIC_KEY_FALSE(interrupt_exit_not_reentrant); > static inline bool exit_must_hard_disable(void) > @@ -396,7 +400,7 @@ notrace unsigned long interrupt_exit_kernel_prepare(struct pt_regs *regs) > /* Returning to a kernel context with local irqs enabled. */ > WARN_ON_ONCE(!(regs->msr & MSR_EE)); > again: > - if (IS_ENABLED(CONFIG_PREEMPTION)) { > + if (need_irq_preemption()) { > /* Return to preemptible kernel context */ > if (unlikely(read_thread_flags() & _TIF_NEED_RESCHED)) { > if (preempt_count() == 0) > diff --git a/arch/powerpc/lib/vmx-helper.c b/arch/powerpc/lib/vmx-helper.c > index 58ed6bd613a6..54340912398f 100644 > --- a/arch/powerpc/lib/vmx-helper.c > +++ b/arch/powerpc/lib/vmx-helper.c > @@ -45,7 +45,7 @@ int exit_vmx_usercopy(void) > * set and we are preemptible. The hack here is to schedule a > * decrementer to fire here and reschedule for us if necessary. > */ > - if (IS_ENABLED(CONFIG_PREEMPTION) && need_resched()) > + if (need_irq_preemption() && need_resched()) > set_dec(1); > return 0; > } > -- > 2.39.3 > > -- -Jirka ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-26 18:33 ` Jirka Hladky @ 2026-07-27 4:18 ` Shrikanth Hegde 2026-07-27 10:13 ` Jirka Hladky 2026-07-27 16:07 ` Paul E. McKenney 0 siblings, 2 replies; 35+ messages in thread From: Shrikanth Hegde @ 2026-07-27 4:18 UTC (permalink / raw) To: Jirka Hladky Cc: maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel, Paul E . McKenney +cc paul for any further/RCU insights. On 7/27/26 12:03 AM, Jirka Hladky wrote: > Hi Shrikanth, Christophe, > Hi Jirka, thanks for the report. > I'm seeing a significant performance regression on ppc64le after this > patch landed in 6.16, caused by CONFIG_PREEMPT_RCU becoming active > once HAVE_PREEMPT_DYNAMIC_KEY is selected. > This is true only if user selected PREEMPT_DYNAMIC option i think. config PREEMPT_RCU bool default y if (PREEMPT || PREEMPT_RT || PREEMPT_DYNAMIC) select TREE_RCU > Benchmark: stress-ng kill stressor (tight kill() syscall loop), > single thread, POWER10 LPAR (8 vCPUs, 1 core SMT-8). > > Bisected across Fedora ELN kernel builds on ppc64le: > > kernel CONFIG_PREEMPT_RCU kill bogo-ops/sec > --- 6.15-rc6 (eln148) no 103,207 > 6.16 (eln150) yes 70,281 (-32%) > 6.18 (eln154) yes 72,552 (-30%) > Does your preemption mode remain the same in two cases? > For comparison, x86_64 (AMD EPYC 9355P) with the same config change > shows only a 2.8% regression: > > 6.12 x86_64 37,436 > 7.2 x86_64 36,392 (-2.8%) > > perf report shows the overhead comes from rcu_read_lock/unlock in the > SELinux AVC path (check_kill_permission -> security_task_kill -> > selinux_task_kill -> avc_has_perm -> avc_lookup): > > Function 6.15 (no PREEMPT_RCU) 6.16 (PREEMPT_RCU) > --- avc_lookup 15.23% 24.79% > __rcu_read_lock ~0% 4.52% > __rcu_read_unlock ~0% 4.17% > selinux_task_kill 6.23% 7.35% > audit_signal_info* 0.94% 3.59% > > On x86_64, rcu_read_lock/unlock are cheap thanks to static calls > (HAVE_PREEMPT_DYNAMIC_CALL). On ppc64le with the KEY-based > implementation, the weak memory model requires real barriers > (lwsync/isync) making each RCU read-side critical section > significantly more expensive. Weak memory model would need barriers irrespective of HAVE_PREEMPT_DYNAMIC_CALL or HAVE_PREEMPT_DYNAMIC_KEY. That's my assumption. I will look more into it. Also i don't know much about PREEMPT_RCU. So might take a while. > > This aligns with Christophe's earlier review comment that > HAVE_PREEMPT_DYNAMIC_CALL should be more performant. Would > implementing static calls for ppc64 be feasible to close this gap? > Static key too is expected to minimal cost. There maybe more into this. > Test details: > - Machine: IBM POWER10 (pvr 0080 0200), pHyp virtualization > - stress-ng 0.21.03, gcc 14.3.1, glibc 2.39 > - Tuned profile: virtual-guest > - SELinux: enforcing (permissive recovers only ~7%) > > Happy to run additional tests if needed. > > ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-27 4:18 ` Shrikanth Hegde @ 2026-07-27 10:13 ` Jirka Hladky 2026-07-27 10:28 ` Shrikanth Hegde 2026-07-27 12:34 ` Shrikanth Hegde 2026-07-27 16:07 ` Paul E. McKenney 1 sibling, 2 replies; 35+ messages in thread From: Jirka Hladky @ 2026-07-27 10:13 UTC (permalink / raw) To: Shrikanth Hegde Cc: maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel, Paul E . McKenney Hi Shrikanth, Thanks for the quick response and for looping in Paul. > This is true only if user selected PREEMPT_DYNAMIC option i think. Yes, exactly. The issue is that CONFIG_PREEMPT_DYNAMIC=y has been in the Fedora/RHEL kernel config since kernel 5.16 (2021). It was silently ignored on ppc64le until your 6.16 patch added HAVE_PREEMPT_DYNAMIC_KEY, so this is the first time PREEMPT_RCU actually takes effect for all Fedora/RHEL ppc64le users. > Does your preemption mode remain the same in two cases? Verified. On 6.15-rc6 (before PREEMPT_DYNAMIC takes effect): CONFIG_PREEMPT_VOLUNTARY=y (no CONFIG_PREEMPT_DYNAMIC, no /sys/kernel/debug/sched/preempt) On both 7.1 and 7.2-rc4 (with PREEMPT_DYNAMIC active): CONFIG_PREEMPT_LAZY=y CONFIG_PREEMPT_DYNAMIC=y CONFIG_PREEMPT_RCU=y cat /sys/kernel/debug/sched/preempt: "full (lazy)" So the runtime preemption mode is the same on 7.1 and 7.2. The difference between 6.15 and 7.1+ is that the preemption model changed from voluntary (static) to full/lazy (dynamic), which is what pulls in PREEMPT_RCU. > Weak memory model would need barriers irrespective of > HAVE_PREEMPT_DYNAMIC_CALL or HAVE_PREEMPT_DYNAMIC_KEY. > Static key too is expected to minimal cost. You're right, I should clarify -- the overhead is not in the static key mechanism itself. The cost comes from __rcu_read_lock() and __rcu_read_unlock() which are called when CONFIG_PREEMPT_RCU=y. These need real memory barriers (lwsync/isync) on ppc64le regardless of whether the dynamic mechanism uses keys or calls. The real question is: why does enabling PREEMPT_RCU cost ~33% on ppc64le but only ~3% on x86_64? The answer is that x86_64's TSO memory model makes the barriers in __rcu_read_lock/__rcu_read_unlock essentially free, while ppc64le's weak ordering requires explicit lwsync/isync instructions, which are expensive when called thousands of times per second in the SELinux AVC hot path. I also have new data from SELinux isolation testing that helps quantify this. On kernel 7.1 (which already has PREEMPT_RCU=y): SELinux mode kill bogo-ops/sec vs enforcing ------------ ----------------- ------------ Enforcing 69,107 baseline Permissive 70,248 +1.6% Disabled 93,566 +35.4% Permissive ~ enforcing confirms the overhead is not in SELinux policy evaluation. Disabling SELinux removes the rcu_read_lock/unlock call sites in the AVC path and recovers most of the performance -- but still leaves a ~13% gap vs 6.12 (no PREEMPT_RCU), which is the base cost of PREEMPT_RCU in the non-SELinux parts of the kill() path. So the core issue is: on ppc64le, CONFIG_PREEMPT_RCU makes rcu_read_lock/unlock significantly more expensive, and the kill() syscall path hits them very heavily through SELinux AVC lookups. Thanks, Jirka On Mon, Jul 27, 2026 at 6:19 AM Shrikanth Hegde <sshegde@linux.ibm.com> wrote: > > +cc paul for any further/RCU insights. > > On 7/27/26 12:03 AM, Jirka Hladky wrote: > > Hi Shrikanth, Christophe, > > > > Hi Jirka, thanks for the report. > > > I'm seeing a significant performance regression on ppc64le after this > > patch landed in 6.16, caused by CONFIG_PREEMPT_RCU becoming active > > once HAVE_PREEMPT_DYNAMIC_KEY is selected. > > > > This is true only if user selected PREEMPT_DYNAMIC option i think. > > config PREEMPT_RCU > bool > default y if (PREEMPT || PREEMPT_RT || PREEMPT_DYNAMIC) > select TREE_RCU > > > > Benchmark: stress-ng kill stressor (tight kill() syscall loop), > > single thread, POWER10 LPAR (8 vCPUs, 1 core SMT-8). > > > > Bisected across Fedora ELN kernel builds on ppc64le: > > > > kernel CONFIG_PREEMPT_RCU kill bogo-ops/sec > > --- 6.15-rc6 (eln148) no 103,207 > > 6.16 (eln150) yes 70,281 (-32%) > > 6.18 (eln154) yes 72,552 (-30%) > > > > Does your preemption mode remain the same in two cases? > > > For comparison, x86_64 (AMD EPYC 9355P) with the same config change > > shows only a 2.8% regression: > > > > 6.12 x86_64 37,436 > > 7.2 x86_64 36,392 (-2.8%) > > > > perf report shows the overhead comes from rcu_read_lock/unlock in the > > SELinux AVC path (check_kill_permission -> security_task_kill -> > > selinux_task_kill -> avc_has_perm -> avc_lookup): > > > > Function 6.15 (no PREEMPT_RCU) 6.16 (PREEMPT_RCU) > > --- avc_lookup 15.23% 24.79% > > __rcu_read_lock ~0% 4.52% > > __rcu_read_unlock ~0% 4.17% > > selinux_task_kill 6.23% 7.35% > > audit_signal_info* 0.94% 3.59% > > > > On x86_64, rcu_read_lock/unlock are cheap thanks to static calls > > (HAVE_PREEMPT_DYNAMIC_CALL). On ppc64le with the KEY-based > > implementation, the weak memory model requires real barriers > > (lwsync/isync) making each RCU read-side critical section > > significantly more expensive. > > Weak memory model would need barriers irrespective of HAVE_PREEMPT_DYNAMIC_CALL > or HAVE_PREEMPT_DYNAMIC_KEY. That's my assumption. I will look > more into it. Also i don't know much about PREEMPT_RCU. So might take a while. > > > > > This aligns with Christophe's earlier review comment that > > HAVE_PREEMPT_DYNAMIC_CALL should be more performant. Would > > implementing static calls for ppc64 be feasible to close this gap? > > > > Static key too is expected to minimal cost. There maybe more into this. > > > Test details: > > - Machine: IBM POWER10 (pvr 0080 0200), pHyp virtualization > > - stress-ng 0.21.03, gcc 14.3.1, glibc 2.39 > > - Tuned profile: virtual-guest > > - SELinux: enforcing (permissive recovers only ~7%) > > > > Happy to run additional tests if needed. > > > > > -- -Jirka ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-27 10:13 ` Jirka Hladky @ 2026-07-27 10:28 ` Shrikanth Hegde 2026-07-27 10:35 ` Christophe Leroy (CS GROUP) 2026-07-27 10:59 ` Jirka Hladky 2026-07-27 12:34 ` Shrikanth Hegde 1 sibling, 2 replies; 35+ messages in thread From: Shrikanth Hegde @ 2026-07-27 10:28 UTC (permalink / raw) To: Jirka Hladky Cc: maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel, Paul E . McKenney Hi Jirka, Please avoid top-posting. On 7/27/26 3:43 PM, Jirka Hladky wrote: > Hi Shrikanth, > > Thanks for the quick response and for looping in Paul. > >> This is true only if user selected PREEMPT_DYNAMIC option i think. > > Yes, exactly. The issue is that CONFIG_PREEMPT_DYNAMIC=y has been in > the Fedora/RHEL kernel config since kernel 5.16 (2021). It was > silently ignored on ppc64le until your 6.16 patch added > HAVE_PREEMPT_DYNAMIC_KEY, so this is the first time PREEMPT_RCU > actually takes effect for all Fedora/RHEL ppc64le users. > >> Does your preemption mode remain the same in two cases? > > Verified. On 6.15-rc6 (before PREEMPT_DYNAMIC takes effect): > > CONFIG_PREEMPT_VOLUNTARY=y > (no CONFIG_PREEMPT_DYNAMIC, no /sys/kernel/debug/sched/preempt) > > On both 7.1 and 7.2-rc4 (with PREEMPT_DYNAMIC active): > > CONFIG_PREEMPT_LAZY=y > CONFIG_PREEMPT_DYNAMIC=y > CONFIG_PREEMPT_RCU=y > cat /sys/kernel/debug/sched/preempt: "full (lazy)" > > So the runtime preemption mode is the same on 7.1 and 7.2. The > difference between 6.15 and 7.1+ is that the preemption model changed > from voluntary (static) to full/lazy (dynamic), which is what pulls > in PREEMPT_RCU. That means comparison is between preempt=voluntary vs preempt=lazy. If you make it full preemption in 6.15 you will likely see similar data as 7.1+. Only on 7.0/7.1 there is force switch to lazy/full. Can you give that a try? If it shows same data, that implies the regression is mainly due to change of preemption modes, rather than the static key stuff. > >> Weak memory model would need barriers irrespective of >> HAVE_PREEMPT_DYNAMIC_CALL or HAVE_PREEMPT_DYNAMIC_KEY. >> Static key too is expected to minimal cost. > > You're right, I should clarify -- the overhead is not in the static > key mechanism itself. The cost comes from __rcu_read_lock() and > __rcu_read_unlock() which are called when CONFIG_PREEMPT_RCU=y. > These need real memory barriers (lwsync/isync) on ppc64le regardless > of whether the dynamic mechanism uses keys or calls. > > The real question is: why does enabling PREEMPT_RCU cost ~33% on > ppc64le but only ~3% on x86_64? The answer is that x86_64's TSO > memory model makes the barriers in __rcu_read_lock/__rcu_read_unlock > essentially free, while ppc64le's weak ordering requires explicit > lwsync/isync instructions, which are expensive when called thousands > of times per second in the SELinux AVC hot path. Plus, it may call schedule in lazy/pull preemption. > > I also have new data from SELinux isolation testing that helps > quantify this. On kernel 7.1 (which already has PREEMPT_RCU=y): > > SELinux mode kill bogo-ops/sec vs enforcing > ------------ ----------------- ------------ > Enforcing 69,107 baseline > Permissive 70,248 +1.6% > Disabled 93,566 +35.4% > > Permissive ~ enforcing confirms the overhead is not in SELinux policy > evaluation. Disabling SELinux removes the rcu_read_lock/unlock call > sites in the AVC path and recovers most of the performance -- but > still leaves a ~13% gap vs 6.12 (no PREEMPT_RCU), which is the base > cost of PREEMPT_RCU in the non-SELinux parts of the kill() path. > This seems strange. How come rcu lock/unlock depends on SELinux policy? One should call rcu lock/unlock if they are working with rcu updated fields. Does the policy change itself protected with rcu lock/unlock? I will check it up. > So the core issue is: on ppc64le, CONFIG_PREEMPT_RCU makes > rcu_read_lock/unlock significantly more expensive, and the kill() > syscall path hits them very heavily through SELinux AVC lookups. > > Thanks, > Jirka > > On Mon, Jul 27, 2026 at 6:19 AM Shrikanth Hegde <sshegde@linux.ibm.com> wrote: >> >> +cc paul for any further/RCU insights. >> >> On 7/27/26 12:03 AM, Jirka Hladky wrote: >>> Hi Shrikanth, Christophe, >>> >> >> Hi Jirka, thanks for the report. >> >>> I'm seeing a significant performance regression on ppc64le after this >>> patch landed in 6.16, caused by CONFIG_PREEMPT_RCU becoming active >>> once HAVE_PREEMPT_DYNAMIC_KEY is selected. >>> >> >> This is true only if user selected PREEMPT_DYNAMIC option i think. >> >> config PREEMPT_RCU >> bool >> default y if (PREEMPT || PREEMPT_RT || PREEMPT_DYNAMIC) >> select TREE_RCU >> >> >>> Benchmark: stress-ng kill stressor (tight kill() syscall loop), >>> single thread, POWER10 LPAR (8 vCPUs, 1 core SMT-8). >>> >>> Bisected across Fedora ELN kernel builds on ppc64le: >>> >>> kernel CONFIG_PREEMPT_RCU kill bogo-ops/sec >>> --- 6.15-rc6 (eln148) no 103,207 >>> 6.16 (eln150) yes 70,281 (-32%) >>> 6.18 (eln154) yes 72,552 (-30%) >>> >> >> Does your preemption mode remain the same in two cases? >> >>> For comparison, x86_64 (AMD EPYC 9355P) with the same config change >>> shows only a 2.8% regression: >>> >>> 6.12 x86_64 37,436 >>> 7.2 x86_64 36,392 (-2.8%) >>> >>> perf report shows the overhead comes from rcu_read_lock/unlock in the >>> SELinux AVC path (check_kill_permission -> security_task_kill -> >>> selinux_task_kill -> avc_has_perm -> avc_lookup): >>> >>> Function 6.15 (no PREEMPT_RCU) 6.16 (PREEMPT_RCU) >>> --- avc_lookup 15.23% 24.79% >>> __rcu_read_lock ~0% 4.52% >>> __rcu_read_unlock ~0% 4.17% >>> selinux_task_kill 6.23% 7.35% >>> audit_signal_info* 0.94% 3.59% >>> >>> On x86_64, rcu_read_lock/unlock are cheap thanks to static calls >>> (HAVE_PREEMPT_DYNAMIC_CALL). On ppc64le with the KEY-based >>> implementation, the weak memory model requires real barriers >>> (lwsync/isync) making each RCU read-side critical section >>> significantly more expensive. >> >> Weak memory model would need barriers irrespective of HAVE_PREEMPT_DYNAMIC_CALL >> or HAVE_PREEMPT_DYNAMIC_KEY. That's my assumption. I will look >> more into it. Also i don't know much about PREEMPT_RCU. So might take a while. >> >>> >>> This aligns with Christophe's earlier review comment that >>> HAVE_PREEMPT_DYNAMIC_CALL should be more performant. Would >>> implementing static calls for ppc64 be feasible to close this gap? >>> >> >> Static key too is expected to minimal cost. There maybe more into this. >> >>> Test details: >>> - Machine: IBM POWER10 (pvr 0080 0200), pHyp virtualization >>> - stress-ng 0.21.03, gcc 14.3.1, glibc 2.39 >>> - Tuned profile: virtual-guest >>> - SELinux: enforcing (permissive recovers only ~7%) >>> >>> Happy to run additional tests if needed. >>> >>> >> > > ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-27 10:28 ` Shrikanth Hegde @ 2026-07-27 10:35 ` Christophe Leroy (CS GROUP) 2026-07-27 16:12 ` Paul E. McKenney 2026-07-27 10:59 ` Jirka Hladky 1 sibling, 1 reply; 35+ messages in thread From: Christophe Leroy (CS GROUP) @ 2026-07-27 10:35 UTC (permalink / raw) To: Shrikanth Hegde, Jirka Hladky Cc: maddy, linuxppc-dev, mpe, npiggin, bigeasy, will, linux-kernel, Paul E . McKenney Hi Shrikanth, Le 27/07/2026 à 12:28, Shrikanth Hegde a écrit : > Hi Jirka, > Please avoid top-posting. > > On 7/27/26 3:43 PM, Jirka Hladky wrote: >> Hi Shrikanth, >> >> Thanks for the quick response and for looping in Paul. >> >>> This is true only if user selected PREEMPT_DYNAMIC option i think. >> >> Yes, exactly. The issue is that CONFIG_PREEMPT_DYNAMIC=y has been in >> the Fedora/RHEL kernel config since kernel 5.16 (2021). It was >> silently ignored on ppc64le until your 6.16 patch added >> HAVE_PREEMPT_DYNAMIC_KEY, so this is the first time PREEMPT_RCU >> actually takes effect for all Fedora/RHEL ppc64le users. >> >>> Does your preemption mode remain the same in two cases? >> >> Verified. On 6.15-rc6 (before PREEMPT_DYNAMIC takes effect): >> >> CONFIG_PREEMPT_VOLUNTARY=y >> (no CONFIG_PREEMPT_DYNAMIC, no /sys/kernel/debug/sched/preempt) >> >> On both 7.1 and 7.2-rc4 (with PREEMPT_DYNAMIC active): >> >> CONFIG_PREEMPT_LAZY=y >> CONFIG_PREEMPT_DYNAMIC=y >> CONFIG_PREEMPT_RCU=y >> cat /sys/kernel/debug/sched/preempt: "full (lazy)" >> >> So the runtime preemption mode is the same on 7.1 and 7.2. The >> difference between 6.15 and 7.1+ is that the preemption model changed >> from voluntary (static) to full/lazy (dynamic), which is what pulls >> in PREEMPT_RCU. > > That means comparison is between preempt=voluntary vs preempt=lazy. As far as I can see CONFIG_PREEMPT_LAZY doesn't pull CONFIG_PREEMPT_RCU. CONFIG_PREEMPT_DYNAMIC does: config PREEMPT_RCU bool default y if (PREEMPT || PREEMPT_RT || PREEMPT_DYNAMIC) select TREE_RCU help This option selects the RCU implementation that is designed for very large SMP systems with hundreds or thousands of CPUs, but for which real-time response is also required. It also scales down nicely to smaller systems. Select this option if you are unsure. Christophe > > If you make it full preemption in 6.15 you will likely see similar data > as 7.1+. > Only on 7.0/7.1 there is force switch to lazy/full. Can you give that a > try? > > If it shows same data, that implies the regression is mainly due to change > of preemption modes, rather than the static key stuff. > >> >>> Weak memory model would need barriers irrespective of >>> HAVE_PREEMPT_DYNAMIC_CALL or HAVE_PREEMPT_DYNAMIC_KEY. >>> Static key too is expected to minimal cost. >> >> You're right, I should clarify -- the overhead is not in the static >> key mechanism itself. The cost comes from __rcu_read_lock() and >> __rcu_read_unlock() which are called when CONFIG_PREEMPT_RCU=y. >> These need real memory barriers (lwsync/isync) on ppc64le regardless >> of whether the dynamic mechanism uses keys or calls. >> >> The real question is: why does enabling PREEMPT_RCU cost ~33% on >> ppc64le but only ~3% on x86_64? The answer is that x86_64's TSO >> memory model makes the barriers in __rcu_read_lock/__rcu_read_unlock >> essentially free, while ppc64le's weak ordering requires explicit >> lwsync/isync instructions, which are expensive when called thousands >> of times per second in the SELinux AVC hot path. > > Plus, it may call schedule in lazy/pull preemption. > >> >> I also have new data from SELinux isolation testing that helps >> quantify this. On kernel 7.1 (which already has PREEMPT_RCU=y): >> >> SELinux mode kill bogo-ops/sec vs enforcing >> ------------ ----------------- ------------ >> Enforcing 69,107 baseline >> Permissive 70,248 +1.6% >> Disabled 93,566 +35.4% >> >> Permissive ~ enforcing confirms the overhead is not in SELinux policy >> evaluation. Disabling SELinux removes the rcu_read_lock/unlock call >> sites in the AVC path and recovers most of the performance -- but >> still leaves a ~13% gap vs 6.12 (no PREEMPT_RCU), which is the base >> cost of PREEMPT_RCU in the non-SELinux parts of the kill() path. >> > > This seems strange. How come rcu lock/unlock depends on SELinux policy? > One should call rcu lock/unlock if they are working with rcu updated > fields. > > Does the policy change itself protected with rcu lock/unlock? > I will check it up. > >> So the core issue is: on ppc64le, CONFIG_PREEMPT_RCU makes >> rcu_read_lock/unlock significantly more expensive, and the kill() >> syscall path hits them very heavily through SELinux AVC lookups. >> >> Thanks, >> Jirka >> >> On Mon, Jul 27, 2026 at 6:19 AM Shrikanth Hegde >> <sshegde@linux.ibm.com> wrote: >>> >>> +cc paul for any further/RCU insights. >>> >>> On 7/27/26 12:03 AM, Jirka Hladky wrote: >>>> Hi Shrikanth, Christophe, >>>> >>> >>> Hi Jirka, thanks for the report. >>> >>>> I'm seeing a significant performance regression on ppc64le after >>>> this >>>> patch landed in 6.16, caused by CONFIG_PREEMPT_RCU becoming active >>>> once HAVE_PREEMPT_DYNAMIC_KEY is selected. >>>> >>> >>> This is true only if user selected PREEMPT_DYNAMIC option i think. >>> >>> config PREEMPT_RCU >>> bool >>> default y if (PREEMPT || PREEMPT_RT || PREEMPT_DYNAMIC) >>> select TREE_RCU >>> >>> >>>> Benchmark: stress-ng kill stressor (tight kill() syscall loop), >>>> single thread, POWER10 LPAR (8 vCPUs, 1 core SMT-8). >>>> >>>> Bisected across Fedora ELN kernel builds on ppc64le: >>>> >>>> kernel CONFIG_PREEMPT_RCU kill bogo-ops/sec >>>> --- 6.15-rc6 (eln148) no 103,207 >>>> 6.16 (eln150) yes 70,281 (-32%) >>>> 6.18 (eln154) yes 72,552 (-30%) >>>> >>> >>> Does your preemption mode remain the same in two cases? >>> >>>> For comparison, x86_64 (AMD EPYC 9355P) with the same config change >>>> shows only a 2.8% regression: >>>> >>>> 6.12 x86_64 37,436 >>>> 7.2 x86_64 36,392 (-2.8%) >>>> >>>> perf report shows the overhead comes from rcu_read_lock/unlock in >>>> the >>>> SELinux AVC path (check_kill_permission -> security_task_kill -> >>>> selinux_task_kill -> avc_has_perm -> avc_lookup): >>>> >>>> Function 6.15 (no PREEMPT_RCU) 6.16 (PREEMPT_RCU) >>>> --- avc_lookup 15.23% 24.79% >>>> __rcu_read_lock ~0% 4.52% >>>> __rcu_read_unlock ~0% 4.17% >>>> selinux_task_kill 6.23% 7.35% >>>> audit_signal_info* 0.94% 3.59% >>>> >>>> On x86_64, rcu_read_lock/unlock are cheap thanks to static calls >>>> (HAVE_PREEMPT_DYNAMIC_CALL). On ppc64le with the KEY-based >>>> implementation, the weak memory model requires real barriers >>>> (lwsync/isync) making each RCU read-side critical section >>>> significantly more expensive. >>> >>> Weak memory model would need barriers irrespective of >>> HAVE_PREEMPT_DYNAMIC_CALL >>> or HAVE_PREEMPT_DYNAMIC_KEY. That's my assumption. I will look >>> more into it. Also i don't know much about PREEMPT_RCU. So might take >>> a while. >>> >>>> >>>> This aligns with Christophe's earlier review comment that >>>> HAVE_PREEMPT_DYNAMIC_CALL should be more performant. Would >>>> implementing static calls for ppc64 be feasible to close this gap? >>>> >>> >>> Static key too is expected to minimal cost. There maybe more into this. >>> >>>> Test details: >>>> - Machine: IBM POWER10 (pvr 0080 0200), pHyp virtualization >>>> - stress-ng 0.21.03, gcc 14.3.1, glibc 2.39 >>>> - Tuned profile: virtual-guest >>>> - SELinux: enforcing (permissive recovers only ~7%) >>>> >>>> Happy to run additional tests if needed. >>>> >>>> >>> >> >> > ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-27 10:35 ` Christophe Leroy (CS GROUP) @ 2026-07-27 16:12 ` Paul E. McKenney 0 siblings, 0 replies; 35+ messages in thread From: Paul E. McKenney @ 2026-07-27 16:12 UTC (permalink / raw) To: Christophe Leroy (CS GROUP) Cc: Shrikanth Hegde, Jirka Hladky, maddy, linuxppc-dev, mpe, npiggin, bigeasy, will, linux-kernel On Mon, Jul 27, 2026 at 12:35:32PM +0200, Christophe Leroy (CS GROUP) wrote: > Hi Shrikanth, > > Le 27/07/2026 à 12:28, Shrikanth Hegde a écrit : > > Hi Jirka, > > Please avoid top-posting. > > > > On 7/27/26 3:43 PM, Jirka Hladky wrote: > > > Hi Shrikanth, > > > > > > Thanks for the quick response and for looping in Paul. > > > > > > > This is true only if user selected PREEMPT_DYNAMIC option i think. > > > > > > Yes, exactly. The issue is that CONFIG_PREEMPT_DYNAMIC=y has been in > > > the Fedora/RHEL kernel config since kernel 5.16 (2021). It was > > > silently ignored on ppc64le until your 6.16 patch added > > > HAVE_PREEMPT_DYNAMIC_KEY, so this is the first time PREEMPT_RCU > > > actually takes effect for all Fedora/RHEL ppc64le users. > > > > > > > Does your preemption mode remain the same in two cases? > > > > > > Verified. On 6.15-rc6 (before PREEMPT_DYNAMIC takes effect): > > > > > > CONFIG_PREEMPT_VOLUNTARY=y > > > (no CONFIG_PREEMPT_DYNAMIC, no /sys/kernel/debug/sched/preempt) > > > > > > On both 7.1 and 7.2-rc4 (with PREEMPT_DYNAMIC active): > > > > > > CONFIG_PREEMPT_LAZY=y > > > CONFIG_PREEMPT_DYNAMIC=y > > > CONFIG_PREEMPT_RCU=y > > > cat /sys/kernel/debug/sched/preempt: "full (lazy)" > > > > > > So the runtime preemption mode is the same on 7.1 and 7.2. The > > > difference between 6.15 and 7.1+ is that the preemption model changed > > > from voluntary (static) to full/lazy (dynamic), which is what pulls > > > in PREEMPT_RCU. > > > > That means comparison is between preempt=voluntary vs preempt=lazy. > > As far as I can see CONFIG_PREEMPT_LAZY doesn't pull CONFIG_PREEMPT_RCU. > CONFIG_PREEMPT_DYNAMIC does: That is correct. Now, PREEMPT_LAZY does add preempt_disable() to rcu_read_lock() and preempt_enable() to rcu_read_unlock(), compared to PREEMPT_NONE. So there might be some performance impact. But hopefully not quite as much as an isync or lwsync instruction. OK, OK, PREEMPT_NONE also has preempt_disable() in rcu_read_lock() and preempt_enable() in rcu_read_unlock(). The real difference is that in PREEMPT_NONE, both preempt_disable() and preempt_enable() are no-ops. In contrast, in PREEMPT_LAZY these two execute real code. Thanx, Paul > config PREEMPT_RCU > bool > default y if (PREEMPT || PREEMPT_RT || PREEMPT_DYNAMIC) > select TREE_RCU > help > This option selects the RCU implementation that is > designed for very large SMP systems with hundreds or > thousands of CPUs, but for which real-time response > is also required. It also scales down nicely to > smaller systems. > > Select this option if you are unsure. > > > Christophe > > > > > If you make it full preemption in 6.15 you will likely see similar data > > as 7.1+. > > Only on 7.0/7.1 there is force switch to lazy/full. Can you give that a > > try? > > > > If it shows same data, that implies the regression is mainly due to change > > of preemption modes, rather than the static key stuff. > > > > > > > > > Weak memory model would need barriers irrespective of > > > > HAVE_PREEMPT_DYNAMIC_CALL or HAVE_PREEMPT_DYNAMIC_KEY. > > > > Static key too is expected to minimal cost. > > > > > > You're right, I should clarify -- the overhead is not in the static > > > key mechanism itself. The cost comes from __rcu_read_lock() and > > > __rcu_read_unlock() which are called when CONFIG_PREEMPT_RCU=y. > > > These need real memory barriers (lwsync/isync) on ppc64le regardless > > > of whether the dynamic mechanism uses keys or calls. > > > > > > The real question is: why does enabling PREEMPT_RCU cost ~33% on > > > ppc64le but only ~3% on x86_64? The answer is that x86_64's TSO > > > memory model makes the barriers in __rcu_read_lock/__rcu_read_unlock > > > essentially free, while ppc64le's weak ordering requires explicit > > > lwsync/isync instructions, which are expensive when called thousands > > > of times per second in the SELinux AVC hot path. > > > > Plus, it may call schedule in lazy/pull preemption. > > > > > > > > I also have new data from SELinux isolation testing that helps > > > quantify this. On kernel 7.1 (which already has PREEMPT_RCU=y): > > > > > > SELinux mode kill bogo-ops/sec vs enforcing > > > ------------ ----------------- ------------ > > > Enforcing 69,107 baseline > > > Permissive 70,248 +1.6% > > > Disabled 93,566 +35.4% > > > > > > Permissive ~ enforcing confirms the overhead is not in SELinux policy > > > evaluation. Disabling SELinux removes the rcu_read_lock/unlock call > > > sites in the AVC path and recovers most of the performance -- but > > > still leaves a ~13% gap vs 6.12 (no PREEMPT_RCU), which is the base > > > cost of PREEMPT_RCU in the non-SELinux parts of the kill() path. > > > > > > > This seems strange. How come rcu lock/unlock depends on SELinux policy? > > One should call rcu lock/unlock if they are working with rcu updated > > fields. > > > > Does the policy change itself protected with rcu lock/unlock? > > I will check it up. > > > > > So the core issue is: on ppc64le, CONFIG_PREEMPT_RCU makes > > > rcu_read_lock/unlock significantly more expensive, and the kill() > > > syscall path hits them very heavily through SELinux AVC lookups. > > > > > > Thanks, > > > Jirka > > > > > > On Mon, Jul 27, 2026 at 6:19 AM Shrikanth Hegde > > > <sshegde@linux.ibm.com> wrote: > > > > > > > > +cc paul for any further/RCU insights. > > > > > > > > On 7/27/26 12:03 AM, Jirka Hladky wrote: > > > > > Hi Shrikanth, Christophe, > > > > > > > > > > > > > Hi Jirka, thanks for the report. > > > > > > > > > I'm seeing a significant performance regression on > > > > > ppc64le after this > > > > > patch landed in 6.16, caused by CONFIG_PREEMPT_RCU becoming active > > > > > once HAVE_PREEMPT_DYNAMIC_KEY is selected. > > > > > > > > > > > > > This is true only if user selected PREEMPT_DYNAMIC option i think. > > > > > > > > config PREEMPT_RCU > > > > bool > > > > default y if (PREEMPT || PREEMPT_RT || PREEMPT_DYNAMIC) > > > > select TREE_RCU > > > > > > > > > > > > > Benchmark: stress-ng kill stressor (tight kill() syscall loop), > > > > > single thread, POWER10 LPAR (8 vCPUs, 1 core SMT-8). > > > > > > > > > > Bisected across Fedora ELN kernel builds on ppc64le: > > > > > > > > > > kernel CONFIG_PREEMPT_RCU kill bogo-ops/sec > > > > > --- 6.15-rc6 (eln148) no 103,207 > > > > > 6.16 (eln150) yes 70,281 (-32%) > > > > > 6.18 (eln154) yes 72,552 (-30%) > > > > > > > > > > > > > Does your preemption mode remain the same in two cases? > > > > > > > > > For comparison, x86_64 (AMD EPYC 9355P) with the same config change > > > > > shows only a 2.8% regression: > > > > > > > > > > 6.12 x86_64 37,436 > > > > > 7.2 x86_64 36,392 (-2.8%) > > > > > > > > > > perf report shows the overhead comes from > > > > > rcu_read_lock/unlock in the > > > > > SELinux AVC path (check_kill_permission -> security_task_kill -> > > > > > selinux_task_kill -> avc_has_perm -> avc_lookup): > > > > > > > > > > Function 6.15 (no PREEMPT_RCU) 6.16 (PREEMPT_RCU) > > > > > --- avc_lookup 15.23% 24.79% > > > > > __rcu_read_lock ~0% 4.52% > > > > > __rcu_read_unlock ~0% 4.17% > > > > > selinux_task_kill 6.23% 7.35% > > > > > audit_signal_info* 0.94% 3.59% > > > > > > > > > > On x86_64, rcu_read_lock/unlock are cheap thanks to static calls > > > > > (HAVE_PREEMPT_DYNAMIC_CALL). On ppc64le with the KEY-based > > > > > implementation, the weak memory model requires real barriers > > > > > (lwsync/isync) making each RCU read-side critical section > > > > > significantly more expensive. > > > > > > > > Weak memory model would need barriers irrespective of > > > > HAVE_PREEMPT_DYNAMIC_CALL > > > > or HAVE_PREEMPT_DYNAMIC_KEY. That's my assumption. I will look > > > > more into it. Also i don't know much about PREEMPT_RCU. So might > > > > take a while. > > > > > > > > > > > > > > This aligns with Christophe's earlier review comment that > > > > > HAVE_PREEMPT_DYNAMIC_CALL should be more performant. Would > > > > > implementing static calls for ppc64 be feasible to close this gap? > > > > > > > > > > > > > Static key too is expected to minimal cost. There maybe more into this. > > > > > > > > > Test details: > > > > > - Machine: IBM POWER10 (pvr 0080 0200), pHyp virtualization > > > > > - stress-ng 0.21.03, gcc 14.3.1, glibc 2.39 > > > > > - Tuned profile: virtual-guest > > > > > - SELinux: enforcing (permissive recovers only ~7%) > > > > > > > > > > Happy to run additional tests if needed. > > > > > > > > > > > > > > > > > > > > > > > ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-27 10:28 ` Shrikanth Hegde 2026-07-27 10:35 ` Christophe Leroy (CS GROUP) @ 2026-07-27 10:59 ` Jirka Hladky 2026-07-27 11:03 ` Shrikanth Hegde 1 sibling, 1 reply; 35+ messages in thread From: Jirka Hladky @ 2026-07-27 10:59 UTC (permalink / raw) To: Shrikanth Hegde Cc: maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel, Paul E . McKenney On Mon, Jul 27, 2026 at 12:29 PM Shrikanth Hegde <sshegde@linux.ibm.com> wrote: > That means comparison is between preempt=voluntary vs preempt=lazy. > > If you make it full preemption in 6.15 you will likely see similar > data as 7.1+. Only on 7.0/7.1 there is force switch to lazy/full. > Can you give that a try? > > If it shows same data, that implies the regression is mainly due to > change of preemption modes, rather than the static key stuff. Tested on 7.1 by switching the runtime mode via /sys/kernel/debug/sched/preempt: Mode kill bogo-ops/sec ---- ----------------- full 57,476 lazy 56,892 Delta ~1% (noise) The preemption mode (full vs lazy) makes no difference. The regression is from CONFIG_PREEMPT_RCU being enabled, not from the choice of preemption mode. And as Christophe pointed out, it's CONFIG_PREEMPT_DYNAMIC that pulls in CONFIG_PREEMPT_RCU, not CONFIG_PREEMPT_LAZY: config PREEMPT_RCU default y if (PREEMPT || PREEMPT_RT || PREEMPT_DYNAMIC) So the chain is: your patch enables HAVE_PREEMPT_DYNAMIC_KEY -> CONFIG_PREEMPT_DYNAMIC takes effect -> CONFIG_PREEMPT_RCU=y -> expensive rcu_read_lock/unlock on ppc64le. > Plus, it may call schedule in lazy/pull preemption. The full vs lazy results above suggest extra scheduling is not a significant factor here. > This seems strange. How come rcu lock/unlock depends on SELinux > policy? One should call rcu lock/unlock if they are working with > rcu updated fields. > > Does the policy change itself protected with rcu lock/unlock? The rcu_read_lock/unlock calls don't depend on SELinux policy -- they are in the SELinux *code path* itself. SELinux uses RCU to protect its AVC (Access Vector Cache) lookups. Every call to avc_has_perm() takes rcu_read_lock() around the avc_lookup() hash table access. When you boot with selinux=0, the SELinux LSM hooks are never called, so the AVC code path (and its rcu_read_lock/unlock pairs) is never reached. That's why disabling SELinux removes those call sites from the hot path. The call chain is: sys_kill -> check_kill_permission -> security_task_kill -> selinux_task_kill -> avc_has_perm -> rcu_read_lock() -> avc_lookup() <-- hash table lookup under RCU protection -> rcu_read_unlock() With selinux=0, security_task_kill() is essentially a no-op and none of the avc/rcu code runs. Jirka ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-27 10:59 ` Jirka Hladky @ 2026-07-27 11:03 ` Shrikanth Hegde 0 siblings, 0 replies; 35+ messages in thread From: Shrikanth Hegde @ 2026-07-27 11:03 UTC (permalink / raw) To: Jirka Hladky Cc: maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel, Paul E . McKenney On 7/27/26 4:29 PM, Jirka Hladky wrote: > On Mon, Jul 27, 2026 at 12:29 PM Shrikanth Hegde <sshegde@linux.ibm.com> wrote: >> That means comparison is between preempt=voluntary vs preempt=lazy. >> >> If you make it full preemption in 6.15 you will likely see similar >> data as 7.1+. Only on 7.0/7.1 there is force switch to lazy/full. >> Can you give that a try? >> >> If it shows same data, that implies the regression is mainly due to >> change of preemption modes, rather than the static key stuff. > > Tested on 7.1 by switching the runtime mode via > /sys/kernel/debug/sched/preempt: > > Mode kill bogo-ops/sec > ---- ----------------- > full 57,476 > lazy 56,892 > Delta ~1% (noise) > What I asked you was to do voluntary vs lazy comparison without CONFIG_PREEMPT_DYNAMIC. > The preemption mode (full vs lazy) makes no difference. The regression > is from CONFIG_PREEMPT_RCU being enabled, not from the choice of > preemption mode. > > And as Christophe pointed out, it's CONFIG_PREEMPT_DYNAMIC that pulls > in CONFIG_PREEMPT_RCU, not CONFIG_PREEMPT_LAZY: > > config PREEMPT_RCU > default y if (PREEMPT || PREEMPT_RT || PREEMPT_DYNAMIC) > > So the chain is: your patch enables HAVE_PREEMPT_DYNAMIC_KEY -> > CONFIG_PREEMPT_DYNAMIC takes effect -> CONFIG_PREEMPT_RCU=y -> > expensive rcu_read_lock/unlock on ppc64le. > >> Plus, it may call schedule in lazy/pull preemption. > > The full vs lazy results above suggest extra scheduling is not a > significant factor here. > >> This seems strange. How come rcu lock/unlock depends on SELinux >> policy? One should call rcu lock/unlock if they are working with >> rcu updated fields. >> >> Does the policy change itself protected with rcu lock/unlock? > > The rcu_read_lock/unlock calls don't depend on SELinux policy -- they > are in the SELinux *code path* itself. SELinux uses RCU to protect > its AVC (Access Vector Cache) lookups. Every call to avc_has_perm() > takes rcu_read_lock() around the avc_lookup() hash table access. > > When you boot with selinux=0, the SELinux LSM hooks are never called, > so the AVC code path (and its rcu_read_lock/unlock pairs) is never > reached. That's why disabling SELinux removes those call sites from > the hot path. > > The call chain is: > sys_kill -> check_kill_permission -> security_task_kill > -> selinux_task_kill -> avc_has_perm > -> rcu_read_lock() > -> avc_lookup() <-- hash table lookup under RCU protection > -> rcu_read_unlock() > > With selinux=0, security_task_kill() is essentially a no-op and none > of the avc/rcu code runs. > > Jirka > ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-27 10:13 ` Jirka Hladky 2026-07-27 10:28 ` Shrikanth Hegde @ 2026-07-27 12:34 ` Shrikanth Hegde 1 sibling, 0 replies; 35+ messages in thread From: Shrikanth Hegde @ 2026-07-27 12:34 UTC (permalink / raw) To: Jirka Hladky Cc: maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel, Paul E . McKenney On 7/27/26 3:43 PM, Jirka Hladky wrote: > Hi Shrikanth, > [...] > > The real question is: why does enabling PREEMPT_RCU cost ~33% on > ppc64le but only ~3% on x86_64? The answer is that x86_64's TSO > memory model makes the barriers in __rcu_read_lock/__rcu_read_unlock > essentially free, while ppc64le's weak ordering requires explicit > lwsync/isync instructions, which are expensive when called thousands > of times per second in the SELinux AVC hot path. > Ensure when comparing the preemption modes are same or not. x86 has dynamic preemption since long time. It might be possible in your testing when you compared for x86, preemption modes were same, whereas in case of powerpc you are comparing between voluntary vs lazy. If it is voluntary vs lazy, this would simplify where to concentrate. (You can easily do this with CONFIG_PREEMPT_DYNAMIC=n on a kernel before 7.0) ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-27 4:18 ` Shrikanth Hegde 2026-07-27 10:13 ` Jirka Hladky @ 2026-07-27 16:07 ` Paul E. McKenney 2026-07-27 16:50 ` Jirka Hladky 1 sibling, 1 reply; 35+ messages in thread From: Paul E. McKenney @ 2026-07-27 16:07 UTC (permalink / raw) To: Shrikanth Hegde Cc: Jirka Hladky, maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel On Mon, Jul 27, 2026 at 09:48:25AM +0530, Shrikanth Hegde wrote: > +cc paul for any further/RCU insights. > > On 7/27/26 12:03 AM, Jirka Hladky wrote: > > Hi Shrikanth, Christophe, > > > > Hi Jirka, thanks for the report. > > > I'm seeing a significant performance regression on ppc64le after this > > patch landed in 6.16, caused by CONFIG_PREEMPT_RCU becoming active > > once HAVE_PREEMPT_DYNAMIC_KEY is selected. > > This is true only if user selected PREEMPT_DYNAMIC option i think. > > config PREEMPT_RCU > bool > default y if (PREEMPT || PREEMPT_RT || PREEMPT_DYNAMIC) > select TREE_RCU Yes, if you select PREEMPT_DYNAMIC, RCU doesn't have much choice but to choose PREEMPT_RCU. Something about not having the guts to implement an RCU that dynamically switches between its preemptible and non-preemptible variants. Cowardly of me, I know! So if you want non-preemptible RCU, you need to turn off PREEMPT_DYNAMIC. > > Benchmark: stress-ng kill stressor (tight kill() syscall loop), > > single thread, POWER10 LPAR (8 vCPUs, 1 core SMT-8). > > > > Bisected across Fedora ELN kernel builds on ppc64le: > > > > kernel CONFIG_PREEMPT_RCU kill bogo-ops/sec > > --- 6.15-rc6 (eln148) no 103,207 > > 6.16 (eln150) yes 70,281 (-32%) > > 6.18 (eln154) yes 72,552 (-30%) > > > > Does your preemption mode remain the same in two cases? > > > For comparison, x86_64 (AMD EPYC 9355P) with the same config change > > shows only a 2.8% regression: > > > > 6.12 x86_64 37,436 > > 7.2 x86_64 36,392 (-2.8%) > > > > perf report shows the overhead comes from rcu_read_lock/unlock in the > > SELinux AVC path (check_kill_permission -> security_task_kill -> > > selinux_task_kill -> avc_has_perm -> avc_lookup): > > > > Function 6.15 (no PREEMPT_RCU) 6.16 (PREEMPT_RCU) > > --- avc_lookup 15.23% 24.79% > > __rcu_read_lock ~0% 4.52% > > __rcu_read_unlock ~0% 4.17% Yes, non-preemptible RCU's __rcu_read_{,un}lock() are (almost) no-ops, but preemptible RCU must actually execute real code. But I would not expect *this* much overhead. > > selinux_task_kill 6.23% 7.35% > > audit_signal_info* 0.94% 3.59% > > > > On x86_64, rcu_read_lock/unlock are cheap thanks to static calls > > (HAVE_PREEMPT_DYNAMIC_CALL). On ppc64le with the KEY-based > > implementation, the weak memory model requires real barriers > > (lwsync/isync) making each RCU read-side critical section > > significantly more expensive. > > Weak memory model would need barriers irrespective of HAVE_PREEMPT_DYNAMIC_CALL > or HAVE_PREEMPT_DYNAMIC_KEY. That's my assumption. I will look > more into it. Also i don't know much about PREEMPT_RCU. So might take a while. OK, if you are executing an isync or an lwsync instruction in each call to __rcu_read_{,un}lock(), that would explain the overhead. CONFIG_PREEMPT_DYNAMIC=n for the win? Thanx, Paul > > This aligns with Christophe's earlier review comment that > > HAVE_PREEMPT_DYNAMIC_CALL should be more performant. Would > > implementing static calls for ppc64 be feasible to close this gap? > > > > Static key too is expected to minimal cost. There maybe more into this. > > > Test details: > > - Machine: IBM POWER10 (pvr 0080 0200), pHyp virtualization > > - stress-ng 0.21.03, gcc 14.3.1, glibc 2.39 > > - Tuned profile: virtual-guest > > - SELinux: enforcing (permissive recovers only ~7%) > > > > Happy to run additional tests if needed. > > > > ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-27 16:07 ` Paul E. McKenney @ 2026-07-27 16:50 ` Jirka Hladky 2026-07-27 17:10 ` Shrikanth Hegde 0 siblings, 1 reply; 35+ messages in thread From: Jirka Hladky @ 2026-07-27 16:50 UTC (permalink / raw) To: paulmck Cc: Shrikanth Hegde, maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel On Mon, Jul 27, 2026 at 6:16 PM Paul E. McKenney <paulmck@kernel.org> wrote: > Yes, non-preemptible RCU's __rcu_read_{,un}lock() are (almost) no-ops, > but preemptible RCU must actually execute real code. But I would not > expect *this* much overhead. I've now isolated the PREEMPT_RCU cost with a controlled experiment. Built two kernels from the same 6.15-rc6 upstream source on the same POWER10 machine, no CONFIG_PREEMPT_DYNAMIC in either case: Config A: CONFIG_PREEMPT_VOLUNTARY=y (no PREEMPT_RCU) Config B: CONFIG_PREEMPT=y (PREEMPT_RCU=y) Results (stress-ng --kill 1 -t 23, SELinux enforcing): Kernel PREEMPT_RCU kill bogo-ops/sec --------------------------- ----------- ----------------- 6.15-rc6-voluntary-test no 105,014 6.15-rc6-preempt-test yes 73,317 Delta -30.2% PREEMPT_RCU alone accounts for ~30% on this workload. The kill() path hits rcu_read_lock/unlock very heavily through the SELinux AVC (avc_has_perm -> avc_lookup wraps every hash table lookup in an RCU read-side critical section). This also answers Shrikanth's question about whether the regression is from the preemption mode change (voluntary -> lazy) or from PREEMPT_RCU. Since no PREEMPT_DYNAMIC is involved in either build, the preemption mode is not a factor. Additionally, switching between full and lazy at runtime on 7.1 showed only ~1% difference (57,476 vs 56,892), further confirming the mode doesn't matter. > OK, if you are executing an isync or an lwsync instruction in each call > to __rcu_read_{,un}lock(), that would explain the overhead. Yes, that's what perf shows. __rcu_read_lock and __rcu_read_unlock together consume ~9% of total cycles on ppc64le with PREEMPT_RCU, vs essentially 0% without. > CONFIG_PREEMPT_DYNAMIC=n for the win? That's the simplest distro workaround for ppc64le. But since commit 7dadeaa6e851 ("sched: Further restrict the preemption modes") removed PREEMPT_VOLUNTARY as an option for architectures with ARCH_HAS_PREEMPT_LAZY (which includes powerpc), distros that want voluntary preemption on ppc64le would need to disable PREEMPT_DYNAMIC anyway. Is there any path to reducing the barrier cost in __rcu_read_lock/__rcu_read_unlock on weakly-ordered architectures? Or is the current implementation fundamentally constrained by the memory model? Jirka ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-27 16:50 ` Jirka Hladky @ 2026-07-27 17:10 ` Shrikanth Hegde 2026-07-27 18:29 ` Christophe Leroy (CS GROUP) 2026-07-28 0:26 ` Jirka Hladky 0 siblings, 2 replies; 35+ messages in thread From: Shrikanth Hegde @ 2026-07-27 17:10 UTC (permalink / raw) To: Jirka Hladky, paulmck Cc: maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel Hi Jirka. On 7/27/26 10:20 PM, Jirka Hladky wrote: > On Mon, Jul 27, 2026 at 6:16 PM Paul E. McKenney <paulmck@kernel.org> wrote: >> Yes, non-preemptible RCU's __rcu_read_{,un}lock() are (almost) no-ops, >> but preemptible RCU must actually execute real code. But I would not >> expect *this* much overhead. > Thanks for doing these experiment. > I've now isolated the PREEMPT_RCU cost with a controlled experiment. > Built two kernels from the same 6.15-rc6 upstream source on the same > POWER10 machine, no CONFIG_PREEMPT_DYNAMIC in either case: > > Config A: CONFIG_PREEMPT_VOLUNTARY=y (no PREEMPT_RCU) > Config B: CONFIG_PREEMPT=y (PREEMPT_RCU=y) That's full preemption mode. > > Results (stress-ng --kill 1 -t 23, SELinux enforcing): > > Kernel PREEMPT_RCU kill bogo-ops/sec > --------------------------- ----------- ----------------- > 6.15-rc6-voluntary-test no 105,014 > 6.15-rc6-preempt-test yes 73,317 > Delta -30.2% > That is voluntary -> full preemption change. When preemption mode changes preempt_enable/disable which were just a barrier earlier now become real preemption points. If the code path repeatedly does the exact same thing, it might pop up. But, can we say is that number expected? it is difficult to put a number to it. What I was asking is below. (You can do this only with below 7.0) Config A: CONFIG_PREEMPT_VOLUNTARY=y (CONFIG_PREEMPT_DYNAMIC=n i.e no PREEMPT_RCU) Config B: CONFIG_PREEMPT_VOLUNTARY=y (CONFIG_PREEMPT_DYNAMIC=y i.e PREEMPT_RCU) That should keep in voluntary preemption. You can confirm with dynamic preemption using /sys/kerenl/debug/sched/preempt. In Config B, though there is rcu_read_lock/unlock it should be just a barrier. > PREEMPT_RCU alone accounts for ~30% on this workload. The kill() > path hits rcu_read_lock/unlock very heavily through the SELinux AVC > (avc_has_perm -> avc_lookup wraps every hash table lookup in an RCU > read-side critical section). > > This also answers Shrikanth's question about whether the regression > is from the preemption mode change (voluntary -> lazy) or from > PREEMPT_RCU. Since no PREEMPT_DYNAMIC is involved in either build, > the preemption mode is not a factor. Additionally, switching between > full and lazy at runtime on 7.1 showed only ~1% difference (57,476 > vs 56,892), further confirming the mode doesn't matter. Lazy/full switch is same. There will not be any additional overhead. The real concern is none/voluntary vs lazy/full. > >> OK, if you are executing an isync or an lwsync instruction in each call >> to __rcu_read_{,un}lock(), that would explain the overhead. > > Yes, that's what perf shows. __rcu_read_lock and __rcu_read_unlock > together consume ~9% of total cycles on ppc64le with PREEMPT_RCU, > vs essentially 0% without. > >> CONFIG_PREEMPT_DYNAMIC=n for the win? > > That's the simplest distro workaround for ppc64le. But since commit > 7dadeaa6e851 ("sched: Further restrict the preemption modes") > removed PREEMPT_VOLUNTARY as an option for architectures with > ARCH_HAS_PREEMPT_LAZY (which includes powerpc), distros that want > voluntary preemption on ppc64le would need to disable PREEMPT_DYNAMIC > anyway. > > Is there any path to reducing the barrier cost in > __rcu_read_lock/__rcu_read_unlock on weakly-ordered architectures? > Or is the current implementation fundamentally constrained by the > memory model? > Are you saying you see regression with voluntary with CONFIG_PREEMPT_DYNAMIC=y? > Jirka > ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-27 17:10 ` Shrikanth Hegde @ 2026-07-27 18:29 ` Christophe Leroy (CS GROUP) 2026-07-28 5:27 ` Shrikanth Hegde 2026-07-28 0:26 ` Jirka Hladky 1 sibling, 1 reply; 35+ messages in thread From: Christophe Leroy (CS GROUP) @ 2026-07-27 18:29 UTC (permalink / raw) To: Shrikanth Hegde, Jirka Hladky, paulmck Cc: maddy, linuxppc-dev, mpe, npiggin, bigeasy, will, linux-kernel Hi Shrikanth, Le 27/07/2026 à 19:10, Shrikanth Hegde a écrit : > Hi Jirka. > > On 7/27/26 10:20 PM, Jirka Hladky wrote: >> On Mon, Jul 27, 2026 at 6:16 PM Paul E. McKenney <paulmck@kernel.org> >> wrote: >>> Yes, non-preemptible RCU's __rcu_read_{,un}lock() are (almost) no-ops, >>> but preemptible RCU must actually execute real code. But I would not >>> expect *this* much overhead. >> > > Thanks for doing these experiment. > >> I've now isolated the PREEMPT_RCU cost with a controlled experiment. >> Built two kernels from the same 6.15-rc6 upstream source on the same >> POWER10 machine, no CONFIG_PREEMPT_DYNAMIC in either case: >> >> Config A: CONFIG_PREEMPT_VOLUNTARY=y (no PREEMPT_RCU) >> Config B: CONFIG_PREEMPT=y (PREEMPT_RCU=y) > > That's full preemption mode. > >> >> Results (stress-ng --kill 1 -t 23, SELinux enforcing): >> >> Kernel PREEMPT_RCU kill bogo-ops/sec >> --------------------------- ----------- ----------------- >> 6.15-rc6-voluntary-test no 105,014 >> 6.15-rc6-preempt-test yes 73,317 >> Delta -30.2% >> > > That is voluntary -> full preemption change. > > When preemption mode changes preempt_enable/disable which were just a > barrier earlier now become real preemption points. If the code path > repeatedly does the exact same thing, it might pop up. > But, can we say is that number expected? it is difficult to put a number > to it. > > What I was asking is below. (You can do this only with below 7.0) > > Config A: CONFIG_PREEMPT_VOLUNTARY=y (CONFIG_PREEMPT_DYNAMIC=n i.e no > PREEMPT_RCU) > Config B: CONFIG_PREEMPT_VOLUNTARY=y (CONFIG_PREEMPT_DYNAMIC=y i.e > PREEMPT_RCU) > > That should keep in voluntary preemption. > You can confirm with dynamic preemption using /sys/kerenl/debug/sched/ > preempt. > > In Config B, though there is rcu_read_lock/unlock it should be just a > barrier. > > >> PREEMPT_RCU alone accounts for ~30% on this workload. The kill() >> path hits rcu_read_lock/unlock very heavily through the SELinux AVC >> (avc_has_perm -> avc_lookup wraps every hash table lookup in an RCU >> read-side critical section). >> >> This also answers Shrikanth's question about whether the regression >> is from the preemption mode change (voluntary -> lazy) or from >> PREEMPT_RCU. Since no PREEMPT_DYNAMIC is involved in either build, >> the preemption mode is not a factor. Additionally, switching between >> full and lazy at runtime on 7.1 showed only ~1% difference (57,476 >> vs 56,892), further confirming the mode doesn't matter. > > Lazy/full switch is same. There will not be any additional overhead. > The real concern is none/voluntary vs lazy/full. That's right with CONFIG_PREEMPT_DYNAMIC=y With CONFIG_PREEMT_DYNAMIC=n: - CONFIG_PREEMPT (full) implies CONFIG_PREEMPT_RCU - CONFIG_PREEMPT_LAZY (lazy) doesn't imply CONFIG_PREEMPT_RCU because of kernel/rcu/Kconfig, config PREEMPT_RCU bool default y if (PREEMPT || PREEMPT_RT || PREEMPT_DYNAMIC) select TREE_RCU Christophe > >> >>> OK, if you are executing an isync or an lwsync instruction in each call >>> to __rcu_read_{,un}lock(), that would explain the overhead. >> >> Yes, that's what perf shows. __rcu_read_lock and __rcu_read_unlock >> together consume ~9% of total cycles on ppc64le with PREEMPT_RCU, >> vs essentially 0% without. >> >>> CONFIG_PREEMPT_DYNAMIC=n for the win? >> >> That's the simplest distro workaround for ppc64le. But since commit >> 7dadeaa6e851 ("sched: Further restrict the preemption modes") >> removed PREEMPT_VOLUNTARY as an option for architectures with >> ARCH_HAS_PREEMPT_LAZY (which includes powerpc), distros that want >> voluntary preemption on ppc64le would need to disable PREEMPT_DYNAMIC >> anyway. >> >> Is there any path to reducing the barrier cost in >> __rcu_read_lock/__rcu_read_unlock on weakly-ordered architectures? >> Or is the current implementation fundamentally constrained by the >> memory model? >> > > Are you saying you see regression with voluntary with > CONFIG_PREEMPT_DYNAMIC=y? > >> Jirka >> > ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-27 18:29 ` Christophe Leroy (CS GROUP) @ 2026-07-28 5:27 ` Shrikanth Hegde 2026-07-28 16:21 ` Paul E. McKenney 0 siblings, 1 reply; 35+ messages in thread From: Shrikanth Hegde @ 2026-07-28 5:27 UTC (permalink / raw) To: Christophe Leroy (CS GROUP), Jirka Hladky, paulmck Cc: maddy, linuxppc-dev, mpe, npiggin, bigeasy, will, linux-kernel Hi Paul, Christophe, On 7/27/26 11:59 PM, Christophe Leroy (CS GROUP) wrote: > Hi Shrikanth, > > > That's right with CONFIG_PREEMPT_DYNAMIC=y > > With CONFIG_PREEMT_DYNAMIC=n: > - CONFIG_PREEMPT (full) implies CONFIG_PREEMPT_RCU > - CONFIG_PREEMPT_LAZY (lazy) doesn't imply CONFIG_PREEMPT_RCU > > because of kernel/rcu/Kconfig, > > config PREEMPT_RCU > bool > default y if (PREEMPT || PREEMPT_RT || PREEMPT_DYNAMIC) > select TREE_RCU > > Christophe > > Right. Looks like __rcu_read_unlock can set need_resched bit if it find irq were disabled and rcu_read_unlock_special.s is set. I don't have much clue about it. So, after seeing __rcu_read_unlock for PREEMPT_RCU I have these concerns now. In current upstream, lazy is a preemption mode with preempt_enable being a preemptible point, 1. If PREEMPT_LAZY=y and PREEMPT_DYNAMIC=n, then PREEMPT_RCU=n. That seems wrong. It is supposed to do the preemption checks, since preempt_count is actual count with lazy preemption. 2. PREEMPT_LAZY=y and PREEMPT_DYNAMIC=n and PREEMPT_LAZY=y and PREEMPT_DYNAMIC=y are supposed to be similar w.r.t to performance. Promise of PREEMPT_DYNAMIC was the ability to switch at runtime based on the user workload and his/her preference. But with PREEMPT_LAZY=y and PREEMPT_DYNAMIC=y, there is additional cost due to PREEMPT_RCU. lazy being the middle ground w.r.t for decent performance, either PREEMPT_RCU should either kick in for both cases or bail out for both. Before 7.0 3. the same concerns would be true to PREEMPT_VOLUNTARY and PREEMPT_NONE with PREEMPT_DYNAMIC=y. Those model never wanted a preemption, but PREEMPT_RCU could have forced a need_resched to be set. Which is also likely wrong. No? ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-28 5:27 ` Shrikanth Hegde @ 2026-07-28 16:21 ` Paul E. McKenney 2026-07-28 16:30 ` Paul E. McKenney 2026-07-30 13:01 ` Shrikanth Hegde 0 siblings, 2 replies; 35+ messages in thread From: Paul E. McKenney @ 2026-07-28 16:21 UTC (permalink / raw) To: Shrikanth Hegde Cc: Christophe Leroy (CS GROUP), Jirka Hladky, maddy, linuxppc-dev, mpe, npiggin, bigeasy, will, linux-kernel On Tue, Jul 28, 2026 at 10:57:57AM +0530, Shrikanth Hegde wrote: > Hi Paul, Christophe, > > On 7/27/26 11:59 PM, Christophe Leroy (CS GROUP) wrote: > > Hi Shrikanth, > > > > > > > That's right with CONFIG_PREEMPT_DYNAMIC=y > > > > With CONFIG_PREEMT_DYNAMIC=n: > > - CONFIG_PREEMPT (full) implies CONFIG_PREEMPT_RCU > > - CONFIG_PREEMPT_LAZY (lazy) doesn't imply CONFIG_PREEMPT_RCU > > > > because of kernel/rcu/Kconfig, > > > > config PREEMPT_RCU > > bool > > default y if (PREEMPT || PREEMPT_RT || PREEMPT_DYNAMIC) > > select TREE_RCU > > > > Christophe > > > > > > Right. > > Looks like __rcu_read_unlock can set need_resched bit if it find irq were disabled > and rcu_read_unlock_special.s is set. I don't have much clue about it. > So, after seeing __rcu_read_unlock for PREEMPT_RCU I have these concerns now. This is because irq-disabled regions of code act as RCU readers. For non-preemptible RCU (even in CONFIG_PREEMPT_LAZY=y kernels), this comes for free. In contrast, preemptible RCU must explicitly (and, as you noticed, rather painfully) handle the irq-disabled case: rcu_read_lock(); do_something(); local_irq_disable(); do_something_else(); rcu_read_unlock(); do_yet_another_thing(); local_irq_enable(); Here, the RCU reader extends all the way from the rcu_read_lock() to the final local_irq_enable(). And this is why RCU checks for IRQs being disabled in __rcu_read_unlock(). > In current upstream, lazy is a preemption mode with preempt_enable being a preemptible point, > > 1. If PREEMPT_LAZY=y and PREEMPT_DYNAMIC=n, then PREEMPT_RCU=n. That seems wrong. It is supposed to > do the preemption checks, since preempt_count is actual count with lazy preemption. Sorry, but no, not wrong at all. This is the way that it is supposed to be. In this configuration, RCU readers explicitly disable preemption. This gets us minimal RCU overhead on architectures such as x86 and arm64 that have prohibited CONFIG_PREEMPT_NONE and CONFIG_PREEMPT_VOLUNTARY. Not zero overhead, but minimal overhead given the constraints imposed by CONFIG_PREEMPT_LAZY. This also prevents preemption of RCU readers, which is extremely important on datacenter servers that have good and sufficient quantities of memory, but which are not well-endowed with memory. > 2. PREEMPT_LAZY=y and PREEMPT_DYNAMIC=n and PREEMPT_LAZY=y and PREEMPT_DYNAMIC=y are supposed > to be similar w.r.t to performance. RCU never made that promise. ;-) With PREMPT_DYNAMIC=y, RCU has no choice but to be preemptible, at least unless and until someone decides to make RCU's preemptibility be changeable at runtime (which I do not recommend). And we really do need non-preemptible RCU for server workloads. So it is not just that RCU never made that promise, it is that RCU cannot reasonably make that promise. > Promise of PREEMPT_DYNAMIC was the ability to > switch at runtime based on the user workload and his/her preference. > But with PREEMPT_LAZY=y and PREEMPT_DYNAMIC=y, there is additional cost due to PREEMPT_RCU. > lazy being the middle ground w.r.t for decent performance, either PREEMPT_RCU should either kick in > for both cases or bail out for both. Absolutely not!!! Please see above. > Before 7.0 > 3. the same concerns would be true to PREEMPT_VOLUNTARY and PREEMPT_NONE with PREEMPT_DYNAMIC=y. > Those model never wanted a preemption, but PREEMPT_RCU could have forced a need_resched to be > set. Which is also likely wrong. No? You lost me on this one. Please give me an explicit sequence of events that would cause things to go wrong in this case. Thanx, Paul ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-28 16:21 ` Paul E. McKenney @ 2026-07-28 16:30 ` Paul E. McKenney 2026-07-30 13:01 ` Shrikanth Hegde 1 sibling, 0 replies; 35+ messages in thread From: Paul E. McKenney @ 2026-07-28 16:30 UTC (permalink / raw) To: Shrikanth Hegde Cc: Christophe Leroy (CS GROUP), Jirka Hladky, maddy, linuxppc-dev, mpe, npiggin, bigeasy, will, linux-kernel On Tue, Jul 28, 2026 at 09:21:55AM -0700, Paul E. McKenney wrote: > On Tue, Jul 28, 2026 at 10:57:57AM +0530, Shrikanth Hegde wrote: > > Hi Paul, Christophe, > > > > On 7/27/26 11:59 PM, Christophe Leroy (CS GROUP) wrote: > > > Hi Shrikanth, > > > > > > > > > > > That's right with CONFIG_PREEMPT_DYNAMIC=y > > > > > > With CONFIG_PREEMT_DYNAMIC=n: > > > - CONFIG_PREEMPT (full) implies CONFIG_PREEMPT_RCU > > > - CONFIG_PREEMPT_LAZY (lazy) doesn't imply CONFIG_PREEMPT_RCU > > > > > > because of kernel/rcu/Kconfig, > > > > > > config PREEMPT_RCU > > > bool > > > default y if (PREEMPT || PREEMPT_RT || PREEMPT_DYNAMIC) > > > select TREE_RCU > > > > > > Christophe > > > > > > > > > > Right. > > > > Looks like __rcu_read_unlock can set need_resched bit if it find irq were disabled > > and rcu_read_unlock_special.s is set. I don't have much clue about it. > > So, after seeing __rcu_read_unlock for PREEMPT_RCU I have these concerns now. > > This is because irq-disabled regions of code act as RCU readers. > For non-preemptible RCU (even in CONFIG_PREEMPT_LAZY=y kernels), this > comes for free. In contrast, preemptible RCU must explicitly (and, > as you noticed, rather painfully) handle the irq-disabled case: > > rcu_read_lock(); > do_something(); > local_irq_disable(); > do_something_else(); > rcu_read_unlock(); > do_yet_another_thing(); > local_irq_enable(); > > Here, the RCU reader extends all the way from the rcu_read_lock() to > the final local_irq_enable(). And this is why RCU checks for IRQs being > disabled in __rcu_read_unlock(). > > > In current upstream, lazy is a preemption mode with preempt_enable being a preemptible point, > > > > 1. If PREEMPT_LAZY=y and PREEMPT_DYNAMIC=n, then PREEMPT_RCU=n. That seems wrong. It is supposed to > > do the preemption checks, since preempt_count is actual count with lazy preemption. > > Sorry, but no, not wrong at all. This is the way that it is supposed > to be. In this configuration, RCU readers explicitly disable preemption. > This gets us minimal RCU overhead on architectures such as x86 and arm64 > that have prohibited CONFIG_PREEMPT_NONE and CONFIG_PREEMPT_VOLUNTARY. > Not zero overhead, but minimal overhead given the constraints imposed by > CONFIG_PREEMPT_LAZY. This also prevents preemption of RCU readers, which > is extremely important on datacenter servers that have good and sufficient > quantities of memory, but which are not well-endowed with memory. Now, if you would like to be able to manually choose between non-preemptible and preemptible RCU when when PREEMPT_LAZY=y, *that* we could discuss. But it looks like you are looking for low overhead, and thus wanting to avoid preemptible RCU. Thanx, Paul > > 2. PREEMPT_LAZY=y and PREEMPT_DYNAMIC=n and PREEMPT_LAZY=y and PREEMPT_DYNAMIC=y are supposed > > to be similar w.r.t to performance. > > RCU never made that promise. ;-) > > With PREMPT_DYNAMIC=y, RCU has no choice but to be preemptible, at > least unless and until someone decides to make RCU's preemptibility be > changeable at runtime (which I do not recommend). And we really do need > non-preemptible RCU for server workloads. > > So it is not just that RCU never made that promise, it is that RCU cannot > reasonably make that promise. > > > Promise of PREEMPT_DYNAMIC was the ability to > > switch at runtime based on the user workload and his/her preference. > > But with PREEMPT_LAZY=y and PREEMPT_DYNAMIC=y, there is additional cost due to PREEMPT_RCU. > > lazy being the middle ground w.r.t for decent performance, either PREEMPT_RCU should either kick in > > for both cases or bail out for both. > > Absolutely not!!! Please see above. > > > Before 7.0 > > 3. the same concerns would be true to PREEMPT_VOLUNTARY and PREEMPT_NONE with PREEMPT_DYNAMIC=y. > > Those model never wanted a preemption, but PREEMPT_RCU could have forced a need_resched to be > > set. Which is also likely wrong. No? > > You lost me on this one. Please give me an explicit sequence of events > that would cause things to go wrong in this case. > > Thanx, Paul ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-28 16:21 ` Paul E. McKenney 2026-07-28 16:30 ` Paul E. McKenney @ 2026-07-30 13:01 ` Shrikanth Hegde 2026-07-30 14:51 ` Paul E. McKenney 1 sibling, 1 reply; 35+ messages in thread From: Shrikanth Hegde @ 2026-07-30 13:01 UTC (permalink / raw) To: paulmck Cc: Christophe Leroy (CS GROUP), Jirka Hladky, maddy, linuxppc-dev, mpe, npiggin, bigeasy, will, linux-kernel Hi Paul. Thanks for taking time looking into this. >> In current upstream, lazy is a preemption mode with preempt_enable being a preemptible point, >> >> 1. If PREEMPT_LAZY=y and PREEMPT_DYNAMIC=n, then PREEMPT_RCU=n. That seems wrong. It is supposed to >> do the preemption checks, since preempt_count is actual count with lazy preemption. > > Sorry, but no, not wrong at all. This is the way that it is supposed > to be. In this configuration, RCU readers explicitly disable preemption. > This gets us minimal RCU overhead on architectures such as x86 and arm64 > that have prohibited CONFIG_PREEMPT_NONE and CONFIG_PREEMPT_VOLUNTARY. This is after 7.0 only right? Before that one could choose even on x86 and arm64 IIUC. After 7.0, even on powerpc, one cannot choose them anymore. > Not zero overhead, but minimal overhead given the constraints imposed by > CONFIG_PREEMPT_LAZY. This also prevents preemption of RCU readers, which > is extremely important on datacenter servers that have good and sufficient > quantities of memory, but which are not well-endowed with memory. > >> 2. PREEMPT_LAZY=y and PREEMPT_DYNAMIC=n and PREEMPT_LAZY=y and PREEMPT_DYNAMIC=y are supposed >> to be similar w.r.t to performance. > > RCU never made that promise. ;-) > > With PREMPT_DYNAMIC=y, RCU has no choice but to be preemptible, at > least unless and until someone decides to make RCU's preemptibility be > changeable at runtime (which I do not recommend). And we really do need > non-preemptible RCU for server workloads. most of the distros i see set PREMPT_DYNAMIC=y. I checked in SLES, RHEL. (I could be wrong here) > > So it is not just that RCU never made that promise, it is that RCU cannot > reasonably make that promise. > >> Promise of PREEMPT_DYNAMIC was the ability to >> switch at runtime based on the user workload and his/her preference. >> But with PREEMPT_LAZY=y and PREEMPT_DYNAMIC=y, there is additional cost due to PREEMPT_RCU. >> lazy being the middle ground w.r.t for decent performance, either PREEMPT_RCU should either kick in >> for both cases or bail out for both. > > Absolutely not!!! Please see above. > >> Before 7.0 >> 3. the same concerns would be true to PREEMPT_VOLUNTARY and PREEMPT_NONE with PREEMPT_DYNAMIC=y. >> Those model never wanted a preemption, but PREEMPT_RCU could have forced a need_resched to be >> set. Which is also likely wrong. No? > > You lost me on this one. Please give me an explicit sequence of events > that would cause things to go wrong in this case. You are right. PREEMPT_RCU may set need_resched. But even then on none/voluntary schedule will not be called since static keys it cannot. ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-30 13:01 ` Shrikanth Hegde @ 2026-07-30 14:51 ` Paul E. McKenney 0 siblings, 0 replies; 35+ messages in thread From: Paul E. McKenney @ 2026-07-30 14:51 UTC (permalink / raw) To: Shrikanth Hegde Cc: Christophe Leroy (CS GROUP), Jirka Hladky, maddy, linuxppc-dev, mpe, npiggin, bigeasy, will, linux-kernel On Thu, Jul 30, 2026 at 06:31:12PM +0530, Shrikanth Hegde wrote: > Hi Paul. Thanks for taking time looking into this. > > > > In current upstream, lazy is a preemption mode with preempt_enable being a preemptible point, > > > > > > 1. If PREEMPT_LAZY=y and PREEMPT_DYNAMIC=n, then PREEMPT_RCU=n. That seems wrong. It is supposed to > > > do the preemption checks, since preempt_count is actual count with lazy preemption. > > > > Sorry, but no, not wrong at all. This is the way that it is supposed > > to be. In this configuration, RCU readers explicitly disable preemption. > > This gets us minimal RCU overhead on architectures such as x86 and arm64 > > that have prohibited CONFIG_PREEMPT_NONE and CONFIG_PREEMPT_VOLUNTARY. > > This is after 7.0 only right? Before that one could choose even on x86 and arm64 IIUC. > After 7.0, even on powerpc, one cannot choose them anymore. Yes, until quite recently, you could select CONFIG_PREEMPT_NONE and CONFIG_PREEMPT_VOLUNTARY. Now you can do so only for architectures that don't support preemption, if I recall correctly. > > Not zero overhead, but minimal overhead given the constraints imposed by > > CONFIG_PREEMPT_LAZY. This also prevents preemption of RCU readers, which > > is extremely important on datacenter servers that have good and sufficient > > quantities of memory, but which are not well-endowed with memory. > > > > > 2. PREEMPT_LAZY=y and PREEMPT_DYNAMIC=n and PREEMPT_LAZY=y and PREEMPT_DYNAMIC=y are supposed > > > to be similar w.r.t to performance. > > > > RCU never made that promise. ;-) > > > > With PREMPT_DYNAMIC=y, RCU has no choice but to be preemptible, at > > least unless and until someone decides to make RCU's preemptibility be > > changeable at runtime (which I do not recommend). And we really do need > > non-preemptible RCU for server workloads. > > most of the distros i see set PREMPT_DYNAMIC=y. > I checked in SLES, RHEL. (I could be wrong here) I believe that to be the case. But there are those of us who build our own kernels and deploy them through large numbers of large datacenters. > > So it is not just that RCU never made that promise, it is that RCU cannot > > reasonably make that promise. > > > > > Promise of PREEMPT_DYNAMIC was the ability to > > > switch at runtime based on the user workload and his/her preference. > > > But with PREEMPT_LAZY=y and PREEMPT_DYNAMIC=y, there is additional cost due to PREEMPT_RCU. > > > lazy being the middle ground w.r.t for decent performance, either PREEMPT_RCU should either kick in > > > for both cases or bail out for both. > > > > Absolutely not!!! Please see above. > > > > > Before 7.0 > > > 3. the same concerns would be true to PREEMPT_VOLUNTARY and PREEMPT_NONE with PREEMPT_DYNAMIC=y. > > > Those model never wanted a preemption, but PREEMPT_RCU could have forced a need_resched to be > > > set. Which is also likely wrong. No? > > > > You lost me on this one. Please give me an explicit sequence of events > > that would cause things to go wrong in this case. > > You are right. PREEMPT_RCU may set need_resched. But even then on none/voluntary > schedule will not be called since static keys it cannot. Whew!!! ;-) Thanx, Paul ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-27 17:10 ` Shrikanth Hegde 2026-07-27 18:29 ` Christophe Leroy (CS GROUP) @ 2026-07-28 0:26 ` Jirka Hladky 2026-07-28 5:11 ` Shrikanth Hegde 1 sibling, 1 reply; 35+ messages in thread From: Jirka Hladky @ 2026-07-28 0:26 UTC (permalink / raw) To: Shrikanth Hegde Cc: paulmck, maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel On Mon, Jul 27, 2026 at 7:10 PM Shrikanth Hegde <sshegde@linux.ibm.com> wrote: > That's full preemption mode. > > When preemption mode changes preempt_enable/disable which were just a > barrier earlier now become real preemption points. If the code path > repeatedly does the exact same thing, it might pop up. > But, can we say is that number expected? it is difficult to put a > number to it. You were right -- my previous test conflated two variables. I've now built a third kernel to separate them. All three are from the same 6.15-rc6 source, same machine (POWER10 lp11), no PREEMPT_DYNAMIC: Config Mode PREEMPT_RCU kill bogo-ops/sec ------------------------------------ ---------- ----------- ----------------- PREEMPT_VOLUNTARY=y voluntary no 105,014 PREEMPT_LAZY=y lazy no 86,878 PREEMPT=y full yes 73,317 voluntary -> lazy -17.3% lazy -> full+PREEMPT_RCU -15.6% voluntary -> full+PREEMPT_RCU -30.2% The regression splits roughly 55/45 between the preemption mode change and PREEMPT_RCU: 1) voluntary -> lazy (-17.3%): preempt_disable/enable becoming real preemption points, as you predicted. On ppc64le this is expensive because the kill() syscall path is very tight and hits these points heavily. 2) lazy -> full+PREEMPT_RCU (-15.6%): __rcu_read_lock/__rcu_read_unlock requiring lwsync/isync barriers on ppc64le. > What I was asking is below. (You can do this only with below 7.0) > > Config A: CONFIG_PREEMPT_VOLUNTARY=y (CONFIG_PREEMPT_DYNAMIC=n) > Config B: CONFIG_PREEMPT_VOLUNTARY=y (CONFIG_PREEMPT_DYNAMIC=y) I couldn't do this exact test because 6.15-rc6 doesn't have HAVE_PREEMPT_DYNAMIC_KEY for powerpc (that's your 6.16 patch), so CONFIG_PREEMPT_DYNAMIC=y would be silently ignored. I would need a 6.16-6.19 kernel for this, which is before 7dadeaa6e851 removed voluntary as an option. But the PREEMPT_LAZY test above achieves the same goal: it isolates the preemption mode cost without PREEMPT_RCU. > Are you saying you see regression with voluntary with > CONFIG_PREEMPT_DYNAMIC=y? Yes. On the ELN kernels with CONFIG_PREEMPT_DYNAMIC=y, the regression appears at 6.16 when HAVE_PREEMPT_DYNAMIC_KEY is added, because: 1) PREEMPT_DYNAMIC forces the runtime mode to lazy/full (voluntary is no longer available on architectures with ARCH_HAS_PREEMPT_LAZY) 2) PREEMPT_DYNAMIC pulls in PREEMPT_RCU Both contribute to the ~30% total regression. Jirka ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-28 0:26 ` Jirka Hladky @ 2026-07-28 5:11 ` Shrikanth Hegde 2026-07-28 14:19 ` Jirka Hladky 0 siblings, 1 reply; 35+ messages in thread From: Shrikanth Hegde @ 2026-07-28 5:11 UTC (permalink / raw) To: Jirka Hladky Cc: paulmck, maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel Hi Jirka, Thanks for these experiments. On 7/28/26 5:56 AM, Jirka Hladky wrote: > On Mon, Jul 27, 2026 at 7:10 PM Shrikanth Hegde <sshegde@linux.ibm.com> wrote: >> That's full preemption mode. >> >> When preemption mode changes preempt_enable/disable which were just a >> barrier earlier now become real preemption points. If the code path >> repeatedly does the exact same thing, it might pop up. >> But, can we say is that number expected? it is difficult to put a >> number to it. > > You were right -- my previous test conflated two variables. I've now > built a third kernel to separate them. All three are from the same > 6.15-rc6 source, same machine (POWER10 lp11), no PREEMPT_DYNAMIC: > > Config Mode PREEMPT_RCU > kill bogo-ops/sec > ------------------------------------ ---------- ----------- > ----------------- > PREEMPT_VOLUNTARY=y voluntary no 105,014 > PREEMPT_LAZY=y lazy no 86,878 > PREEMPT=y full yes 73,317 > > voluntary -> lazy -17.3% > lazy -> full+PREEMPT_RCU -15.6% > voluntary -> full+PREEMPT_RCU -30.2% > > The regression splits roughly 55/45 between the preemption mode > change and PREEMPT_RCU: > > 1) voluntary -> lazy (-17.3%): preempt_disable/enable becoming real > preemption points, as you predicted. On ppc64le this is expensive > because the kill() syscall path is very tight and hits these > points heavily. That's true for all archs. Please check your preemption mode in your x86 experiment. If it remained same, then that small difference could PREEMPT_RCU cost. even preempt_enable/disable has barriers. > > 2) lazy -> full+PREEMPT_RCU (-15.6%): __rcu_read_lock/__rcu_read_unlock > requiring lwsync/isync barriers on ppc64le. > Full is more aggressive in setting in the need_resched bit and PREEMPT_RCU doing more than just barriers specially __rcu_read_unlock. >> What I was asking is below. (You can do this only with below 7.0) >> >> Config A: CONFIG_PREEMPT_VOLUNTARY=y (CONFIG_PREEMPT_DYNAMIC=n) >> Config B: CONFIG_PREEMPT_VOLUNTARY=y (CONFIG_PREEMPT_DYNAMIC=y) > > I couldn't do this exact test because 6.15-rc6 doesn't have > HAVE_PREEMPT_DYNAMIC_KEY for powerpc (that's your 6.16 patch), so > CONFIG_PREEMPT_DYNAMIC=y would be silently ignored. I would need a > 6.16-6.19 kernel for this, which is before 7dadeaa6e851 removed > voluntary as an option. > > But the PREEMPT_LAZY test above achieves the same goal: it isolates > the preemption mode cost without PREEMPT_RCU. > No. It doesn't confirm. I would recommend you do that case to find out the cost of PREEMPT_RCU alone. The reason being, lazy is a real preemption mode. All the callsites of preempt_enable could force a context switch. Whereas, >> Config A: CONFIG_PREEMPT_VOLUNTARY=y (CONFIG_PREEMPT_DYNAMIC=n) >> Config B: CONFIG_PREEMPT_VOLUNTARY=y (CONFIG_PREEMPT_DYNAMIC=y) Both are expected to same/similar w.r.t preempt_enable. But as we have discovered PREEMPT_DYNAMIC in additions enables PREEMPT_RCU. If we get the above data, then we can quantify the cost due to PREEMPT_RCU alone. Preemption mode cost is one thing, i.e preempt enable/disable cost, additional cost is call to schedule itself if need resched is set, that will likely over weigh the preemption cost. That is observed in your experiments too. full is more aggressive in setting the need_resched bit. Plus additional cost of PREEMPT_RCU which too can set need_resched bits. >> Are you saying you see regression with voluntary with >> CONFIG_PREEMPT_DYNAMIC=y? > > Yes. On the ELN kernels with CONFIG_PREEMPT_DYNAMIC=y, the regression > appears at 6.16 when HAVE_PREEMPT_DYNAMIC_KEY is added, because: > 1) PREEMPT_DYNAMIC forces the runtime mode to lazy/full (voluntary > is no longer available on architectures with ARCH_HAS_PREEMPT_LAZY) 1. Is not true. PREEMPT_DYNAMIC doesn't force the preemption mode switch. You can still choose voluntary even with PREEMPT_DYNAMIC on 6.16 to 6.19 kernel. Forced mode switch to lazy/full due to ARCH_HAS_PREEMPT_LAZY has happened in 7.0. > 2) PREEMPT_DYNAMIC pulls in PREEMPT_RCU > This looks it can set need_resched bit aggressive to force a quiescent state? Concerns i see with this config, I have put it in other thread. > Both contribute to the ~30% total regression. > > Jirka > ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-28 5:11 ` Shrikanth Hegde @ 2026-07-28 14:19 ` Jirka Hladky 2026-07-30 6:44 ` Shrikanth Hegde 0 siblings, 1 reply; 35+ messages in thread From: Jirka Hladky @ 2026-07-28 14:19 UTC (permalink / raw) To: Shrikanth Hegde Cc: paulmck, maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel On Tue, Jul 28, 2026 at 7:12 AM Shrikanth Hegde <sshegde@linux.ibm.com> wrote: > No. It doesn't confirm. I would recommend you do that case to find out > the cost of PREEMPT_RCU alone. > > Config A: CONFIG_PREEMPT_VOLUNTARY=y (CONFIG_PREEMPT_DYNAMIC=n) > Config B: CONFIG_PREEMPT_VOLUNTARY=y (CONFIG_PREEMPT_DYNAMIC=y) Done. Built two kernels from 6.18 upstream source on the same POWER10 machine. Both are voluntary preemption, differing only in PREEMPT_DYNAMIC (and thus PREEMPT_RCU): Config A: PREEMPT_VOLUNTARY=y, PREEMPT_DYNAMIC=n (no PREEMPT_RCU) Config B: PREEMPT_VOLUNTARY=y, PREEMPT_DYNAMIC=y (PREEMPT_RCU=y) Config B runtime mode confirmed as voluntary: cat /sys/kernel/debug/sched/preempt: "none (voluntary) full lazy" Results (stress-ng --kill 1 -t 23, SELinux enforcing, mean of 3 runs): Kernel PREEMPT_RCU kill bogo-ops/sec stddev ---------------------- ----------- ----------------- ------ 6.18.0-vol-nodynamic no 108,836 19 6.18.0-vol-dynamic yes 68,197 1,146 Delta -37.3% PREEMPT_RCU alone costs 37.3% on ppc64le with zero preemption mode change. Both kernels run voluntary preemption. > That's true for all archs. Please check your preemption mode in your > x86 experiment. Checked. On x86_64 (AMD EPYC 7313): Kernel PREEMPT_RCU Runtime mode kill bogo-ops/sec ------------------- ----------- ------------------ ----------------- 6.12.0-211 (el10) yes none (voluntary) 37,436 7.2.0-rc4 (eln158) yes full (lazy) 36,392 (-2.8%) Both x86 kernels already had PREEMPT_RCU=y, so the x86 comparison only shows the voluntary->lazy mode change cost (~3%), not the PREEMPT_RCU enablement cost. > 1. Is not true. PREEMPT_DYNAMIC doesn't force the preemption mode > switch. You can still choose voluntary even with PREEMPT_DYNAMIC on > 6.16 to 6.19 kernel. You are correct, I apologize for the error. The forced switch to lazy/full happened only in 7.0 with commit 7dadeaa6e851. On 6.16-6.19, voluntary is still available with PREEMPT_DYNAMIC, as confirmed by Config B above: $ cat /sys/kernel/debug/sched/preempt none (voluntary) full lazy Jirka ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-28 14:19 ` Jirka Hladky @ 2026-07-30 6:44 ` Shrikanth Hegde 2026-07-30 12:08 ` Jirka Hladky 0 siblings, 1 reply; 35+ messages in thread From: Shrikanth Hegde @ 2026-07-30 6:44 UTC (permalink / raw) To: Jirka Hladky Cc: paulmck, maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel Hi Jirka, Paul, On 7/28/26 7:49 PM, Jirka Hladky wrote: > On Tue, Jul 28, 2026 at 7:12 AM Shrikanth Hegde <sshegde@linux.ibm.com> wrote: >> No. It doesn't confirm. I would recommend you do that case to find out >> the cost of PREEMPT_RCU alone. >> >> Config A: CONFIG_PREEMPT_VOLUNTARY=y (CONFIG_PREEMPT_DYNAMIC=n) >> Config B: CONFIG_PREEMPT_VOLUNTARY=y (CONFIG_PREEMPT_DYNAMIC=y) > > Done. Built two kernels from 6.18 upstream source on the same POWER10 > machine. Both are voluntary preemption, differing only in > PREEMPT_DYNAMIC (and thus PREEMPT_RCU): > > Config A: PREEMPT_VOLUNTARY=y, PREEMPT_DYNAMIC=n (no PREEMPT_RCU) > Config B: PREEMPT_VOLUNTARY=y, PREEMPT_DYNAMIC=y (PREEMPT_RCU=y) > > Config B runtime mode confirmed as voluntary: > cat /sys/kernel/debug/sched/preempt: "none (voluntary) full lazy" > > Results (stress-ng --kill 1 -t 23, SELinux enforcing, mean of 3 runs): > > Kernel PREEMPT_RCU kill bogo-ops/sec stddev > ---------------------- ----------- ----------------- ------ > 6.18.0-vol-nodynamic no 108,836 19 > 6.18.0-vol-dynamic yes 68,197 1,146 > Delta -37.3% > > PREEMPT_RCU alone costs 37.3% on ppc64le with zero preemption mode > change. Both kernels run voluntary preemption. > I tried to repro using "taskset -c 0-7 stress-ng --kill 1 -t 23 --metrics" since system had more than 1 core. I did observe close to 25% regression with Config B Config A: PREEMPT_VOLUNTARY=y, PREEMPT_DYNAMIC=n Config B: PREEMPT_VOLUNTARY=y, PREEMPT_DYNAMIC=y I spent some more time debugging it as it was bugging me for few reasons. 1. There is barrier even when CONFIG_PREEMPTION=n. See include/linux/preempt.h. #define preempt_disable() barrier() #define preempt_enable() barrier() So i was doubting all the cost is due to that. 2. Seeing the stress-ng --kill 1 -t 23, it spawns 3 threads IIUC. two will be long running. Given there are 8 CPUs in the test, preemption should be minimal. (This is only a guess) 3. Though rcu_lock/unlock shows up only in one case, it could be just that they are inline in PREEMPT_DYNAMIC=n. They still do barriers. A did below hacks to see where the cost is coming from. =================================== First thing i did was to remove PREEMPT_RCU for PREEMPT_DYNAMIC=y. diff --git a/kernel/rcu/Kconfig b/kernel/rcu/Kconfig index 4d9b21f69eaa..1d67060b2261 100644 --- a/kernel/rcu/Kconfig +++ b/kernel/rcu/Kconfig @@ -18,7 +18,7 @@ config TREE_RCU config PREEMPT_RCU bool - default y if (PREEMPT || PREEMPT_RT || PREEMPT_DYNAMIC) + default y if (PREEMPT || PREEMPT_RT) select TREE_RCU help This option selects the RCU implementation that is This improves it by 5%. But doesn't cover the whole regression. ============================================================================ So PREEMPT_RCU is not the main reason. Now what else PREEMPT_DYNAMIC adds, 1. PREEMPT_DYNAMIC select CONFIG_PREEMPTION and that selects PREEMPT_COUNT. That turns every preempt_enable/disable to dec/inc the preempt count. Even though it isn't finally used for voluntary preemption. This can have overhead on any RISC architecture if all the workload does is hitting that path, without doing any meaningful work. 2. Static key overheads. ++++++++++++++++++++++++++++++++++++++ For 1, first thought came to my mind was is it due to preempt_count being part of thread_info. Tried to move it PACA as it is more efficient(atleast for 64 bit). Even with that numbers didn;t improve much. Then i thought, is it purely due to preempt count itself. So did below, diff --git a/kernel/Kconfig.preempt b/kernel/Kconfig.preempt index da326800c1c9..d00c600dc071 100644 --- a/kernel/Kconfig.preempt +++ b/kernel/Kconfig.preempt @@ -117,11 +117,11 @@ config PREEMPT_RT_NEEDS_BH_LOCK the old synchronized behaviour. config PREEMPTION - bool - select PREEMPT_COUNT + bool + select PREEMPT_COUNT if !PREEMPT_VOLUNTARY That is able to recover all the regression. You can give it a try if you want. But that's not a solution as dynamic preemption just won't work. ++++++++++++++++++++++++ For 2, Sadly, i lost the system to try any hacks for static key overheads. But given above, i don't expect it to be a major one. ============================================================================== From the above, it is quite evident that main cost is cost of preempt_disable/preempt_enable due to inc/dec of preempt count itself. This is due to nature of this workload which probably hits just lock/unlock likely, and no other work outside of it. The cost of preempt_count is likely un-avoidable with DYNAMIC_PREEMPTION for all RISC architecture. I think CISC cost is minimal since it can update memory and folding of need_resched bit into the preempt count. Both are not doable in RISC. Also given that after 7.0, all major archs including powerpc, can have only full/lazy preemption. None/voluntary are no longer possible. So making any sort of optimization for preempt count is not useful since it has to be there for full/lazy. Also, evaluate it with any real life workloads, IIRC i have run hackbench, schbench, daytrader(db2 workload) this cost wasn't visible. >> That's true for all archs. Please check your preemption mode in your >> x86 experiment. > > Checked. On x86_64 (AMD EPYC 7313): > > Kernel PREEMPT_RCU Runtime mode kill bogo-ops/sec > ------------------- ----------- ------------------ ----------------- > 6.12.0-211 (el10) yes none (voluntary) 37,436 > 7.2.0-rc4 (eln158) yes full (lazy) 36,392 (-2.8%) > > Both x86 kernels already had PREEMPT_RCU=y, so the x86 comparison > only shows the voluntary->lazy mode change cost (~3%), not the > PREEMPT_RCU enablement cost. > ^ permalink raw reply related [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-30 6:44 ` Shrikanth Hegde @ 2026-07-30 12:08 ` Jirka Hladky 2026-07-30 14:47 ` Paul E. McKenney 0 siblings, 1 reply; 35+ messages in thread From: Jirka Hladky @ 2026-07-30 12:08 UTC (permalink / raw) To: Shrikanth Hegde Cc: paulmck, maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel On Thu, Jul 30, 2026 at 8:44 AM Shrikanth Hegde <sshegde@linux.ibm.com> wrote: > From the above, it is quite evident that main cost is cost of > preempt_disable/preempt_enable due to inc/dec of preempt count > itself. Thanks for the deep debugging, Shrikanth. This changes the picture significantly. So the chain is: PREEMPT_DYNAMIC -> PREEMPTION -> PREEMPT_COUNT -> every preempt_disable/enable becomes load-modify-store with barriers And the __rcu_read_lock/__rcu_read_unlock overhead I measured was actually the preempt_disable/preempt_enable inside them, not the RCU logic itself. That explains why removing PREEMPT_RCU only recovered ~5% -- the remaining preempt_count operations throughout the syscall path are the dominant cost. > The cost of preempt_count is likely un-avoidable with > DYNAMIC_PREEMPTION for all RISC architecture. Agreed. On CISC (x86), the preempt_count update is a single memory inc/dec instruction. On RISC, it requires load-modify-store plus barriers for the atomic update, which is fundamentally more expensive per operation. > Also given that after 7.0, all major archs including powerpc, can > have only full/lazy preemption. None/voluntary are no longer possible. > So making any sort of optimization for preempt count is not useful > since it has to be there for full/lazy. Right. With full/lazy, PREEMPT_COUNT is required regardless of PREEMPT_DYNAMIC. > Also, evaluate it with any real life workloads, IIRC i have run > hackbench, schbench, daytrader(db2 workload) this cost wasn't visible. Good to know. I reviewed our full CI results across all benchmark suites on ppc64le and I don't see regressions outside of stress-ng. The stress-ng kill stressor is a worst case -- a tight syscall loop that hits preempt_disable/enable many times per call through the SELinux AVC path. Real workloads that do actual work between syscalls amortize this cost. I'll update our internal tracking with the corrected root cause. Thanks again for your persistence on isolating this. Good to have the real root cause understood, even if it's a fundamental RISC cost we have to accept. Jirka ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-30 12:08 ` Jirka Hladky @ 2026-07-30 14:47 ` Paul E. McKenney 2026-07-30 15:08 ` Jirka Hladky 0 siblings, 1 reply; 35+ messages in thread From: Paul E. McKenney @ 2026-07-30 14:47 UTC (permalink / raw) To: Jirka Hladky Cc: Shrikanth Hegde, maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel On Thu, Jul 30, 2026 at 02:08:54PM +0200, Jirka Hladky wrote: > On Thu, Jul 30, 2026 at 8:44 AM Shrikanth Hegde <sshegde@linux.ibm.com> wrote: > > From the above, it is quite evident that main cost is cost of > > preempt_disable/preempt_enable due to inc/dec of preempt count > > itself. > > Thanks for the deep debugging, Shrikanth. This changes the picture > significantly. > > So the chain is: > PREEMPT_DYNAMIC -> PREEMPTION -> PREEMPT_COUNT > -> every preempt_disable/enable becomes load-modify-store with barriers > > And the __rcu_read_lock/__rcu_read_unlock overhead I measured was > actually the preempt_disable/preempt_enable inside them, not the RCU > logic itself. That explains why removing PREEMPT_RCU only recovered > ~5% -- the remaining preempt_count operations throughout the syscall > path are the dominant cost. > > > The cost of preempt_count is likely un-avoidable with > > DYNAMIC_PREEMPTION for all RISC architecture. > > Agreed. On CISC (x86), the preempt_count update is a single memory > inc/dec instruction. On RISC, it requires load-modify-store plus > barriers for the atomic update, which is fundamentally more expensive > per operation. > > > Also given that after 7.0, all major archs including powerpc, can > > have only full/lazy preemption. None/voluntary are no longer possible. > > So making any sort of optimization for preempt count is not useful > > since it has to be there for full/lazy. > > Right. With full/lazy, PREEMPT_COUNT is required regardless of > PREEMPT_DYNAMIC. > > > Also, evaluate it with any real life workloads, IIRC i have run > > hackbench, schbench, daytrader(db2 workload) this cost wasn't visible. > > Good to know. I reviewed our full CI results across all benchmark > suites on ppc64le and I don't see regressions outside of stress-ng. The > stress-ng kill stressor is a worst case -- a tight syscall loop that > hits preempt_disable/enable many times per call through the SELinux > AVC path. Real workloads that do actual work between syscalls > amortize this cost. > > I'll update our internal tracking with the corrected root cause. > > Thanks again for your persistence on isolating this. Good to have > the real root cause understood, even if it's a fundamental RISC cost > we have to accept. Good on all of you! But is this really a fundamental RISC cost? For example, does arm64 see the same performance issues? In particular, I can see why the preempt_count() operations need to be interrupt-safe, but I don't see why you would need barriers. And doesn't powerpc still use software interrupt disabling? If so, why not use that to simply software-disable interrupts around the preempt_count() operations? What am I missing here? Thanx, Paul ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-30 14:47 ` Paul E. McKenney @ 2026-07-30 15:08 ` Jirka Hladky 2026-07-30 16:26 ` Paul E. McKenney 2026-07-30 17:10 ` Shrikanth Hegde 0 siblings, 2 replies; 35+ messages in thread From: Jirka Hladky @ 2026-07-30 15:08 UTC (permalink / raw) To: paulmck Cc: Shrikanth Hegde, maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel On Thu, Jul 30, 2026 at 4:53 PM Paul E. McKenney <paulmck@kernel.org> wrote: > But is this really a fundamental RISC cost? For example, does arm64 > see the same performance issues? We tested arm64 (Ampere Altra Max) with the same controlled experiment -- two 6.18 kernels, both voluntary, differing only in PREEMPT_DYNAMIC: Arch PREEMPT_DYNAMIC kill bogo-ops/sec Delta ------- --------------- ----------------- ----- ppc64le off 108,836 ppc64le on 68,197 -37.3% aarch64 off 5,538 aarch64 on 5,082 -8.2% arm64 sees -8.2% vs ppc64le's -37.3%. So arm64 is affected but much less severely. > In particular, I can see why the preempt_count() operations need to be > interrupt-safe, but I don't see why you would need barriers. And > doesn't powerpc still use software interrupt disabling? If so, why > not use that to simply software-disable interrupts around the > preempt_count() operations? > > What am I missing here? That's a good question -- I don't know enough about the powerpc preempt_count implementation to answer this. Shrikanth, could you comment on whether removing the barriers or using software interrupt disabling around preempt_count is feasible? Thank you Jirka ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-30 15:08 ` Jirka Hladky @ 2026-07-30 16:26 ` Paul E. McKenney 2026-07-30 17:10 ` Shrikanth Hegde 1 sibling, 0 replies; 35+ messages in thread From: Paul E. McKenney @ 2026-07-30 16:26 UTC (permalink / raw) To: Jirka Hladky Cc: Shrikanth Hegde, maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel On Thu, Jul 30, 2026 at 05:08:13PM +0200, Jirka Hladky wrote: > On Thu, Jul 30, 2026 at 4:53 PM Paul E. McKenney <paulmck@kernel.org> wrote: > > But is this really a fundamental RISC cost? For example, does arm64 > > see the same performance issues? > > We tested arm64 (Ampere Altra Max) with the same controlled > experiment -- two 6.18 kernels, both voluntary, differing only in > PREEMPT_DYNAMIC: > > Arch PREEMPT_DYNAMIC kill bogo-ops/sec Delta > ------- --------------- ----------------- ----- > ppc64le off 108,836 > ppc64le on 68,197 -37.3% > aarch64 off 5,538 > aarch64 on 5,082 -8.2% > > arm64 sees -8.2% vs ppc64le's -37.3%. So arm64 is affected but > much less severely. That is more like I would expect. Yes, there is added overhead, but it should not be excessively expensive. Though I suspect that arm64 could also do better. Easy for me to say, I know! ;-) Thanx, Paul > > In particular, I can see why the preempt_count() operations need to be > > interrupt-safe, but I don't see why you would need barriers. And > > doesn't powerpc still use software interrupt disabling? If so, why > > not use that to simply software-disable interrupts around the > > preempt_count() operations? > > > > What am I missing here? > > That's a good question -- I don't know enough about the powerpc > preempt_count implementation to answer this. Shrikanth, could you > comment on whether removing the barriers or using software interrupt > disabling around preempt_count is feasible? > > Thank you > Jirka > ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-30 15:08 ` Jirka Hladky 2026-07-30 16:26 ` Paul E. McKenney @ 2026-07-30 17:10 ` Shrikanth Hegde 2026-07-30 17:26 ` Paul E. McKenney 2026-07-31 5:03 ` Christophe Leroy (CS GROUP) 1 sibling, 2 replies; 35+ messages in thread From: Shrikanth Hegde @ 2026-07-30 17:10 UTC (permalink / raw) To: Jirka Hladky, paulmck Cc: maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel, Will Deacon Hi Jirka, Paul, +cc will On 7/30/26 8:38 PM, Jirka Hladky wrote: > On Thu, Jul 30, 2026 at 4:53 PM Paul E. McKenney <paulmck@kernel.org> wrote: >> But is this really a fundamental RISC cost? For example, does arm64 >> see the same performance issues? > > We tested arm64 (Ampere Altra Max) with the same controlled > experiment -- two 6.18 kernels, both voluntary, differing only in > PREEMPT_DYNAMIC: > > Arch PREEMPT_DYNAMIC kill bogo-ops/sec Delta > ------- --------------- ----------------- ----- > ppc64le off 108,836 > ppc64le on 68,197 -37.3% > aarch64 off 5,538 > aarch64 on 5,082 -8.2% > > arm64 sees -8.2% vs ppc64le's -37.3%. So arm64 is affected but > much less severely. Ouch!. But that's good to know. > >> In particular, I can see why the preempt_count() operations need to be >> interrupt-safe, but I don't see why you would need barriers. And >> doesn't powerpc still use software interrupt disabling? If so, why >> not use that to simply software-disable interrupts around the >> preempt_count() operations? Barrier are in core implementation, not in arch specific. #ifdef CONFIG_PREEMPT_COUNT #define preempt_disable() \ do { \ preempt_count_inc(); \ barrier(); \ } while (0) #ifdef CONFIG_PREEMPTION #define preempt_enable() \ do { \ barrier(); \ if (unlikely(preempt_count_dec_and_test())) \ __preempt_schedule(); \ } while (0) >> >> What am I missing here? > > That's a good question -- I don't know enough about the powerpc > preempt_count implementation to answer this. Shrikanth, could you > comment on whether removing the barriers or using software interrupt > disabling around preempt_count is feasible? > > Thank you > Jirka > PowerPC currently uses asm-generic implementation which is probably sub-optimal w.r.t to check of need_resched. When i see ARM's implementation, i see there is trick of splitting it into two. union { u64 preempt_count; /* 0 => preemptible, <0 => bug */ struct { #ifdef CONFIG_CPU_BIG_ENDIAN u32 need_resched; u32 count; #else u32 count; u32 need_resched; #endif } preempt; }; Seeing Will's changelog is on similar direction. 396244692232 arm64: preempt: Provide our own implementation of asm/preempt.h "The asm-generic/preempt.h implementation doesn't make use of the PREEMPT_NEED_RESCHED flag, since this can interact badly with load/store architectures which rely on the preempt_count word being unchanged across an interrupt. However, since we're a 64-bit architecture and the preempt count is only 32 bits wide, we can simply pack it next to the resched flag and load the whole thing in one go, so that a dec-and-test operation doesn't need to load twice. " I am speculating this might help solve for ppc64 too. But i don't have a system to try this right now, will get back once i do ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-30 17:10 ` Shrikanth Hegde @ 2026-07-30 17:26 ` Paul E. McKenney 2026-07-30 18:40 ` Segher Boessenkool 2026-07-31 5:03 ` Christophe Leroy (CS GROUP) 1 sibling, 1 reply; 35+ messages in thread From: Paul E. McKenney @ 2026-07-30 17:26 UTC (permalink / raw) To: Shrikanth Hegde Cc: Jirka Hladky, maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel On Thu, Jul 30, 2026 at 10:40:38PM +0530, Shrikanth Hegde wrote: > Hi Jirka, Paul, > > > +cc will > > On 7/30/26 8:38 PM, Jirka Hladky wrote: > > On Thu, Jul 30, 2026 at 4:53 PM Paul E. McKenney <paulmck@kernel.org> wrote: > > > But is this really a fundamental RISC cost? For example, does arm64 > > > see the same performance issues? > > > > We tested arm64 (Ampere Altra Max) with the same controlled > > experiment -- two 6.18 kernels, both voluntary, differing only in > > PREEMPT_DYNAMIC: > > > > Arch PREEMPT_DYNAMIC kill bogo-ops/sec Delta > > ------- --------------- ----------------- ----- > > ppc64le off 108,836 > > ppc64le on 68,197 -37.3% > > aarch64 off 5,538 > > aarch64 on 5,082 -8.2% > > > > arm64 sees -8.2% vs ppc64le's -37.3%. So arm64 is affected but > > much less severely. > > Ouch!. But that's good to know. > > > > > > In particular, I can see why the preempt_count() operations need to be > > > interrupt-safe, but I don't see why you would need barriers. And > > > doesn't powerpc still use software interrupt disabling? If so, why > > > not use that to simply software-disable interrupts around the > > > preempt_count() operations? > > Barrier are in core implementation, not in arch specific. > > #ifdef CONFIG_PREEMPT_COUNT > #define preempt_disable() \ > do { \ > preempt_count_inc(); \ > barrier(); \ > } while (0) > > > #ifdef CONFIG_PREEMPTION > #define preempt_enable() \ > do { \ > barrier(); \ > if (unlikely(preempt_count_dec_and_test())) \ > __preempt_schedule(); \ > } while (0) But barrier() is just "__asm__ __volatile__("": : :"memory")", which does not emit any instructions. Or is this doing more machine-register flushing/restoring than one might expect? > > > What am I missing here? > > > > That's a good question -- I don't know enough about the powerpc > > preempt_count implementation to answer this. Shrikanth, could you > > comment on whether removing the barriers or using software interrupt > > disabling around preempt_count is feasible? > > > > Thank you > > Jirka > > > > PowerPC currently uses asm-generic implementation which is probably sub-optimal > w.r.t to check of need_resched. > > When i see ARM's implementation, i see there is trick of splitting it into two. > > union { > u64 preempt_count; /* 0 => preemptible, <0 => bug */ > struct { > #ifdef CONFIG_CPU_BIG_ENDIAN > u32 need_resched; > u32 count; > #else > u32 count; > u32 need_resched; > #endif > } preempt; > }; > > > Seeing Will's changelog is on similar direction. > > 396244692232 arm64: preempt: Provide our own implementation of asm/preempt.h > "The asm-generic/preempt.h implementation doesn't make use of the > PREEMPT_NEED_RESCHED flag, since this can interact badly with load/store > architectures which rely on the preempt_count word being unchanged across > an interrupt. > > However, since we're a 64-bit architecture and the preempt count is > only 32 bits wide, we can simply pack it next to the resched flag and > load the whole thing in one go, so that a dec-and-test operation doesn't > need to load twice. " > > I am speculating this might help solve for ppc64 too. But i don't have a system > to try this right now, will get back once i do Looking forward to seeing what you come up with! Thanx, Paul ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-30 17:26 ` Paul E. McKenney @ 2026-07-30 18:40 ` Segher Boessenkool 2026-07-31 4:59 ` Christophe Leroy (CS GROUP) 0 siblings, 1 reply; 35+ messages in thread From: Segher Boessenkool @ 2026-07-30 18:40 UTC (permalink / raw) To: Paul E. McKenney Cc: Shrikanth Hegde, Jirka Hladky, maddy, linuxppc-dev, christophe.leroy, mpe, npiggin, bigeasy, will, linux-kernel On Thu, Jul 30, 2026 at 10:26:58AM -0700, Paul E. McKenney wrote: > On Thu, Jul 30, 2026 at 10:40:38PM +0530, Shrikanth Hegde wrote: > > Barrier are in core implementation, not in arch specific. "Compiler barrier"s are not actually a thing, it is not a barrier for anything. It's just telling the compiler that at the point of the "barrier" all the registers should hold the values that they conceptually do also *actually*. (In theory the compiler can sometimes prove it can do things that do not even guarantee that, but in practice this holds). > But barrier() is just "__asm__ __volatile__("": : :"memory")", which > does not emit any instructions. Or is this doing more machine-register > flushing/restoring than one might expect? (__volatile__ is redundant, any asm without outputs is always counted as volatile. If this wasn't true, GCC could always delete any such asm, since it has no side effects at all! People often think "volatile" asm is some magic that prohibits the compiler from optimising stuff, but it is not, it has very contrained and very specific meaning). Nope. The "memory" clobber says that all memory can be read and written in that asm, so any value that conceptually resides in memory there should have a stable value there. This can trigger some save/restore stuff, sure, but on all Power ABIs we have actual registers for pretty much everything, so nothing at all is done here. Segher ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-30 18:40 ` Segher Boessenkool @ 2026-07-31 4:59 ` Christophe Leroy (CS GROUP) 0 siblings, 0 replies; 35+ messages in thread From: Christophe Leroy (CS GROUP) @ 2026-07-31 4:59 UTC (permalink / raw) To: Segher Boessenkool, Paul E. McKenney Cc: Shrikanth Hegde, Jirka Hladky, maddy, linuxppc-dev, mpe, npiggin, bigeasy, will, linux-kernel Le 30/07/2026 à 20:40, Segher Boessenkool a écrit : > On Thu, Jul 30, 2026 at 10:26:58AM -0700, Paul E. McKenney wrote: >> On Thu, Jul 30, 2026 at 10:40:38PM +0530, Shrikanth Hegde wrote: >>> Barrier are in core implementation, not in arch specific. > > "Compiler barrier"s are not actually a thing, it is not a barrier for > anything. It's just telling the compiler that at the point of the > "barrier" all the registers should hold the values that they > conceptually do also *actually*. > > (In theory the compiler can sometimes prove it can do things that do not > even guarantee that, but in practice this holds). > >> But barrier() is just "__asm__ __volatile__("": : :"memory")", which >> does not emit any instructions. Or is this doing more machine-register >> flushing/restoring than one might expect? > > (__volatile__ is redundant, any asm without outputs is always counted as > volatile. If this wasn't true, GCC could always delete any such asm, > since it has no side effects at all! There is a comment for the volatile: /* Optimization barrier */ #ifndef barrier /* The "volatile" is due to gcc bugs */ # define barrier() __asm__ __volatile__("": : :"memory") #endif > > People often think "volatile" asm is some magic that prohibits the > compiler from optimising stuff, but it is not, it has very contrained > and very specific meaning). > > Nope. The "memory" clobber says that all memory can be read and written > in that asm, so any value that conceptually resides in memory there > should have a stable value there. This can trigger some save/restore > stuff, sure, but on all Power ABIs we have actual registers for pretty > much everything, so nothing at all is done here. > > > Segher ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-30 17:10 ` Shrikanth Hegde 2026-07-30 17:26 ` Paul E. McKenney @ 2026-07-31 5:03 ` Christophe Leroy (CS GROUP) 2026-07-31 7:18 ` Jirka Hladky 1 sibling, 1 reply; 35+ messages in thread From: Christophe Leroy (CS GROUP) @ 2026-07-31 5:03 UTC (permalink / raw) To: Shrikanth Hegde, Jirka Hladky, paulmck Cc: maddy, linuxppc-dev, mpe, npiggin, bigeasy, will, linux-kernel Le 30/07/2026 à 19:10, Shrikanth Hegde a écrit : > Hi Jirka, Paul, > > > +cc will > > On 7/30/26 8:38 PM, Jirka Hladky wrote: >> On Thu, Jul 30, 2026 at 4:53 PM Paul E. McKenney <paulmck@kernel.org> >> wrote: >>> But is this really a fundamental RISC cost? For example, does arm64 >>> see the same performance issues? >> >> We tested arm64 (Ampere Altra Max) with the same controlled >> experiment -- two 6.18 kernels, both voluntary, differing only in >> PREEMPT_DYNAMIC: >> >> Arch PREEMPT_DYNAMIC kill bogo-ops/sec Delta >> ------- --------------- ----------------- ----- >> ppc64le off 108,836 >> ppc64le on 68,197 -37.3% >> aarch64 off 5,538 >> aarch64 on 5,082 -8.2% >> >> arm64 sees -8.2% vs ppc64le's -37.3%. So arm64 is affected but >> much less severely. > > Ouch!. But that's good to know. Might be a stupid question, but what is your .config ? Are you sure it doesn't contain CONFIG_DEBUG_PREEMPT ? > >> >>> In particular, I can see why the preempt_count() operations need to be >>> interrupt-safe, but I don't see why you would need barriers. And >>> doesn't powerpc still use software interrupt disabling? If so, why >>> not use that to simply software-disable interrupts around the >>> preempt_count() operations? > > Barrier are in core implementation, not in arch specific. > > #ifdef CONFIG_PREEMPT_COUNT > #define preempt_disable() \ > do { \ > preempt_count_inc(); \ > barrier(); \ > } while (0) > > > #ifdef CONFIG_PREEMPTION > #define preempt_enable() \ > do { \ > barrier(); \ > if (unlikely(preempt_count_dec_and_test())) \ > __preempt_schedule(); \ > } while (0) > > > >>> >>> What am I missing here? >> >> That's a good question -- I don't know enough about the powerpc >> preempt_count implementation to answer this. Shrikanth, could you >> comment on whether removing the barriers or using software interrupt >> disabling around preempt_count is feasible? >> >> Thank you >> Jirka >> > > PowerPC currently uses asm-generic implementation which is probably sub- > optimal > w.r.t to check of need_resched. > > When i see ARM's implementation, i see there is trick of splitting it > into two. > > union { > u64 preempt_count; /* 0 => preemptible, <0 > => bug */ > struct { > #ifdef CONFIG_CPU_BIG_ENDIAN > u32 need_resched; > u32 count; > #else > u32 count; > u32 need_resched; > #endif > } preempt; > }; > > > Seeing Will's changelog is on similar direction. > > 396244692232 arm64: preempt: Provide our own implementation of asm/ > preempt.h > "The asm-generic/preempt.h implementation doesn't make use of the > PREEMPT_NEED_RESCHED flag, since this can interact badly with load/store > architectures which rely on the preempt_count word being unchanged across > an interrupt. > > However, since we're a 64-bit architecture and the preempt count is > only 32 bits wide, we can simply pack it next to the resched flag and > load the whole thing in one go, so that a dec-and-test operation doesn't > need to load twice. " > > I am speculating this might help solve for ppc64 too. But i don't have a > system > to try this right now, will get back once i do ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-31 5:03 ` Christophe Leroy (CS GROUP) @ 2026-07-31 7:18 ` Jirka Hladky 2026-07-31 8:02 ` Shrikanth Hegde 0 siblings, 1 reply; 35+ messages in thread From: Jirka Hladky @ 2026-07-31 7:18 UTC (permalink / raw) To: Christophe Leroy (CS GROUP) Cc: Shrikanth Hegde, paulmck, maddy, linuxppc-dev, mpe, npiggin, bigeasy, will, linux-kernel On Fri, Jul 31, 2026 at 7:03 AM Christophe Leroy (CS GROUP) <chleroy@kernel.org> wrote: > > > > Le 30/07/2026 à 19:10, Shrikanth Hegde a écrit : > > Hi Jirka, Paul, > > > > > > +cc will > > > > On 7/30/26 8:38 PM, Jirka Hladky wrote: > >> On Thu, Jul 30, 2026 at 4:53 PM Paul E. McKenney <paulmck@kernel.org> > >> wrote: > >>> But is this really a fundamental RISC cost? For example, does arm64 > >>> see the same performance issues? > >> > >> We tested arm64 (Ampere Altra Max) with the same controlled > >> experiment -- two 6.18 kernels, both voluntary, differing only in > >> PREEMPT_DYNAMIC: > >> > >> Arch PREEMPT_DYNAMIC kill bogo-ops/sec Delta > >> ------- --------------- ----------------- ----- > >> ppc64le off 108,836 > >> ppc64le on 68,197 -37.3% > >> aarch64 off 5,538 > >> aarch64 on 5,082 -8.2% > >> > >> arm64 sees -8.2% vs ppc64le's -37.3%. So arm64 is affected but > >> much less severely. > > > > Ouch!. But that's good to know. > > Might be a stupid question, but what is your .config ? > Are you sure it doesn't contain CONFIG_DEBUG_PREEMPT ? I have double-checked that and it's not set: # CONFIG_DEBUG_PREEMPT is not set Thanks Jirka ^ permalink raw reply [flat|nested] 35+ messages in thread
* Re: [PATCH v4 1/1] powerpc: enable dynamic preemption 2026-07-31 7:18 ` Jirka Hladky @ 2026-07-31 8:02 ` Shrikanth Hegde 0 siblings, 0 replies; 35+ messages in thread From: Shrikanth Hegde @ 2026-07-31 8:02 UTC (permalink / raw) To: Jirka Hladky, Christophe Leroy (CS GROUP) Cc: paulmck, maddy, linuxppc-dev, mpe, npiggin, bigeasy, will, linux-kernel Hi. On 7/31/26 12:48 PM, Jirka Hladky wrote: > On Fri, Jul 31, 2026 at 7:03 AM Christophe Leroy (CS GROUP) > <chleroy@kernel.org> wrote: >> >> >> >> Le 30/07/2026 à 19:10, Shrikanth Hegde a écrit : >>> Hi Jirka, Paul, >>> >>> >>> +cc will >>> >>> On 7/30/26 8:38 PM, Jirka Hladky wrote: >>>> On Thu, Jul 30, 2026 at 4:53 PM Paul E. McKenney <paulmck@kernel.org> >>>> wrote: >>>>> But is this really a fundamental RISC cost? For example, does arm64 >>>>> see the same performance issues? >>>> >>>> We tested arm64 (Ampere Altra Max) with the same controlled >>>> experiment -- two 6.18 kernels, both voluntary, differing only in >>>> PREEMPT_DYNAMIC: >>>> >>>> Arch PREEMPT_DYNAMIC kill bogo-ops/sec Delta >>>> ------- --------------- ----------------- ----- >>>> ppc64le off 108,836 >>>> ppc64le on 68,197 -37.3% >>>> aarch64 off 5,538 >>>> aarch64 on 5,082 -8.2% >>>> >>>> arm64 sees -8.2% vs ppc64le's -37.3%. So arm64 is affected but >>>> much less severely. >>> >>> Ouch!. But that's good to know. >> >> Might be a stupid question, but what is your .config ? >> Are you sure it doesn't contain CONFIG_DEBUG_PREEMPT ? > > I have double-checked that and it's not set: > # CONFIG_DEBUG_PREEMPT is not set > > Thanks > Jirka > Coming into numbers, I did notice later, arm64 numbers are almost 20x less. I believe you are having similar core count or benchmark is same. But if we compare the time taken for each operations, it tells a different story. PREEMPT_DYNAMIC ppc64le off 108836 ops/s = 9.19 us/op ppc64le on 68197 ops/s = 14.66 us/op delta +5.47 us/op aarch64 off 5538 ops/s = 180.57 us/op aarch64 on 5082 ops/s = 196.77 us/op delta +16.20 us/op PS: I tried porting some of those changes in arm64 to powerpc to split preempt count into two. but i don;t see much improvement there. If i see get better numbers i will reply with that. ^ permalink raw reply [flat|nested] 35+ messages in thread
end of thread, other threads:[~2026-07-31 8:03 UTC | newest] Thread overview: 35+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-02-10 18:43 [PATCH v4 0/1] powerpc: Enable dynamic preemption Shrikanth Hegde 2025-02-10 18:43 ` [PATCH v4 1/1] powerpc: enable " Shrikanth Hegde 2026-07-26 18:33 ` Jirka Hladky 2026-07-27 4:18 ` Shrikanth Hegde 2026-07-27 10:13 ` Jirka Hladky 2026-07-27 10:28 ` Shrikanth Hegde 2026-07-27 10:35 ` Christophe Leroy (CS GROUP) 2026-07-27 16:12 ` Paul E. McKenney 2026-07-27 10:59 ` Jirka Hladky 2026-07-27 11:03 ` Shrikanth Hegde 2026-07-27 12:34 ` Shrikanth Hegde 2026-07-27 16:07 ` Paul E. McKenney 2026-07-27 16:50 ` Jirka Hladky 2026-07-27 17:10 ` Shrikanth Hegde 2026-07-27 18:29 ` Christophe Leroy (CS GROUP) 2026-07-28 5:27 ` Shrikanth Hegde 2026-07-28 16:21 ` Paul E. McKenney 2026-07-28 16:30 ` Paul E. McKenney 2026-07-30 13:01 ` Shrikanth Hegde 2026-07-30 14:51 ` Paul E. McKenney 2026-07-28 0:26 ` Jirka Hladky 2026-07-28 5:11 ` Shrikanth Hegde 2026-07-28 14:19 ` Jirka Hladky 2026-07-30 6:44 ` Shrikanth Hegde 2026-07-30 12:08 ` Jirka Hladky 2026-07-30 14:47 ` Paul E. McKenney 2026-07-30 15:08 ` Jirka Hladky 2026-07-30 16:26 ` Paul E. McKenney 2026-07-30 17:10 ` Shrikanth Hegde 2026-07-30 17:26 ` Paul E. McKenney 2026-07-30 18:40 ` Segher Boessenkool 2026-07-31 4:59 ` Christophe Leroy (CS GROUP) 2026-07-31 5:03 ` Christophe Leroy (CS GROUP) 2026-07-31 7:18 ` Jirka Hladky 2026-07-31 8:02 ` Shrikanth Hegde
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox