Skip to main content

hopper_runtime/
utils.rs

1//! Small utilities for Hopper program authors.
2//!
3//! The line for inclusion is narrow: a helper lands here when it is
4//! too small to justify its own module and too broadly useful to
5//! leave as a local copy in three places. At the moment that means
6//! branch-prediction hints; future additions fit the same rule or
7//! they do not fit at all.
8
9/// Branch-prediction hints for hot handlers.
10///
11/// Both functions are identity over `bool` on every supported
12/// target. The call site cost is zero: the compiler inlines them
13/// into the containing branch with no runtime effect. What they
14/// communicate is intent. A handler that expects the fast path to
15/// win 99% of the time writes
16///
17/// ```ignore
18/// if hopper::utils::hint::likely(is_cached) {
19///     return fast_path(ctx);
20/// }
21/// slow_path(ctx)
22/// ```
23///
24/// and the compiler keeps the fast path straight-line, pushing the
25/// spill into the cold branch. The `unlikely` helper expresses the inverse
26/// opposite direction.
27///
28/// On host targets (tests, off-chain tooling) future versions may
29/// route through `core::intrinsics::likely` when that intrinsic is
30/// stabilized; the API shape stays identical so user code never
31/// needs to change. On SBF the Solana runtime does not expose a
32/// branch-weight hint today, so the hint compiles out entirely.
33/// Leaving the calls in the code path is safe and free.
34pub mod hint {
35    /// Hint the branch condition is probably `true`. Zero runtime
36    /// cost on SBF; on host targets it maps to LLVM's
37    /// `llvm.expect.i1` via `core::hint::likely` when available,
38    /// and to an identity otherwise.
39    #[inline(always)]
40    pub const fn likely(cond: bool) -> bool {
41        // `core::hint::likely` is not stable. A call to a `#[cold]`
42        // function on the other arm tells the optimizer the same thing:
43        // the arm that reaches it is the unlikely one.
44        if cond {
45            true
46        } else {
47            cold_path();
48            false
49        }
50    }
51
52    /// Hint the branch condition is probably `false`. Mirror of
53    /// [`likely`].
54    #[inline(always)]
55    pub const fn unlikely(cond: bool) -> bool {
56        if cond {
57            cold_path();
58            true
59        } else {
60            false
61        }
62    }
63
64    /// Marks the path that calls it as rarely taken. Empty, so it costs
65    /// no instruction; the optimizer lays the other path out as the
66    /// fall-through.
67    #[cold]
68    #[inline(always)]
69    pub const fn cold_path() {}
70
71    #[cfg(test)]
72    mod tests {
73        use super::*;
74
75        #[test]
76        fn likely_returns_its_condition() {
77            assert!(likely(true));
78            assert!(!likely(false));
79        }
80
81        #[test]
82        fn unlikely_returns_its_condition() {
83            assert!(unlikely(true));
84            assert!(!unlikely(false));
85        }
86    }
87}