summaryrefslogtreecommitdiff
path: root/tools/perf/scripts/python/bin
diff options
context:
space:
mode:
authorMark Rutland <mark.rutland@arm.com>2026-09-08 16:17:26 +0100
committerCatalin Marinas <catalin.marinas@arm.com>2026-09-24 14:51:40 +0100
commit1bee18253c2ea9db07fca4496b0e25ab3f5db8e1 (patch)
treed583b8d22eaaf82e9707ff1178fb976ece918ac5 /tools/perf/scripts/python/bin
parentde2824489899f34db976f6c8f1a548d4cf76fc44 (diff)
arm64: preempt: Simplify and optimize __preempt_count_dec_and_test()
In arm64's __preempt_count_dec_and_test(), the final conditional load of 'ti->preempt_count' is always executed in the common case. The conditional load leads to unfortunate code generation for preempt_enable[_notrace](), and it would be better to unconditionally load 'ti->preempt_count', as described below. On arm64, struct thread_info contains the following union: | union { | u64 preempt_count; | struct { | u32 count; | u32 need_resched; | } preempt; | }; Note: 'need_resched' is encoded so that '0' means a reschedule is needed, and '1' means a reschedule is NOT needed. The core logic of __preempt_count_dec_and_test() is: | static inline bool __preempt_count_dec_and_test(void) | { | struct thread_info *ti = current_thread_info(); | u64 pc = READ_ONCE(ti->preempt_count); | | WRITE_ONCE(ti->preempt.count, --pc); | | return !pc || !READ_ONCE(ti->preempt_count); | } The '!pc' condition can only be true when both: * The initial value of 'need_resched' was 0, meaning that a reschedule is needed. This should be rare. * The initial value of 'count' was exactly 1. This cannot be true for a nested preempt_disable() ... preempt_enable() sequence. Hence in common cases, '!pc' will be false, and it's necessary to execute the final READ_ONCE(ti->preempt_count). This results in a conditional branch in the common case, as can be seen when __preempt_count_dec_and_test() is outlined: | <outline___preempt_count_dec_and_test>: | mrs x2, sp_el0 | ldr x1, [x2, #8] | mov w0, #0x1 | sub x1, x1, #0x1 | str w1, [x2, #8] | cbz x1, 1f | ldr x0, [x2, #8] | cmp x0, #0x0 | cset w0, eq // eq = none | 1: ret It would be better to avoid the special case for 'pc == 0', and to always load 'ti->preempt_count' after decrementing 'ti->preempt.count'. For the common cases this will remove a conditional branch. For the rare cases where preemption is needed initially, this only adds a single load, whose cost should be dominated by other factors. Remove the special case for 'pc == 0', and always load the combined 'ti->preempt_count' after decrementing 'ti->preempt.count'. The removal of the conditional branch helps with code generation, as the compiler can more easily move a dependent slow path out-of-line, as demonstrated with the following compiled with GCC 15.2.0: | void outline_preempt_enable_notrace(void) | { | preempt_enable_notrace(); | } Before this patch: | <outline_preempt_enable_notrace>: | mrs x1, sp_el0 | ldr x0, [x1, #8] | sub x0, x0, #0x1 | str w0, [x1, #8] | cbz x0, 1f | ldr x0, [x1, #8] | cbnz x0, 2f | 1: paciasp | stp x29, x30, [sp, #-16]! | mov x29, sp | bl preempt_schedule_notrace | ldp x29, x30, [sp], #16 | autiasp | ret | 2: ret After this patch: | <outline_preempt_enable_notrace>: | mrs x0, sp_el0 | ldr w1, [x0, #8] | sub w1, w1, #0x1 | str w1, [x0, #8] | ldr x0, [x0, #8] | cbz x0, 1f | ret | 1: paciasp | stp x29, x30, [sp, #-16]! | mov x29, sp | bl preempt_schedule_notrace | ldp x29, x30, [sp], #16 | autiasp | ret Signed-off-by: Mark Rutland <mark.rutland@arm.com> Reviewed-by: Jinjie Ruan <ruanjinjie@huawei.com> Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com> Cc: Ada Couprie Diaz <ada.coupriediaz@arm.com> Cc: Ard Biesheuvel <ardb@kernel.org> Cc: James Morse <james.morse@arm.com> Cc: Marc Zyngier <maz@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Vladimir Murzin <vladimir.murzin@arm.com> Cc: Will Deacon <will@kernel.org> Cc: Yang Shi <yang@os.amperecomputing.com> [catalin.marinas@arm.com: fixed typo in comment] Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
Diffstat (limited to 'tools/perf/scripts/python/bin')
0 files changed, 0 insertions, 0 deletions