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}