Linux Trace Kernel
 help / color / mirror / Atom feed
* [PATCH v5 0/8] tracing/osnoise: Track IPIs
@ 2026-09-02 12:39 Valentin Schneider
  2026-09-02 12:39 ` [PATCH v5 1/8] rtla/osnoise: Add IPI tracking cmdline option Valentin Schneider
                   ` (7 more replies)
  0 siblings, 8 replies; 12+ messages in thread
From: Valentin Schneider @ 2026-09-02 12:39 UTC (permalink / raw)
  To: linux-kernel, linux-trace-kernel
  Cc: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers, Tomas Glozar,
	Costa Shulyupin, Crystal Wood, John Kacur, Ivan Pravdin,
	Jonathan Corbet

Hi folks,

So I've seen a few times now reports of latency spikes caused by IPIs, usually
because of isolation misconfiguration, but only detected at the tail of end
e.g. a 24h timerlat run.

It's not because those IPIs are rare, but rather that they don't by themselves
cause a monitered CPU to reach the latency threshold, it's usually a combined
interference that gets us there.

I'd like to make it easier to detect such misconfigurations and thus IPIs
hitting supposedly-isolated CPUs. I initially kludged a timerlat option to stop
tracing as soon as an IPI was sent to a monitored CPU, regardless of the latency
threshold. It sort of did the trick, but Tomáš convinced me timerlat wasn't
really the place for that.

Patches are available at

https://gitlab.com/vschneid/linux.git -b mainline/tracing/osnoise-ipi-userspace/v5

Cheers,
Valentin

Revisions
=========

v4 -> v5
++++++++

o Made events processing follow user-specified order

v3 -> v4
++++++++

o Rebase onto v7.2-rc4
o Fix changelog typo

v2 -> v3
++++++++

o Dropped the short-form -i option to leave it free 
o Re-arranged top header printing 
o Fixed tracefs_event_file_write() return value handling

o Changed IPI filtering to allow it to gracefully fail on older kernels
o Added filter clearing for -e events to ensure a known state

v1 -> v2
++++++++

o Dropped the in-kernel osnoise_sample changes and made it all userspace

Valentin Schneider (8):
  rtla/osnoise: Add IPI tracking cmdline option
  rtla/osnoise: Record IPI count in osnoise top
  rtla/osnoise: Leverage IPI event filters when tracing a subset of CPUs
  rtla/osnoise: Allow IPI filters to gracefully fail
  rtla: make struct trace_events double linked
  rtla: Enable and disable events in the user-defined order
  rtla: Unconditionally clean any pre-existing filters for user-provided
    events
  rtla/osnoise: Trace IPI events when recording a trace file

 Documentation/tools/rtla/common_options.txt   |   9 +-
 Documentation/tools/rtla/rtla-osnoise-top.rst |   4 +
 tools/tracing/rtla/src/cli.c                  |   1 +
 tools/tracing/rtla/src/cli_p.h                |   7 +-
 tools/tracing/rtla/src/common.c               |   2 +-
 tools/tracing/rtla/src/common.h               |   3 +-
 tools/tracing/rtla/src/osnoise.c              |  72 +++++++-
 tools/tracing/rtla/src/osnoise.h              |   4 +
 tools/tracing/rtla/src/osnoise_top.c          | 155 +++++++++++++++++-
 tools/tracing/rtla/src/trace.c                |  28 +++-
 tools/tracing/rtla/src/trace.h                |   1 +
 11 files changed, 276 insertions(+), 10 deletions(-)

-- 
2.55.0


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH v5 1/8] rtla/osnoise: Add IPI tracking cmdline option
  2026-09-02 12:39 [PATCH v5 0/8] tracing/osnoise: Track IPIs Valentin Schneider
@ 2026-09-02 12:39 ` Valentin Schneider
  2026-09-02 12:39 ` [PATCH v5 2/8] rtla/osnoise: Record IPI count in osnoise top Valentin Schneider
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Valentin Schneider @ 2026-09-02 12:39 UTC (permalink / raw)
  To: linux-kernel, linux-trace-kernel
  Cc: Tomas Glozar, Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
	Costa Shulyupin, Crystal Wood, John Kacur, Ivan Pravdin,
	Jonathan Corbet

Later commits will add IPI tracking to osnoise top. To avoid breaking
existing scripts, this new feature will be gated behind a new --ipi option.

Suggested-by: Tomas Glozar <tglozar@redhat.com>
Signed-off-by: Valentin Schneider <vschneid@redhat.com>
---
 Documentation/tools/rtla/rtla-osnoise-top.rst | 4 ++++
 tools/tracing/rtla/src/cli.c                  | 1 +
 tools/tracing/rtla/src/cli_p.h                | 3 +++
 tools/tracing/rtla/src/common.h               | 1 +
 4 files changed, 9 insertions(+)

diff --git a/Documentation/tools/rtla/rtla-osnoise-top.rst b/Documentation/tools/rtla/rtla-osnoise-top.rst
index b91c02ac2bbe1..b948a813d45cb 100644
--- a/Documentation/tools/rtla/rtla-osnoise-top.rst
+++ b/Documentation/tools/rtla/rtla-osnoise-top.rst
@@ -28,6 +28,10 @@ OPTIONS
 =======
 .. include:: common_osnoise_options.txt
 
+**--ipi**
+
+	Track sources of IPIs.
+
 .. include:: common_top_options.txt
 
 .. include:: common_options.txt
diff --git a/tools/tracing/rtla/src/cli.c b/tools/tracing/rtla/src/cli.c
index fb8c972c0746b..8c02b94ce4321 100644
--- a/tools/tracing/rtla/src/cli.c
+++ b/tools/tracing/rtla/src/cli.c
@@ -78,6 +78,7 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv)
 		RTLA_OPT_STOP_TOTAL('S', "stop-total", "total sample"),
 		OSNOISE_OPT_THRESHOLD,
 		RTLA_OPT_TRACE_OUTPUT("osnoise", opt_osnoise_trace_output_cb),
