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.

Signed-off-by: Valentin Schneider <vschneid@redhat.com>
Link: https://lore.kernel.org/r/20260902123942.695822-9-vschneid@redhat.com
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
This commit is contained in:
Valentin Schneider 2026-09-02 14:39:37 +02:00 committed by Tomas Glozar
parent 20e92ac8c1
commit cf89b1086d
5 changed files with 80 additions and 36 deletions

View File

@ -228,7 +228,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;

View File

@ -177,7 +177,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,

View File

@ -1222,10 +1222,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;
@ -1240,6 +1286,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);

View File

@ -65,6 +65,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;

View File

@ -393,7 +393,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;
@ -425,41 +425,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