All of lore.kernel.org
 help / color / mirror / Atom feed
* [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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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; 15+ 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] 15+ 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)
  0 siblings, 1 reply; 15+ 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] 15+ 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)
  0 siblings, 0 replies; 15+ 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] 15+ messages in thread

end of thread, other threads:[~2026-07-27 18:29 UTC | newest]

Thread overview: 15+ 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)

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.