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` - Report sections spec: `"all"`, `"auto"`, an exact list like `"functions-timing,channels"`, or auto with exclusions like `"auto,-threads"`. Default: auto (function and thread sections plus every instrumented section with data). 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 exact report sections, or hide a section from the auto report:
70///
71/// ```rust,no_run
72/// #[hotpath::main(report = "functions-timing,channels")]
73/// fn main() {
74/// // Your code here
75/// }
76/// ```
77///
78/// ```rust,no_run
79/// #[hotpath::main(report = "auto,-threads")]
80/// fn main() {
81/// // Your code here
82/// }
83/// ```
84///
85/// Per-resource limits:
86///
87/// ```rust,no_run
88/// #[hotpath::main(limit = 10, functions_limit = 20, channels_limit = 5)]
89/// fn main() {
90/// // Your code here
91/// }
92/// ```
93///
94/// # Usage with Tokio
95///
96/// When using with tokio, place `#[tokio::main]` before `#[hotpath::main]`:
97///
98/// ```rust,no_run
99/// #[tokio::main]
100/// #[hotpath::main]
101/// async fn main() {
102/// // Your code here
103/// }
104/// ```
105///
106/// # Limitations
107///
108/// Only one hotpath guard can be active at a time. Creating a second guard (either via this
109/// macro or via [`HotpathGuardBuilder`](../hotpath/struct.HotpathGuardBuilder.html)) will cause a panic.
110///
111/// # See Also
112///
113/// * [`measure`](macro@measure) - Attribute macro for instrumenting functions
114/// * [`measure_block!`](../hotpath/macro.measure_block.html) - Macro for measuring code blocks
115/// * [`HotpathGuardBuilder`](../hotpath/struct.HotpathGuardBuilder.html) - Programmatic alternative to this macro
116#[proc_macro_attribute]
117pub fn main(attr: TokenStream, item: TokenStream) -> TokenStream {
118 #[cfg(feature = "hotpath")]
119 {
120 lib_on::main_impl(attr, item)
121 }
122 #[cfg(not(feature = "hotpath"))]
123 {
124 lib_off::main_impl(attr, item)
125 }
126}
127
128/// Instruments a function to measure execution time or memory allocations.
129///
130/// Automatically detects sync vs async and inserts the appropriate measurement guard.
131/// Compiles to zero overhead when the `hotpath` feature is disabled.
132///
133/// # Measurements
134///
135/// * **Time profiling** (default) - execution duration via high-precision timers
136/// * **Allocation profiling** (`hotpath-alloc` feature) - bytes allocated and allocation count
137///
138/// # Parameters
139///
140/// * `log` - If `true`, logs the return value on each call (requires `Debug` on return type)
141/// * `future` - If `true`, also tracks the future lifecycle (poll count, state transitions, cancellation). Only valid on async functions.
142///
143/// # Examples
144///
145/// ```rust,no_run
146/// #[hotpath::measure]
147/// fn process(data: &[u8]) -> usize {
148/// data.len()
149/// }
150///
151/// #[hotpath::measure(log = true)]
152/// fn compute() -> i32 {
153/// 42
154/// }
155///
156/// #[hotpath::measure(future = true)]
157/// async fn fetch_data() -> Vec<u8> {
158/// vec![1, 2, 3]
159/// }
160/// ```
161///
162/// # Async Allocation Limitation
163///
164/// Allocation profiling requires `current_thread` tokio runtime because thread-local
165/// tracking cannot follow tasks across threads. Time profiling works with any runtime.
166///
167/// # See Also
168///
169/// * [`main`](macro@main) - Initializes the profiling system
170/// * [`measure_all`](macro@measure_all) - Bulk instrumentation for modules and impl blocks
171/// * [`measure_block!`](../hotpath/macro.measure_block.html) - Instruments code blocks
172#[proc_macro_attribute]
173pub fn measure(attr: TokenStream, item: TokenStream) -> TokenStream {
174 #[cfg(feature = "hotpath")]
175 {
176 lib_on::measure_impl(attr, item)
177 }
178 #[cfg(not(feature = "hotpath"))]
179 {
180 lib_off::measure_impl(attr, item)
181 }
182}
183
184/// Instruments an async function to track its lifecycle as a Future.
185///
186/// Wraps the function body with the `future!` macro to track poll counts,
187/// state transitions (pending/ready/cancelled), and optionally the output value.
188/// Can only be applied to `async fn`.
189///
190/// # Parameters
191///
192/// * `log` - If `true`, logs the output value on completion (requires `Debug` on return type)
193///
194/// # Examples
195///
196/// ```rust,no_run
197/// #[hotpath::future_fn]
198/// async fn fetch_data() -> Vec<u8> {
199/// vec![1, 2, 3]
200/// }
201///
202/// #[hotpath::future_fn(log = true)]
203/// async fn compute() -> i32 {
204/// 42
205/// }
206/// ```
207///
208/// # See Also
209///
210/// * [`measure`](macro@measure) - Instruments execution time / allocations
211/// * [`future!`](../hotpath/macro.future.html) - Declarative macro for wrapping future expressions
212#[proc_macro_attribute]
213pub fn future_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
214 #[cfg(feature = "hotpath")]
215 {
216 lib_on::future_fn_impl(attr, item)
217 }
218 #[cfg(not(feature = "hotpath"))]
219 {
220 lib_off::future_fn_impl(attr, item)
221 }
222}
223
224/// Marks a function to be excluded from profiling when used with [`measure_all`](macro@measure_all).
225///
226/// # Usage
227///
228/// ```rust,no_run
229/// #[hotpath::measure_all]
230/// impl MyStruct {
231/// fn important_method(&self) {
232/// // This will be measured
233/// }
234///
235/// #[hotpath::skip]
236/// fn not_so_important_method(&self) -> usize {
237/// // This will NOT be measured
238/// self.value
239/// }
240/// }
241/// ```
242///
243/// # See Also
244///
245/// * [`measure_all`](macro@measure_all) - Bulk instrumentation macro
246/// * [`measure`](macro@measure) - Individual function instrumentation
247#[proc_macro_attribute]
248pub fn skip(attr: TokenStream, item: TokenStream) -> TokenStream {
249 #[cfg(feature = "hotpath")]
250 {
251 lib_on::skip_impl(attr, item)
252 }
253 #[cfg(not(feature = "hotpath"))]
254 {
255 lib_off::skip_impl(attr, item)
256 }
257}
258
259/// Instruments all functions in a module or impl block with the `measure` profiling macro.
260///
261/// This attribute macro applies the [`measure`](macro@measure) macro to every function
262/// in the annotated module or impl block, providing bulk instrumentation without needing
263/// to annotate each function individually.
264///
265/// # Usage
266///
267/// On modules:
268///
269/// ```rust,no_run
270/// #[hotpath::measure_all]
271/// mod my_module {
272/// fn function_one() {
273/// // This will be automatically measured
274/// }
275///
276/// fn function_two() {
277/// // This will also be automatically measured
278/// }
279/// }
280/// ```
281///
282/// On impl blocks:
283///
284/// ```rust,no_run
285/// struct MyStruct;
286///
287/// #[hotpath::measure_all]
288/// impl MyStruct {
289/// fn method_one(&self) {
290/// // This will be automatically measured
291/// }
292///
293/// fn method_two(&self) {
294/// // This will also be automatically measured
295/// }
296/// }
297/// ```
298///
299/// # See Also
300///
301/// * [`measure`](macro@measure) - Attribute macro for instrumenting individual functions
302/// * [`main`](macro@main) - Attribute macro that initializes profiling
303/// * [`skip`](macro@skip) - Marker to exclude specific functions from measurement
304#[proc_macro_attribute]
305pub fn measure_all(attr: TokenStream, item: TokenStream) -> TokenStream {
306 #[cfg(feature = "hotpath")]
307 {
308 lib_on::measure_all_impl(attr, item)
309 }
310 #[cfg(not(feature = "hotpath"))]
311 {
312 lib_off::measure_all_impl(attr, item)
313 }
314}