canic_macros/perf.rs
1/// Log elapsed instruction counts since the last `perf!` invocation.
2///
3/// Records the delta in instructions between calls and emits a
4/// [`Log::Perf`](crate::Log::Perf)
5/// entry with the provided label (any tokens accepted by `format!`). Use this
6/// to highlight hot paths in long-running maintenance tasks.
7#[macro_export]
8macro_rules! perf {
9 ($($label:tt)*) => {{
10 $crate::utils::perf::PERF_LAST.with(|last| {
11 let now = $crate::cdk::api::performance_counter(1);
12 let then = *last.borrow();
13 let delta = now.saturating_sub(then);
14 *last.borrow_mut() = now;
15
16 let delta_fmt = $crate::utils::instructions::format_instructions(delta);
17 let now_fmt = $crate::utils::instructions::format_instructions(now);
18
19 $crate::cdk::println!(
20 "{}: '{}' used {}i since last (total: {}i)",
21 module_path!(),
22 format!($($label)*),
23 delta_fmt,
24 now_fmt
25 );
26 });
27 }};
28}
29
30/// Record a single-call instruction counter snapshot when the surrounding
31/// scope exits.
32///
33/// Expands to a `defer!` guard that logs the total instructions consumed in
34/// the enclosing scope, tagged as [`Log::Perf`](crate::Log::Perf). Pair this
35/// with manual checkpoints logged via [`macro@perf`] to track both cumulative and incremental
36/// usage.
37#[macro_export]
38macro_rules! perf_start {
39 () => {
40 $crate::export::defer::defer!({
41 let end = $crate::cdk::api::performance_counter(1);
42 let end_fmt = $crate::utils::instructions::format_instructions(end);
43
44 $crate::cdk::println!("{} used {}i in this call", module_path!(), end_fmt,)
45 });
46 };
47}