rlx_runtime/kernel_trace.rs
1// RLX — versatile ML compiler + runtime.
2// Copyright (C) 2026 Eugene Hauptmann, Nataliya Kosmyna.
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, version 3.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with this program. If not, see <https://www.gnu.org/licenses/>.
15
16//! Compile-time gated kernel tracing (plan #7).
17//!
18//! Borrowed from MAX's `Trace, TraceLevel, trace_arg` pattern.
19//! Tracing calls are baked into hot paths but the *macro* expands to
20//! either a stamped `eprintln!` (when the `kernel-trace` feature is
21//! on) or to nothing (default). The compiler eliminates the
22//! disabled branch entirely — production builds pay zero overhead.
23//!
24//! Use it like:
25//! ```ignore
26//! rlx_runtime::ktrace!("matmul", "m={m} k={k} n={n}");
27//! ```
28//!
29//! The macro takes a `kind` (op/section name) and a format string
30//! plus args. Output is namespaced with `[ktrace:<kind>]` and
31//! includes a monotonic timestamp from `rlx_ir::Tick`.
32
33#[cfg(feature = "kernel-trace")]
34#[doc(hidden)]
35pub fn _emit(kind: &str, msg: std::fmt::Arguments<'_>) {
36 use std::sync::OnceLock;
37 static T0: OnceLock<rlx_ir::Tick> = OnceLock::new();
38 let start = *T0.get_or_init(rlx_ir::Tick::now);
39 let now = rlx_ir::Tick::now();
40 eprintln!("[ktrace:{kind}] +{:>10} ns {msg}", now.elapsed_ns(start));
41}
42
43#[cfg(not(feature = "kernel-trace"))]
44#[doc(hidden)]
45pub fn _emit(_kind: &str, _msg: std::fmt::Arguments<'_>) {}
46
47/// Compile-time gated kernel trace. Expands to a no-op call without
48/// the `kernel-trace` feature; the optimizer removes it entirely.
49#[macro_export]
50macro_rules! ktrace {
51 ($kind:expr, $($arg:tt)+) => {{
52 $crate::kernel_trace::_emit($kind, format_args!($($arg)+));
53 }};
54}
55
56#[cfg(test)]
57mod tests {
58 #[test]
59 fn macro_compiles_and_runs() {
60 // The macro must compile and run regardless of feature state.
61 // With the feature off, this is a no-op call — verify it
62 // doesn't panic and doesn't write anything we can observe in
63 // a unit test.
64 crate::ktrace!("test", "x={} y={}", 1, 2);
65 }
66}