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}