+		OSNOISE_OPT_IPI,
 
 	OPT_GROUP("Event Configuration:"),
 		RTLA_OPT_EVENT,
diff --git a/tools/tracing/rtla/src/cli_p.h b/tools/tracing/rtla/src/cli_p.h
index 661240d44ad9a..f2dd7c610093d 100644
--- a/tools/tracing/rtla/src/cli_p.h
+++ b/tools/tracing/rtla/src/cli_p.h
@@ -497,6 +497,9 @@ static int opt_filter_cb(const struct option *opt, const char *arg, int unset)
 #define OSNOISE_OPT_THRESHOLD RTLA_OPT_LLONG('T', "threshold", &params->threshold, "us", \
 	"the minimum delta to be considered a noise")
 
+#define OSNOISE_OPT_IPI OPT_BOOLEAN(0, "ipi", &params->common.ipi, \
+	"track sources of IPIs")
+
 /*
  * Callback functions for command line options for osnoise tools
  */
diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h
index 04b287a03f6d4..045253230fcf2 100644
--- a/tools/tracing/rtla/src/common.h
+++ b/tools/tracing/rtla/src/common.h
@@ -108,6 +108,7 @@ struct common_params {
 	bool			kernel_workload;
 	bool			user_data;
 	bool			aa_only;
+	bool			ipi;
 
 	struct actions		threshold_actions;
 	struct actions		end_actions;
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v5 2/8] rtla/osnoise: Record IPI count in osnoise top
  2026-09-02 12:39 [PATCH v5 0/8] tracing/osnoise: Track IPIs Valentin Schneider
  2026-09-02 12:39 ` [PATCH v5 1/8] rtla/osnoise: Add IPI tracking cmdline option Valentin Schneider
@ 2026-09-02 12:39 ` Valentin Schneider
  2026-09-02 13:01   ` sashiko-bot
  2026-09-02 12:39 ` [PATCH v5 3/8] rtla/osnoise: Leverage IPI event filters when tracing a subset of CPUs Valentin Schneider
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 12+ messages in thread
From: Valentin Schneider @ 2026-09-02 12:39 UTC (permalink / raw)
  To: linux-kernel, linux-trace-kernel
  Cc: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers, Tomas Glozar,
	Costa Shulyupin, Crystal Wood, John Kacur, Ivan Pravdin,
	Jonathan Corbet

Leverage the ipi_send_cpu and ipi_send_cpumask trace events to record the
count of IPIs sent to monitored CPUs. These interferences are already
accounted by the IRQ count, but this split gives a better overall picture.

This uses the newly added --ipi cmdline option.

Signed-off-by: Valentin Schneider <vschneid@redhat.com>
---
 tools/tracing/rtla/src/osnoise_top.c | 116 ++++++++++++++++++++++++++-
 1 file changed, 115 insertions(+), 1 deletion(-)

diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c
index 512a6299cb018..7b5ae5336cf08 100644
--- a/tools/tracing/rtla/src/osnoise_top.c
+++ b/tools/tracing/rtla/src/osnoise_top.c
@@ -8,6 +8,7 @@
 #include <string.h>
 #include <signal.h>
 #include <unistd.h>
+#include <errno.h>
 #include <stdio.h>
 #include <time.h>
 
@@ -25,6 +26,7 @@ struct osnoise_top_cpu {
 	unsigned long long	irq_count;
 	unsigned long long	softirq_count;
 	unsigned long long	thread_count;
+	unsigned long long	ipi_count;
 
 	int			sum_cycles;
 };
@@ -164,6 +166,8 @@ static void osnoise_top_header(struct osnoise_tool *top)
 		goto eol;
 
 	trace_seq_printf(s, "          IRQ      Softirq       Thread");
+	if (params->common.ipi)
+		trace_seq_printf(s, "          IPI");
 
 eol:
 	if (pretty)
@@ -218,7 +222,10 @@ static void osnoise_top_print(struct osnoise_tool *tool, int cpu)
 
 	trace_seq_printf(s, "%12llu ", cpu_data->irq_count);
 	trace_seq_printf(s, "%12llu ", cpu_data->softirq_count);
