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