Skip to content

Commit 1a885da

Browse files
committed
Make initialization in OnceNonZeroUsize::get_or_try_init #[cold].
In typical use, the Some branch is going to be taken extremely frequently but the None branch is only going to be taken once (or a very small number of times) at startup. If `get_or_try_init` is in a performance-sensitive segment of code, then it is important that `get_or_try_init` be inlined and that the compiler understands that the Some branch is (much) more likely than the None branch. When this happens, the call site basically becomes a load followed by a conditional jump that is basically never taken; which is ideal. When `get_or_try_init` is used in many places in the user's code, it is important to avoid inlining any of the None branch into the call sites. Unfortunately, the Rust compiler is sometimes not good at recognizing that code that calls a #[cold] function unconditionally must be cold itself. So, sometimes it isn't enough to mark our f as `#[cold] #[inline(never)]`. Move the entire body of the None branch into a function that is marked because some post-inlining optimization passes in the compiler seem to not understand `#[cold]`, and because we don't want any part of that branch to be in the calling code.
1 parent 4fbd4a5 commit 1a885da

File tree

4 files changed

+19
-15
lines changed

4 files changed

+19
-15
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Unreleased
44

5+
- Outline initialization in `race`: [#273](https://github.com/matklad/once_cell/pull/273).
6+
57
## 1.20.2
68

79
- Remove `portable_atomic` from Cargo.lock if it is not, in fact, used: [#267](https://github.com/matklad/once_cell/pull/267)

Cargo.lock.msrv

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "once_cell"
3-
version = "1.20.2"
3+
version = "1.20.3"
44
authors = ["Aleksey Kladov <aleksey.kladov@gmail.com>"]
55
license = "MIT OR Apache-2.0"
66
edition = "2021"

src/race.rs

+15-13
Original file line numberDiff line numberDiff line change
@@ -93,19 +93,21 @@ impl OnceNonZeroUsize {
9393
F: FnOnce() -> Result<NonZeroUsize, E>,
9494
{
9595
let val = self.inner.load(Ordering::Acquire);
96-
let res = match NonZeroUsize::new(val) {
97-
Some(it) => it,
98-
None => {
99-
let mut val = f()?.get();
100-
let exchange =
101-
self.inner.compare_exchange(0, val, Ordering::AcqRel, Ordering::Acquire);
102-
if let Err(old) = exchange {
103-
val = old;
104-
}
105-
unsafe { NonZeroUsize::new_unchecked(val) }
106-
}
107-
};
108-
Ok(res)
96+
match NonZeroUsize::new(val) {
97+
Some(it) => Ok(it),
98+
None => self.init(f),
99+
}
100+
}
101+
102+
#[cold]
103+
#[inline(never)]
104+
fn init<E>(&self, f: impl FnOnce() -> Result<NonZeroUsize, E>) -> Result<NonZeroUsize, E> {
105+
let mut val = f()?.get();
106+
let exchange = self.inner.compare_exchange(0, val, Ordering::AcqRel, Ordering::Acquire);
107+
if let Err(old) = exchange {
108+
val = old;
109+
}
110+
Ok(unsafe { NonZeroUsize::new_unchecked(val) })
109111
}
110112
}
111113

0 commit comments

Comments
 (0)