-	trace_seq_printf(s, "%12llu\n", cpu_data->thread_count);
+	trace_seq_printf(s, "%12llu", cpu_data->thread_count);
+	if (params->common.ipi)
+		trace_seq_printf(s, " %12llu", cpu_data->ipi_count);
+	trace_seq_printf(s, "\n");
 }
 
 /*
@@ -275,12 +282,93 @@ osnoise_top_apply_config(struct osnoise_tool *tool)
 	return -1;
 }
 
+static void account_ipi(struct osnoise_tool *tool, unsigned long long dst_cpu)
+{
+	struct osnoise_top_cpu *cpu_data;
+	struct osnoise_top_data *data;
+	unsigned long long inc = 1;
+
+	data = tool->data;
+	cpu_data = &data->cpu_data[dst_cpu];
+
+	update_sum(&cpu_data->ipi_count, &inc);
+}
+
+/*
+ * osnoise_ipi_cpu_handler - this is the handler for single CPU IPI events.
+ */
+static int
+osnoise_ipi_cpu_handler(struct trace_seq *s, struct tep_record *record,
+		     struct tep_event *event, void *context)
+{
+	struct osnoise_tool *tool;
+	struct osnoise_params *params;
+	unsigned long long dst_cpu;
+	struct trace_instance *trace = context;
+
+	tool = container_of(trace, struct osnoise_tool, trace);
+	params = to_osnoise_params(tool->params);
+
+	tep_get_field_val(s, event, "cpu", record, &dst_cpu, 1);
+
+	if (CPU_ISSET(dst_cpu, &params->common.monitored_cpus))
+		account_ipi(tool, dst_cpu);
+
+	return 0;
+}
+
+static cpu_set_t cpumask_tmp_cpus;
+
+/*
+ * osnoise_ipi_cpumask_handler - this is the handler for broadcasted IPI events.
+ */
+static int
+osnoise_ipi_cpumask_handler(struct trace_seq *s, struct tep_record *record,
+			 struct tep_event *event, void *context)
+{
+	struct trace_instance *trace = context;
+	struct osnoise_tool *tool;
+	struct osnoise_params *params;
+	struct tep_format_field *field;
+	cpu_set_t *event_cpus;
+	int len;
+
+	tool = container_of(trace, struct osnoise_tool, trace);
+	params = to_osnoise_params(tool->params);
+
+	field = tep_find_field(event, "cpumask");
+	if (!field)
+		return 0;
+
+	event_cpus = tep_get_field_raw(s, event, "cpumask", record, &len, 1);
+	if (!event_cpus) {
+		err_msg("Failed to get cpumask field\n");
+		return 0;
+	}
+
+	CPU_AND(&cpumask_tmp_cpus, event_cpus, &params->common.monitored_cpus);
+
+	/*
+	 * Computing the mask weight is overkill but there is no leaner option
+	 * provided by glibc, e.g cpumask_first() or somesuch.
+	 */
+	if (CPU_COUNT(&cpumask_tmp_cpus)) {
+		for (int cpu = 0; cpu < nr_cpus; cpu++) {
+			if (CPU_ISSET(cpu, &cpumask_tmp_cpus))
+				account_ipi(tool, cpu);
+		}
+	}
+
+	return 0;
+}
+
 /*
  * osnoise_init_top - initialize a osnoise top tool with parameters
  */
 struct osnoise_tool *osnoise_init_top(struct common_params *params)
 {
 	struct osnoise_tool *tool;
+	int retval;
 
 	tool = osnoise_init_tool("osnoise_top");
 	if (!tool)
@@ -295,7 +383,33 @@ struct osnoise_tool *osnoise_init_top(struct common_params *params)
 	tep_register_event_handler(tool->trace.tep, -1, "ftrace", "osnoise",
 				   osnoise_top_handler, NULL);
 
+	if (!params->ipi)
+		goto out;
+
+	retval = tracefs_event_enable(tool->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(tool->trace.inst, "ipi", "ipi_send_cpumask");
+	if (retval < 0 && !errno) {
+		err_msg("Could not find ipi_send_cpumask event\n");
+		goto out_err;
+	}
+
+	tep_register_event_handler(tool->trace.tep, -1, "ipi", "ipi_send_cpu",
+				   osnoise_ipi_cpu_handler, NULL);
+
+	tep_register_event_handler(tool->trace.tep, -1, "ipi", "ipi_send_cpumask",
+				   osnoise_ipi_cpumask_handler, NULL);
+
+out:
 	return tool;
+out_err:
+	osnoise_free_top_tool(tool);
+	osnoise_destroy_tool(tool);
+	return NULL;
 }
 
 struct tool_ops osnoise_top_ops = {
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v5 3/8] rtla/osnoise: Leverage IPI event filters when tracing a subset of CPUs
  2026-09-02 12:39 [PATCH v5 0/8] tracing/osnoise: Track IPIs Valentin Schneider
  2026-09-02 12:39 ` [PATCH v5 1/8] rtla/osnoise: Add IPI tracking cmdline option Valentin Schneider
  2026-09-02 12:39 ` [PATCH v5 2/8] rtla/osnoise: Record IPI count in osnoise top Valentin Schneider
@ 2026-09-02 12:39 ` Valentin Schneider
  2026-09-02 12:39 ` [PATCH v5 4/8] rtla/osnoise: Allow IPI filters to gracefully fail Valentin Schneider
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Valentin Schneider @ 2026-09-02 12:39 UTC (permalink / raw)
  To: linux-kernel, linux-trace-kernel
  Cc: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers, Tomas Glozar,
	Costa Shulyupin, Crystal Wood, John Kacur, Ivan Pravdin,
	Jonathan Corbet

Leverage the kernel event filtering infrastructure to only emit IPI events
if they target CPUs that are being traced, as specified by the -c cmdline
option.

Note that some post-processing is still required for the ipi_send_cpumask
event, as the event being emitted means *some* CPUs targeted by that event
are monitored, but not all of them - userspace has to recompute that
intersection.

Signed-off-by: Valentin Schneider <vschneid@redhat.com>
---
 tools/tracing/rtla/src/osnoise_top.c | 38 ++++++++++++++++++++++++----
 1 file changed, 33 insertions(+), 5 deletions(-)

diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c
index 7b5ae5336cf08..353b435fefcf8 100644
--- a/tools/tracing/rtla/src/osnoise_top.c
+++ b/tools/tracing/rtla/src/osnoise_top.c
@@ -302,17 +302,13 @@ osnoise_ipi_cpu_handler(struct trace_seq *s, struct tep_record *record,
 		     struct tep_event *event, void *context)
 {
 	struct osnoise_tool *tool;
-	struct osnoise_params *params;
 	unsigned long long dst_cpu;
 	struct trace_instance *trace = context;
 
 	tool = container_of(trace, struct osnoise_tool, trace);
-	params = to_osnoise_params(tool->params);
-
 	tep_get_field_val(s, event, "cpu", record, &dst_cpu, 1);
 
-	if (CPU_ISSET(dst_cpu, &params->common.monitored_cpus))
-		account_ipi(tool, dst_cpu);
+	account_ipi(tool, dst_cpu);
 
 	return 0;
 }
@@ -346,6 +342,11 @@ osnoise_ipi_cpumask_handler(struct trace_seq *s, struct tep_record *record,
 		return 0;
 	}
 
+	/*
+	 * Despite already filtering for such an intersection, we need to compute
+	 * the intersection here as the @cpumask field may contain non-monitored
+	 * CPUs.
+	 */
 	CPU_AND(&cpumask_tmp_cpus, event_cpus, &params->common.monitored_cpus);
 
 	/*
@@ -398,6 +399,33 @@ 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.
+	 */
+	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) {
+			err_msg("Could not set ipi_send_cpu CPU filter\n");
+			goto out_err;
+		}
+
+
+		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) {
+			err_msg("Could not set ipi_send_cpumask CPU filter\n");
+			goto out_err;
+		}
+	}
+
 	tep_register_event_handler(tool->trace.tep, -1, "ipi", "ipi_send_cpu",
 				   osnoise_ipi_cpu_handler, NULL);
 
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v5 4/8] rtla/osnoise: Allow IPI filters to gracefully fail
  2026-09-02 12:39 [PATCH v5 0/8] tracing/osnoise: Track IPIs Valentin Schneider
                   ` (2 preceding siblings ...)
  2026-09-02 12:39 ` [PATCH v5 3/8] rtla/osnoise: Leverage IPI event filters when tracing a subset of CPUs Valentin Schneider
@ 2026-09-02 12:39 ` Valentin Schneider
  2026-09-02 12:39 ` [PATCH v5 5/8] rtla: make struct trace_events double linked Valentin Schneider
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Valentin Schneider @ 2026-09-02 12:39 UTC (permalink / raw)
  To: linux-kernel, linux-trace-kernel
  Cc: Tomas Glozar, Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
	Costa Shulyupin, Crystal Wood, John Kacur, Ivan Pravdin,
	Jonathan Corbet

Kernels pre v6.6 won't have:

  39f7c41c908b ("tracing/filters: Enable filtering a cpumask field by another cpumask")

and thus won't be able to filter events using a user-provided cpumask, but
will still be capable of recording IPI events.

Make failing to set a filter for IPI events an acceptable error and fall
back to event handlers that do the filtering job themselves.

Suggested-by: Tomas Glozar <tglozar@redhat.com>
Signed-off-by: Valentin Schneider <vschneid@redhat.com>
---
 tools/tracing/rtla/src/osnoise_top.c | 49 +++++++++++++++++++++++++---
 1 file changed, 45 insertions(+), 4 deletions(-)

diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c
index 353b435fefcf8..afab2f341a1e9 100644
--- a/tools/tracing/rtla/src/osnoise_top.c
+++ b/tools/tracing/rtla/src/osnoise_top.c
@@ -313,6 +313,30 @@ osnoise_ipi_cpu_handler(struct trace_seq *s, struct tep_record *record,
 	return 0;
 }
 
+/*
+ * osnoise_ipi_cpu_unfiltered_handler - this is the handler for single CPU IPI
+ *                                      events. Slightly less optimized than
+ *                                      the filtered variant.
+ */
+static int
+osnoise_ipi_cpu_unfiltered_handler(struct trace_seq *s, struct tep_record *record,
+		     struct tep_event *event, void *context)
+{
+	struct osnoise_tool *tool;
+	unsigned long long dst_cpu;
+	struct osnoise_params *params;
+	struct trace_instance *trace = context;
+
+	tool = container_of(trace, struct osnoise_tool, trace);
+	params = to_osnoise_params(tool->params);
+	tep_get_field_val(s, event, "cpu", record, &dst_cpu, 1);
+
+	if (CPU_ISSET(dst_cpu, &params->common.monitored_cpus))
+		account_ipi(tool, dst_cpu);
+
+	return 0;
+}
+
 static cpu_set_t cpumask_tmp_cpus;
 
 /*
@@ -343,7 +367,7 @@ osnoise_ipi_cpumask_handler(struct trace_seq *s, struct tep_record *record,
 	}
 
 	/*
-	 * Despite already filtering for such an intersection, we need to compute
+	 * Even if already filtering for such an intersection, we need to compute
 	 * the intersection here as the @cpumask field may contain non-monitored
 	 * CPUs.
 	 */
@@ -368,6 +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;
 	struct osnoise_tool *tool;
 	int retval;
 
@@ -402,6 +427,8 @@ struct osnoise_tool *osnoise_init_top(struct common_params *params)
 	/*
 	 * 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];
@@ -411,8 +438,8 @@ struct osnoise_tool *osnoise_init_top(struct common_params *params)
 						  "ipi", "ipi_send_cpu", "filter",
 						  filter);
 		if (retval < 0) {
-			err_msg("Could not set ipi_send_cpu CPU filter\n");
-			goto out_err;
+			debug_msg("Could not set ipi_send_cpu CPU filter\n");
+			goto no_filter;
 		}
 
 
@@ -421,13 +448,27 @@ struct osnoise_tool *osnoise_init_top(struct common_params *params)
 						  "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");
 			goto out_err;
 		}
+
+		ipi_filters_enabled = true;
 	}
+no_filter:
 
+	/*
+	 * If no filtering is available and we're tracing all CPUs, we can still
+	 * use the filtered callback since stats are collected for all CPUs.
+	 */
 	tep_register_event_handler(tool->trace.tep, -1, "ipi", "ipi_send_cpu",
-				   osnoise_ipi_cpu_handler, NULL);
+				   (!params->cpus || ipi_filters_enabled) ?
+				   osnoise_ipi_cpu_handler :
+				   osnoise_ipi_cpu_unfiltered_handler,
+				   NULL);
 
 	tep_register_event_handler(tool->trace.tep, -1, "ipi", "ipi_send_cpumask",
 				   osnoise_ipi_cpumask_handler, NULL);
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v5 5/8] rtla: make struct trace_events double linked
  2026-09-02 12:39 [PATCH v5 0/8] tracing/osnoise: Track IPIs Valentin Schneider
                   ` (3 preceding siblings ...)
  2026-09-02 12:39 ` [PATCH v5 4/8] rtla/osnoise: Allow IPI filters to gracefully fail Valentin Schneider
@ 2026-09-02 12:39 ` Valentin Schneider
  2026-09-02 12:39 ` [PATCH v5 6/8] rtla: Enable and disable events in the user-defined order Valentin Schneider
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 12+ messages in thread
From: Valentin Schneider @ 2026-09-02 12:39 UTC (permalink / raw)
  To: linux-kernel, linux-trace-kernel
  Cc: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers, Tomas Glozar,
	Costa Shulyupin, Crystal Wood, John Kacur, Ivan Pravdin,
	Jonathan Corbet

The events list is currently a single linked list. New events are prepended
to the list, making them the new head.

This makes it easy to fetch the last-defined event when handling trigger
and filter options on the cmdline, as they apply to the last-defined event,
but means the events are then processed in LIFO order with regards to the
command line order.

To prepare for processing the events in the user-defined order, make the
events list double linked.

Signed-off-by: Valentin Schneider <vschneid@redhat.com>
---
 tools/tracing/rtla/src/cli_p.h | 4 +++-
 tools/tracing/rtla/src/trace.h | 1 +
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/tools/tracing/rtla/src/cli_p.h b/tools/tracing/rtla/src/cli_p.h
index f2dd7c610093d..7e3a713f97c62 100644
--- a/tools/tracing/rtla/src/cli_p.h
+++ b/tools/tracing/rtla/src/cli_p.h
@@ -394,8 +394,10 @@ static int opt_event_cb(const struct option *opt, const char *arg, int unset)
 	if (!tevent)
 		fatal("Error alloc trace event");
 
-	if (*events)
+	if (*events) {
 		tevent->next = *events;
+		(*events)->prev = tevent;
+	}
 	*events = tevent;
 
 	return 0;
diff --git a/tools/tracing/rtla/src/trace.h b/tools/tracing/rtla/src/trace.h
index 95b911a2228b2..eacafc0c96b31 100644
--- a/tools/tracing/rtla/src/trace.h
+++ b/tools/tracing/rtla/src/trace.h
@@ -4,6 +4,7 @@
 
 struct trace_events {
 	struct trace_events *next;
+	struct trace_events *prev;
 	char *system;
 	char *event;
 	char *filter;
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v5 6/8] rtla: Enable and disable events in the user-defined order
  2026-09-02 12:39 [PATCH v5 0/8] tracing/osnoise: Track IPIs Valentin Schneider
                   ` (4 preceding siblings ...)
  2026-09-02 12:39 ` [PATCH v5 5/8] rtla: make struct trace_events double linked Valentin Schneider
@ 2026-09-02 12:39 ` Valentin Schneider
  2026-09-02 12:39 ` [PATCH v5 7/8] rtla: Unconditionally clean any pre-existing filters for user-provided events Valentin Schneider
  2026-09-02 12:39 ` [PATCH v5 8/8] rtla/osnoise: Trace IPI events when recording a trace file Valentin Schneider
  7 siblings, 0 replies; 12+ messages in thread
From: Valentin Schneider @ 2026-09-02 12:39 UTC (permalink / raw)
  To: linux-kernel, linux-trace-kernel
  Cc: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers, Tomas Glozar,
	Costa Shulyupin, Crystal Wood, John Kacur, Ivan Pravdin,
	Jonathan Corbet

Events are processed in LIFO order for ease of internal processing, but
this is can be confusing to users if the processing ordering is exposed to
them.

A following commit will do just that by making it so the last-defined event
options (filters/triggers) overrides any previous options for that same
event. Thus, process the events in the user-defined order.

Signed-off-by: Valentin Schneider <vschneid@redhat.com>
---
 tools/tracing/rtla/src/trace.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c
index e407447773d04..17d148f7d5d6e 100644
--- a/tools/tracing/rtla/src/trace.c
+++ b/tools/tracing/rtla/src/trace.c
@@ -440,6 +440,21 @@ static void trace_event_disable_trigger(struct trace_instance *instance,
 			tevent->event ? : "*", tevent->trigger);
 }
 
+static inline struct trace_events *trace_events_tail(struct trace_events *tevent)
+{
+	while (tevent && tevent->next)
+		tevent = tevent->next;
+
+	return tevent;
+}
+
+/*
+ * Events are stashed in LIFO order; flip that to FIFO to process them in the
+ * same order as they are defined by the user on the command line.
+ */
+#define for_each_trace_event(tevent) \
+	for (tevent = trace_events_tail(tevent); tevent; tevent = tevent->prev)
+
 /*
  * trace_events_disable - disable all trace events
  */
@@ -451,7 +466,7 @@ void trace_events_disable(struct trace_instance *instance,
 	if (!events)
 		return;
 
-	while (tevent) {
+	for_each_trace_event(tevent) {
 		debug_msg("Disabling event %s:%s\n", tevent->system, tevent->event ? : "*");
 		if (tevent->enabled) {
 			trace_event_disable_filter(instance, tevent);
@@ -460,7 +475,6 @@ void trace_events_disable(struct trace_instance *instance,
 		}
 
 		tevent->enabled = 0;
-		tevent = tevent->next;
 	}
 }
 
@@ -544,7 +558,10 @@ int trace_events_enable(struct trace_instance *instance,
 	struct trace_events *tevent = events;
 	int retval;
 
-	while (tevent) {
+	if (!events)
+		return 0;
+
+	for_each_trace_event(tevent) {
 		debug_msg("Enabling event %s:%s\n", tevent->system, tevent->event ? : "*");
 		retval = tracefs_event_enable(instance->inst, tevent->system, tevent->event);
 		if (retval < 0) {
@@ -562,7 +579,6 @@ int trace_events_enable(struct trace_instance *instance,
 			return 1;
 
 		tevent->enabled = 1;
-		tevent = tevent->next;
 	}
 
 	return 0;
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v5 7/8] rtla: Unconditionally clean any pre-existing filters for user-provided events
  2026-09-02 12:39 [PATCH v5 0/8] tracing/osnoise: Track IPIs Valentin Schneider
                   ` (5 preceding siblings ...)
  2026-09-02 12:39 ` [PATCH v5 6/8] rtla: Enable and disable events in the user-defined order Valentin Schneider
@ 2026-09-02 12:39 ` Valentin Schneider
  2026-09-02 13:44   ` sashiko-bot
  2026-09-02 12:39 ` [PATCH v5 8/8] rtla/osnoise: Trace IPI events when recording a trace file Valentin Schneider
  7 siblings, 1 reply; 12+ messages in thread
From: Valentin Schneider @ 2026-09-02 12:39 UTC (permalink / raw)
  To: linux-kernel, linux-trace-kernel
  Cc: Tomas Glozar, Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers,
	Costa Shulyupin, Crystal Wood, John Kacur, Ivan Pravdin,
	Jonathan Corbet

A later commit will apply a filter to events recorded to the trace
output. To prevent any user confusion, remove pre-existing filters when
enabling an event provided via the '-e' command line argument.

Suggested-by: Tomas Glozar <tglozar@redhat.com>
Signed-off-by: Valentin Schneider <vschneid@redhat.com>
---
 Documentation/tools/rtla/common_options.txt | 9 ++++++++-
 tools/tracing/rtla/src/trace.c              | 4 ++++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/Documentation/tools/rtla/common_options.txt b/Documentation/tools/rtla/common_options.txt
index 38da1cf443a48..6bf0f86393333 100644
--- a/Documentation/tools/rtla/common_options.txt
+++ b/Documentation/tools/rtla/common_options.txt
@@ -26,12 +26,19 @@
 
 **--filter** *<filter>*
 
-        Filter the previous **-e** *sys:event* event with *<filter>*. For further information about event filtering see https://www.kernel.org/doc/html/latest/trace/events.html#event-filtering.
+        Filter the previous **-e** *sys:event* event with *<filter>*.
+
+        If the same event is specified more than once but with different filters, the last specified filter will be the only one applied.
+
+	For further information about event filtering see https://www.kernel.org/doc/html/latest/trace/events.html#event-filtering.
 
         This option cannot be unset.
 
 **--trigger** *<trigger>*
         Enable a trace event trigger to the previous **-e** *sys:event*.
+
+        If the same event is specified more than once but with different triggers, the last specified trigger will be the only one applied.
+
         If the *hist:* trigger is activated, the output histogram will be automatically saved to a file named *system_event_hist.txt*.
         For example, the command:
 
diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c
index 17d148f7d5d6e..06204d339f967 100644
--- a/tools/tracing/rtla/src/trace.c
+++ b/tools/tracing/rtla/src/trace.c
@@ -487,6 +487,10 @@ static int trace_event_enable_filter(struct trace_instance *instance,
 	char filter[MAX_PATH];
 	int retval;
 
+	/* Unconditionally clean any pre-existing filters */
+	tracefs_event_file_write(instance->inst, tevent->system,
+				 tevent->event, "filter", "0");
+
 	if (!tevent->filter)
 		return 0;
 
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH v5 8/8] rtla/osnoise: Trace IPI events when recording a trace file
  2026-09-02 12:39 [PATCH v5 0/8] tracing/osnoise: Track IPIs Valentin Schneider
                   ` (6 preceding siblings ...)
  2026-09-02 12:39 ` [PATCH v5 7/8] rtla: Unconditionally clean any pre-existing filters for user-provided events Valentin Schneider
@ 2026-09-02 12:39 ` Valentin Schneider
  2026-09-02 13:55   ` sashiko-bot
  7 siblings, 1 reply; 12+ messages in thread
From: Valentin Schneider @ 2026-09-02 12:39 UTC (permalink / raw)
  To: linux-kernel, linux-trace-kernel
  Cc: Steven Rostedt, Masami Hiramatsu, Mathieu Desnoyers, Tomas Glozar,
	Costa Shulyupin, Crystal Wood, John Kacur, Ivan Pravdin,
	Jonathan Corbet

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@redhat.com>
---
 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 8c7f5e75b2ec8..2f6cf83475550 100644
--- a/tools/tracing/rtla/src/common.c
+++ b/tools/tracing/rtla/src/common.c
@@ -205,7 +205,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


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH v5 2/8] rtla/osnoise: Record IPI count in osnoise top
  2026-09-02 12:39 ` [PATCH v5 2/8] rtla/osnoise: Record IPI count in osnoise top Valentin Schneider
@ 2026-09-02 13:01   ` sashiko-bot
  0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-09-02 13:01 UTC (permalink / raw)
  To: Valentin Schneider; +Cc: linux-trace-kernel

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] Out-of-bounds read and potential unaligned access when parsing the dynamically sized cpumask trace field with CPU_AND.
- [Medium] Missing return value check for tep_get_field_val() leaves dst_cpu uninitialized, leading to out-of-bounds memory accesses.
--

commit ff03318823c0d1c72fb9d5969112afecabf91462
Author: Valentin Schneider <vschneid@redhat.com>

rtla/osnoise: Record IPI count in osnoise top

This commit leverages the ipi_send_cpu and ipi_send_cpumask trace events to
record the count of IPIs sent to monitored CPUs. It adds these statistics to
the osnoise top output, enabled via the new --ipi command line option.

> diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c
> index 512a6299cb018..7b5ae5336cf08 100644
> --- a/tools/tracing/rtla/src/osnoise_top.c
> +++ b/tools/tracing/rtla/src/osnoise_top.c

[ ... ]

> @@ -275,12 +282,93 @@ osnoise_top_apply_config(struct osnoise_tool *tool)
>  	return -1;
>  }
>  
> +static void account_ipi(struct osnoise_tool *tool, unsigned long long dst_cpu)
> +{
> +	struct osnoise_top_cpu *cpu_data;
> +	struct osnoise_top_data *data;
> +	unsigned long long inc = 1;
> +
> +	data = tool->data;
> +	cpu_data = &data->cpu_data[dst_cpu];
> +
> +	update_sum(&cpu_data->ipi_count, &inc);
> +}
> +
> +/*
> + * osnoise_ipi_cpu_handler - this is the handler for single CPU IPI events.
> + */
> +static int
> +osnoise_ipi_cpu_handler(struct trace_seq *s, struct tep_record *record,
> +		     struct tep_event *event, void *context)
> +{
> +	struct osnoise_tool *tool;
> +	struct osnoise_params *params;
> +	unsigned long long dst_cpu;
> +	struct trace_instance *trace = context;
> +
> +	tool = container_of(trace, struct osnoise_tool, trace);
> +	params = to_osnoise_params(tool->params);
> +
> +	tep_get_field_val(s, event, "cpu", record, &dst_cpu, 1);
> +
> +	if (CPU_ISSET(dst_cpu, &params->common.monitored_cpus))
> +		account_ipi(tool, dst_cpu);

[Severity: Medium]
If tep_get_field_val() fails to extract the field (for instance, due to a
trace format mismatch), the return value is ignored and dst_cpu is left
uninitialized.

Could this result in an out-of-bounds read inside the CPU_ISSET() macro, or
an out-of-bounds heap write when dst_cpu is passed to account_ipi() and used
as an index for data->cpu_data[dst_cpu]?

> +
> +	return 0;
> +}
> +
> +static cpu_set_t cpumask_tmp_cpus;
> +
> +/*
> + * osnoise_ipi_cpumask_handler - this is the handler for broadcasted IPI events.
> + */
> +static int
> +osnoise_ipi_cpumask_handler(struct trace_seq *s, struct tep_record *record,
> +			 struct tep_event *event, void *context)
> +{
> +	struct trace_instance *trace = context;
> +	struct osnoise_tool *tool;
> +	struct osnoise_params *params;
> +	struct tep_format_field *field;
> +	cpu_set_t *event_cpus;
> +	int len;
> +
> +	tool = container_of(trace, struct osnoise_tool, trace);
> +	params = to_osnoise_params(tool->params);
> +
> +	field = tep_find_field(event, "cpumask");
> +	if (!field)
> +		return 0;
> +
> +	event_cpus = tep_get_field_raw(s, event, "cpumask", record, &len, 1);
> +	if (!event_cpus) {
> +		err_msg("Failed to get cpumask field\n");
> +		return 0;
> +	}
> +
> +	CPU_AND(&cpumask_tmp_cpus, event_cpus, &params->common.monitored_cpus);

[Severity: Medium]
The event_cpus pointer returned by tep_get_field_raw() points to dynamically
sized raw bytes according to the len parameter. The glibc CPU_AND() macro
assumes both source arguments are full cpu_set_t objects and unconditionally
operates on 128 bytes.

Does this cause an out-of-bounds read and potential unaligned access when
parsing the trace field with CPU_AND()?

> +
> +	/*
> +	 * Computing the mask weight is overkill but there is no leaner option
> +	 * provided by glibc, e.g cpumask_first() or somesuch.
> +	 */
> +	if (CPU_COUNT(&cpumask_tmp_cpus)) {
> +		for (int cpu = 0; cpu < nr_cpus; cpu++) {
> +			if (CPU_ISSET(cpu, &cpumask_tmp_cpus))
> +				account_ipi(tool, cpu);
> +		}
> +	}
> +
> +	return 0;
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260902123942.695822-1-vschneid@redhat.com?part=2

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v5 7/8] rtla: Unconditionally clean any pre-existing filters for user-provided events
  2026-09-02 12:39 ` [PATCH v5 7/8] rtla: Unconditionally clean any pre-existing filters for user-provided events Valentin Schneider
@ 2026-09-02 13:44   ` sashiko-bot
  0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-09-02 13:44 UTC (permalink / raw)
  To: Valentin Schneider; +Cc: linux-trace-kernel

Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [Medium] Logic error in command-line trigger processing causing triggers to accumulate instead of overriding.
- [Medium] Unconditionally clearing filters during event processing destroys previously configured specific event filters when a subsystem is enabled.
- [Medium] Out-of-bounds read in osnoise_ipi_cpumask_handler due to using glibc CPU_AND on a dynamically sized trace event field.
- [Medium] Missing bounds check on `dst_cpu` parsed from trace record leads to an out-of-bounds array write.
--

commit 5cb00dbb92aa356c89071b1755fbef9a7743360f
Author: Valentin Schneider <vschneid@redhat.com>

rtla: Unconditionally clean any pre-existing filters for user-provided events

This commit unconditionally cleans up pre-existing filters when enabling an
event provided via the '-e' command line argument to prevent confusion. It
also documents that when the same event is specified multiple times, only
the last specified filter or trigger applies.

> diff --git a/Documentation/tools/rtla/common_options.txt b/Documentation/tools/rtla/common_options.txt
> index 38da1cf443a48..6bf0f86393333 100644
> --- a/Documentation/tools/rtla/common_options.txt
> +++ b/Documentation/tools/rtla/common_options.txt
> @@ -26,12 +26,19 @@
>  
>  **--filter** *<filter>*
>  
> -        Filter the previous **-e** *sys:event* event with *<filter>*. For further information about event filtering see https://www.kernel.org/doc/html/latest/trace/events.html#event-filtering.
> +        Filter the previous **-e** *sys:event* event with *<filter>*.
> +
> +        If the same event is specified more than once but with different filters, the last specified filter will be the only one applied.
> +
> +	For further information about event filtering see https://www.kernel.org/doc/html/latest/trace/events.html#event-filtering.
>  
>          This option cannot be unset.
>  
>  **--trigger** *<trigger>*
>          Enable a trace event trigger to the previous **-e** *sys:event*.
> +
> +        If the same event is specified more than once but with different triggers, the last specified trigger will be the only one applied.
> +

[Severity: Medium]
Does the command-line trigger processing actually implement this override
behavior?

Looking at trace_event_enable_trigger() in tools/tracing/rtla/src/trace.c,
the new trigger is written without clearing prior triggers for the same
event:

	retval = tracefs_event_file_write(instance->inst, tevent->system,
					  tevent->event, "trigger", trigger);

Since tracefs 'trigger' files are cumulative by default, could this cause
triggers to accumulate instead of replacing the previous one?

