Skip to content

Export cold_path() in std::hint #510

Closed
@x17jiri

Description

@x17jiri

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    ACP-acceptedAPI Change Proposal is accepted (seconded with no objections)T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions