From: Mitchell Levy <levymitchell0@gmail.com>
To: "Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Andrew Morton" <akpm@linux-foundation.org>,
"Dennis Zhou" <dennis@kernel.org>, "Tejun Heo" <tj@kernel.org>,
"Christoph Lameter" <cl@linux.com>,
"Danilo Krummrich" <dakr@kernel.org>,
"Benno Lossin" <lossin@kernel.org>,
"Yury Norov" <yury.norov@gmail.com>,
"Viresh Kumar" <viresh.kumar@linaro.org>,
"Boqun Feng" <boqun@kernel.org>
Cc: Tyler Hicks <code@tyhicks.com>,
Allen Pais <apais@linux.microsoft.com>,
linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
linux-mm@kvack.org, Mitchell Levy <levymitchell0@gmail.com>
Subject: [PATCH v5 8/8] rust: percpu: cache per-CPU pointers in the dynamic case
Date: Fri, 10 Apr 2026 14:35:38 -0700 [thread overview]
Message-ID: <20260410-rust-percpu-v5-8-4292380d7a41@gmail.com> (raw)
In-Reply-To: <20260410-rust-percpu-v5-0-4292380d7a41@gmail.com>
Currently, the creation of a `PerCpuNumeric` requires a memory read via
the `Arc` managing the dynamic allocation. While the compiler might be
clever enough to consolidate these reads in some cases, the read must
happen *somewhere*, which, when we're concerning ourselves with
individual instructions, is a very high burden.
Instead, cache the `PerCpuPointer` inside the `DynamicPerCpu` structure;
then, the `Arc` is used solely to manage the allocation.
We might as well also use this speed-up in the standard `get` and
`get_mut` accessors that give a `{Checked,}PerCpuToken`
Signed-off-by: Mitchell Levy <levymitchell0@gmail.com>
---
rust/kernel/percpu/dynamic.rs | 34 ++++++++++++++++++----------------
rust/kernel/percpu/numeric.rs | 4 ++--
2 files changed, 20 insertions(+), 18 deletions(-)
diff --git a/rust/kernel/percpu/dynamic.rs b/rust/kernel/percpu/dynamic.rs
index a717138b93dc..675210098ed8 100644
--- a/rust/kernel/percpu/dynamic.rs
+++ b/rust/kernel/percpu/dynamic.rs
@@ -101,6 +101,9 @@ pub struct DynamicPerCpu<T> {
// INVARIANT: The memory location in each CPU's per-CPU area pointed at by the alloc is
// initialized.
alloc: Option<Arc<PerCpuAllocation<T>>>,
+ // INVARIANT: `ptr` is the per-CPU pointer managed by `alloc`, which does not change for the
+ // lifetime of `self`.
+ pub(super) ptr: PerCpuPtr<T>,
}
impl<T: Zeroable> DynamicPerCpu<T> {
@@ -112,9 +115,13 @@ impl<T: Zeroable> DynamicPerCpu<T> {
pub fn new_zero(flags: Flags) -> Option<Self> {
let alloc: PerCpuAllocation<T> = PerCpuAllocation::new_zero()?;
+ let ptr = alloc.0;
let arc = Arc::new(alloc, flags).ok()?;
- Some(Self { alloc: Some(arc) })
+ Some(Self {
+ alloc: Some(arc),
+ ptr,
+ })
}
}
@@ -158,15 +165,10 @@ pub fn new_from(mut initer: impl FnMut(CpuId) -> T, flags: Flags) -> Option<Self
}
}
- Some(Self { alloc: Some(arc) })
- }
-}
-
-impl<T> DynamicPerCpu<T> {
- /// Gets the allocation backing this per-CPU variable.
- pub(crate) fn alloc(&self) -> &Arc<PerCpuAllocation<T>> {
- // SAFETY: This type's invariant ensures that `self.alloc` is `Some`.
- unsafe { self.alloc.as_ref().unwrap_unchecked() }
+ Some(Self {
+ alloc: Some(arc),
+ ptr,
+ })
}
}
@@ -178,11 +180,11 @@ unsafe fn get_mut(&mut self, guard: CpuGuard) -> PerCpuToken<'_, T> {
// exists on the current CPU.
// 3. The invariants of `DynamicPerCpu` ensure that the contents of the allocation are
// initialized on each CPU.
- // 4. The existence of a reference to the `PerCpuAllocation` ensures that the allocation is
- // live.
+ // 4. `&mut self` holds a reference to the `PerCpuAllocation`, so the allocation it manages
+ // is live.
// 5. The invariants of `DynamicPerCpu` ensure that the allocation is sized and aligned for
// a `T`.
- unsafe { PerCpuToken::new(guard, &self.alloc.as_ref().unwrap_unchecked().0) }
+ unsafe { PerCpuToken::new(guard, &self.ptr) }
}
}
@@ -192,11 +194,11 @@ fn get(&self, guard: CpuGuard) -> CheckedPerCpuToken<'_, T> {
// 1. Invariants of this type assure that `alloc` is `Some`.
// 2. The invariants of `DynamicPerCpu` ensure that the contents of the allocation are
// initialized on each CPU.
- // 3. The existence of a reference to the `PerCpuAllocation` ensures that the allocation is
- // live.
+ // 3. `&mut self` holds a reference to the `PerCpuAllocation`, so the allocation it manages
+ // is live.
// 4. The invariants of `DynamicPerCpu` ensure that the allocation is sized and aligned for
// a `T`.
- unsafe { CheckedPerCpuToken::new(guard, &self.alloc.as_ref().unwrap_unchecked().0) }
+ unsafe { CheckedPerCpuToken::new(guard, &self.ptr) }
}
}
diff --git a/rust/kernel/percpu/numeric.rs b/rust/kernel/percpu/numeric.rs
index 13b4ab4a794d..4841843b05f7 100644
--- a/rust/kernel/percpu/numeric.rs
+++ b/rust/kernel/percpu/numeric.rs
@@ -22,7 +22,7 @@ impl DynamicPerCpu<$ty> {
pub fn num(&mut self) -> PerCpuNumeric<'_, $ty> {
// The invariant is satisfied because `DynamicPerCpu`'s invariant guarantees that
// this pointer is valid and initialized on all CPUs.
- PerCpuNumeric { ptr: &self.alloc().0 }
+ PerCpuNumeric { ptr: &self.ptr }
}
}
impl StaticPerCpu<$ty> {
@@ -78,7 +78,7 @@ impl DynamicPerCpu<$ty> {
pub fn num(&mut self) -> PerCpuNumeric<'_, $ty> {
// The invariant is satisfied because `DynamicPerCpu`'s invariant guarantees that
// this pointer is valid and initialized on all CPUs.
- PerCpuNumeric { ptr: &self.alloc().0 }
+ PerCpuNumeric { ptr: &self.ptr }
}
}
impl StaticPerCpu<$ty> {
--
2.34.1
prev parent reply other threads:[~2026-04-10 21:36 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-10 21:35 [PATCH v5 0/8] rust: Add Per-CPU Variable API Mitchell Levy
2026-04-10 21:35 ` [PATCH v5 1/8] rust: cpumask: Add a `Cpumask` iterator Mitchell Levy
2026-04-10 21:35 ` [PATCH v5 2/8] rust: cpumask: Add getters for globally defined cpumasks Mitchell Levy
2026-04-10 21:35 ` [PATCH v5 3/8] rust: percpu: Add C bindings for per-CPU variable API Mitchell Levy
2026-04-10 21:35 ` [PATCH v5 4/8] rust: percpu: introduce a rust API for static per-CPU variables Mitchell Levy
2026-04-10 21:35 ` [PATCH v5 5/8] rust: percpu: introduce a rust API for dynamic " Mitchell Levy
2026-04-10 21:35 ` [PATCH v5 6/8] rust: percpu: add a rust per-CPU variable sample Mitchell Levy
2026-04-10 21:35 ` [PATCH v5 7/8] rust: percpu: Add pin-hole optimizations for numerics Mitchell Levy
2026-04-11 3:06 ` Yury Norov
2026-04-15 20:34 ` Mitchell Levy
2026-04-15 21:57 ` Yury Norov
2026-04-10 21:35 ` Mitchell Levy [this message]
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=20260410-rust-percpu-v5-8-4292380d7a41@gmail.com \
--to=levymitchell0@gmail.com \
--cc=a.hindborg@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=apais@linux.microsoft.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=cl@linux.com \
--cc=code@tyhicks.com \
--cc=dakr@kernel.org \
--cc=dennis@kernel.org \
--cc=gary@garyguo.net \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=lossin@kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tj@kernel.org \
--cc=tmgross@umich.edu \
--cc=viresh.kumar@linaro.org \
--cc=yury.norov@gmail.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.