Thread (21 messages) 21 messages, 4 authors, 1d ago

Re: [PATCH v4 1/1] powerpc: enable dynamic preemption

From: Jirka Hladky <hidden>
Date: 2026-07-26 18:33:37
Also in: lkml

  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 [off-list ref] wrote:
quoted hunk ↗ jump to hunk
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 <redacted>
---
 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

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help