Skip to main content

ktrace_macro/
lib.rs

1// Copyright 2026 The Fuchsia Authors
2//
3// Use of this source code is governed by a MIT-style
4// license that can be found in the LICENSE file or at
5// https://opensource.org/licenses/MIT
6
7#![no_std]
8
9/// Resolves a string parameter to a reference to an `InternedString`.
10/// If a string literal is provided, it is statically interned at compile-time.
11#[macro_export]
12macro_rules! resolve_string {
13    ($string:ident) => {
14        $string
15    };
16    ($string:literal) => {{
17        #[unsafe(link_section = "__fxt_interned_string_table")]
18        #[used]
19        static STRING: crate::ktrace_rs::InternedString =
20            unsafe { crate::ktrace_rs::InternedString::new_raw(concat!($string, "\0").as_ptr()) };
21        &STRING
22    }};
23    ($string:expr) => {
24        $string
25    };
26}
27
28/// Resolves a category parameter to a reference to an `InternedCategory`.
29/// If a string literal is provided, it is declared as an external category.
30#[macro_export]
31macro_rules! resolve_category {
32    ($category:ident) => {
33        $category
34    };
35    ($category:literal) => {{
36        crate::ktrace_rs::declare_interned_category!(CATEGORY, $category, extern);
37        CATEGORY
38    }};
39}
40
41/// Writes an instant event associated with the current thread when the given category is enabled.
42///
43/// # Arguments:
44/// - category: Filter category for the event. Expects a string literal or expression.
45/// - label: Label for the event. Expects a string literal or expression.
46/// - ...: List of key => value argument pairs.
47#[macro_export]
48macro_rules! instant {
49    ($category:tt, $label:tt, $context:expr $(, $key:tt => $val:expr)* $(,)?) => {
50        {
51            let category = $crate::resolve_category!($category);
52            let ktrace = crate::ktrace_rs::KTrace::get_instance();
53            if ktrace.is_category_enabled(category) {
54                ktrace.emit_event(
55                    crate::ktrace_rs::EventType::Instant,
56                    category,
57                    $crate::resolve_string!($label),
58                    crate::ktrace_rs::timer_current_boot_ticks(),
59                    $context,
60                    None,
61                    &[
62                        $(crate::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
63                    ],
64                );
65            }
66        }
67    };
68    ($category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
69        $crate::instant!($category, $label, crate::ktrace_rs::Context::Thread $(, $key => $val)*)
70    };
71}
72
73/// Similar to `instant!`, but associates the event with the current CPU instead of the current
74/// thread.
75#[macro_export]
76macro_rules! cpu_instant {
77    ($category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
78        $crate::instant!($category, $label, crate::ktrace_rs::Context::Cpu $(, $key => $val)*)
79    };
80}
81
82/// Writes a duration begin event associated with the current thread when the given category is
83/// enabled.
84///
85/// # Arguments:
86/// - category: Filter category for the event. Expects a string literal or expression.
87/// - label: Label for the event. Expects a string literal or expression.
88/// - ...: List of key => value argument pairs.
89#[macro_export]
90macro_rules! duration_begin {
91    ($category:tt, $label:tt, $context:expr $(, $key:tt => $val:expr)* $(,)?) => {
92        {
93            let category = $crate::resolve_category!($category);
94            let ktrace = crate::ktrace_rs::KTrace::get_instance();
95            if ktrace.is_category_enabled(category) {
96                ktrace.emit_event(
97                    crate::ktrace_rs::EventType::DurationBegin,
98                    category,
99                    $crate::resolve_string!($label),
100                    crate::ktrace_rs::timer_current_boot_ticks(),
101                    $context,
102                    None,
103                    &[
104                        $(crate::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
105                    ],
106                );
107            }
108        }
109    };
110    ($category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
111        $crate::duration_begin!($category, $label, crate::ktrace_rs::Context::Thread $(, $key => $val)*)
112    };
113}
114
115/// Similar to `duration_begin!`, but associates the event with the current CPU instead of the
116/// current thread.
117#[macro_export]
118macro_rules! cpu_duration_begin {
119    ($category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
120        $crate::duration_begin!($category, $label, crate::ktrace_rs::Context::Cpu $(, $key => $val)*)
121    };
122}
123
124/// Writes a duration end event associated with the current thread when the given category is
125/// enabled.
126///
127/// # Arguments:
128/// - category: Filter category for the event. Expects a string literal or expression.
129/// - label: Label for the event. Expects a string literal or expression.
130/// - ...: List of key => value argument pairs.
131#[macro_export]
132macro_rules! duration_end {
133    ($category:tt, $label:tt, $context:expr $(, $key:tt => $val:expr)* $(,)?) => {
134        {
135            let category = $crate::resolve_category!($category);
136            let ktrace = crate::ktrace_rs::KTrace::get_instance();
137            if ktrace.is_category_enabled(category) {
138                ktrace.emit_event(
139                    crate::ktrace_rs::EventType::DurationEnd,
140                    category,
141                    $crate::resolve_string!($label),
142                    crate::ktrace_rs::timer_current_boot_ticks(),
143                    $context,
144                    None,
145                    &[
146                        $(crate::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
147                    ],
148                );
149            }
150        }
151    };
152    ($category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
153        $crate::duration_end!($category, $label, crate::ktrace_rs::Context::Thread $(, $key => $val)*)
154    };
155}
156
157/// Similar to `duration_end!`, but associates the event with the current CPU instead of the
158/// current thread.
159#[macro_export]
160macro_rules! cpu_duration_end {
161    ($category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
162        $crate::duration_end!($category, $label, crate::ktrace_rs::Context::Cpu $(, $key => $val)*)
163    };
164}
165
166/// Writes a counter event associated with the current thread when the given category is enabled.
167///
168/// Each argument is rendered as a separate value series named "<label>:<arg name>:<counter_id>".
169///
170/// # Arguments:
171/// - category: Filter category for the event. Expects a string literal or expression.
172/// - label: Label for the event. Expects a string literal or expression.
173/// - counter_id: Correlation id for the event. Must be convertible to u64.
174/// - ...: List of key => value argument pairs.
175#[macro_export]
176macro_rules! counter {
177    ($category:tt, $label:tt, $counter_id:expr $(, $key:tt => $val:expr)* $(,)?) => {
178        {
179            let category = $crate::resolve_category!($category);
180            let ktrace = crate::ktrace_rs::KTrace::get_instance();
181            if ktrace.is_category_enabled(category) {
182                ktrace.emit_event(
183                    crate::ktrace_rs::EventType::Counter,
184                    category,
185                    $crate::resolve_string!($label),
186                    crate::ktrace_rs::timer_current_boot_ticks(),
187                    crate::ktrace_rs::Context::Thread,
188                    Some($counter_id as u64),
189                    &[
190                        $(crate::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
191                    ],
192                );
193            }
194        }
195    };
196}
197
198/// Writes a flow begin event associated with the current thread when the given category is enabled.
199///
200/// # Arguments:
201/// - category: Filter category for the event. Expects a string literal or expression.
202/// - label: Label for the event. Expects a string literal or expression.
203/// - flow_id: Flow id for the event. Must be convertible to u64.
204/// - ...: List of key => value argument pairs.
205#[macro_export]
206macro_rules! flow_begin {
207    ($category:tt, $label:tt, $flow_id:expr $(, $key:tt => $val:expr)* $(,)?) => {
208        {
209            let category = $crate::resolve_category!($category);
210            let ktrace = crate::ktrace_rs::KTrace::get_instance();
211            if ktrace.is_category_enabled(category) {
212                ktrace.emit_event(
213                    crate::ktrace_rs::EventType::FlowBegin,
214                    category,
215                    $crate::resolve_string!($label),
216                    crate::ktrace_rs::timer_current_boot_ticks(),
217                    crate::ktrace_rs::Context::Thread,
218                    Some($flow_id as u64),
219                    &[
220                        $(crate::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
221                    ],
222                );
223            }
224        }
225    };
226}
227
228/// Writes a flow step event associated with the current thread when the given category is enabled.
229///
230/// # Arguments:
231/// - category: Filter category for the event. Expects a string literal or expression.
232/// - label: Label for the event. Expects a string literal or expression.
233/// - flow_id: Flow id for the event. Must be convertible to u64.
234/// - ...: List of key => value argument pairs.
235#[macro_export]
236macro_rules! flow_step {
237    ($category:tt, $label:tt, $flow_id:expr $(, $key:tt => $val:expr)* $(,)?) => {
238        {
239            let category = $crate::resolve_category!($category);
240            let ktrace = crate::ktrace_rs::KTrace::get_instance();
241            if ktrace.is_category_enabled(category) {
242                ktrace.emit_event(
243                    crate::ktrace_rs::EventType::FlowStep,
244                    category,
245                    $crate::resolve_string!($label),
246                    crate::ktrace_rs::timer_current_boot_ticks(),
247                    crate::ktrace_rs::Context::Thread,
248                    Some($flow_id as u64),
249                    &[
250                        $(crate::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
251                    ],
252                );
253            }
254        }
255    };
256}
257
258/// Writes a flow end event associated with the current thread when the given category is enabled.
259///
260/// # Arguments:
261/// - category: Filter category for the event. Expects a string literal or expression.
262/// - label: Label for the event. Expects a string literal or expression.
263/// - flow_id: Flow id for the event. Must be convertible to u64.
264/// - ...: List of key => value argument pairs.
265#[macro_export]
266macro_rules! flow_end {
267    ($category:tt, $label:tt, $flow_id:expr $(, $key:tt => $val:expr)* $(,)?) => {
268        {
269            let category = $crate::resolve_category!($category);
270            let ktrace = crate::ktrace_rs::KTrace::get_instance();
271            if ktrace.is_category_enabled(category) {
272                ktrace.emit_event(
273                    crate::ktrace_rs::EventType::FlowEnd,
274                    category,
275                    $crate::resolve_string!($label),
276                    crate::ktrace_rs::timer_current_boot_ticks(),
277                    crate::ktrace_rs::Context::Thread,
278                    Some($flow_id as u64),
279                    &[
280                        $(crate::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
281                    ],
282                );
283            }
284        }
285    };
286}
287
288/// Creates a delegate to capture the given arguments at the beginning of a scope when the given
289/// category is enabled. The returned value should be used to construct a `ktrace::Scope` to track
290/// the lifetime of the scope and emit the complete trace event. The complete event is associated
291/// with the current thread.
292///
293/// # Arguments:
294/// - category: Filter category for the event. Expects a string literal or expression.
295/// - label: Label for the event. Expects a string literal or expression.
296/// - ...: List of key => value argument pairs.
297#[macro_export]
298macro_rules! begin_scope {
299    ($category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
300        crate::ktrace_rs::KTraceScope::begin(
301            $crate::resolve_category!($category),
302            $crate::resolve_string!($label),
303            crate::ktrace_rs::Context::Thread,
304            [$(crate::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*],
305        )
306    };
307}
308
309/// Similar to `begin_scope!`, but associates the event with the current CPU instead of the
310/// current thread.
311#[macro_export]
312macro_rules! cpu_begin_scope {
313    ($category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
314        crate::ktrace_rs::KTraceScope::begin(
315            $crate::resolve_category!($category),
316            $crate::resolve_string!($label),
317            crate::ktrace_rs::Context::Cpu,
318            [$(crate::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*],
319        )
320    };
321}
322
323/// Similar to `begin_scope!`, but checks the given runtime_condition, in addition to the given
324/// category, to determine whether to emit the event.
325#[macro_export]
326macro_rules! begin_scope_cond {
327    ($cond:expr, $category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
328        {
329            let category = $crate::resolve_category!($category);
330            let ktrace = crate::ktrace_rs::KTrace::get_instance();
331            if $cond && ktrace.is_category_enabled(category) {
332                Some(crate::ktrace_rs::KTraceScope::begin(
333                    category,
334                    $crate::resolve_string!($label),
335                    crate::ktrace_rs::Context::Thread,
336                    [$(crate::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*],
337                ))
338            } else {
339                None
340            }
341        }
342    };
343}
344
345/// Writes a duration complete event associated with the current thread when the given category is
346/// enabled.
347///
348/// # Arguments:
349/// - category: Filter category for the event. Expects a string literal or expression.
350/// - label: Label for the event. Expects a string literal or expression.
351/// - start_timestamp: The starting timestamp for the event. Must be convertible to i64.
352/// - ...: List of key => value argument pairs.
353#[macro_export]
354macro_rules! complete {
355    ($category:tt, $label:tt, $start_timestamp:expr, $context:expr $(, $key:tt => $val:expr)* $(,)?) => {
356        {
357            let category = $crate::resolve_category!($category);
358            let ktrace = crate::ktrace_rs::KTrace::get_instance();
359            if ktrace.is_category_enabled(category) {
360                ktrace.emit_event(
361                    crate::ktrace_rs::EventType::DurationComplete,
362                    category,
363                    $crate::resolve_string!($label),
364                    $start_timestamp,
365                    $context,
366                    Some(crate::ktrace_rs::timer_current_boot_ticks().0 as u64),
367                    &[
368                        $(crate::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
369                    ],
370                );
371            }
372        }
373    };
374    ($category:tt, $label:tt, $start_timestamp:expr $(, $key:tt => $val:expr)* $(,)?) => {
375        $crate::complete!($category, $label, $start_timestamp, crate::ktrace_rs::Context::Thread $(, $key => $val)*)
376    };
377}
378
379/// Similar to `complete!`, but associates the event with the current CPU instead of the current
380/// thread.
381#[macro_export]
382macro_rules! cpu_complete {
383    ($category:tt, $label:tt, $start_timestamp:expr $(, $key:tt => $val:expr)* $(,)?) => {
384        $crate::complete!($category, $label, $start_timestamp, crate::ktrace_rs::Context::Cpu $(, $key => $val)*)
385    };
386}
387
388/// Writes a kernel object record when the given trace category is enabled.
389///
390/// # Arguments:
391/// - category: Filter category for the object record. Expects a string literal or expression.
392/// - koid: Kernel object id of the object. Expects type u64.
393/// - obj_type: The type the object. Expects type u32.
394/// - name: The name of the object. Expects a string literal or expression.
395/// - ...: List of key => value argument pairs.
396#[macro_export]
397macro_rules! kernel_object {
398    ($category:tt, $koid:expr, $obj_type:expr, $name:expr $(, $key:tt => $val:expr)* $(,)?) => {
399        {
400            let category = $crate::resolve_category!($category);
401            let ktrace = crate::ktrace_rs::KTrace::get_instance();
402            if ktrace.is_category_enabled(category) {
403                ktrace.emit_kernel_object_outlined(
404                    $koid as u64,
405                    $obj_type as u32,
406                    $crate::resolve_string!($name),
407                    &[
408                        $(crate::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
409                    ],
410                );
411            }
412        }
413    };
414}
415
416/// Writes a kernel object record unconditionally. Useful for generating the initial set of object
417/// info records before tracing is enabled.
418///
419/// # Arguments:
420/// - koid: Kernel object id of the object. Expects type u64.
421/// - obj_type: The type the object. Expects type u32.
422/// - name: The name of the object. Expects a string literal or expression.
423/// - ...: List of key => value argument pairs.
424#[macro_export]
425macro_rules! kernel_object_always {
426    ($koid:expr, $obj_type:expr, $name:expr $(, $key:tt => $val:expr)* $(,)?) => {
427        {
428            let ktrace = crate::ktrace_rs::KTrace::get_instance();
429            ktrace.emit_kernel_object_outlined(
430                $koid as u64,
431                $obj_type as u32,
432                $crate::resolve_string!($name),
433                &[
434                    $(crate::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
435                ],
436            );
437        }
438    };
439}