hotpath_macros/
lib.rs

1use proc_macro::TokenStream;
2
3#[cfg(all(feature = "hotpath", not(feature = "hotpath-off")))]
4mod lib_on;
5
6#[cfg(any(not(feature = "hotpath"), feature = "hotpath-off"))]
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 to enable profiling.
12/// It creates a guard that initializes the background measurement processing thread and
13/// automatically displays a performance summary when the program exits.
14/// Additionally it creates a measurement guard that will be used to measure the wrapper function itself.
15///
16/// # Parameters
17///
18/// * `percentiles` - Array of percentile values (0-100) to display in the report. Default: `[95]`
19/// * `format` - Output format as a string: `"table"` (default), `"json"`, or `"json-pretty"`
20/// * `limit` - Maximum number of functions to display in the report (0 = show all). Default: `15`
21/// * `timeout` - Optional timeout in milliseconds. If specified, the program will print the report and exit after the timeout.
22///
23/// # Examples
24///
25/// Basic usage with default settings (P95 percentile, table format):
26///
27/// ```rust,no_run
28/// #[hotpath::main]
29/// fn main() {
30///     // Your code here
31/// }
32/// ```
33///
34/// Custom percentiles:
35///
36/// ```rust,no_run
37/// #[tokio::main]
38/// #[hotpath::main(percentiles = [50, 90, 95, 99])]
39/// async fn main() {
40///     // Your code here
41/// }
42/// ```
43///
44/// JSON output format:
45///
46/// ```rust,no_run
47/// #[hotpath::main(format = "json-pretty")]
48/// fn main() {
49///     // Your code here
50/// }
51/// ```
52///
53/// Combined parameters:
54///
55/// ```rust,no_run
56/// #[hotpath::main(percentiles = [50, 99], format = "json")]
57/// fn main() {
58///     // Your code here
59/// }
60/// ```
61///
62/// Custom limit (show top 20 functions):
63///
64/// ```rust,no_run
65/// #[hotpath::main(limit = 20)]
66/// fn main() {
67///     // Your code here
68/// }
69/// ```
70///
71/// # Usage with Tokio
72///
73/// When using with tokio, place `#[tokio::main]` before `#[hotpath::main]`:
74///
75/// ```rust,no_run
76/// #[tokio::main]
77/// #[hotpath::main]
78/// async fn main() {
79///     // Your code here
80/// }
81/// ```
82///
83/// # Limitations
84///
85/// Only one hotpath guard can be active at a time. Creating a second guard (either via this
86/// macro or via [`FunctionsGuardBuilder`](../hotpath/struct.FunctionsGuardBuilder.html)) will cause a panic.
87///
88/// # See Also
89///
90/// * [`measure`](macro@measure) - Attribute macro for instrumenting functions
91/// * [`measure_block!`](../hotpath/macro.measure_block.html) - Macro for measuring code blocks
92/// * [`FunctionsGuardBuilder`](../hotpath/struct.FunctionsGuardBuilder.html) - Manual control over profiling lifecycle
93#[proc_macro_attribute]
94pub fn main(attr: TokenStream, item: TokenStream) -> TokenStream {
95    #[cfg(all(feature = "hotpath", not(feature = "hotpath-off")))]
96    {
97        lib_on::main_impl(attr, item)
98    }
99    #[cfg(any(not(feature = "hotpath"), feature = "hotpath-off"))]
100    {
101        lib_off::main_impl(attr, item)
102    }
103}
104
105/// Instruments a function to send performance measurements to the hotpath profiler.
106///
107/// This attribute macro wraps functions with profiling code that measures execution time
108/// or memory allocations (depending on enabled feature flags). The measurements are sent
109/// to a background processing thread for aggregation.
110///
111/// # Behavior
112///
113/// The macro automatically detects whether the function is sync or async and instruments
114/// it appropriately. Measurements include:
115///
116/// * **Time profiling** (default): Execution duration using high-precision timers
117/// * **Allocation profiling**: Memory allocations when allocation features are enabled
118///   - `hotpath-alloc` - Total bytes allocated
119///   - `hotpath-alloc` - Total allocation count
120///
121/// # Async Function Limitations
122///
123/// When using allocation profiling features with async functions, you must use the
124/// `tokio` runtime in `current_thread` mode:
125///
126/// ```rust,no_run
127/// #[tokio::main(flavor = "current_thread")]
128/// async fn main() {
129///     // Your async code here
130/// }
131/// ```
132///
133/// This limitation exists because allocation tracking uses thread-local storage. In multi-threaded
134/// runtimes, async tasks can migrate between threads, making it impossible to accurately
135/// attribute allocations to specific function calls. Time-based profiling works with any runtime flavor.
136///
137/// When the `hotpath` feature is disabled, this macro compiles to zero overhead (no instrumentation).
138///
139/// # Parameters
140///
141/// * `log` - If `true`, logs the result value when the function returns (requires `Debug` on return type)
142///
143/// # Examples
144///
145/// With result logging (requires Debug on return type):
146///
147/// ```rust,no_run
148/// #[hotpath::measure(log = true)]
149/// fn compute() -> i32 {
150///     // The result value will be logged in TUI console
151///     42
152/// }
153/// ```
154///
155/// # See Also
156///
157/// * [`main`](macro@main) - Attribute macro that initializes profiling
158/// * [`measure_block!`](../hotpath/macro.measure_block.html) - Macro for measuring code blocks
159#[proc_macro_attribute]
160pub fn measure(attr: TokenStream, item: TokenStream) -> TokenStream {
161    #[cfg(all(feature = "hotpath", not(feature = "hotpath-off")))]
162    {
163        lib_on::measure_impl(attr, item)
164    }
165    #[cfg(any(not(feature = "hotpath"), feature = "hotpath-off"))]
166    {
167        lib_off::measure_impl(attr, item)
168    }
169}
170
171/// Instruments an async function to track its lifecycle as a Future.
172///
173/// This attribute macro wraps async functions with the `future!` macro, enabling
174/// tracking of poll counts, state transitions (pending/ready/cancelled), and
175/// optionally logging the result value.
176///
177/// # Parameters
178///
179/// * `log` - If `true`, logs the result value when the future completes (requires `Debug` on return type)
180///
181/// # Examples
182///
183/// Basic usage (no Debug requirement on return type):
184///
185/// ```rust,no_run
186/// #[hotpath::future_fn]
187/// async fn fetch_data() -> Vec<u8> {
188///     // This future's lifecycle will be tracked
189///     vec![1, 2, 3]
190/// }
191/// ```
192///
193/// With result logging (requires Debug on return type):
194///
195/// ```rust,no_run
196/// #[hotpath::future_fn(log = true)]
197/// async fn compute() -> i32 {
198///     // The result value will be logged in TUI console
199///     42
200/// }
201/// ```
202///
203/// # See Also
204///
205/// * [`measure`](macro@measure) - Attribute macro for instrumenting sync/async function timing
206/// * [`future!`](../hotpath/macro.future.html) - Declarative macro for instrumenting future expressions
207#[proc_macro_attribute]
208pub fn future_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
209    #[cfg(all(feature = "hotpath", not(feature = "hotpath-off")))]
210    {
211        lib_on::future_fn_impl(attr, item)
212    }
213    #[cfg(any(not(feature = "hotpath"), feature = "hotpath-off"))]
214    {
215        lib_off::future_fn_impl(attr, item)
216    }
217}
218
219/// Marks a function to be excluded from profiling when used with [`measure_all`](macro@measure_all).
220///
221/// # Usage
222///
223/// ```rust,no_run
224/// #[hotpath::measure_all]
225/// impl MyStruct {
226///     fn important_method(&self) {
227///         // This will be measured
228///     }
229///
230///     #[hotpath::skip]
231///     fn not_so_important_method(&self) -> usize {
232///         // This will NOT be measured
233///         self.value
234///     }
235/// }
236/// ```
237///
238/// # See Also
239///
240/// * [`measure_all`](macro@measure_all) - Bulk instrumentation macro
241/// * [`measure`](macro@measure) - Individual function instrumentation
242#[proc_macro_attribute]
243pub fn skip(attr: TokenStream, item: TokenStream) -> TokenStream {
244    #[cfg(all(feature = "hotpath", not(feature = "hotpath-off")))]
245    {
246        lib_on::skip_impl(attr, item)
247    }
248    #[cfg(any(not(feature = "hotpath"), feature = "hotpath-off"))]
249    {
250        lib_off::skip_impl(attr, item)
251    }
252}
253
254/// Instruments all functions in a module or impl block with the `measure` profiling macro.
255///
256/// This attribute macro applies the [`measure`](macro@measure) macro to every function
257/// in the annotated module or impl block, providing bulk instrumentation without needing
258/// to annotate each function individually.
259///
260/// # Usage
261///
262/// On modules:
263///
264/// ```rust,no_run
265/// #[hotpath::measure_all]
266/// mod my_module {
267///     fn function_one() {
268///         // This will be automatically measured
269///     }
270///
271///     fn function_two() {
272///         // This will also be automatically measured
273///     }
274/// }
275/// ```
276///
277/// On impl blocks:
278///
279/// ```rust,no_run
280/// struct MyStruct;
281///
282/// #[hotpath::measure_all]
283/// impl MyStruct {
284///     fn method_one(&self) {
285///         // This will be automatically measured
286///     }
287///
288///     fn method_two(&self) {
289///         // This will also be automatically measured
290///     }
291/// }
292/// ```
293///
294/// # See Also
295///
296/// * [`measure`](macro@measure) - Attribute macro for instrumenting individual functions
297/// * [`main`](macro@main) - Attribute macro that initializes profiling
298/// * [`skip`](macro@skip) - Marker to exclude specific functions from measurement
299#[proc_macro_attribute]
300pub fn measure_all(attr: TokenStream, item: TokenStream) -> TokenStream {
301    #[cfg(all(feature = "hotpath", not(feature = "hotpath-off")))]
302    {
303        lib_on::measure_all_impl(attr, item)
304    }
305    #[cfg(any(not(feature = "hotpath"), feature = "hotpath-off"))]
306    {
307        lib_off::measure_all_impl(attr, item)
308    }
309}