All of lore.kernel.org
 help / color / mirror / Atom feed
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 :)
> 



  reply	other threads:[~2026-08-05 10:27 UTC|newest]

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

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 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.