canic_core/macros/
perf.rs

1/// Log elapsed instruction counts since the last `perf!` invocation in this thread.
2///
3/// - Uses a thread-local `PERF_LAST` snapshot.
4/// - Computes `delta = now - last`.
5/// - Prints a human-readable line for debugging.
6///
7/// Intended usage:
8/// - Long-running maintenance tasks where you want *checkpoints* in a single call.
9/// - Pair with `perf_scope!` to also capture the *full call total* at scope exit.
10///
11/// Notes:
12/// - On non-wasm targets, `perf_counter()` returns 0, so this becomes a no-op-ish
13///   counter (still records 0 deltas); this keeps unit tests compiling cleanly.
14#[macro_export]
15macro_rules! perf {
16    ($($label:tt)*) => {{
17        $crate::perf::PERF_LAST.with(|last| {
18            // Use the wrapper so non-wasm builds compile.
19            let now = $crate::perf::perf_counter();
20            let then = *last.borrow();
21            let delta = now.saturating_sub(then);
22
23            // Update last checkpoint.
24            *last.borrow_mut() = now;
25
26            // Format label + pretty-print counters.
27            let label = format!($($label)*);
28            let delta_fmt = $crate::utils::instructions::format_instructions(delta);
29            let now_fmt = $crate::utils::instructions::format_instructions(now);
30
31            // ❌ NO structured recording here
32            // ✔️ Debug log only
33            $crate::log!(
34                Info,
35                Topic::Perf,
36                "{}: '{}' used {}i since last (total: {}i)",
37                module_path!(),
38                label,
39                delta_fmt,
40                now_fmt
41            );
42        });
43    }};
44}
45
46#[macro_export]
47macro_rules! perf_scope {
48    ($($label:tt)*) => {
49        // Format the label eagerly at scope entry.
50        let __perf_label = format!($($label)*);
51
52        // Create an RAII guard whose Drop implementation records the
53        // performance measurement when the surrounding scope exits.
54        //
55        // We call the `defer` *function* directly (not the `defer!` macro)
56        // to avoid fixed-name shadowing issues that would cause early drops
57        // if multiple defers were introduced in the same scope.
58        //
59        // The guard is bound to a local variable so it remains alive until
60        // the end of the enclosing scope (including across `.await` points
61        // in async functions).
62        let _perf_scope_guard = $crate::__reexports::defer::defer(move || {
63            let __perf_end = $crate::perf::perf_counter();
64
65      //      $crate::log!(Info, "perf: [0] {}, [1] {}", canic_cdk::api::performance_counter(0), canic_cdk::api::performance_counter(1));
66
67            $crate::perf::record_endpoint(&__perf_label, __perf_end);
68        });
69    };
70}