blob: bc6703c8bc36a52b320ebe16766d0597282fd130 [file]
// Copyright 2026 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#![no_std]
/// Resolves a string parameter to a reference to an `InternedString`.
/// If a string literal is provided, it is statically interned at compile-time.
#[macro_export]
macro_rules! resolve_string {
($string:ident) => {
$string
};
($string:literal) => {{
#[unsafe(link_section = "__fxt_interned_string_table")]
#[used]
static STRING: ::ktrace_rs::InternedString =
unsafe { ::ktrace_rs::InternedString::new_raw(concat!($string, "\0").as_ptr()) };
&STRING
}};
}
/// Resolves a category parameter to a reference to an `InternedCategory`.
/// If a string literal is provided, it is declared as an external category.
#[macro_export]
macro_rules! resolve_category {
($category:ident) => {
$category
};
($category:literal) => {{
::ktrace_rs::declare_interned_category!(CATEGORY, $category, extern);
CATEGORY
}};
}
/// Writes an instant event associated with the current thread when the given category is enabled.
///
/// # Arguments:
/// - category: Filter category for the event. Expects a string literal or expression.
/// - label: Label for the event. Expects a string literal or expression.
/// - ...: List of key => value argument pairs.
#[macro_export]
macro_rules! instant {
($category:tt, $label:tt, $context:expr $(, $key:tt => $val:expr)* $(,)?) => {
{
let category = $crate::resolve_category!($category);
let ktrace = ::ktrace_rs::KTrace::get_instance();
if ktrace.is_category_enabled(category) {
ktrace.emit_event(
::ktrace_rs::EventType::Instant,
category,
$crate::resolve_string!($label),
::ktrace_rs::timer_current_boot_ticks(),
$context,
None,
&[
$(::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
],
);
}
}
};
($category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
$crate::instant!($category, $label, ::ktrace_rs::Context::Thread $(, $key => $val)*)
};
}
/// Similar to `instant!`, but associates the event with the current CPU instead of the current
/// thread.
#[macro_export]
macro_rules! cpu_instant {
($category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
$crate::instant!($category, $label, ::ktrace_rs::Context::Cpu $(, $key => $val)*)
};
}
/// Writes a duration begin event associated with the current thread when the given category is
/// enabled.
///
/// # Arguments:
/// - category: Filter category for the event. Expects a string literal or expression.
/// - label: Label for the event. Expects a string literal or expression.
/// - ...: List of key => value argument pairs.
#[macro_export]
macro_rules! duration_begin {
($category:tt, $label:tt, $context:expr $(, $key:tt => $val:expr)* $(,)?) => {
{
let category = $crate::resolve_category!($category);
let ktrace = ::ktrace_rs::KTrace::get_instance();
if ktrace.is_category_enabled(category) {
ktrace.emit_event(
::ktrace_rs::EventType::DurationBegin,
category,
$crate::resolve_string!($label),
::ktrace_rs::timer_current_boot_ticks(),
$context,
None,
&[
$(::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
],
);
}
}
};
($category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
$crate::duration_begin!($category, $label, ::ktrace_rs::Context::Thread $(, $key => $val)*)
};
}
/// Similar to `duration_begin!`, but associates the event with the current CPU instead of the
/// current thread.
#[macro_export]
macro_rules! cpu_duration_begin {
($category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
$crate::duration_begin!($category, $label, ::ktrace_rs::Context::Cpu $(, $key => $val)*)
};
}
/// Writes a duration end event associated with the current thread when the given category is
/// enabled.
///
/// # Arguments:
/// - category: Filter category for the event. Expects a string literal or expression.
/// - label: Label for the event. Expects a string literal or expression.
/// - ...: List of key => value argument pairs.
#[macro_export]
macro_rules! duration_end {
($category:tt, $label:tt, $context:expr $(, $key:tt => $val:expr)* $(,)?) => {
{
let category = $crate::resolve_category!($category);
let ktrace = ::ktrace_rs::KTrace::get_instance();
if ktrace.is_category_enabled(category) {
ktrace.emit_event(
::ktrace_rs::EventType::DurationEnd,
category,
$crate::resolve_string!($label),
::ktrace_rs::timer_current_boot_ticks(),
$context,
None,
&[
$(::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
],
);
}
}
};
($category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
$crate::duration_end!($category, $label, ::ktrace_rs::Context::Thread $(, $key => $val)*)
};
}
/// Similar to `duration_end!`, but associates the event with the current CPU instead of the
/// current thread.
#[macro_export]
macro_rules! cpu_duration_end {
($category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
$crate::duration_end!($category, $label, ::ktrace_rs::Context::Cpu $(, $key => $val)*)
};
}
/// Writes a counter event associated with the current thread when the given category is enabled.
///
/// Each argument is rendered as a separate value series named "<label>:<arg name>:<counter_id>".
///
/// # Arguments:
/// - category: Filter category for the event. Expects a string literal or expression.
/// - label: Label for the event. Expects a string literal or expression.
/// - counter_id: Correlation id for the event. Must be convertible to u64.
/// - ...: List of key => value argument pairs.
#[macro_export]
macro_rules! counter {
($category:tt, $label:tt, $counter_id:expr $(, $key:tt => $val:expr)* $(,)?) => {
{
let category = $crate::resolve_category!($category);
let ktrace = ::ktrace_rs::KTrace::get_instance();
if ktrace.is_category_enabled(category) {
ktrace.emit_event(
::ktrace_rs::EventType::Counter,
category,
$crate::resolve_string!($label),
::ktrace_rs::timer_current_boot_ticks(),
::ktrace_rs::Context::Thread,
Some($counter_id as u64),
&[
$(::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
],
);
}
}
};
}
/// Writes a flow begin event associated with the current thread when the given category is enabled.
///
/// # Arguments:
/// - category: Filter category for the event. Expects a string literal or expression.
/// - label: Label for the event. Expects a string literal or expression.
/// - flow_id: Flow id for the event. Must be convertible to u64.
/// - ...: List of key => value argument pairs.
#[macro_export]
macro_rules! flow_begin {
($category:tt, $label:tt, $flow_id:expr $(, $key:tt => $val:expr)* $(,)?) => {
{
let category = $crate::resolve_category!($category);
let ktrace = ::ktrace_rs::KTrace::get_instance();
if ktrace.is_category_enabled(category) {
ktrace.emit_event(
::ktrace_rs::EventType::FlowBegin,
category,
$crate::resolve_string!($label),
::ktrace_rs::timer_current_boot_ticks(),
::ktrace_rs::Context::Thread,
Some($flow_id as u64),
&[
$(::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
],
);
}
}
};
}
/// Writes a flow step event associated with the current thread when the given category is enabled.
///
/// # Arguments:
/// - category: Filter category for the event. Expects a string literal or expression.
/// - label: Label for the event. Expects a string literal or expression.
/// - flow_id: Flow id for the event. Must be convertible to u64.
/// - ...: List of key => value argument pairs.
#[macro_export]
macro_rules! flow_step {
($category:tt, $label:tt, $flow_id:expr $(, $key:tt => $val:expr)* $(,)?) => {
{
let category = $crate::resolve_category!($category);
let ktrace = ::ktrace_rs::KTrace::get_instance();
if ktrace.is_category_enabled(category) {
ktrace.emit_event(
::ktrace_rs::EventType::FlowStep,
category,
$crate::resolve_string!($label),
::ktrace_rs::timer_current_boot_ticks(),
::ktrace_rs::Context::Thread,
Some($flow_id as u64),
&[
$(::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
],
);
}
}
};
}
/// Writes a flow end event associated with the current thread when the given category is enabled.
///
/// # Arguments:
/// - category: Filter category for the event. Expects a string literal or expression.
/// - label: Label for the event. Expects a string literal or expression.
/// - flow_id: Flow id for the event. Must be convertible to u64.
/// - ...: List of key => value argument pairs.
#[macro_export]
macro_rules! flow_end {
($category:tt, $label:tt, $flow_id:expr $(, $key:tt => $val:expr)* $(,)?) => {
{
let category = $crate::resolve_category!($category);
let ktrace = ::ktrace_rs::KTrace::get_instance();
if ktrace.is_category_enabled(category) {
ktrace.emit_event(
::ktrace_rs::EventType::FlowEnd,
category,
$crate::resolve_string!($label),
::ktrace_rs::timer_current_boot_ticks(),
::ktrace_rs::Context::Thread,
Some($flow_id as u64),
&[
$(::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
],
);
}
}
};
}
/// Creates a delegate to capture the given arguments at the beginning of a scope when the given
/// category is enabled. The returned value should be used to construct a `ktrace::Scope` to track
/// the lifetime of the scope and emit the complete trace event. The complete event is associated
/// with the current thread.
///
/// # Arguments:
/// - category: Filter category for the event. Expects a string literal or expression.
/// - label: Label for the event. Expects a string literal or expression.
/// - ...: List of key => value argument pairs.
#[macro_export]
macro_rules! begin_scope {
($category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
::ktrace_rs::KTraceScope::begin(
$crate::resolve_category!($category),
$crate::resolve_string!($label),
::ktrace_rs::Context::Thread,
&[$(::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*],
)
};
}
/// Similar to `begin_scope!`, but associates the event with the current CPU instead of the
/// current thread.
#[macro_export]
macro_rules! cpu_begin_scope {
($category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
::ktrace_rs::KTraceScope::begin(
$crate::resolve_category!($category),
$crate::resolve_string!($label),
::ktrace_rs::Context::Cpu,
&[$(::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*],
)
};
}
/// Similar to `begin_scope!`, but checks the given runtime_condition, in addition to the given
/// category, to determine whether to emit the event.
#[macro_export]
macro_rules! begin_scope_cond {
($cond:expr, $category:tt, $label:tt $(, $key:tt => $val:expr)* $(,)?) => {
{
let category = $crate::resolve_category!($category);
let ktrace = ::ktrace_rs::KTrace::get_instance();
if $cond && ktrace.is_category_enabled(category) {
Some(::ktrace_rs::KTraceScope::begin(
category,
$crate::resolve_string!($label),
::ktrace_rs::Context::Thread,
&[$(::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*],
))
} else {
None
}
}
};
}
/// Writes a duration complete event associated with the current thread when the given category is
/// enabled.
///
/// # Arguments:
/// - category: Filter category for the event. Expects a string literal or expression.
/// - label: Label for the event. Expects a string literal or expression.
/// - start_timestamp: The starting timestamp for the event. Must be convertible to i64.
/// - ...: List of key => value argument pairs.
#[macro_export]
macro_rules! complete {
($category:tt, $label:tt, $start_timestamp:expr, $context:expr $(, $key:tt => $val:expr)* $(,)?) => {
{
let category = $crate::resolve_category!($category);
let ktrace = ::ktrace_rs::KTrace::get_instance();
if ktrace.is_category_enabled(category) {
ktrace.emit_event(
::ktrace_rs::EventType::DurationComplete,
category,
$crate::resolve_string!($label),
$start_timestamp,
$context,
Some(::ktrace_rs::timer_current_boot_ticks().0 as u64),
&[
$(::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
],
);
}
}
};
($category:tt, $label:tt, $start_timestamp:expr $(, $key:tt => $val:expr)* $(,)?) => {
$crate::complete!($category, $label, $start_timestamp, ::ktrace_rs::Context::Thread $(, $key => $val)*)
};
}
/// Similar to `complete!`, but associates the event with the current CPU instead of the current
/// thread.
#[macro_export]
macro_rules! cpu_complete {
($category:tt, $label:tt, $start_timestamp:expr $(, $key:tt => $val:expr)* $(,)?) => {
$crate::complete!($category, $label, $start_timestamp, ::ktrace_rs::Context::Cpu $(, $key => $val)*)
};
}
/// Writes a kernel object record when the given trace category is enabled.
///
/// # Arguments:
/// - category: Filter category for the object record. Expects a string literal or expression.
/// - koid: Kernel object id of the object. Expects type u64.
/// - obj_type: The type the object. Expects type u32.
/// - name: The name of the object. Expects a string literal or expression.
/// - ...: List of key => value argument pairs.
#[macro_export]
macro_rules! kernel_object {
($category:tt, $koid:expr, $obj_type:expr, $name:tt $(, $key:tt => $val:expr)* $(,)?) => {
{
let category = $crate::resolve_category!($category);
let ktrace = ::ktrace_rs::KTrace::get_instance();
if ktrace.is_category_enabled(category) {
ktrace.emit_kernel_object_outlined(
$koid as u64,
$obj_type as u32,
$crate::resolve_string!($name),
&[
$(::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
],
);
}
}
};
}
/// Writes a kernel object record unconditionally. Useful for generating the initial set of object
/// info records before tracing is enabled.
///
/// # Arguments:
/// - koid: Kernel object id of the object. Expects type u64.
/// - obj_type: The type the object. Expects type u32.
/// - name: The name of the object. Expects a string literal or expression.
/// - ...: List of key => value argument pairs.
#[macro_export]
macro_rules! kernel_object_always {
($koid:expr, $obj_type:expr, $name:tt $(, $key:tt => $val:expr)* $(,)?) => {
{
let ktrace = ::ktrace_rs::KTrace::get_instance();
ktrace.emit_kernel_object_outlined(
$koid as u64,
$obj_type as u32,
$crate::resolve_string!($name),
&[
$(::ktrace_rs::Argument::new($crate::resolve_string!($key), $val)),*
],
);
}
};
}