Description
Proposal
Problem statement
It is sometimes helpful to let the compiler know what code path is the fast path, so it can be optimized at the expense of the slow path. This proposal suggests that the cold_path()
intrinsic is simple and reliable way to provide this information and it could be reexported in std::hint
.
grep-ing the LLVM source code for BlockFrequencyInfo
and BranchProbabilityInfo
shows that this information is used at many places in the optimizer. Such as:
- block placement - improve locality by making the fast path compact and move everything else out of the way
- inlining, loop unrolling - these optimizations can be less aggressive on the cold path therefore reducing code size
- register allocation - preferably keep in registers the data needed on the fast path
Motivating examples or use cases
The cold_path()
call can be simply placed on some code path marking it as cold.
if condition {
// this is the fast path
} else {
cold_path();
// this path is unlikely
}
match a {
1 => a,
2 => b,
3 => { cold_path(); c }, // this branch is unlikely
_ => { cold_path(); d }, // this is also unlikely
}
let buf = Global.allocate(layout).map_err(|_| {
// the error is unlikely
cold_path();
Error::new_alloc_failed("Cannot allocate memory.")
})?;
Solution sketch
This is already implemented in intrinsics. All we have to do is create a wrapper in std::hint
:
#[inline(always)]
pub fn cold_path() {
std::intrinsics::cold_path()
}
Alternatives
likely
/unlikely
These are harder to use for idiomatic Rust. For example they don't work well with match arms. On the other hand, sometimes they can be more readable and may also be worth reexporting in std::hint
.
For example, this would be harder to express using cold_path()
:
if likely(x) && unlikely(y) {
true_branch
}
And this looks better without the extra branch:
if likely(cond) {
true_branch
}
if cond {
true_branch
} else {
cold_path()
}
extending the functionality of #[cold]
attribute
This attribute could be allowed on match arms or on closures. I'm not sure if it's worth it adding extra syntax if the functionality can be implemented by a library call.
Links and related work
rust-lang/rust#120370 - added cold_path()
as part of fixing likely
and unlikely
rust-lang/rust#133852 - improvements of the cold_path()
implementation
rust-lang/rust#120193 - proposal for #[cold]
on match arms