* [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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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; 18+ 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] 18+ 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 0 siblings, 0 replies; 18+ 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] 18+ 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; 18+ 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] 18+ 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 0 siblings, 0 replies; 18+ 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] 18+ messages in thread
end of thread, other threads:[~2026-07-28 5:28 UTC | newest] Thread overview: 18+ 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 0:26 ` Jirka Hladky 2026-07-28 5:11 ` Shrikanth Hegde
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox