* [RFC PATCH v2 0/4] tracing/osnoise: Track IPIs
@ 2026-06-17 13:17 Valentin Schneider
2026-06-17 13:17 ` [RFC PATCH v2 1/4] rtla/osnoise: Add IPI tracking cmdline option Valentin Schneider
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Valentin Schneider @ 2026-06-17 13:17 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.
So here's IPI tracking added to osnoise. This time around fully in userspace, as
Tomáš pointed out to me that this will make it a lot easier to deploy to older
kernels.
Based on top of linux/next at 'next-20260616' to have the latest libsubcmd
changes.
Cheers,
Valentin
Revisions
=========
v1 -> v2
++++++++
o Dropped the in-kernel osnoise_sample changes and made it all userspace
Valentin Schneider (4):
rtla/osnoise: Add IPI tracking cmdline option
rtla/osnoise: Record IPI count in osnoise top
rtla/osnoise: Trace IPI events when recording a trace file
rtla/osnoise: Leverage IPI event filters when tracing a subset of CPUs
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.c | 2 +-
tools/tracing/rtla/src/common.h | 3 +-
tools/tracing/rtla/src/osnoise.c | 17 +-
tools/tracing/rtla/src/osnoise_top.c | 153 +++++++++++++++++-
7 files changed, 179 insertions(+), 4 deletions(-)
--
2.54.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [RFC PATCH v2 1/4] rtla/osnoise: Add IPI tracking cmdline option
2026-06-17 13:17 [RFC PATCH v2 0/4] tracing/osnoise: Track IPIs Valentin Schneider
@ 2026-06-17 13:17 ` Valentin Schneider
2026-06-17 13:17 ` [RFC PATCH v2 2/4] rtla/osnoise: Record IPI count in osnoise top Valentin Schneider
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Valentin Schneider @ 2026-06-17 13:17 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 -i 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..98f77f8971a69 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
+**-i**, **--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 c5279c9875310..eb1e76a6b0dea 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 3c939de9abf02..7d3f982cfabdb 100644
--- a/tools/tracing/rtla/src/cli_p.h
+++ b/tools/tracing/rtla/src/cli_p.h
@@ -305,6 +305,9 @@ static int opt_filter_cb(const struct option *opt, const char *arg, int unset)
"the minimum delta to be considered a noise", \
opt_llong_callback)
+#define OSNOISE_OPT_IPI OPT_BOOLEAN('i', "ipi", ¶ms->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.54.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [RFC PATCH v2 2/4] rtla/osnoise: Record IPI count in osnoise top
2026-06-17 13:17 [RFC PATCH v2 0/4] tracing/osnoise: Track IPIs Valentin Schneider
2026-06-17 13:17 ` [RFC PATCH v2 1/4] rtla/osnoise: Add IPI tracking cmdline option Valentin Schneider
@ 2026-06-17 13:17 ` Valentin Schneider
2026-06-17 13:17 ` [RFC PATCH v2 3/4] rtla/osnoise: Trace IPI events when recording a trace file Valentin Schneider
2026-06-17 13:17 ` [RFC PATCH v2 4/4] rtla/osnoise: Leverage IPI event filters when tracing a subset of CPUs Valentin Schneider
3 siblings, 0 replies; 5+ messages in thread
From: Valentin Schneider @ 2026-06-17 13:17 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 -i cmdline option.
Signed-off-by: Valentin Schneider <vschneid@redhat.com>
---
tools/tracing/rtla/src/osnoise_top.c | 124 ++++++++++++++++++++++++++-
1 file changed, 123 insertions(+), 1 deletion(-)
diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c
index 512a6299cb018..5b462a3543b97 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;
};
@@ -70,6 +72,91 @@ static struct osnoise_top_data *osnoise_alloc_top(void)
return NULL;
}
+static void account_ipi(struct osnoise_tool *tool,
+ unsigned long long src_cpu, 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 src_cpu, dst_cpu;
+ struct trace_instance *trace = context;
+
+ tool = container_of(trace, struct osnoise_tool, trace);
+ params = to_osnoise_params(tool->params);
+
+ src_cpu = record->cpu;
+ tep_get_field_val(s, event, "cpu", record, &dst_cpu, 1);
+
+ if (CPU_ISSET(dst_cpu, ¶ms->common.monitored_cpus))
+ account_ipi(tool, src_cpu, 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;
+ unsigned long long src_cpu;
+ cpu_set_t *event_cpus;
+ int len;
+
+ tool = container_of(trace, struct osnoise_tool, trace);
+ params = to_osnoise_params(tool->params);
+
+ src_cpu = record->cpu;
+
+ 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, ¶ms->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, src_cpu, cpu);
+ }
+ }
+
+ return 0;
+}
+
/*
* osnoise_top_handler - this is the handler for osnoise tracer events
*/
@@ -164,6 +251,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 +307,13 @@ 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, "\n");
+ return;
+ }
+
+ trace_seq_printf(s, " %12llu\n", cpu_data->ipi_count);
}
/*
@@ -281,6 +376,7 @@ osnoise_top_apply_config(struct osnoise_tool *tool)
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 +391,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.54.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [RFC PATCH v2 3/4] rtla/osnoise: Trace IPI events when recording a trace file
2026-06-17 13:17 [RFC PATCH v2 0/4] tracing/osnoise: Track IPIs Valentin Schneider
2026-06-17 13:17 ` [RFC PATCH v2 1/4] rtla/osnoise: Add IPI tracking cmdline option Valentin Schneider
2026-06-17 13:17 ` [RFC PATCH v2 2/4] rtla/osnoise: Record IPI count in osnoise top Valentin Schneider
@ 2026-06-17 13:17 ` Valentin Schneider
2026-06-17 13:17 ` [RFC PATCH v2 4/4] rtla/osnoise: Leverage IPI event filters when tracing a subset of CPUs Valentin Schneider
3 siblings, 0 replies; 5+ messages in thread
From: Valentin Schneider @ 2026-06-17 13:17 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.
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 | 17 ++++++++++++++++-
3 files changed, 18 insertions(+), 3 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..281f6f57d15af 100644
--- a/tools/tracing/rtla/src/osnoise.c
+++ b/tools/tracing/rtla/src/osnoise.c
@@ -1181,7 +1181,8 @@ struct osnoise_tool *osnoise_init_tool(char *tool_name)
/*
* 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 +1197,20 @@ struct osnoise_tool *osnoise_init_trace_tool(const char *tracer)
goto out_err;
}
+ if (params->ipi) {
+ 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;
+ }
+ }
+
retval = enable_tracer_by_name(trace->trace.inst, tracer);
if (retval) {
err_msg("Could not enable %s tracer for tracing\n", tracer);
--
2.54.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [RFC PATCH v2 4/4] rtla/osnoise: Leverage IPI event filters when tracing a subset of CPUs
2026-06-17 13:17 [RFC PATCH v2 0/4] tracing/osnoise: Track IPIs Valentin Schneider
` (2 preceding siblings ...)
2026-06-17 13:17 ` [RFC PATCH v2 3/4] rtla/osnoise: Trace IPI events when recording a trace file Valentin Schneider
@ 2026-06-17 13:17 ` Valentin Schneider
3 siblings, 0 replies; 5+ messages in thread
From: Valentin Schneider @ 2026-06-17 13:17 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
Instead of post-processing the events in the tracefs_iterate_raw_events()
callbacks, 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 | 37 +++++++++++++++++++++++++---
1 file changed, 33 insertions(+), 4 deletions(-)
diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c
index 5b462a3543b97..8040521710884 100644
--- a/tools/tracing/rtla/src/osnoise_top.c
+++ b/tools/tracing/rtla/src/osnoise_top.c
@@ -93,18 +93,15 @@ 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 src_cpu, dst_cpu;
struct trace_instance *trace = context;
tool = container_of(trace, struct osnoise_tool, trace);
- params = to_osnoise_params(tool->params);
src_cpu = record->cpu;
tep_get_field_val(s, event, "cpu", record, &dst_cpu, 1);
- if (CPU_ISSET(dst_cpu, ¶ms->common.monitored_cpus))
- account_ipi(tool, src_cpu, dst_cpu);
+ account_ipi(tool, src_cpu, dst_cpu);
return 0;
}
@@ -141,6 +138,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-monitered
+ * CPUs.
+ */
CPU_AND(&cpumask_tmp_cpus, event_cpus, ¶ms->common.monitored_cpus);
/*
@@ -406,6 +408,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) {
+ 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) {
+ 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.54.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-06-17 13:18 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-17 13:17 [RFC PATCH v2 0/4] tracing/osnoise: Track IPIs Valentin Schneider
2026-06-17 13:17 ` [RFC PATCH v2 1/4] rtla/osnoise: Add IPI tracking cmdline option Valentin Schneider
2026-06-17 13:17 ` [RFC PATCH v2 2/4] rtla/osnoise: Record IPI count in osnoise top Valentin Schneider
2026-06-17 13:17 ` [RFC PATCH v2 3/4] rtla/osnoise: Trace IPI events when recording a trace file Valentin Schneider
2026-06-17 13:17 ` [RFC PATCH v2 4/4] rtla/osnoise: Leverage IPI event filters when tracing a subset of CPUs Valentin Schneider
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox