Skip to main content

hotpath/
lib_on.rs

1#[doc(hidden)]
2pub use cfg_if::cfg_if;
3pub use hotpath_macros::{future_fn, main, measure, measure_all, skip};
4
5use std::sync::OnceLock;
6
7use crate::instant::Instant;
8
9pub(crate) static START_TIME: OnceLock<Instant> = OnceLock::new();
10
11pub mod channels;
12pub mod cpu_baseline;
13pub mod data_flow;
14pub mod debug;
15pub mod futures;
16pub mod streams;
17#[cfg(feature = "threads")]
18pub mod threads;
19#[cfg(feature = "tokio")]
20pub mod tokio_runtime;
21
22pub mod functions;
23
24pub use channels::{InstrumentChannel, InstrumentChannelLog};
25pub use futures::{InstrumentFuture, InstrumentFutureLog};
26pub use streams::{InstrumentStream, InstrumentStreamLog};
27
28pub mod hotpath_guard;
29pub(crate) mod report;
30
31pub use functions::{
32    measure_async, measure_async_future, measure_async_future_log, measure_async_log,
33    measure_sync_log, MeasurementGuardAsync, MeasurementGuardSync,
34};
35pub use hotpath_guard::{HotpathGuard, HotpathGuardBuilder};
36
37cfg_if::cfg_if! {
38    if #[cfg(feature = "hotpath-alloc")] {
39        #[global_allocator]
40        static GLOBAL: functions::alloc::allocator::CountingAllocator = functions::alloc::allocator::CountingAllocator {};
41    }
42}
43
44#[must_use = "guard is dropped immediately without suspending tracking"]
45pub(crate) struct SuspendAllocTracking {
46    #[cfg(feature = "hotpath-alloc")]
47    previous_enabled: bool,
48}
49
50impl SuspendAllocTracking {
51    #[inline]
52    pub(crate) fn new() -> Self {
53        #[cfg(feature = "hotpath-alloc")]
54        {
55            let previous_enabled = functions::alloc::core::suspend_alloc_tracking();
56            Self { previous_enabled }
57        }
58        #[cfg(not(feature = "hotpath-alloc"))]
59        {
60            Self {}
61        }
62    }
63}
64
65impl Drop for SuspendAllocTracking {
66    #[inline]
67    fn drop(&mut self) {
68        #[cfg(feature = "hotpath-alloc")]
69        functions::alloc::core::resume_alloc_tracking(self.previous_enabled);
70    }
71}
72
73/// Measures the execution time or memory allocations of a code block.
74///
75/// This macro wraps a block of code with profiling instrumentation, similar to the
76/// [`measure`](hotpath_macros::measure) attribute macro but for inline code blocks.
77/// The block is labeled with a static string identifier.
78///
79/// # Arguments
80///
81/// * `$label` - A static string label to identify this code block in the profiling report
82/// * `$expr` - The expression or code block to measure
83///
84/// # Behavior
85///
86/// The macro automatically uses the appropriate measurement based on enabled feature flags:
87/// - **Time profiling** (default): Measures execution duration
88/// - **Allocation profiling**: Tracks memory allocations when allocation features are enabled
89///
90/// # Examples
91///
92/// ```rust
93/// # {
94/// use std::time::Duration;
95///
96/// hotpath::measure_block!("data_processing", {
97///     // Your code here
98///     std::thread::sleep(Duration::from_millis(10));
99/// });
100/// # }
101/// ```
102///
103/// # See Also
104///
105/// * [`measure`](hotpath_macros::measure) - Attribute macro for instrumenting functions
106/// * [`main`](hotpath_macros::main) - Attribute macro that initializes profiling
107#[macro_export]
108macro_rules! measure_block {
109    ($label:expr, $expr:expr) => {{
110        let _guard = hotpath::functions::build_measurement_guard_sync($label, false);
111
112        $expr
113    }};
114}
115
116/// Debug macro that tracks debug output in the profiler.
117///
118/// Works like `std::dbg!` but sends debug logs to a background worker thread
119/// for tracking in the profiler. The logs can be viewed in the TUI or via
120/// the HTTP API at `/debug`, `/debug/dbg/{id}/logs`, `/debug/val/{id}/logs`,
121/// and `/debug/gauge/{id}/logs`.
122///
123/// # Variants
124///
125/// - `dbg!(expr)` - Returns value, logs expression + result
126/// - `dbg!(a, b, c)` - Multiple expressions, returns tuple
127///
128/// # Examples
129///
130/// ```rust,ignore
131/// use hotpath::dbg;
132///
133/// // Debug a single value
134/// let x = dbg!(1 + 2);  // returns 3, logs "1 + 2 = 3"
135///
136/// // Debug multiple values
137/// let (a, b) = dbg!(1, 2);  // returns (1, 2)
138/// ```
139#[macro_export]
140macro_rules! dbg {
141    ($val:expr $(,)?) => {{
142        static DBG_ID: std::sync::OnceLock<u32> = std::sync::OnceLock::new();
143        let id = *DBG_ID.get_or_init(|| {
144            $crate::debug::DEBUG_ID_COUNTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed)
145        });
146        const DBG_LOC: &'static str = concat!(file!(), ":", line!());
147        const DBG_EXPR: &'static str = stringify!($val);
148        match $val {
149            tmp => {
150                $crate::debug::dbg::log_dbg(id, DBG_LOC, DBG_EXPR, &tmp);
151                tmp
152            }
153        }
154    }};
155    ($($val:expr),+ $(,)?) => {
156        ($($crate::dbg!($val)),+,)
157    };
158}
159
160/// Value tracking macro that logs key-value pairs to the profiler.
161///
162/// Unlike `dbg!`, this macro takes a string key and returns a handle
163/// with a `.set()` method. Values are grouped by key (not source location),
164/// but each log entry records its source location for debugging.
165///
166/// # Examples
167///
168/// ```rust,ignore
169/// use hotpath::val;
170///
171/// // Track a counter value
172/// hotpath::val!("counter").set(&count);
173///
174/// // Track state changes
175/// hotpath::val!("state").set(&current_state);
176///
177/// // Dynamic keys work too
178/// let key = format!("counter_{}", id);
179/// hotpath::val!(key).set(&value);
180/// ```
181#[macro_export]
182macro_rules! val {
183    ($key:expr) => {{
184        const VAL_LOC: &'static str = concat!(file!(), ":", line!());
185        $crate::debug::val::ValHandle::new($key, VAL_LOC)
186    }};
187}
188
189/// Gauge macro for tracking numeric values with set/inc/dec operations.
190///
191/// Returns a `GaugeHandle` that can be used to set, increment, or decrement
192/// a numeric value. Gauges track the current value, min/max values, and
193/// update history. Gauges are displayed in the Debug tab of the TUI.
194///
195/// # Examples
196///
197/// ```rust,ignore
198/// use hotpath::gauge;
199///
200/// // Set an absolute value
201/// hotpath::gauge!("queue_size").set(42.0);
202///
203/// // Increment/decrement with fluent API
204/// hotpath::gauge!("active_connections").inc(1.0);
205/// hotpath::gauge!("active_connections").dec(1.0);
206///
207/// // Chain operations
208/// hotpath::gauge!("counter").set(0.0).inc(5.0).dec(2.0);
209/// ```
210#[macro_export]
211macro_rules! gauge {
212    ($key:expr) => {{
213        const GAUGE_LOC: &'static str = concat!(file!(), ":", line!());
214        $crate::debug::gauge::GaugeHandle::new($key, GAUGE_LOC)
215    }};
216}
217
218/// Initialize Tokio runtime metrics monitoring.
219///
220/// # Variants
221///
222/// - `tokio_runtime!()` — uses `tokio::runtime::Handle::current()`
223/// - `tokio_runtime!($handle)` — uses the provided `&Handle`
224#[macro_export]
225macro_rules! tokio_runtime {
226    () => {
227        hotpath::tokio_runtime::init_runtime_monitoring(&tokio::runtime::Handle::current());
228    };
229    ($handle:expr) => {
230        hotpath::tokio_runtime::init_runtime_monitoring($handle);
231    };
232}
233
234#[cfg(test)]
235mod tests {
236    use crate::lib_on::HotpathGuard;
237
238    fn is_send_sync<T: Send + Sync>() {}
239
240    #[test]
241    fn test_hotpath_is_send_sync() {
242        is_send_sync::<HotpathGuard>();
243    }
244}