From: David Laight <david.laight.linux@gmail.com>
To: Pedro Falcato <pfalcato@suse.de>
Cc: Mark Rutland <mark.rutland@arm.com>,
vladimir.murzin@arm.com, ryan.roberts@arm.com,
peterz@infradead.org, catalin.marinas@arm.com,
ruanjinjie@huawei.com, stable@vger.kernel.org,
james.morse@arm.com, yang@os.amperecomputing.com, cl@gentwo.org,
maz@kernel.org, david@kernel.org, ljs@kernel.org,
will@kernel.org, ardb@kernel.org,
linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH v2 13/20] arm64: percpu: Add infrastructure for preemptible this_cpu_*() ops
Date: Wed, 5 Aug 2026 11:27:07 +0100 [thread overview]
Message-ID: <20260805112707.0204f00e@pumpkin> (raw)
In-Reply-To: <anJm-EDndC8H6xMi@pedro-suse.lan>
On Tue, 4 Aug 2026 23:45:56 +0100
Pedro Falcato <pfalcato@suse.de> wrote:
> On Tue, Aug 04, 2026 at 06:04:56PM +0100, Mark Rutland wrote:
> > Currently arm64's this_cpu_*() ops transiently disable preemption in
> > order to guarantee that the address generation and memory access(es)
> > occur on the same CPU.
> >
> > Transiently disabling preemption can be expensive. When re-enabling
> > preemption it is necessary to make a conditional function call to
> > preempt_schedule[_notrace]() in order to handle the rare case that the
> > task needs to be rescheduled. The potential function call has a number
> > of negative effects on code generation (e.g. due to the need to create a
> > stack frame and spill registers), and the conditionality can result in
> > poor code generation and/or poor branch prediction.
> >
> > This patch adds infrastructure for a scheme where this_cpu_*() ops do
> > not need to transiently disable preemption, avoiding the negative
> > impacts described above. Individual operations will be converted in
> > subsequent patches.
> >
> > Each operation registers a critical section during which the exception
> > return code will adjust the offset and addresses if preemption occurs
> > mid-sequence. The critical section is registered/unregistered with a
> > small prologue and epilogue which encodes three distinct GPRRs (<pcp>,
> > <off>, <addr>) into a new thread_info::pcp_gprs field:
> >
> > // Prologue. Enable fixups for <off> and <addr>.
> > mrs <tsk>, sp_el0
> > mov <tmp>, #__VAL_PCPU_GPRS(<pcp>, <off>, <addr>)
> > strh <tmp>, [<tsk>, #TSK_TI_PCPU_GPRS]
> >
> > // Generate cpu-specific address
> > mrs <off>, TPIDR_ELx
> > add <addr>, <pcp>, <off>
> >
> > // Perform access sequence
> > ldr <val>, [<addr>]
> >
> > // Epilogue. Disable fixups
> > strh wzr, [<tsk>, #TSK_TI_PCPU_GPRS]
> >
> > If an exception is taken from within the critical section, the exception
> > return code will adjust <off> to be the current CPU's offset, and will
> > adjust <addr> to be (<pcp> + <off>). Distinct registers are used for
> > <pcp>, <off>, and <addr>, so that the fixup can be applied safely at any
> > point during the critical section.
> >
> > To ensure that this_cpu_*() operations within exception handlers work
> > correctly and do not corrupt state, thread_info::pcpu_gprs is saved
> > into a new pt_regs::pcpu_gprs field upon exception entry, and restored
> > upon exception return.
> >
> > Looking at a simple this_cpu_operation:
> >
> > | void outline_this_cpu_add_u64(u64 __percpu *p, u64 v)
> > | {
> > | this_cpu_add(*p, v);
> > | }
...
> I think I had an Interesting Idea(tm) while reading the per-cpu discussion
> in linux-mm. In case the 3 instruction preamble is too expensive:
>
> 1) Pass -ffixed-x18 (this natively conflicts with SHADOW_CALL_STACK.
> SHADOW_CALL_STACK is already not-optimal codegen wise, so maybe not a big deal).
> 2) arm64 kernel bits will use x18 as a cheap task flags register
> 3) #define TASK_KRSEQ (1 << 0)
> 4) Switching into the krseq mode is just a matter of toggling the bit in x18, so
> orr x18, x18, #TASK_KRSEQ
> a single instruction.
> 5) Switching off is just a matter of clearing the bit in x18, so:
> and x18, x18, #~TASK_KRSEQ
> 6) On the preempt side we keep the krseq tables in memory, and do a sort of lookup
> (binary search sounds easiest?) on them. But _only_ if x18 TASK_KRSEQ is set.
> This penalises unlucky preempts but keeps fast paths maximally fast.
> 7) entry points of course get to clear it after saving it
>
> The end result would look something like:
> | <outline_this_cpu_add_u64>:
> | orr x18, x18, #TASK_KRSEQ
> | mrs x4, tpidr_el1
> | add x3, x0, x4
> | 1: ldxr x6, [x3]
> | add x6, x6, x1
> | stxr w5, x6, [x3]
> | cbnz w5, 1b
> | 2:
> | and x18, x18, #~TASK_KRSEQ
> | ret
> | .pushsection .data.krseq
> | .word 1b
> | .word 2b
> | .word whateverelse
> | .popsection
>
> This of course precludes the use of x18 for the compiler, so it would
> require careful benchmarking in case it negatively affects codegen too much.
> But it avoids any sort of extraneous stores in the fast path.
The extra stores are independent of the main instruction flow.
On a multi-issue (and especially out-of-order) cpu they are pretty much
likely to be noise.
The biggest cost is likely to be in the I-cache and instruction decoders.
Put a memory read in the 'main' path and the few clocks needed for the
D-cache read are likely to dominate - so the writes to the pcp_gprs
are actually likely to be free.
OTOH stealing a gpr for some flags will cost everwhere.
David
>
> Other architectures could do similar as long as they have interesting ways of
> signaling this using solely the register set.
>
> Anyway, just throwing it out there in case this can actually make a
> difference & rings some bells on people smarter than me :)
>
next prev parent reply other threads:[~2026-08-05 10:27 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-04 17:04 [PATCH v2 00/20] arm64: Preemptible this_cpu_*() operations Mark Rutland
2026-08-04 17:04 ` [PATCH v2 01/20] arm64: percpu: Fix this_cpu_write() casting Mark Rutland
2026-08-05 8:37 ` David Laight
2026-08-07 4:00 ` Jinjie Ruan
2026-08-04 17:04 ` [PATCH v2 02/20] arm64: percpu: Fix this_cpu_and() mask generation Mark Rutland
2026-08-05 9:14 ` David Laight
2026-08-05 13:02 ` Mark Rutland
2026-08-06 8:28 ` David Laight
2026-08-06 10:23 ` Mark Rutland
2026-08-07 9:52 ` Jinjie Ruan
2026-08-04 17:04 ` [PATCH v2 03/20] arm64: cmpxchg: LL/SC: Avoid redundant extension Mark Rutland
2026-08-04 17:04 ` [PATCH v2 04/20] arm64: cmpxchg128: LSE: Remove redundant operands Mark Rutland
2026-09-07 8:42 ` Jinjie Ruan
2026-08-04 17:04 ` [PATCH v2 05/20] arm64: preempt: Simplify and optimize __preempt_count_dec_and_test() Mark Rutland
2026-08-04 17:04 ` [PATCH v2 06/20] arm64: preempt: Treat should_resched() as unlikely Mark Rutland
2026-08-04 17:04 ` [PATCH v2 07/20] arm64: ptrace: Always inline pt_regs_[read,write}_reg() Mark Rutland
2026-08-04 17:04 ` [PATCH v2 08/20] arm64: percpu: Factor out percpu offset asm Mark Rutland
2026-08-04 17:04 ` [PATCH v2 09/20] arm64: gpr-num: Add wxN aliases for wN registers Mark Rutland
2026-08-04 17:04 ` [PATCH v2 10/20] arm64: gpr-num: add __GPR_NUM() helper Mark Rutland
2026-08-04 17:04 ` [PATCH v2 11/20] arm64: entry: sdei: Restore all clobberable GPRs Mark Rutland
2026-08-07 11:35 ` Mark Rutland
2026-08-04 17:04 ` [PATCH v2 12/20] arm64: entry: sdei: Make 'tsk' available Mark Rutland
2026-08-04 17:04 ` [PATCH v2 13/20] arm64: percpu: Add infrastructure for preemptible this_cpu_*() ops Mark Rutland
2026-08-04 22:45 ` Pedro Falcato
2026-08-05 10:27 ` David Laight [this message]
2026-08-05 12:50 ` Pedro Falcato
2026-08-05 6:45 ` David Hildenbrand (Arm)
2026-08-05 6:47 ` David Hildenbrand (Arm)
2026-08-06 11:21 ` Mark Rutland
2026-08-06 11:32 ` David Hildenbrand (Arm)
2026-08-06 12:02 ` Mark Rutland
2026-08-06 13:25 ` David Laight
2026-08-06 13:30 ` David Hildenbrand (Arm)
2026-08-04 17:04 ` [PATCH v2 14/20] arm64: percpu: Implement preemptible read/write ops Mark Rutland
2026-08-05 9:24 ` Ryan Roberts
2026-08-05 12:08 ` David Laight
2026-08-05 13:34 ` Mark Rutland
2026-08-04 17:04 ` [PATCH v2 15/20] arm64: percpu: Implement preemptible void RMW ops Mark Rutland
2026-08-04 17:04 ` [PATCH v2 16/20] arm64: percpu: Implement preemptible return " Mark Rutland
2026-08-04 17:05 ` [PATCH v2 17/20] arm64: percpu: Implement preemptible XCHG ops Mark Rutland
2026-08-04 17:05 ` [PATCH v2 18/20] arm64: percpu: Implement preemptible CMPXCHG ops Mark Rutland
2026-08-04 17:05 ` [PATCH v2 19/20] arm64: percpu: Implement preemptible CMPXCHG128 ops Mark Rutland
2026-08-04 17:05 ` [PATCH v2 20/20] arm64: percpu: Remove _pcp_protect*() wrappers Mark Rutland
2026-09-02 11:55 ` [PATCH v2 00/20] arm64: Preemptible this_cpu_*() operations Usama Anjum
2026-09-02 13:16 ` Lorenzo Stoakes (ARM)
2026-09-02 13:32 ` Mark Rutland
2026-09-02 15:42 ` David Laight
2026-09-02 18:24 ` David Laight
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260805112707.0204f00e@pumpkin \
--to=david.laight.linux@gmail.com \
--cc=ardb@kernel.org \
--cc=catalin.marinas@arm.com \
--cc=cl@gentwo.org \
--cc=david@kernel.org \
--cc=james.morse@arm.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=ljs@kernel.org \
--cc=mark.rutland@arm.com \
--cc=maz@kernel.org \
--cc=peterz@infradead.org \
--cc=pfalcato@suse.de \
--cc=ruanjinjie@huawei.com \
--cc=ryan.roberts@arm.com \
--cc=stable@vger.kernel.org \
--cc=vladimir.murzin@arm.com \
--cc=will@kernel.org \
--cc=yang@os.amperecomputing.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox