Skip to main content

hotpath_macros/
lib.rs

1use proc_macro::TokenStream;
2
3#[cfg(feature = "hotpath")]
4mod lib_on;
5
6#[cfg(not(feature = "hotpath"))]
7mod lib_off;
8
9/// Initializes the hotpath profiling system and generates a performance report on program exit.
10///
11/// This attribute macro should be applied to your program's main (or other entry point) function
12/// to enable profiling. It creates a guard that initializes the background measurement processing
13/// thread and automatically displays a performance summary when the program exits. Additionally
14/// it creates a measurement guard that will be used to measure the wrapper function itself.
15///
16/// For programmatic control over the same options, see
17/// [`HotpathGuardBuilder`](../hotpath/struct.HotpathGuardBuilder.html).
18///
19/// # Parameters
20///
21/// * `percentiles` - Array of percentile values (0.0-100.0) to compute, e.g. `[50, 95, 99.9]`. Default: `[95]`
22/// * `format` - Output format: `"table"` (default), `"json"`, `"json-pretty"`, or `"none"`
23/// * `limit` - Global maximum number of items shown in each report section (functions, channels, streams, futures, threads). `0` = unlimited.
24/// * `functions_limit` - Maximum number of functions shown in the report. Overrides `limit` for functions.
25/// * `channels_limit` - Maximum number of channels shown in the report. Overrides `limit` for channels.
26/// * `streams_limit` - Maximum number of streams shown in the report. Overrides `limit` for streams.
27/// * `futures_limit` - Maximum number of futures shown in the report. Overrides `limit` for futures.
28/// * `threads_limit` - Maximum number of threads shown in the report. Overrides `limit` for threads.
29/// * `output_path` - File path for the report. Defaults to stdout. Overridden by `HOTPATH_OUTPUT_PATH` env var.
30/// * `report` - Comma-separated sections to include: `"functions-timing"`, `"functions-alloc"`, `"channels"`, `"streams"`, `"futures"`, `"threads"`, `"debug"`, or `"all"`. Overridden by `HOTPATH_REPORT` env var.
31/// * `allocator` - Optional allocator type path used when `hotpath-alloc` is enabled.
32///   Defaults to `std::alloc::System`.
33///
34/// Environment variable precedence for report output:
35/// `HOTPATH_LIMIT`, `HOTPATH_FUNCTIONS_LIMIT`, `HOTPATH_CHANNELS_LIMIT`,
36/// `HOTPATH_STREAMS_LIMIT`, `HOTPATH_FUTURES_LIMIT`, and `HOTPATH_THREADS_LIMIT`
37/// override the matching macro arguments. Per-resource env vars override `HOTPATH_LIMIT`.
38///
39/// # Examples
40///
41/// Basic usage with default settings (P95 percentile, table format):
42///
43/// ```rust,no_run
44/// #[hotpath::main]
45/// fn main() {
46///     // Your code here
47/// }
48/// ```
49///
50/// Custom percentiles:
51///
52/// ```rust,no_run
53/// #[tokio::main]
54/// #[hotpath::main(percentiles = [50, 90, 95, 99.9])]
55/// async fn main() {
56///     // Your code here
57/// }
58/// ```
59///
60/// JSON output to file:
61///
62/// ```rust,no_run
63/// #[hotpath::main(format = "json-pretty", output_path = "report.json")]
64/// fn main() {
65///     // Your code here
66/// }
67/// ```
68///
69/// Select report sections:
70///
71/// ```rust,no_run
72/// #[hotpath::main(report = "functions-timing,channels")]
73/// fn main() {
74///     // Your code here
75/// }
76/// ```
77///
78/// Per-resource limits:
79///
80/// ```rust,no_run
81/// #[hotpath::main(limit = 10, functions_limit = 20, channels_limit = 5)]
82/// fn main() {
83///     // Your code here
84/// }
85/// ```
86///
87/// # Usage with Tokio
88///
89/// When using with tokio, place `#[tokio::main]` before `#[hotpath::main]`:
90///
91/// ```rust,no_run
92/// #[tokio::main]
93/// #[hotpath::main]
94/// async fn main() {
95///     // Your code here
96/// }
97/// ```
98///
99/// # Limitations
100///
101/// Only one hotpath guard can be active at a time. Creating a second guard (either via this
102/// macro or via [`HotpathGuardBuilder`](../hotpath/struct.HotpathGuardBuilder.html)) will cause a panic.
103///
104/// # See Also
105///
106/// * [`measure`](macro@measure) - Attribute macro for instrumenting functions
107/// * [`measure_block!`](../hotpath/macro.measure_block.html) - Macro for measuring code blocks
108/// * [`HotpathGuardBuilder`](../hotpath/struct.HotpathGuardBuilder.html) - Programmatic alternative to this macro
109#[proc_macro_attribute]
110pub fn main(attr: TokenStream, item: TokenStream) -> TokenStream {
111    #[cfg(feature = "hotpath")]
112    {
113        lib_on::main_impl(attr, item)
114    }
115    #[cfg(not(feature = "hotpath"))]
116    {
117        lib_off::main_impl(attr, item)
118    }
119}
120
121/// Instruments a function to measure execution time or memory allocations.
122///
123/// Automatically detects sync vs async and inserts the appropriate measurement guard.
124/// Compiles to zero overhead when the `hotpath` feature is disabled.
125///
126/// # Measurements
127///
128/// * **Time profiling** (default) - execution duration via high-precision timers
129/// * **Allocation profiling** (`hotpath-alloc` feature) - bytes allocated and allocation count
130///
131/// # Parameters
132///
133/// * `log` - If `true`, logs the return value on each call (requires `Debug` on return type)
134/// * `future` - If `true`, also tracks the future lifecycle (poll count, state transitions, cancellation). Only valid on async functions.
135///
136/// # Examples
137///
138/// ```rust,no_run
139/// #[hotpath::measure]
140/// fn process(data: &[u8]) -> usize {
141///     data.len()
142/// }
143///
144/// #[hotpath::measure(log = true)]
145/// fn compute() -> i32 {
146///     42
147/// }
148///
149/// #[hotpath::measure(future = true)]
150/// async fn fetch_data() -> Vec<u8> {
151///     vec![1, 2, 3]
152/// }
153/// ```
154///
155/// # Async Allocation Limitation
156///
157/// Allocation profiling requires `current_thread` tokio runtime because thread-local
158/// tracking cannot follow tasks across threads. Time profiling works with any runtime.
159///
160/// # See Also
161///
162/// * [`main`](macro@main) - Initializes the profiling system
163/// * [`measure_all`](macro@measure_all) - Bulk instrumentation for modules and impl blocks
164/// * [`measure_block!`](../hotpath/macro.measure_block.html) - Instruments code blocks
165#[proc_macro_attribute]
166pub fn measure(attr: TokenStream, item: TokenStream) -> TokenStream {
167    #[cfg(feature = "hotpath")]
168    {
169        lib_on::measure_impl(attr, item)
170    }
171    #[cfg(not(feature = "hotpath"))]
172    {
173        lib_off::measure_impl(attr, item)
174    }
175}
176
177/// Instruments an async function to track its lifecycle as a Future.
178///
179/// Wraps the function body with the `future!` macro to track poll counts,
180/// state transitions (pending/ready/cancelled), and optionally the output value.
181/// Can only be applied to `async fn`.
182///
183/// # Parameters
184///
185/// * `log` - If `true`, logs the output value on completion (requires `Debug` on return type)
186///
187/// # Examples
188///
189/// ```rust,no_run
190/// #[hotpath::future_fn]
191/// async fn fetch_data() -> Vec<u8> {
192///     vec![1, 2, 3]
193/// }
194///
195/// #[hotpath::future_fn(log = true)]
196/// async fn compute() -> i32 {
197///     42
198/// }
199/// ```
200///
201/// # See Also
202///
203/// * [`measure`](macro@measure) - Instruments execution time / allocations
204/// * [`future!`](../hotpath/macro.future.html) - Declarative macro for wrapping future expressions
205#[proc_macro_attribute]
206pub fn future_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
207    #[cfg(feature = "hotpath")]
208    {
209        lib_on::future_fn_impl(attr, item)
210    }
211    #[cfg(not(feature = "hotpath"))]
212    {
213        lib_off::future_fn_impl(attr, item)
214    }
215}
216
217/// Marks a function to be excluded from profiling when used with [`measure_all`](macro@measure_all).
218///
219/// # Usage
220///
221/// ```rust,no_run
222/// #[hotpath::measure_all]
223/// impl MyStruct {
224///     fn important_method(&self) {
225///         // This will be measured
226///     }
227///
228///     #[hotpath::skip]
229///     fn not_so_important_method(&self) -> usize {
230///         // This will NOT be measured
231///         self.value
232///     }
233/// }
234/// ```
235///
236/// # See Also
237///
238/// * [`measure_all`](macro@measure_all) - Bulk instrumentation macro
239/// * [`measure`](macro@measure) - Individual function instrumentation
240#[proc_macro_attribute]
241pub fn skip(attr: TokenStream, item: TokenStream) -> TokenStream {
242    #[cfg(feature = "hotpath")]
243    {
244        lib_on::skip_impl(attr, item)
245    }
246    #[cfg(not(feature = "hotpath"))]
247    {
248        lib_off::skip_impl(attr, item)
249    }
250}
251
252/// Instruments all functions in a module or impl block with the `measure` profiling macro.
253///
254/// This attribute macro applies the [`measure`](macro@measure) macro to every function
255/// in the annotated module or impl block, providing bulk instrumentation without needing
256/// to annotate each function individually.
257///
258/// # Usage
259///
260/// On modules:
261///
262/// ```rust,no_run
263/// #[hotpath::measure_all]
264/// mod my_module {
265///     fn function_one() {
266///         // This will be automatically measured
267///     }
268///
269///     fn function_two() {
270///         // This will also be automatically measured
271///     }
272/// }
273/// ```
274///
275/// On impl blocks:
276///
277/// ```rust,no_run
278/// struct MyStruct;
279///
280/// #[hotpath::measure_all]
281/// impl MyStruct {
282///     fn method_one(&self) {
283///         // This will be automatically measured
284///     }
285///
286///     fn method_two(&self) {
287///         // This will also be automatically measured
288///     }
289/// }
290/// ```
291///
292/// # See Also
293///
294/// * [`measure`](macro@measure) - Attribute macro for instrumenting individual functions
295/// * [`main`](macro@main) - Attribute macro that initializes profiling
296/// * [`skip`](macro@skip) - Marker to exclude specific functions from measurement
297#[proc_macro_attribute]
298pub fn measure_all(attr: TokenStream, item: TokenStream) -> TokenStream {
299    #[cfg(feature = "hotpath")]
300    {
301        lib_on::measure_all_impl(attr, item)
302    }
303    #[cfg(not(feature = "hotpath"))]
304    {
305        lib_off::measure_all_impl(attr, item)
306    }
307}