[PATCH v3 6/6] rtla/osnoise: Trace IPI events when recording a trace file
From: Valentin Schneider
Date: Wed Jul 15 2026 - 11:55:06 EST
IPIs can now be monitored and accounted by osnoise top. When that is
the case, also record them when saving a trace file.
To match what is being recorded by the tool for its own analysis, event
filters are applied to the events recorded to the trace output.
Signed-off-by: Valentin Schneider <vschneid@xxxxxxxxxx>
---
tools/tracing/rtla/src/common.c | 2 +-
tools/tracing/rtla/src/common.h | 2 +-
tools/tracing/rtla/src/osnoise.c | 72 +++++++++++++++++++++++++++-
tools/tracing/rtla/src/osnoise.h | 4 ++
tools/tracing/rtla/src/osnoise_top.c | 36 ++------------
5 files changed, 80 insertions(+), 36 deletions(-)
diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c
index d0a8a6edbf0cb..dd302427557ca 100644
--- a/tools/tracing/rtla/src/common.c
+++ b/tools/tracing/rtla/src/common.c
@@ -204,7 +204,7 @@ int run_tool(struct tool_ops *ops, int argc, char *argv[])
if (params->threshold_actions.present[ACTION_TRACE_OUTPUT] ||
params->end_actions.present[ACTION_TRACE_OUTPUT]) {
- tool->record = osnoise_init_trace_tool(ops->tracer);
+ tool->record = osnoise_init_trace_tool(params, ops->tracer);
if (!tool->record) {
err_msg("Failed to enable the trace instance\n");
goto out_free;
diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h
index 045253230fcf2..421e06e10f3f1 100644
--- a/tools/tracing/rtla/src/common.h
+++ b/tools/tracing/rtla/src/common.h
@@ -178,7 +178,7 @@ int osnoise_set_workload(struct osnoise_context *context, bool onoff);
void osnoise_destroy_tool(struct osnoise_tool *top);
struct osnoise_tool *osnoise_init_tool(char *tool_name);
-struct osnoise_tool *osnoise_init_trace_tool(const char *tracer);
+struct osnoise_tool *osnoise_init_trace_tool(struct common_params *params, const char *tracer);
bool osnoise_trace_is_off(struct osnoise_tool *tool, struct osnoise_tool *record);
int osnoise_set_stop_us(struct osnoise_context *context, long long stop_us);
int osnoise_set_stop_total_us(struct osnoise_context *context,
diff --git a/tools/tracing/rtla/src/osnoise.c b/tools/tracing/rtla/src/osnoise.c
index 4ff5dad013b10..ae6e5f03e828f 100644
--- a/tools/tracing/rtla/src/osnoise.c
+++ b/tools/tracing/rtla/src/osnoise.c
@@ -1178,10 +1178,56 @@ struct osnoise_tool *osnoise_init_tool(char *tool_name)
return top;
}
+/*
+ * osnoise_init_ipi_filters - Initialize event filtering for IPI events
+ */
+int osnoise_init_ipi_filters(struct osnoise_tool *tool,
+ struct common_params *params,
+ bool *filters_enabled)
+{
+ char filter[MAX_PATH];
+ int retval;
+ /*
+ * If tracing on a subset of possible CPUs, leverage the kernel filtering
+ * infrastructure to only generate events on traced CPUs.
+ * Older kernels (pre v6.6) may have the IPI events but not the ability
+ * to filter them, so allow that to fail gracefully.
+ */
+
+ snprintf(filter, ARRAY_SIZE(filter), "cpu & CPUS{%s}\n", params->cpus);
+ retval = tracefs_event_file_write(tool->trace.inst,
+ "ipi", "ipi_send_cpu", "filter",
+ filter);
+ if (retval < 0) {
+ debug_msg("Could not set ipi_send_cpu CPU filter\n");
+ *filters_enabled = false;
+ return 0;
+ }
+
+
+ snprintf(filter, ARRAY_SIZE(filter), "cpumask & CPUS{%s}\n", params->cpus);
+ retval = tracefs_event_file_write(tool->trace.inst,
+ "ipi", "ipi_send_cpumask", "filter",
+ filter);
+ if (retval < 0) {
+ /*
+ * If we managed to set up the previous filter but not
+ * this one, something's really wrong
+ */
+ err_msg("Could not set ipi_send_cpumask CPU filter\n");
+ *filters_enabled = false;
+ return -1;
+ }
+
+ *filters_enabled = true;
+ return 0;
+}
+
/*
* osnoise_init_trace_tool - init a tracer instance to trace osnoise events
*/
-struct osnoise_tool *osnoise_init_trace_tool(const char *tracer)
+struct osnoise_tool *osnoise_init_trace_tool(struct common_params *params,
+ const char *tracer)
{
struct osnoise_tool *trace;
int retval;
@@ -1196,6 +1242,30 @@ struct osnoise_tool *osnoise_init_trace_tool(const char *tracer)
goto out_err;
}
+ if (!params->ipi)
+ goto done;
+
+ retval = tracefs_event_enable(trace->trace.inst, "ipi", "ipi_send_cpu");
+ if (retval < 0 && !errno) {
+ err_msg("Could not find ipi_send_cpu event\n");
+ goto out_err;
+ }
+
+ retval = tracefs_event_enable(trace->trace.inst, "ipi", "ipi_send_cpumask");
+ if (retval < 0 && !errno) {
+ err_msg("Could not find ipi_send_cpumask event\n");
+ goto out_err;
+ }
+
+ if (params->cpus) {
+ bool unused;
+
+ retval = osnoise_init_ipi_filters(trace, params, &unused);
+ if (retval < 0)
+ goto out_err;
+ }
+
+done:
retval = enable_tracer_by_name(trace->trace.inst, tracer);
if (retval) {
err_msg("Could not enable %s tracer for tracing\n", tracer);
diff --git a/tools/tracing/rtla/src/osnoise.h b/tools/tracing/rtla/src/osnoise.h
index 340ff5a64e6e4..81a704c361ec0 100644
--- a/tools/tracing/rtla/src/osnoise.h
+++ b/tools/tracing/rtla/src/osnoise.h
@@ -63,6 +63,10 @@ int osnoise_enable(struct osnoise_tool *tool);
int osnoise_main(int argc, char **argv);
int hwnoise_main(int argc, char **argv);
+int osnoise_init_ipi_filters(struct osnoise_tool *tool,
+ struct common_params *params,
+ bool *filters_enabled);
+
extern struct tool_ops timerlat_top_ops, timerlat_hist_ops;
extern struct tool_ops osnoise_top_ops, osnoise_hist_ops;
diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c
index afab2f341a1e9..87d28865515b5 100644
--- a/tools/tracing/rtla/src/osnoise_top.c
+++ b/tools/tracing/rtla/src/osnoise_top.c
@@ -392,7 +392,7 @@ osnoise_ipi_cpumask_handler(struct trace_seq *s, struct tep_record *record,
*/
struct osnoise_tool *osnoise_init_top(struct common_params *params)
{
- bool ipi_filters_enabled = false;
+ bool ipi_filters_enabled;
struct osnoise_tool *tool;
int retval;
@@ -424,41 +424,11 @@ struct osnoise_tool *osnoise_init_top(struct common_params *params)
goto out_err;
}
- /*
- * If tracing on a subset of possible CPUs, leverage the kernel filtering
- * infrastructure to only generate events on traced CPUs.
- * Older kernels (pre v6.6) may have the IPI events but not the ability
- * to filter them, so allow that to fail gracefully.
- */
if (params->cpus) {
- char filter[MAX_PATH];
-
- snprintf(filter, ARRAY_SIZE(filter), "cpu & CPUS{%s}\n", params->cpus);
- retval = tracefs_event_file_write(tool->trace.inst,
- "ipi", "ipi_send_cpu", "filter",
- filter);
- if (retval < 0) {
- debug_msg("Could not set ipi_send_cpu CPU filter\n");
- goto no_filter;
- }
-
-
- snprintf(filter, ARRAY_SIZE(filter), "cpumask & CPUS{%s}\n", params->cpus);
- retval = tracefs_event_file_write(tool->trace.inst,
- "ipi", "ipi_send_cpumask", "filter",
- filter);
- if (retval < 0) {
- /*
- * If we managed to set up the previous filter but not
- * this one, something's really wrong
- */
- err_msg("Could not set ipi_send_cpumask CPU filter\n");
+ retval = osnoise_init_ipi_filters(tool, params, &ipi_filters_enabled);
+ if (retval < 0)
goto out_err;
- }
-
- ipi_filters_enabled = true;
}
-no_filter:
/*
* If no filtering is available and we're tracing all CPUs, we can still
--
2.55.0