Skip to main content

ktrace_macro/
lib.rs

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