#compiler-optimization #optimization #cold #inline #inlining

ice_code

A macro to mark code paths as cold, allowing the common case to be inlined

5 releases

0.1.4 Feb 26, 2024
0.1.3 Feb 26, 2024
0.1.2 Feb 26, 2024
0.1.1 Feb 26, 2024
0.1.0 Feb 26, 2024

#354 in Rust patterns

Download history 210/week @ 2024-06-25 156/week @ 2024-07-02 803/week @ 2024-07-09 97/week @ 2024-07-16 226/week @ 2024-07-23 341/week @ 2024-07-30 633/week @ 2024-08-06 858/week @ 2024-08-13 903/week @ 2024-08-20 586/week @ 2024-08-27 538/week @ 2024-09-03 289/week @ 2024-09-10 372/week @ 2024-09-17 113/week @ 2024-09-24 327/week @ 2024-10-01 675/week @ 2024-10-08

1,634 downloads per month

Apache-2.0

115KB

What's cooler than being cool?

🧊 Ice Code 🧊

Alright alright alright alright alright alright alright alright

What is this?

This crate provides the ice! macro, which labels a given block of Rust code as a "cold path" in the application--one that is rarely executed. This information allows the compiler to prioritize optimizing the other code paths, leading to better method inlining behavior and boosting performance in the common case.

Usage

Source

Here's an example method that branches into two paths:

  1. The common case, where the argument it receives is exactly what it's expecting.
  2. The error handling branch, where the validation logic rejects the argument.
/// Returns the length of the provided string as long as it's shorter than 256 bytes.
fn short_str_len(input: &str) -> Result<u8, String> {
    if let Ok(short_len) = u8::try_from(input.len()) {
        // We expect this path to be taken almost every time
        Ok(short_len)
    } else { 
        // Oops, the string is too big. This path will almost never be executed.
        //
        // The `format!` call below requires a surprising amount of assembly to
        // heap-allocate a string, serialize its arguments, and panic if the
        // system is out of memory.
        // 
        // Let's mark the code that constructs a nicely formatted error as being
        // the cold path--ice code.
        ice! {
            Err(format!("Input string was {} bytes, which is too long.", input.len()))
        }
    }
}

pub fn main() {
    let result = short_str_len("foobar".repeat(1_000).as_str());
    assert!(result.is_err());
}

Compiled output

As this godbolt.org output shows, the happy path's code got inlined into main while all of the machinery needed to construct an error string has been pushed somewhere else and is hidden behind a call instruction.

cold_anonymous_fn.png

Labeled cold code

If you use multiple ice! invocations in the same method, the mangled anonymous names produced by the compiler may be difficult for humans to disambiguate. You can add a label to the generated assembly by using this syntax:

cold! {
    // label          expression
    error_handler => Err(format!("..."))
}

This will produce assembly like the following:

cold_named_fn.png

No runtime deps