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