>          If the *hist:* trigger is activated, the output histogram will be automatically saved to a file named *system_event_hist.txt*.
>          For example, the command:
>  
> diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c
> index 17d148f7d5d6e..06204d339f967 100644
> --- a/tools/tracing/rtla/src/trace.c
> +++ b/tools/tracing/rtla/src/trace.c
> @@ -487,6 +487,10 @@ static int trace_event_enable_filter(struct trace_instance *instance,
>  	char filter[MAX_PATH];
>  	int retval;
>  
> +	/* Unconditionally clean any pre-existing filters */
> +	tracefs_event_file_write(instance->inst, tevent->system,
> +				 tevent->event, "filter", "0");
> +

[Severity: Medium]
Will this destroy previously configured specific event filters when a broader
subsystem is enabled?

If tevent->event is NULL (e.g., when enabling an entire subsystem like
'-e sched'), unconditionally writing '0' to the subsystem's filter file
might wipe out all specific event filters previously configured within
that subsystem.

>  	if (!tevent->filter)
>  		return 0;
>  

While reviewing this series, I also noticed a couple of issues introduced
in osnoise_top.c:

[Severity: Medium]
Does osnoise_ipi_cpumask_handler() have an out-of-bounds read when parsing
the cpumask field?

When processing a broadcast IPI trace event, the dynamically sized 'cpumask'
field is extracted into event_cpus:

tools/tracing/rtla/src/osnoise_top.c:osnoise_ipi_cpumask_handler() {
    ...
    event_cpus = tep_get_field_raw(s, event, "cpumask", record, &len, 1);
    ...
    CPU_AND(&cpumask_tmp_cpus, event_cpus, &params->common.monitored_cpus);
    ...
}

Since glibc's CPU_AND() unconditionally reads 128 bytes (sizeof(cpu_set_t))
from event_cpus, and the raw buffer size is only 'len' bytes, could this
read past the end of the buffer?


[Severity: Medium]
Is there a missing bounds check on dst_cpu in osnoise_ipi_cpu_handler()
that could lead to an out-of-bounds write?

The 'cpu' field is parsed from the trace record directly into dst_cpu and
used as an array index:

tools/tracing/rtla/src/osnoise_top.c:osnoise_ipi_cpu_handler() {
    ...
    tep_get_field_val(s, event, "cpu", record, &dst_cpu, 1);
    account_ipi(tool, dst_cpu);
    ...
}

tools/tracing/rtla/src/osnoise_top.c:account_ipi() {
    ...
    cpu_data = &data->cpu_data[dst_cpu];
    update_sum(&cpu_data->ipi_count, &inc);
    ...
}

If the trace record contains an unexpectedly high CPU ID (e.g., due to hotplug
or trace buffer corruption), could this write beyond the bounds of the
data->cpu_data array since there's no verification that dst_cpu < nr_cpus?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260902123942.695822-1-vschneid@redhat.com?part=7

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH v5 8/8] rtla/osnoise: Trace IPI events when recording a trace file
  2026-09-02 12:39 ` [PATCH v5 8/8] rtla/osnoise: Trace IPI events when recording a trace file Valentin Schneider
@ 2026-09-02 13:55   ` sashiko-bot
  0 siblings, 0 replies; 12+ messages in thread
From: sashiko-bot @ 2026-09-02 13:55 UTC (permalink / raw)
  To: Valentin Schneider; +Cc: linux-trace-kernel

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Medium] Out-of-bounds read in osnoise_ipi_cpumask_handler due to using CPU_AND on a dynamically sized trace event field.
--

commit 25aed6d1003b38e3162e406562eb91e3fee93066
Author: Valentin Schneider <vschneid@redhat.com>

rtla/osnoise: Trace IPI events when recording a trace file

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.

> 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;

[Severity: Medium]
Can this lead to an out-of-bounds read when processing the IPI cpumask?

Looking at osnoise_ipi_cpumask_handler() above, it processes the
ipi_send_cpumask trace event:

tools/tracing/rtla/src/osnoise_top.c:osnoise_ipi_cpumask_handler() {
    ...
    cpumask = tep_get_field_raw(s, event, "cpumask", record, &len, 1);
    ...
    event_cpus = (cpu_set_t *)cpumask;
    ...
    CPU_AND(&cpumask_tmp_cpus, event_cpus, &params->common.monitored_cpus);
    ...
}

tep_get_field_raw() returns a pointer to a dynamically sized field and its
actual length in len.

Since the code ignores len and casts the pointer to a cpu_set_t *, and
glibc's CPU_AND() unconditionally iterates and reads sizeof(cpu_set_t)
(128 bytes) from the source pointers, does this read well past the end
of the trace field for the cpumask (which would be 8 bytes for 64 CPUs)?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260902123942.695822-1-vschneid@redhat.com?part=8

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-09-02 13:55 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-02 12:39 [PATCH v5 0/8] tracing/osnoise: Track IPIs Valentin Schneider
2026-09-02 12:39 ` [PATCH v5 1/8] rtla/osnoise: Add IPI tracking cmdline option Valentin Schneider
2026-09-02 12:39 ` [PATCH v5 2/8] rtla/osnoise: Record IPI count in osnoise top Valentin Schneider
2026-09-02 13:01   ` sashiko-bot
2026-09-02 12:39 ` [PATCH v5 3/8] rtla/osnoise: Leverage IPI event filters when tracing a subset of CPUs Valentin Schneider
2026-09-02 12:39 ` [PATCH v5 4/8] rtla/osnoise: Allow IPI filters to gracefully fail Valentin Schneider
2026-09-02 12:39 ` [PATCH v5 5/8] rtla: make struct trace_events double linked Valentin Schneider
2026-09-02 12:39 ` [PATCH v5 6/8] rtla: Enable and disable events in the user-defined order Valentin Schneider
2026-09-02 12:39 ` [PATCH v5 7/8] rtla: Unconditionally clean any pre-existing filters for user-provided events Valentin Schneider
2026-09-02 13:44   ` sashiko-bot
2026-09-02 12:39 ` [PATCH v5 8/8] rtla/osnoise: Trace IPI events when recording a trace file Valentin Schneider
2026-09-02 13:55   ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox