From 11aa4a18094f04a8ba7e403c272a9a5d85c9c9fc Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Sun, 12 Oct 2025 10:11:30 +0300 Subject: [PATCH 01/30] tools/rtla: Remove unused function declarations Historically four function declarations remain orphaned or duplicated. Remove them to keep the source clean. Signed-off-by: Costa Shulyupin Link: https://lore.kernel.org/r/20251012071133.290225-1-costa.shul@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/osnoise.h | 3 --- tools/tracing/rtla/src/utils.h | 1 - 2 files changed, 4 deletions(-) diff --git a/tools/tracing/rtla/src/osnoise.h b/tools/tracing/rtla/src/osnoise.h index 895687030c0b..75de0d5c706a 100644 --- a/tools/tracing/rtla/src/osnoise.h +++ b/tools/tracing/rtla/src/osnoise.h @@ -58,8 +58,6 @@ int osnoise_set_irq_disable(struct osnoise_context *context, bool onoff); void osnoise_report_missed_events(struct osnoise_tool *tool); int osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params *params); -int osnoise_hist_main(int argc, char *argv[]); -int osnoise_top_main(int argc, char **argv); int osnoise_enable(struct osnoise_tool *tool); int osnoise_main(int argc, char **argv); int hwnoise_main(int argc, char **argv); @@ -68,4 +66,3 @@ extern struct tool_ops timerlat_top_ops, timerlat_hist_ops; extern struct tool_ops osnoise_top_ops, osnoise_hist_ops; int run_tool(struct tool_ops *ops, int argc, char *argv[]); -int hist_main_loop(struct osnoise_tool *tool); diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h index 091df4ba4587..ed7618842e82 100644 --- a/tools/tracing/rtla/src/utils.h +++ b/tools/tracing/rtla/src/utils.h @@ -24,7 +24,6 @@ void fatal(const char *fmt, ...); long parse_seconds_duration(char *val); void get_duration(time_t start_time, char *output, int output_size); -int parse_cpu_list(char *cpu_list, char **monitored_cpus); char *parse_optional_arg(int argc, char **argv); long long get_llong_from_str(char *start); From c219d4ee1d63b772d5fa8ed453b9cec18a9e2f6a Mon Sep 17 00:00:00 2001 From: Crystal Wood Date: Wed, 12 Nov 2025 09:25:29 -0600 Subject: [PATCH 02/30] rtla: Set stop threshold after all instances are enabled This avoids startup races where one of the instances hit a threshold before all instances were enabled, and thus tracing stops without the relevant event. In particular, this is not uncommon with the tests that set a very tight threshold and then complain if there's no analysis. This also ensures that we don't stop tracing during a warmup. The downside is a small chance of having an event over the threshold early in the output, without stopping on it, which could cause user confusion. This should be less likely if the warmup feature is used, but that doesn't eliminate the race window, just the odds of an unusual spike right at that moment. Signed-off-by: Crystal Wood Link: https://lore.kernel.org/r/20251112152529.956778-6-crwood@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/common.c | 20 ++++++++++++++++++++ tools/tracing/rtla/src/common.h | 4 ++++ tools/tracing/rtla/src/osnoise.c | 17 ++++------------- tools/tracing/rtla/src/osnoise.h | 5 ----- tools/tracing/rtla/src/timerlat.c | 29 ++++++++++------------------- 5 files changed, 38 insertions(+), 37 deletions(-) diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c index b197037fc58b..46e0263d6ae8 100644 --- a/tools/tracing/rtla/src/common.c +++ b/tools/tracing/rtla/src/common.c @@ -348,3 +348,23 @@ int hist_main_loop(struct osnoise_tool *tool) return retval; } + +int osn_set_stop(struct osnoise_tool *tool) +{ + struct common_params *params = tool->params; + int retval; + + retval = osnoise_set_stop_us(tool->context, params->stop_us); + if (retval) { + err_msg("Failed to set stop us\n"); + return retval; + } + + retval = osnoise_set_stop_total_us(tool->context, params->stop_total_us); + if (retval) { + err_msg("Failed to set stop total us\n"); + return retval; + } + + return 0; +} diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h index 9ec2b7632c37..c5e73d4600a0 100644 --- a/tools/tracing/rtla/src/common.h +++ b/tools/tracing/rtla/src/common.h @@ -152,7 +152,11 @@ 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); 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, + long long stop_total_us); int common_apply_config(struct osnoise_tool *tool, struct common_params *params); int top_main_loop(struct osnoise_tool *tool); int hist_main_loop(struct osnoise_tool *tool); +int osn_set_stop(struct osnoise_tool *tool); diff --git a/tools/tracing/rtla/src/osnoise.c b/tools/tracing/rtla/src/osnoise.c index 312c511fa004..945eb61efc46 100644 --- a/tools/tracing/rtla/src/osnoise.c +++ b/tools/tracing/rtla/src/osnoise.c @@ -1128,18 +1128,6 @@ osnoise_apply_config(struct osnoise_tool *tool, struct osnoise_params *params) goto out_err; } - retval = osnoise_set_stop_us(tool->context, params->common.stop_us); - if (retval) { - err_msg("Failed to set stop us\n"); - goto out_err; - } - - retval = osnoise_set_stop_total_us(tool->context, params->common.stop_total_us); - if (retval) { - err_msg("Failed to set stop total us\n"); - goto out_err; - } - retval = osnoise_set_tracing_thresh(tool->context, params->threshold); if (retval) { err_msg("Failed to set tracing_thresh\n"); @@ -1184,9 +1172,12 @@ int osnoise_enable(struct osnoise_tool *tool) debug_msg("Error cleaning up the buffer"); return retval; } - } + retval = osn_set_stop(tool); + if (retval) + return retval; + return 0; } diff --git a/tools/tracing/rtla/src/osnoise.h b/tools/tracing/rtla/src/osnoise.h index 75de0d5c706a..168669aa7e0d 100644 --- a/tools/tracing/rtla/src/osnoise.h +++ b/tools/tracing/rtla/src/osnoise.h @@ -34,12 +34,7 @@ int osnoise_set_runtime_period(struct osnoise_context *context, unsigned long long period); void osnoise_restore_runtime_period(struct osnoise_context *context); -int osnoise_set_stop_us(struct osnoise_context *context, - long long stop_us); void osnoise_restore_stop_us(struct osnoise_context *context); - -int osnoise_set_stop_total_us(struct osnoise_context *context, - long long stop_total_us); void osnoise_restore_stop_total_us(struct osnoise_context *context); int osnoise_set_timerlat_period_us(struct osnoise_context *context, diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c index df4f9bfe3433..ee15e344cf37 100644 --- a/tools/tracing/rtla/src/timerlat.c +++ b/tools/tracing/rtla/src/timerlat.c @@ -48,25 +48,6 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) } } - if (params->mode != TRACING_MODE_BPF) { - /* - * In tracefs and mixed mode, timerlat tracer handles stopping - * on threshold - */ - retval = osnoise_set_stop_us(tool->context, params->common.stop_us); - if (retval) { - err_msg("Failed to set stop us\n"); - goto out_err; - } - - retval = osnoise_set_stop_total_us(tool->context, params->common.stop_total_us); - if (retval) { - err_msg("Failed to set stop total us\n"); - goto out_err; - } - } - - retval = osnoise_set_timerlat_period_us(tool->context, params->timerlat_period_us ? params->timerlat_period_us : @@ -184,6 +165,16 @@ int timerlat_enable(struct osnoise_tool *tool) } } + /* + * In tracefs and mixed mode, timerlat tracer handles stopping + * on threshold + */ + if (params->mode != TRACING_MODE_BPF) { + retval = osn_set_stop(tool); + if (retval) + return retval; + } + return 0; } From a08e012e814d346c191726a877b18901c3bc204f Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Mon, 24 Nov 2025 08:31:46 +0200 Subject: [PATCH 03/30] tools/rtla: Add common_usage() The rtla tools have significant code quadruplication in their usage functions. Each tool implements its own version of the same help text formatting and option descriptions, leading to maintenance overhead and inconsistencies. Documentation/tools/rtla/common_options.rst lists 14 common options. Add common_usage() infrastructure to consolidate help formatting. Subsequent patches will extend this to handle other common options. The refactored output is almost identical to the original, with the following changes: - add square brackets to specify optionality: `usage: [rtla] ...` - remove `-q` from timerlat hist because hist tools don't support it - minor spacing Signed-off-by: Costa Shulyupin Link: https://lore.kernel.org/r/20251124063204.845425-1-costa.shul@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/common.c | 39 ++++++++++++++++++++++++++ tools/tracing/rtla/src/common.h | 3 ++ tools/tracing/rtla/src/osnoise_hist.c | 22 ++++++--------- tools/tracing/rtla/src/osnoise_top.c | 37 ++++++++++-------------- tools/tracing/rtla/src/timerlat_hist.c | 22 ++++++--------- tools/tracing/rtla/src/timerlat_top.c | 22 ++++++--------- 6 files changed, 81 insertions(+), 64 deletions(-) diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c index 46e0263d6ae8..009a4bce9737 100644 --- a/tools/tracing/rtla/src/common.c +++ b/tools/tracing/rtla/src/common.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include "common.h" @@ -368,3 +369,41 @@ int osn_set_stop(struct osnoise_tool *tool) return 0; } + +static void print_msg_array(const char * const *msgs) +{ + if (!msgs) + return; + + for (int i = 0; msgs[i]; i++) + fprintf(stderr, "%s\n", msgs[i]); +} + +/* + * common_usage - print complete usage information + */ +void common_usage(const char *tool, const char *mode, + const char *desc, const char * const *start_msgs, const char * const *opt_msgs) +{ + static const char * const common_options[] = { + " -h/--help: print this menu", + NULL + }; + fprintf(stderr, "rtla %s", tool); + if (strcmp(mode, "")) + fprintf(stderr, " %s", mode); + fprintf(stderr, ": %s (version %s)\n\n", desc, VERSION); + fprintf(stderr, " usage: [rtla] %s ", tool); + + if (strcmp(mode, "top") == 0) + fprintf(stderr, "[top] [-h] "); + else + fprintf(stderr, "%s [-h] ", mode); + + print_msg_array(start_msgs); + fprintf(stderr, "\n"); + print_msg_array(common_options); + print_msg_array(opt_msgs); + + exit(EXIT_SUCCESS); +} diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h index c5e73d4600a0..c48c9bfd20e3 100644 --- a/tools/tracing/rtla/src/common.h +++ b/tools/tracing/rtla/src/common.h @@ -160,3 +160,6 @@ int common_apply_config(struct osnoise_tool *tool, struct common_params *params) int top_main_loop(struct osnoise_tool *tool); int hist_main_loop(struct osnoise_tool *tool); int osn_set_stop(struct osnoise_tool *tool); + +void common_usage(const char *tool, const char *mode, + const char *desc, const char * const *start_msgs, const char * const *opt_msgs); diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c index ff8c231e47c4..372128db9e4a 100644 --- a/tools/tracing/rtla/src/osnoise_hist.c +++ b/tools/tracing/rtla/src/osnoise_hist.c @@ -409,16 +409,15 @@ osnoise_print_stats(struct osnoise_tool *tool) */ static void osnoise_hist_usage(void) { - int i; - - static const char * const msg[] = { - "", - " usage: rtla osnoise hist [-h] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\", + static const char * const msg_start[] = { + "[-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\", " [-T us] [-t [file]] [-e sys[:event]] [--filter ] [--trigger ] \\", " [-c cpu-list] [-H cpu-list] [-P priority] [-b N] [-E N] [--no-header] [--no-summary] \\", " [--no-index] [--with-zeros] [-C [cgroup_name]] [--warm-up]", - "", - " -h/--help: print this menu", + NULL, + }; + + static const char * const msg_opts[] = { " -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit", " -p/--period us: osnoise period in us", " -r/--runtime us: osnoise runtime in us", @@ -453,13 +452,8 @@ static void osnoise_hist_usage(void) NULL, }; - fprintf(stderr, "rtla osnoise hist: a per-cpu histogram of the OS noise (version %s)\n", - VERSION); - - for (i = 0; msg[i]; i++) - fprintf(stderr, "%s\n", msg[i]); - - exit(EXIT_SUCCESS); + common_usage("osnoise", "hist", "a per-cpu histogram of the OS noise", + msg_start, msg_opts); } /* diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c index 04c699bdd736..1db1d946b600 100644 --- a/tools/tracing/rtla/src/osnoise_top.c +++ b/tools/tracing/rtla/src/osnoise_top.c @@ -257,14 +257,16 @@ osnoise_print_stats(struct osnoise_tool *top) */ static void osnoise_top_usage(struct osnoise_params *params) { - int i; + const char *tool, *mode, *desc; - static const char * const msg[] = { - " [-h] [-q] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\", + static const char * const msg_start[] = { + "[-q] [-D] [-d s] [-a us] [-p us] [-r us] [-s us] [-S us] \\", " [-T us] [-t [file]] [-e sys[:event]] [--filter ] [--trigger ] \\", " [-c cpu-list] [-H cpu-list] [-P priority] [-C [cgroup_name]] [--warm-up s]", - "", - " -h/--help: print this menu", + NULL, + }; + + static const char * const msg_opts[] = { " -a/--auto: set automatic trace mode, stopping the session if argument in us sample is hit", " -p/--period us: osnoise period in us", " -r/--runtime us: osnoise runtime in us", @@ -295,25 +297,16 @@ static void osnoise_top_usage(struct osnoise_params *params) }; if (params->mode == MODE_OSNOISE) { - fprintf(stderr, - "rtla osnoise top: a per-cpu summary of the OS noise (version %s)\n", - VERSION); - - fprintf(stderr, " usage: rtla osnoise [top]"); + tool = "osnoise"; + mode = "top"; + desc = "a per-cpu summary of the OS noise"; + } else { + tool = "hwnoise"; + mode = ""; + desc = "a summary of hardware-related noise"; } - if (params->mode == MODE_HWNOISE) { - fprintf(stderr, - "rtla hwnoise: a summary of hardware-related noise (version %s)\n", - VERSION); - - fprintf(stderr, " usage: rtla hwnoise"); - } - - for (i = 0; msg[i]; i++) - fprintf(stderr, "%s\n", msg[i]); - - exit(EXIT_SUCCESS); + common_usage(tool, mode, desc, msg_start, msg_opts); } /* diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c index 1fb471a787b7..2a5c543217ba 100644 --- a/tools/tracing/rtla/src/timerlat_hist.c +++ b/tools/tracing/rtla/src/timerlat_hist.c @@ -696,17 +696,16 @@ timerlat_print_stats(struct osnoise_tool *tool) */ static void timerlat_hist_usage(void) { - int i; - - char *msg[] = { - "", - " usage: [rtla] timerlat hist [-h] [-q] [-d s] [-D] [-n] [-a us] [-p us] [-i us] [-T us] [-s us] \\", + static const char * const msg_start[] = { + "[-d s] [-D] [-n] [-a us] [-p us] [-i us] [-T us] [-s us] \\", " [-t [file]] [-e sys[:event]] [--filter ] [--trigger ] [-c cpu-list] [-H cpu-list]\\", " [-P priority] [-E N] [-b N] [--no-irq] [--no-thread] [--no-header] [--no-summary] \\", " [--no-index] [--with-zeros] [--dma-latency us] [-C [cgroup_name]] [--no-aa] [--dump-task] [-u|-k]", " [--warm-up s] [--deepest-idle-state n]", - "", - " -h/--help: print this menu", + NULL, + }; + + static const char * const msg_opts[] = { " -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit", " -p/--period us: timerlat period in us", " -i/--irq us: stop trace if the irq latency is higher than the argument in us", @@ -750,13 +749,8 @@ static void timerlat_hist_usage(void) NULL, }; - fprintf(stderr, "rtla timerlat hist: a per-cpu histogram of the timer latency (version %s)\n", - VERSION); - - for (i = 0; msg[i]; i++) - fprintf(stderr, "%s\n", msg[i]); - - exit(EXIT_SUCCESS); + common_usage("timerlat", "hist", "a per-cpu histogram of the timer latency", + msg_start, msg_opts); } /* diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index 29c2c1f717ed..9ed8b931552f 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -476,15 +476,14 @@ timerlat_print_stats(struct osnoise_tool *top) */ static void timerlat_top_usage(void) { - int i; - - static const char *const msg[] = { - "", - " usage: rtla timerlat [top] [-h] [-q] [-a us] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] \\", + static const char *const msg_start[] = { + "[-q] [-a us] [-d s] [-D] [-n] [-p us] [-i us] [-T us] [-s us] \\", " [[-t [file]] [-e sys[:event]] [--filter ] [--trigger ] [-c cpu-list] [-H cpu-list]\\", " [-P priority] [--dma-latency us] [--aa-only us] [-C [cgroup_name]] [-u|-k] [--warm-up s] [--deepest-idle-state n]", - "", - " -h/--help: print this menu", + NULL, + }; + + static const char *const msg_opts[] = { " -a/--auto: set automatic trace mode, stopping the session if argument in us latency is hit", " --aa-only us: stop if latency is hit, only printing the auto analysis (reduces CPU usage)", " -p/--period us: timerlat period in us", @@ -522,13 +521,8 @@ static void timerlat_top_usage(void) NULL, }; - fprintf(stderr, "rtla timerlat top: a per-cpu summary of the timer latency (version %s)\n", - VERSION); - - for (i = 0; msg[i]; i++) - fprintf(stderr, "%s\n", msg[i]); - - exit(EXIT_SUCCESS); + common_usage("timerlat", "top", "a per-cpu summary of the timer latency", + msg_start, msg_opts); } /* From 8cd0f08ac72e25e2a048c72d76730676ab0106f3 Mon Sep 17 00:00:00 2001 From: Tomas Glozar Date: Wed, 26 Nov 2025 15:41:59 +0100 Subject: [PATCH 04/30] rtla/timerlat: Support tail call from BPF program Add a map to the rtla-timerlat BPF program that holds a file descriptor of another BPF program, to be executed on threshold overflow. timerlat_bpf_set_action() is added as an interface to set the program. Link: https://lore.kernel.org/r/20251126144205.331954-2-tglozar@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/timerlat.bpf.c | 25 +++++++++++++++++++++---- tools/tracing/rtla/src/timerlat_bpf.c | 13 +++++++++++++ tools/tracing/rtla/src/timerlat_bpf.h | 1 + 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/tools/tracing/rtla/src/timerlat.bpf.c b/tools/tracing/rtla/src/timerlat.bpf.c index e2265b5d6491..549d2d2191d2 100644 --- a/tools/tracing/rtla/src/timerlat.bpf.c +++ b/tools/tracing/rtla/src/timerlat.bpf.c @@ -40,6 +40,17 @@ struct { __uint(max_entries, 1); } signal_stop_tracing SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_PROG_ARRAY); + __uint(key_size, sizeof(unsigned int)); + __uint(max_entries, 1); + __array(values, unsigned int (void *)); +} bpf_action SEC(".maps") = { + .values = { + [0] = 0 + }, +}; + /* Params to be set by rtla */ const volatile int bucket_size = 1; const volatile int output_divisor = 1000; @@ -109,7 +120,7 @@ nosubprog void update_summary(void *map, map_set(map, SUMMARY_SUM, map_get(map, SUMMARY_SUM) + latency); } -nosubprog void set_stop_tracing(void) +nosubprog void set_stop_tracing(struct trace_event_raw_timerlat_sample *tp_args) { int value = 0; @@ -118,6 +129,12 @@ nosubprog void set_stop_tracing(void) /* Signal to userspace */ bpf_ringbuf_output(&signal_stop_tracing, &value, sizeof(value), 0); + + /* + * Call into BPF action program, if attached. + * Otherwise, just silently fail. + */ + bpf_tail_call(tp_args, &bpf_action, 0); } SEC("tp/osnoise/timerlat_sample") @@ -138,19 +155,19 @@ int handle_timerlat_sample(struct trace_event_raw_timerlat_sample *tp_args) update_summary(&summary_irq, latency, bucket); if (irq_threshold != 0 && latency_us >= irq_threshold) - set_stop_tracing(); + set_stop_tracing(tp_args); } else if (tp_args->context == 1) { update_main_hist(&hist_thread, bucket); update_summary(&summary_thread, latency, bucket); if (thread_threshold != 0 && latency_us >= thread_threshold) - set_stop_tracing(); + set_stop_tracing(tp_args); } else { update_main_hist(&hist_user, bucket); update_summary(&summary_user, latency, bucket); if (thread_threshold != 0 && latency_us >= thread_threshold) - set_stop_tracing(); + set_stop_tracing(tp_args); } return 0; diff --git a/tools/tracing/rtla/src/timerlat_bpf.c b/tools/tracing/rtla/src/timerlat_bpf.c index e97d16646bcd..1d619e502c65 100644 --- a/tools/tracing/rtla/src/timerlat_bpf.c +++ b/tools/tracing/rtla/src/timerlat_bpf.c @@ -59,6 +59,19 @@ int timerlat_bpf_init(struct timerlat_params *params) return 0; } +/* + * timerlat_bpf_set_action - set action on threshold executed on BPF side + */ +static int timerlat_bpf_set_action(struct bpf_program *prog) +{ + unsigned int key = 0, value = bpf_program__fd(prog); + + return bpf_map__update_elem(bpf->maps.bpf_action, + &key, sizeof(key), + &value, sizeof(value), + BPF_ANY); +} + /* * timerlat_bpf_attach - attach BPF program to collect timerlat data */ diff --git a/tools/tracing/rtla/src/timerlat_bpf.h b/tools/tracing/rtla/src/timerlat_bpf.h index 118487436d30..b5009092c7a3 100644 --- a/tools/tracing/rtla/src/timerlat_bpf.h +++ b/tools/tracing/rtla/src/timerlat_bpf.h @@ -12,6 +12,7 @@ enum summary_field { }; #ifndef __bpf__ +#include #ifdef HAVE_BPF_SKEL int timerlat_bpf_init(struct timerlat_params *params); int timerlat_bpf_attach(void); From f967d1eca7d0bde7c896014577ea876096831c6e Mon Sep 17 00:00:00 2001 From: Tomas Glozar Date: Wed, 26 Nov 2025 15:42:00 +0100 Subject: [PATCH 05/30] rtla/timerlat: Add --bpf-action option Add option --bpf-action that allows the user to attach an external BPF program that will be executed via BPF tail call on latency threshold overflow. Executing additional BPF code on latency threshold overflow allows doing low-latency and in-kernel troubleshooting of the cause of the overflow. The option takes an argument, which is a path to a BPF ELF file expected to contain a function named "action_handler" in a section named "tp/timerlat_action" (the section is necessary for libbpf to assign the correct BPF program type to it). Link: https://lore.kernel.org/r/20251126144205.331954-3-tglozar@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/timerlat.c | 11 ++++++ tools/tracing/rtla/src/timerlat.h | 2 +- tools/tracing/rtla/src/timerlat_bpf.c | 53 ++++++++++++++++++++++++++ tools/tracing/rtla/src/timerlat_bpf.h | 6 ++- tools/tracing/rtla/src/timerlat_hist.c | 5 +++ tools/tracing/rtla/src/timerlat_top.c | 5 +++ 6 files changed, 80 insertions(+), 2 deletions(-) diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c index ee15e344cf37..8f6cf55f4a94 100644 --- a/tools/tracing/rtla/src/timerlat.c +++ b/tools/tracing/rtla/src/timerlat.c @@ -48,6 +48,17 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params) } } + /* Check if BPF action program is requested but BPF is not available */ + if (params->bpf_action_program) { + if (params->mode == TRACING_MODE_TRACEFS) { + err_msg("BPF actions are not supported in tracefs-only mode\n"); + goto out_err; + } + + if (timerlat_load_bpf_action_program(params->bpf_action_program)) + goto out_err; + } + retval = osnoise_set_timerlat_period_us(tool->context, params->timerlat_period_us ? params->timerlat_period_us : diff --git a/tools/tracing/rtla/src/timerlat.h b/tools/tracing/rtla/src/timerlat.h index fd6065f48bb7..8dd5d134ce08 100644 --- a/tools/tracing/rtla/src/timerlat.h +++ b/tools/tracing/rtla/src/timerlat.h @@ -27,6 +27,7 @@ struct timerlat_params { int dump_tasks; int deepest_idle_state; enum timerlat_tracing_mode mode; + const char *bpf_action_program; }; #define to_timerlat_params(ptr) container_of(ptr, struct timerlat_params, common) @@ -36,4 +37,3 @@ int timerlat_main(int argc, char *argv[]); int timerlat_enable(struct osnoise_tool *tool); void timerlat_analyze(struct osnoise_tool *tool, bool stopped); void timerlat_free(struct osnoise_tool *tool); - diff --git a/tools/tracing/rtla/src/timerlat_bpf.c b/tools/tracing/rtla/src/timerlat_bpf.c index 1d619e502c65..05adf18303df 100644 --- a/tools/tracing/rtla/src/timerlat_bpf.c +++ b/tools/tracing/rtla/src/timerlat_bpf.c @@ -7,6 +7,10 @@ static struct timerlat_bpf *bpf; +/* BPF object and program for action program */ +static struct bpf_object *obj; +static struct bpf_program *prog; + /* * timerlat_bpf_init - load and initialize BPF program to collect timerlat data */ @@ -96,6 +100,11 @@ void timerlat_bpf_detach(void) void timerlat_bpf_destroy(void) { timerlat_bpf__destroy(bpf); + bpf = NULL; + if (obj) + bpf_object__close(obj); + obj = NULL; + prog = NULL; } static int handle_rb_event(void *ctx, void *data, size_t data_sz) @@ -190,4 +199,48 @@ int timerlat_bpf_get_summary_value(enum summary_field key, bpf->maps.summary_user, key, value_irq, value_thread, value_user, cpus); } + +/* + * timerlat_load_bpf_action_program - load and register a BPF action program + */ +int timerlat_load_bpf_action_program(const char *program_path) +{ + int err; + + obj = bpf_object__open_file(program_path, NULL); + if (!obj) { + err_msg("Failed to open BPF action program: %s\n", program_path); + goto out_err; + } + + err = bpf_object__load(obj); + if (err) { + err_msg("Failed to load BPF action program: %s\n", program_path); + goto out_obj_err; + } + + prog = bpf_object__find_program_by_name(obj, "action_handler"); + if (!prog) { + err_msg("BPF action program must have 'action_handler' function: %s\n", + program_path); + goto out_obj_err; + } + + err = timerlat_bpf_set_action(prog); + if (err) { + err_msg("Failed to register BPF action program: %s\n", program_path); + goto out_prog_err; + } + + return 0; + +out_prog_err: + prog = NULL; +out_obj_err: + bpf_object__close(obj); + obj = NULL; +out_err: + return 1; +} + #endif /* HAVE_BPF_SKEL */ diff --git a/tools/tracing/rtla/src/timerlat_bpf.h b/tools/tracing/rtla/src/timerlat_bpf.h index b5009092c7a3..169abeaf4363 100644 --- a/tools/tracing/rtla/src/timerlat_bpf.h +++ b/tools/tracing/rtla/src/timerlat_bpf.h @@ -30,7 +30,7 @@ int timerlat_bpf_get_summary_value(enum summary_field key, long long *value_thread, long long *value_user, int cpus); - +int timerlat_load_bpf_action_program(const char *program_path); static inline int have_libbpf_support(void) { return 1; } #else static inline int timerlat_bpf_init(struct timerlat_params *params) @@ -58,6 +58,10 @@ static inline int timerlat_bpf_get_summary_value(enum summary_field key, { return -1; } +static inline int timerlat_load_bpf_action_program(const char *program_path) +{ + return -1; +} static inline int have_libbpf_support(void) { return 0; } #endif /* HAVE_BPF_SKEL */ #endif /* __bpf__ */ diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c index 2a5c543217ba..ec43e6fda743 100644 --- a/tools/tracing/rtla/src/timerlat_hist.c +++ b/tools/tracing/rtla/src/timerlat_hist.c @@ -746,6 +746,7 @@ static void timerlat_hist_usage(void) " --deepest-idle-state n: only go down to idle state n on cpus used by timerlat to reduce exit from idle latency", " --on-threshold : define action to be executed at latency threshold, multiple are allowed", " --on-end : define action to be executed at measurement end, multiple are allowed", + " --bpf-action : load and execute BPF program when latency threshold is exceeded", NULL, }; @@ -825,6 +826,7 @@ static struct common_params {"deepest-idle-state", required_argument, 0, '\4'}, {"on-threshold", required_argument, 0, '\5'}, {"on-end", required_argument, 0, '\6'}, + {"bpf-action", required_argument, 0, '\7'}, {0, 0, 0, 0} }; @@ -1006,6 +1008,9 @@ static struct common_params if (retval) fatal("Invalid action %s", optarg); break; + case '\7': + params->bpf_action_program = optarg; + break; default: fatal("Invalid option"); } diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index 9ed8b931552f..af20b3eee472 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -518,6 +518,7 @@ static void timerlat_top_usage(void) " --deepest-idle-state n: only go down to idle state n on cpus used by timerlat to reduce exit from idle latency", " --on-threshold : define action to be executed at latency threshold, multiple are allowed", " --on-end: define action to be executed at measurement end, multiple are allowed", + " --bpf-action : load and execute BPF program when latency threshold is exceeded", NULL, }; @@ -589,6 +590,7 @@ static struct common_params {"deepest-idle-state", required_argument, 0, '8'}, {"on-threshold", required_argument, 0, '9'}, {"on-end", required_argument, 0, '\1'}, + {"bpf-action", required_argument, 0, '\2'}, {0, 0, 0, 0} }; @@ -756,6 +758,9 @@ static struct common_params if (retval) fatal("Invalid action %s", optarg); break; + case '\2': + params->bpf_action_program = optarg; + break; default: fatal("Invalid option"); } From 0304a3b7ec9a207637ab6f360a41af5fb25e1f44 Mon Sep 17 00:00:00 2001 From: Tomas Glozar Date: Wed, 26 Nov 2025 15:42:01 +0100 Subject: [PATCH 06/30] rtla/timerlat: Add example for BPF action program Add an example BPF action program that prints the measured latency to the tracefs buffer via bpf_printk(). A new Makefile target, "examples", is added to build the example. In addition, "sample/" subfolder is renamed to "example". If BPF skeleton support is unavailable or disabled, a warning will be displayed when building the BPF action program example. Link: https://lore.kernel.org/r/20251126144205.331954-4-tglozar@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/Makefile | 9 ++++++++- tools/tracing/rtla/example/timerlat_bpf_action.c | 16 ++++++++++++++++ .../rtla/{sample => example}/timerlat_load.py | 0 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 tools/tracing/rtla/example/timerlat_bpf_action.c rename tools/tracing/rtla/{sample => example}/timerlat_load.py (100%) diff --git a/tools/tracing/rtla/Makefile b/tools/tracing/rtla/Makefile index 746ccf2f5808..5f1529ce3693 100644 --- a/tools/tracing/rtla/Makefile +++ b/tools/tracing/rtla/Makefile @@ -73,9 +73,15 @@ src/timerlat.bpf.o: src/timerlat.bpf.c src/timerlat.skel.h: src/timerlat.bpf.o $(QUIET_GENSKEL)$(SYSTEM_BPFTOOL) gen skeleton $< > $@ + +example/timerlat_bpf_action.o: example/timerlat_bpf_action.c + $(QUIET_CLANG)$(CLANG) -g -O2 -target bpf -c $(filter %.c,$^) -o $@ else src/timerlat.skel.h: $(Q)echo '/* BPF skeleton is disabled */' > src/timerlat.skel.h + +example/timerlat_bpf_action.o: example/timerlat_bpf_action.c + $(Q)echo "BPF skeleton support is disabled, skipping example/timerlat_bpf_action.o" endif $(RTLA): $(RTLA_IN) @@ -96,7 +102,8 @@ clean: doc_clean fixdep-clean $(Q)find . -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete $(Q)rm -f rtla rtla-static fixdep FEATURE-DUMP rtla-* $(Q)rm -rf feature - $(Q)rm -f src/timerlat.bpf.o src/timerlat.skel.h + $(Q)rm -f src/timerlat.bpf.o src/timerlat.skel.h example/timerlat_bpf_action.o check: $(RTLA) RTLA=$(RTLA) prove -o -f tests/ +examples: example/timerlat_bpf_action.o .PHONY: FORCE clean check diff --git a/tools/tracing/rtla/example/timerlat_bpf_action.c b/tools/tracing/rtla/example/timerlat_bpf_action.c new file mode 100644 index 000000000000..ac1be049a848 --- /dev/null +++ b/tools/tracing/rtla/example/timerlat_bpf_action.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +char LICENSE[] SEC("license") = "GPL"; + +struct trace_event_raw_timerlat_sample { + unsigned long long timer_latency; +} __attribute__((preserve_access_index)); + +SEC("tp/timerlat_action") +int action_handler(struct trace_event_raw_timerlat_sample *tp_args) +{ + bpf_printk("Latency: %lld\n", tp_args->timer_latency); + return 0; +} diff --git a/tools/tracing/rtla/sample/timerlat_load.py b/tools/tracing/rtla/example/timerlat_load.py similarity index 100% rename from tools/tracing/rtla/sample/timerlat_load.py rename to tools/tracing/rtla/example/timerlat_load.py From 5525aebd4e0c6f7d92ec1cb074218bbcf3d46f13 Mon Sep 17 00:00:00 2001 From: Tomas Glozar Date: Wed, 26 Nov 2025 15:42:02 +0100 Subject: [PATCH 07/30] rtla/tests: Test BPF action program Add a test that implements a BPF program writing to a test map, which is attached to RTLA via --bpf-action to be executed on theshold overflow. A combination of --on-threshold shell with bpftool (which is always present if BPF support is enabled) is used to check whether the BPF program has executed successfully. Suggested-by: Crystal Wood Link: https://lore.kernel.org/r/20251126144205.331954-5-tglozar@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/Makefile | 10 ++++++-- tools/tracing/rtla/tests/bpf/bpf_action_map.c | 25 +++++++++++++++++++ tools/tracing/rtla/tests/timerlat.t | 15 +++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 tools/tracing/rtla/tests/bpf/bpf_action_map.c diff --git a/tools/tracing/rtla/Makefile b/tools/tracing/rtla/Makefile index 5f1529ce3693..aef814b639b7 100644 --- a/tools/tracing/rtla/Makefile +++ b/tools/tracing/rtla/Makefile @@ -76,12 +76,18 @@ src/timerlat.skel.h: src/timerlat.bpf.o example/timerlat_bpf_action.o: example/timerlat_bpf_action.c $(QUIET_CLANG)$(CLANG) -g -O2 -target bpf -c $(filter %.c,$^) -o $@ + +tests/bpf/bpf_action_map.o: tests/bpf/bpf_action_map.c + $(QUIET_CLANG)$(CLANG) -g -O2 -target bpf -c $(filter %.c,$^) -o $@ else src/timerlat.skel.h: $(Q)echo '/* BPF skeleton is disabled */' > src/timerlat.skel.h example/timerlat_bpf_action.o: example/timerlat_bpf_action.c $(Q)echo "BPF skeleton support is disabled, skipping example/timerlat_bpf_action.o" + +tests/bpf/bpf_action_map.o: tests/bpf/bpf_action_map.c + $(Q)echo "BPF skeleton support is disabled, skipping tests/bpf/bpf_action_map.o" endif $(RTLA): $(RTLA_IN) @@ -103,7 +109,7 @@ clean: doc_clean fixdep-clean $(Q)rm -f rtla rtla-static fixdep FEATURE-DUMP rtla-* $(Q)rm -rf feature $(Q)rm -f src/timerlat.bpf.o src/timerlat.skel.h example/timerlat_bpf_action.o -check: $(RTLA) - RTLA=$(RTLA) prove -o -f tests/ +check: $(RTLA) tests/bpf/bpf_action_map.o + RTLA=$(RTLA) BPFTOOL=$(SYSTEM_BPFTOOL) prove -o -f tests/ examples: example/timerlat_bpf_action.o .PHONY: FORCE clean check diff --git a/tools/tracing/rtla/tests/bpf/bpf_action_map.c b/tools/tracing/rtla/tests/bpf/bpf_action_map.c new file mode 100644 index 000000000000..1686e0b858e6 --- /dev/null +++ b/tools/tracing/rtla/tests/bpf/bpf_action_map.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include + +char LICENSE[] SEC("license") = "GPL"; + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 1); + __type(key, unsigned int); + __type(value, unsigned long long); +} rtla_test_map SEC(".maps"); + +struct trace_event_raw_timerlat_sample; + +SEC("tp/timerlat_action") +int action_handler(struct trace_event_raw_timerlat_sample *tp_args) +{ + unsigned int key = 0; + unsigned long long value = 42; + + bpf_map_update_elem(&rtla_test_map, &key, &value, BPF_ANY); + + return 0; +} diff --git a/tools/tracing/rtla/tests/timerlat.t b/tools/tracing/rtla/tests/timerlat.t index bbaa1897d8a8..fd4935fd7b49 100644 --- a/tools/tracing/rtla/tests/timerlat.t +++ b/tools/tracing/rtla/tests/timerlat.t @@ -67,6 +67,21 @@ check "hist with trace output at end" \ "timerlat hist -d 1s --on-end trace" 0 "^ Saving trace to timerlat_trace.txt$" check "top with trace output at end" \ "timerlat top -d 1s --on-end trace" 0 "^ Saving trace to timerlat_trace.txt$" + +# BPF action program tests +if [ "$option" -eq 0 ] +then + # Test BPF action program properly in BPF mode + [ -z "$BPFTOOL" ] && BPFTOOL=bpftool + check "hist with BPF action program (BPF mode)" \ + "timerlat hist -T 2 --bpf-action tests/bpf/bpf_action_map.o --on-threshold shell,command='$BPFTOOL map dump name rtla_test_map'" \ + 2 '"value": 42' +else + # Test BPF action program failure in non-BPF mode + check "hist with BPF action program (non-BPF mode)" \ + "timerlat hist -T 2 --bpf-action tests/bpf/bpf_action_map.o" \ + 1 "BPF actions are not supported in tracefs-only mode" +fi done test_end From fbb8ed6682f84e6e27c798a3117b0bcd4d0623c4 Mon Sep 17 00:00:00 2001 From: Tomas Glozar Date: Wed, 26 Nov 2025 15:42:03 +0100 Subject: [PATCH 08/30] rtla/tests: Run Test::Harness in verbose mode Add -v flag to prove command to also print the names of tests that succeeded, not only those that failed, to allow easier debugging of the test suite. Also, drop printing the option and value to stdout in check_with_osnoise_options, which was a debugging print that was accidentally left in the final commit, and which would be otherwise now visible in make check output, as stdout is no longer suppressed. Suggested-by: Crystal Wood Reviewed-by: Wander Lairson Costa Link: https://lore.kernel.org/r/20251126144205.331954-6-tglozar@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/Makefile | 2 +- tools/tracing/rtla/tests/engine.sh | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/tracing/rtla/Makefile b/tools/tracing/rtla/Makefile index aef814b639b7..2701256abaf3 100644 --- a/tools/tracing/rtla/Makefile +++ b/tools/tracing/rtla/Makefile @@ -110,6 +110,6 @@ clean: doc_clean fixdep-clean $(Q)rm -rf feature $(Q)rm -f src/timerlat.bpf.o src/timerlat.skel.h example/timerlat_bpf_action.o check: $(RTLA) tests/bpf/bpf_action_map.o - RTLA=$(RTLA) BPFTOOL=$(SYSTEM_BPFTOOL) prove -o -f tests/ + RTLA=$(RTLA) BPFTOOL=$(SYSTEM_BPFTOOL) prove -o -f -v tests/ examples: example/timerlat_bpf_action.o .PHONY: FORCE clean check diff --git a/tools/tracing/rtla/tests/engine.sh b/tools/tracing/rtla/tests/engine.sh index c7de3d6ed6a8..ed261e07c6d9 100644 --- a/tools/tracing/rtla/tests/engine.sh +++ b/tools/tracing/rtla/tests/engine.sh @@ -105,7 +105,6 @@ check_with_osnoise_options() { [ "$1" == "" ] && continue option=$(echo $1 | cut -d '=' -f 1) value=$(echo $1 | cut -d '=' -f 2) - echo "option: $option, value: $value" echo "$value" > "/sys/kernel/tracing/osnoise/$option" || return 1 done fi From 6627556c16fb1122e71110f57a90a961589ad8bf Mon Sep 17 00:00:00 2001 From: Tomas Glozar Date: Wed, 26 Nov 2025 15:42:04 +0100 Subject: [PATCH 09/30] Documentation/rtla: Rename sample/ to example/ The sample/ directory in tools/tracing/rtla was renamed to example/ in an earlier commit. Rename it also in the documentation. Reviewed-by: Wander Lairson Costa Link: https://lore.kernel.org/r/20251126144205.331954-7-tglozar@redhat.com Signed-off-by: Tomas Glozar --- Documentation/tools/rtla/common_timerlat_options.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/tools/rtla/common_timerlat_options.txt b/Documentation/tools/rtla/common_timerlat_options.txt index 33070b264cae..0cf7eca1f7b6 100644 --- a/Documentation/tools/rtla/common_timerlat_options.txt +++ b/Documentation/tools/rtla/common_timerlat_options.txt @@ -64,4 +64,4 @@ Set timerlat to run without workload, waiting for the user to dispatch a per-cpu task that waits for a new period on the tracing/osnoise/per_cpu/cpu$ID/timerlat_fd. - See linux/tools/rtla/sample/timerlat_load.py for an example of user-load code. + See linux/tools/rtla/example/timerlat_load.py for an example of user-load code. From 26e1a9bd4dd3c03336b608d8068f045d87c8ee6a Mon Sep 17 00:00:00 2001 From: Tomas Glozar Date: Wed, 26 Nov 2025 15:42:05 +0100 Subject: [PATCH 10/30] Documentation/rtla: Document --bpf-action option Add new option --bpf-action into common_timerlat_options.txt, including the format in which it takes the BPF program, and a reference to an example. Link: https://lore.kernel.org/r/20251126144205.331954-8-tglozar@redhat.com Signed-off-by: Tomas Glozar --- .../tools/rtla/common_timerlat_options.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Documentation/tools/rtla/common_timerlat_options.txt b/Documentation/tools/rtla/common_timerlat_options.txt index 0cf7eca1f7b6..07a285fcf7cf 100644 --- a/Documentation/tools/rtla/common_timerlat_options.txt +++ b/Documentation/tools/rtla/common_timerlat_options.txt @@ -65,3 +65,21 @@ Set timerlat to run without workload, waiting for the user to dispatch a per-cpu task that waits for a new period on the tracing/osnoise/per_cpu/cpu$ID/timerlat_fd. See linux/tools/rtla/example/timerlat_load.py for an example of user-load code. + +**--bpf-action** *bpf-program* + + Loads a BPF program from an ELF file and executes it when a latency threshold is exceeded. + + The BPF program must be a valid ELF file loadable with libbpf. The program must contain + a function named ``action_handler``, stored in an ELF section with the ``tp_`` prefix. + The prefix is used by libbpf to set BPF program type to BPF_PROG_TYPE_TRACEPOINT. + + The program receives a ``struct trace_event_raw_timerlat_sample`` parameter + containing timerlat sample data. + + An example is provided in ``tools/tracing/rtla/example/timerlat_bpf_action.c``. + This example demonstrates how to create a BPF program that prints latency information using + bpf_trace_printk() when a threshold is exceeded. + + **Note**: BPF actions require BPF support to be available. If BPF is not available + or disabled, the tool falls back to tracefs mode and BPF actions are not supported. From 850cd24cb6d648262b994b99e189409b21a2c09b Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Tue, 9 Dec 2025 12:00:40 +0200 Subject: [PATCH 11/30] tools/rtla: Add common_parse_options() Each rtla tool duplicates parsing of many common options. This creates maintenance overhead and risks inconsistencies when updating these options. Add common_parse_options() to centralize parsing of options used across all tools. Common options to be migrated in future patches. Changes since v1: - restore opterr Signed-off-by: Costa Shulyupin Link: https://lore.kernel.org/r/20251209100047.2692515-1-costa.shul@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/common.c | 35 ++++++++++++++++++++++++++ tools/tracing/rtla/src/common.h | 1 + tools/tracing/rtla/src/osnoise_hist.c | 3 +++ tools/tracing/rtla/src/osnoise_top.c | 3 +++ tools/tracing/rtla/src/timerlat_hist.c | 3 +++ tools/tracing/rtla/src/timerlat_top.c | 3 +++ 6 files changed, 48 insertions(+) diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c index 009a4bce9737..c01de7972bea 100644 --- a/tools/tracing/rtla/src/common.c +++ b/tools/tracing/rtla/src/common.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "common.h" struct trace_instance *trace_inst; @@ -38,6 +39,40 @@ static void set_signals(struct common_params *params) } } +/* + * common_parse_options - parse common command line options + * + * @argc: argument count + * @argv: argument vector + * @common: common parameters structure + * + * Parse command line options that are common to all rtla tools. + * + * Returns: non zero if a common option was parsed, or 0 + * if the option should be handled by tool-specific parsing. + */ +int common_parse_options(int argc, char **argv, struct common_params *common) +{ + int saved_state = optind; + int c; + + static struct option long_options[] = { + {0, 0, 0, 0} + }; + + opterr = 0; + c = getopt_long(argc, argv, "", long_options, NULL); + opterr = 1; + + switch (c) { + default: + optind = saved_state; + return 0; + } + + return c; +} + /* * common_apply_config - apply common configs to the initialized tool */ diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h index c48c9bfd20e3..ef17ea5be540 100644 --- a/tools/tracing/rtla/src/common.h +++ b/tools/tracing/rtla/src/common.h @@ -156,6 +156,7 @@ int osnoise_set_stop_us(struct osnoise_context *context, long long stop_us); int osnoise_set_stop_total_us(struct osnoise_context *context, long long stop_total_us); +int common_parse_options(int argc, char **argv, struct common_params *common); int common_apply_config(struct osnoise_tool *tool, struct common_params *params); int top_main_loop(struct osnoise_tool *tool); int hist_main_loop(struct osnoise_tool *tool); diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c index 372128db9e4a..d5c78e07bf60 100644 --- a/tools/tracing/rtla/src/osnoise_hist.c +++ b/tools/tracing/rtla/src/osnoise_hist.c @@ -512,6 +512,9 @@ static struct common_params {0, 0, 0, 0} }; + if (common_parse_options(argc, argv, ¶ms->common)) + continue; + c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:p:P:r:s:S:t::T:01234:5:6:7:", long_options, NULL); diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c index 1db1d946b600..2bb154da1139 100644 --- a/tools/tracing/rtla/src/osnoise_top.c +++ b/tools/tracing/rtla/src/osnoise_top.c @@ -363,6 +363,9 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) {0, 0, 0, 0} }; + if (common_parse_options(argc, argv, ¶ms->common)) + continue; + c = getopt_long(argc, argv, "a:c:C::d:De:hH:p:P:qr:s:S:t::T:0:1:2:3:", long_options, NULL); diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c index ec43e6fda743..a17111b6aa6d 100644 --- a/tools/tracing/rtla/src/timerlat_hist.c +++ b/tools/tracing/rtla/src/timerlat_hist.c @@ -830,6 +830,9 @@ static struct common_params {0, 0, 0, 0} }; + if (common_parse_options(argc, argv, ¶ms->common)) + continue; + c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:i:knp:P:s:t::T:uU0123456:7:8:9\1\2:\3:", long_options, NULL); diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index af20b3eee472..b14a785361b1 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -594,6 +594,9 @@ static struct common_params {0, 0, 0, 0} }; + if (common_parse_options(argc, argv, ¶ms->common)) + continue; + c = getopt_long(argc, argv, "a:c:C::d:De:hH:i:knp:P:qs:t::T:uU0:1:2:345:6:7:", long_options, NULL); From 28dc445919bf4019ffdaf65d94bf26ace25d4a5e Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Tue, 9 Dec 2025 12:00:41 +0200 Subject: [PATCH 12/30] tools/rtla: Consolidate -c/--cpus option parsing Each rtla tool duplicates parsing of -c/--cpus. Migrate the option parsing from individual tools to the common_parse_options(). Signed-off-by: Costa Shulyupin Link: https://lore.kernel.org/r/20251209100047.2692515-2-costa.shul@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/common.c | 8 +++++++- tools/tracing/rtla/src/osnoise_hist.c | 9 +-------- tools/tracing/rtla/src/osnoise_top.c | 9 +-------- tools/tracing/rtla/src/timerlat_hist.c | 9 +-------- tools/tracing/rtla/src/timerlat_top.c | 9 +-------- 5 files changed, 11 insertions(+), 33 deletions(-) diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c index c01de7972bea..1b9e0108b0ba 100644 --- a/tools/tracing/rtla/src/common.c +++ b/tools/tracing/rtla/src/common.c @@ -57,14 +57,20 @@ int common_parse_options(int argc, char **argv, struct common_params *common) int c; static struct option long_options[] = { + {"cpus", required_argument, 0, 'c'}, {0, 0, 0, 0} }; opterr = 0; - c = getopt_long(argc, argv, "", long_options, NULL); + c = getopt_long(argc, argv, "c:", long_options, NULL); opterr = 1; switch (c) { + case 'c': + if (parse_cpu_set(optarg, &common->monitored_cpus)) + fatal("Invalid -c cpu list"); + common->cpus = optarg; + break; default: optind = saved_state; return 0; diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c index d5c78e07bf60..443cb7f0e3a2 100644 --- a/tools/tracing/rtla/src/osnoise_hist.c +++ b/tools/tracing/rtla/src/osnoise_hist.c @@ -485,7 +485,6 @@ static struct common_params {"auto", required_argument, 0, 'a'}, {"bucket-size", required_argument, 0, 'b'}, {"entries", required_argument, 0, 'E'}, - {"cpus", required_argument, 0, 'c'}, {"cgroup", optional_argument, 0, 'C'}, {"debug", no_argument, 0, 'D'}, {"duration", required_argument, 0, 'd'}, @@ -515,7 +514,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:p:P:r:s:S:t::T:01234:5:6:7:", + c = getopt_long(argc, argv, "a:C::b:d:e:E:DhH:p:P:r:s:S:t::T:01234:5:6:7:", long_options, NULL); /* detect the end of the options. */ @@ -541,12 +540,6 @@ static struct common_params params->common.hist.bucket_size >= 1000000) fatal("Bucket size needs to be > 0 and <= 1000000"); break; - case 'c': - retval = parse_cpu_set(optarg, ¶ms->common.monitored_cpus); - if (retval) - fatal("Invalid -c cpu list"); - params->common.cpus = optarg; - break; case 'C': params->common.cgroup = 1; params->common.cgroup_name = parse_optional_arg(argc, argv); diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c index 2bb154da1139..8ba0757225b3 100644 --- a/tools/tracing/rtla/src/osnoise_top.c +++ b/tools/tracing/rtla/src/osnoise_top.c @@ -339,7 +339,6 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) while (1) { static struct option long_options[] = { {"auto", required_argument, 0, 'a'}, - {"cpus", required_argument, 0, 'c'}, {"cgroup", optional_argument, 0, 'C'}, {"debug", no_argument, 0, 'D'}, {"duration", required_argument, 0, 'd'}, @@ -366,7 +365,7 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:c:C::d:De:hH:p:P:qr:s:S:t::T:0:1:2:3:", + c = getopt_long(argc, argv, "a:C::d:De:hH:p:P:qr:s:S:t::T:0:1:2:3:", long_options, NULL); /* Detect the end of the options. */ @@ -385,12 +384,6 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) if (!trace_output) trace_output = "osnoise_trace.txt"; - break; - case 'c': - retval = parse_cpu_set(optarg, ¶ms->common.monitored_cpus); - if (retval) - fatal("Invalid -c cpu list"); - params->common.cpus = optarg; break; case 'C': params->common.cgroup = 1; diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c index a17111b6aa6d..3571aa8233c1 100644 --- a/tools/tracing/rtla/src/timerlat_hist.c +++ b/tools/tracing/rtla/src/timerlat_hist.c @@ -791,7 +791,6 @@ static struct common_params while (1) { static struct option long_options[] = { {"auto", required_argument, 0, 'a'}, - {"cpus", required_argument, 0, 'c'}, {"cgroup", optional_argument, 0, 'C'}, {"bucket-size", required_argument, 0, 'b'}, {"debug", no_argument, 0, 'D'}, @@ -833,7 +832,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:c:C::b:d:e:E:DhH:i:knp:P:s:t::T:uU0123456:7:8:9\1\2:\3:", + c = getopt_long(argc, argv, "a:C::b:d:e:E:DhH:i:knp:P:s:t::T:uU0123456:7:8:9\1\2:\3:", long_options, NULL); /* detect the end of the options. */ @@ -855,12 +854,6 @@ static struct common_params if (!trace_output) trace_output = "timerlat_trace.txt"; - break; - case 'c': - retval = parse_cpu_set(optarg, ¶ms->common.monitored_cpus); - if (retval) - fatal("Invalid -c cpu list"); - params->common.cpus = optarg; break; case 'C': params->common.cgroup = 1; diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index b14a785361b1..b0a048cded29 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -561,7 +561,6 @@ static struct common_params while (1) { static struct option long_options[] = { {"auto", required_argument, 0, 'a'}, - {"cpus", required_argument, 0, 'c'}, {"cgroup", optional_argument, 0, 'C'}, {"debug", no_argument, 0, 'D'}, {"duration", required_argument, 0, 'd'}, @@ -597,7 +596,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:c:C::d:De:hH:i:knp:P:qs:t::T:uU0:1:2:345:6:7:", + c = getopt_long(argc, argv, "a:C::d:De:hH:i:knp:P:qs:t::T:uU0:1:2:345:6:7:", long_options, NULL); /* detect the end of the options. */ @@ -634,12 +633,6 @@ static struct common_params /* set aa_only to avoid parsing the trace */ params->common.aa_only = 1; break; - case 'c': - retval = parse_cpu_set(optarg, ¶ms->common.monitored_cpus); - if (retval) - fatal("Invalid -c cpu list"); - params->common.cpus = optarg; - break; case 'C': params->common.cgroup = 1; params->common.cgroup_name = optarg; From edb23c8372222395fd4e4297240cbe2191425dbf Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Tue, 9 Dec 2025 12:00:42 +0200 Subject: [PATCH 13/30] tools/rtla: Consolidate -C/--cgroup option parsing Each rtla tool duplicates parsing of -C/--cgroup. Migrate the option parsing from individual tools to the common_parse_options(). Signed-off-by: Costa Shulyupin Link: https://lore.kernel.org/r/20251209100047.2692515-3-costa.shul@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/common.c | 7 ++++++- tools/tracing/rtla/src/osnoise_hist.c | 7 +------ tools/tracing/rtla/src/osnoise_top.c | 7 +------ tools/tracing/rtla/src/timerlat_hist.c | 7 +------ tools/tracing/rtla/src/timerlat_top.c | 7 +------ 5 files changed, 10 insertions(+), 25 deletions(-) diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c index 1b9e0108b0ba..3400836f66ef 100644 --- a/tools/tracing/rtla/src/common.c +++ b/tools/tracing/rtla/src/common.c @@ -58,11 +58,12 @@ int common_parse_options(int argc, char **argv, struct common_params *common) static struct option long_options[] = { {"cpus", required_argument, 0, 'c'}, + {"cgroup", optional_argument, 0, 'C'}, {0, 0, 0, 0} }; opterr = 0; - c = getopt_long(argc, argv, "c:", long_options, NULL); + c = getopt_long(argc, argv, "c:C::", long_options, NULL); opterr = 1; switch (c) { @@ -71,6 +72,10 @@ int common_parse_options(int argc, char **argv, struct common_params *common) fatal("Invalid -c cpu list"); common->cpus = optarg; break; + case 'C': + common->cgroup = 1; + common->cgroup_name = parse_optional_arg(argc, argv); + break; default: optind = saved_state; return 0; diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c index 443cb7f0e3a2..bcd4b4c96354 100644 --- a/tools/tracing/rtla/src/osnoise_hist.c +++ b/tools/tracing/rtla/src/osnoise_hist.c @@ -485,7 +485,6 @@ static struct common_params {"auto", required_argument, 0, 'a'}, {"bucket-size", required_argument, 0, 'b'}, {"entries", required_argument, 0, 'E'}, - {"cgroup", optional_argument, 0, 'C'}, {"debug", no_argument, 0, 'D'}, {"duration", required_argument, 0, 'd'}, {"house-keeping", required_argument, 0, 'H'}, @@ -514,7 +513,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:C::b:d:e:E:DhH:p:P:r:s:S:t::T:01234:5:6:7:", + c = getopt_long(argc, argv, "a:b:d:e:E:DhH:p:P:r:s:S:t::T:01234:5:6:7:", long_options, NULL); /* detect the end of the options. */ @@ -540,10 +539,6 @@ static struct common_params params->common.hist.bucket_size >= 1000000) fatal("Bucket size needs to be > 0 and <= 1000000"); break; - case 'C': - params->common.cgroup = 1; - params->common.cgroup_name = parse_optional_arg(argc, argv); - break; case 'D': config_debug = 1; break; diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c index 8ba0757225b3..2799dd75a4e2 100644 --- a/tools/tracing/rtla/src/osnoise_top.c +++ b/tools/tracing/rtla/src/osnoise_top.c @@ -339,7 +339,6 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) while (1) { static struct option long_options[] = { {"auto", required_argument, 0, 'a'}, - {"cgroup", optional_argument, 0, 'C'}, {"debug", no_argument, 0, 'D'}, {"duration", required_argument, 0, 'd'}, {"event", required_argument, 0, 'e'}, @@ -365,7 +364,7 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:C::d:De:hH:p:P:qr:s:S:t::T:0:1:2:3:", + c = getopt_long(argc, argv, "a:d:De:hH:p:P:qr:s:S:t::T:0:1:2:3:", long_options, NULL); /* Detect the end of the options. */ @@ -384,10 +383,6 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) if (!trace_output) trace_output = "osnoise_trace.txt"; - break; - case 'C': - params->common.cgroup = 1; - params->common.cgroup_name = parse_optional_arg(argc, argv); break; case 'D': config_debug = 1; diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c index 3571aa8233c1..64c1dbb1fccc 100644 --- a/tools/tracing/rtla/src/timerlat_hist.c +++ b/tools/tracing/rtla/src/timerlat_hist.c @@ -791,7 +791,6 @@ static struct common_params while (1) { static struct option long_options[] = { {"auto", required_argument, 0, 'a'}, - {"cgroup", optional_argument, 0, 'C'}, {"bucket-size", required_argument, 0, 'b'}, {"debug", no_argument, 0, 'D'}, {"entries", required_argument, 0, 'E'}, @@ -832,7 +831,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:C::b:d:e:E:DhH:i:knp:P:s:t::T:uU0123456:7:8:9\1\2:\3:", + c = getopt_long(argc, argv, "a:b:d:e:E:DhH:i:knp:P:s:t::T:uU0123456:7:8:9\1\2:\3:", long_options, NULL); /* detect the end of the options. */ @@ -854,10 +853,6 @@ static struct common_params if (!trace_output) trace_output = "timerlat_trace.txt"; - break; - case 'C': - params->common.cgroup = 1; - params->common.cgroup_name = parse_optional_arg(argc, argv); break; case 'b': params->common.hist.bucket_size = get_llong_from_str(optarg); diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index b0a048cded29..bdc8bf265836 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -561,7 +561,6 @@ static struct common_params while (1) { static struct option long_options[] = { {"auto", required_argument, 0, 'a'}, - {"cgroup", optional_argument, 0, 'C'}, {"debug", no_argument, 0, 'D'}, {"duration", required_argument, 0, 'd'}, {"event", required_argument, 0, 'e'}, @@ -596,7 +595,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:C::d:De:hH:i:knp:P:qs:t::T:uU0:1:2:345:6:7:", + c = getopt_long(argc, argv, "a:d:De:hH:i:knp:P:qs:t::T:uU0:1:2:345:6:7:", long_options, NULL); /* detect the end of the options. */ @@ -633,10 +632,6 @@ static struct common_params /* set aa_only to avoid parsing the trace */ params->common.aa_only = 1; break; - case 'C': - params->common.cgroup = 1; - params->common.cgroup_name = optarg; - break; case 'D': config_debug = 1; break; From fd788c49a90328f5b2edaa87aa5af18648ade718 Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Tue, 9 Dec 2025 12:00:43 +0200 Subject: [PATCH 14/30] tools/rtla: Consolidate -D/--debug option parsing Each rtla tool duplicates parsing of -D/--debug. Migrate the option parsing from individual tools to the common_parse_options(). Signed-off-by: Costa Shulyupin Link: https://lore.kernel.org/r/20251209100047.2692515-4-costa.shul@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/common.c | 6 +++++- tools/tracing/rtla/src/osnoise_hist.c | 6 +----- tools/tracing/rtla/src/osnoise_top.c | 6 +----- tools/tracing/rtla/src/timerlat_hist.c | 6 +----- tools/tracing/rtla/src/timerlat_top.c | 6 +----- 5 files changed, 9 insertions(+), 21 deletions(-) diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c index 3400836f66ef..f71cf7c7f4e3 100644 --- a/tools/tracing/rtla/src/common.c +++ b/tools/tracing/rtla/src/common.c @@ -59,11 +59,12 @@ int common_parse_options(int argc, char **argv, struct common_params *common) static struct option long_options[] = { {"cpus", required_argument, 0, 'c'}, {"cgroup", optional_argument, 0, 'C'}, + {"debug", no_argument, 0, 'D'}, {0, 0, 0, 0} }; opterr = 0; - c = getopt_long(argc, argv, "c:C::", long_options, NULL); + c = getopt_long(argc, argv, "c:C::D", long_options, NULL); opterr = 1; switch (c) { @@ -76,6 +77,9 @@ int common_parse_options(int argc, char **argv, struct common_params *common) common->cgroup = 1; common->cgroup_name = parse_optional_arg(argc, argv); break; + case 'D': + config_debug = 1; + break; default: optind = saved_state; return 0; diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c index bcd4b4c96354..c9422b596622 100644 --- a/tools/tracing/rtla/src/osnoise_hist.c +++ b/tools/tracing/rtla/src/osnoise_hist.c @@ -485,7 +485,6 @@ static struct common_params {"auto", required_argument, 0, 'a'}, {"bucket-size", required_argument, 0, 'b'}, {"entries", required_argument, 0, 'E'}, - {"debug", no_argument, 0, 'D'}, {"duration", required_argument, 0, 'd'}, {"house-keeping", required_argument, 0, 'H'}, {"help", no_argument, 0, 'h'}, @@ -513,7 +512,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:b:d:e:E:DhH:p:P:r:s:S:t::T:01234:5:6:7:", + c = getopt_long(argc, argv, "a:b:d:e:E:hH:p:P:r:s:S:t::T:01234:5:6:7:", long_options, NULL); /* detect the end of the options. */ @@ -539,9 +538,6 @@ static struct common_params params->common.hist.bucket_size >= 1000000) fatal("Bucket size needs to be > 0 and <= 1000000"); break; - case 'D': - config_debug = 1; - break; case 'd': params->common.duration = parse_seconds_duration(optarg); if (!params->common.duration) diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c index 2799dd75a4e2..8d49042d10f0 100644 --- a/tools/tracing/rtla/src/osnoise_top.c +++ b/tools/tracing/rtla/src/osnoise_top.c @@ -339,7 +339,6 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) while (1) { static struct option long_options[] = { {"auto", required_argument, 0, 'a'}, - {"debug", no_argument, 0, 'D'}, {"duration", required_argument, 0, 'd'}, {"event", required_argument, 0, 'e'}, {"house-keeping", required_argument, 0, 'H'}, @@ -364,7 +363,7 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:d:De:hH:p:P:qr:s:S:t::T:0:1:2:3:", + c = getopt_long(argc, argv, "a:d:e:hH:p:P:qr:s:S:t::T:0:1:2:3:", long_options, NULL); /* Detect the end of the options. */ @@ -383,9 +382,6 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) if (!trace_output) trace_output = "osnoise_trace.txt"; - break; - case 'D': - config_debug = 1; break; case 'd': params->common.duration = parse_seconds_duration(optarg); diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c index 64c1dbb1fccc..c08f628047c1 100644 --- a/tools/tracing/rtla/src/timerlat_hist.c +++ b/tools/tracing/rtla/src/timerlat_hist.c @@ -792,7 +792,6 @@ static struct common_params static struct option long_options[] = { {"auto", required_argument, 0, 'a'}, {"bucket-size", required_argument, 0, 'b'}, - {"debug", no_argument, 0, 'D'}, {"entries", required_argument, 0, 'E'}, {"duration", required_argument, 0, 'd'}, {"house-keeping", required_argument, 0, 'H'}, @@ -831,7 +830,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:b:d:e:E:DhH:i:knp:P:s:t::T:uU0123456:7:8:9\1\2:\3:", + c = getopt_long(argc, argv, "a:b:d:e:E:hH:i:knp:P:s:t::T:uU0123456:7:8:9\1\2:\3:", long_options, NULL); /* detect the end of the options. */ @@ -860,9 +859,6 @@ static struct common_params params->common.hist.bucket_size >= 1000000) fatal("Bucket size needs to be > 0 and <= 1000000"); break; - case 'D': - config_debug = 1; - break; case 'd': params->common.duration = parse_seconds_duration(optarg); if (!params->common.duration) diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index bdc8bf265836..7c0a3f582273 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -561,7 +561,6 @@ static struct common_params while (1) { static struct option long_options[] = { {"auto", required_argument, 0, 'a'}, - {"debug", no_argument, 0, 'D'}, {"duration", required_argument, 0, 'd'}, {"event", required_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, @@ -595,7 +594,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:d:De:hH:i:knp:P:qs:t::T:uU0:1:2:345:6:7:", + c = getopt_long(argc, argv, "a:d:e:hH:i:knp:P:qs:t::T:uU0:1:2:345:6:7:", long_options, NULL); /* detect the end of the options. */ @@ -632,9 +631,6 @@ static struct common_params /* set aa_only to avoid parsing the trace */ params->common.aa_only = 1; break; - case 'D': - config_debug = 1; - break; case 'd': params->common.duration = parse_seconds_duration(optarg); if (!params->common.duration) From 76975581fb0eba03820fe312094981c995c225f9 Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Tue, 9 Dec 2025 12:00:44 +0200 Subject: [PATCH 15/30] tools/rtla: Consolidate -d/--duration option parsing Each rtla tool duplicates parsing of -d/--duration. Migrate the option parsing from individual tools to the common_parse_options(). Signed-off-by: Costa Shulyupin Link: https://lore.kernel.org/r/20251209100047.2692515-5-costa.shul@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/common.c | 8 +++++++- tools/tracing/rtla/src/osnoise_hist.c | 8 +------- tools/tracing/rtla/src/osnoise_top.c | 8 +------- tools/tracing/rtla/src/timerlat_hist.c | 8 +------- tools/tracing/rtla/src/timerlat_top.c | 8 +------- 5 files changed, 11 insertions(+), 29 deletions(-) diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c index f71cf7c7f4e3..0776f1568d23 100644 --- a/tools/tracing/rtla/src/common.c +++ b/tools/tracing/rtla/src/common.c @@ -60,11 +60,12 @@ int common_parse_options(int argc, char **argv, struct common_params *common) {"cpus", required_argument, 0, 'c'}, {"cgroup", optional_argument, 0, 'C'}, {"debug", no_argument, 0, 'D'}, + {"duration", required_argument, 0, 'd'}, {0, 0, 0, 0} }; opterr = 0; - c = getopt_long(argc, argv, "c:C::D", long_options, NULL); + c = getopt_long(argc, argv, "c:C::Dd:", long_options, NULL); opterr = 1; switch (c) { @@ -80,6 +81,11 @@ int common_parse_options(int argc, char **argv, struct common_params *common) case 'D': config_debug = 1; break; + case 'd': + common->duration = parse_seconds_duration(optarg); + if (!common->duration) + fatal("Invalid -d duration"); + break; default: optind = saved_state; return 0; diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c index c9422b596622..f34c88fd57e2 100644 --- a/tools/tracing/rtla/src/osnoise_hist.c +++ b/tools/tracing/rtla/src/osnoise_hist.c @@ -485,7 +485,6 @@ static struct common_params {"auto", required_argument, 0, 'a'}, {"bucket-size", required_argument, 0, 'b'}, {"entries", required_argument, 0, 'E'}, - {"duration", required_argument, 0, 'd'}, {"house-keeping", required_argument, 0, 'H'}, {"help", no_argument, 0, 'h'}, {"period", required_argument, 0, 'p'}, @@ -512,7 +511,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:b:d:e:E:hH:p:P:r:s:S:t::T:01234:5:6:7:", + c = getopt_long(argc, argv, "a:b:e:E:hH:p:P:r:s:S:t::T:01234:5:6:7:", long_options, NULL); /* detect the end of the options. */ @@ -538,11 +537,6 @@ static struct common_params params->common.hist.bucket_size >= 1000000) fatal("Bucket size needs to be > 0 and <= 1000000"); break; - case 'd': - params->common.duration = parse_seconds_duration(optarg); - if (!params->common.duration) - fatal("Invalid -D duration"); - break; case 'e': tevent = trace_event_alloc(optarg); if (!tevent) diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c index 8d49042d10f0..695c6ecf0098 100644 --- a/tools/tracing/rtla/src/osnoise_top.c +++ b/tools/tracing/rtla/src/osnoise_top.c @@ -339,7 +339,6 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) while (1) { static struct option long_options[] = { {"auto", required_argument, 0, 'a'}, - {"duration", required_argument, 0, 'd'}, {"event", required_argument, 0, 'e'}, {"house-keeping", required_argument, 0, 'H'}, {"help", no_argument, 0, 'h'}, @@ -363,7 +362,7 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:d:e:hH:p:P:qr:s:S:t::T:0:1:2:3:", + c = getopt_long(argc, argv, "a:e:hH:p:P:qr:s:S:t::T:0:1:2:3:", long_options, NULL); /* Detect the end of the options. */ @@ -383,11 +382,6 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) trace_output = "osnoise_trace.txt"; break; - case 'd': - params->common.duration = parse_seconds_duration(optarg); - if (!params->common.duration) - fatal("Invalid -d duration"); - break; case 'e': tevent = trace_event_alloc(optarg); if (!tevent) diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c index c08f628047c1..d625dbe44676 100644 --- a/tools/tracing/rtla/src/timerlat_hist.c +++ b/tools/tracing/rtla/src/timerlat_hist.c @@ -793,7 +793,6 @@ static struct common_params {"auto", required_argument, 0, 'a'}, {"bucket-size", required_argument, 0, 'b'}, {"entries", required_argument, 0, 'E'}, - {"duration", required_argument, 0, 'd'}, {"house-keeping", required_argument, 0, 'H'}, {"help", no_argument, 0, 'h'}, {"irq", required_argument, 0, 'i'}, @@ -830,7 +829,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:b:d:e:E:hH:i:knp:P:s:t::T:uU0123456:7:8:9\1\2:\3:", + c = getopt_long(argc, argv, "a:b:e:E:hH:i:knp:P:s:t::T:uU0123456:7:8:9\1\2:\3:", long_options, NULL); /* detect the end of the options. */ @@ -859,11 +858,6 @@ static struct common_params params->common.hist.bucket_size >= 1000000) fatal("Bucket size needs to be > 0 and <= 1000000"); break; - case 'd': - params->common.duration = parse_seconds_duration(optarg); - if (!params->common.duration) - fatal("Invalid -D duration"); - break; case 'e': tevent = trace_event_alloc(optarg); if (!tevent) diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index 7c0a3f582273..95e949f49cbd 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -561,7 +561,6 @@ static struct common_params while (1) { static struct option long_options[] = { {"auto", required_argument, 0, 'a'}, - {"duration", required_argument, 0, 'd'}, {"event", required_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"house-keeping", required_argument, 0, 'H'}, @@ -594,7 +593,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:d:e:hH:i:knp:P:qs:t::T:uU0:1:2:345:6:7:", + c = getopt_long(argc, argv, "a:e:hH:i:knp:P:qs:t::T:uU0:1:2:345:6:7:", long_options, NULL); /* detect the end of the options. */ @@ -631,11 +630,6 @@ static struct common_params /* set aa_only to avoid parsing the trace */ params->common.aa_only = 1; break; - case 'd': - params->common.duration = parse_seconds_duration(optarg); - if (!params->common.duration) - fatal("Invalid -d duration"); - break; case 'e': tevent = trace_event_alloc(optarg); if (!tevent) From c93c25fca5ab3c27b42f1f941871209573c0b41b Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Tue, 9 Dec 2025 12:00:45 +0200 Subject: [PATCH 16/30] tools/rtla: Consolidate -e/--event option parsing Each rtla tool duplicates parsing of -e/--event. Migrate the option parsing from individual tools to the common_parse_options(). Signed-off-by: Costa Shulyupin Link: https://lore.kernel.org/r/20251209100047.2692515-6-costa.shul@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/common.c | 13 ++++++++++++- tools/tracing/rtla/src/osnoise_hist.c | 14 +------------- tools/tracing/rtla/src/osnoise_top.c | 14 +------------- tools/tracing/rtla/src/timerlat_hist.c | 14 +------------- tools/tracing/rtla/src/timerlat_top.c | 13 +------------ 5 files changed, 16 insertions(+), 52 deletions(-) diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c index 0776f1568d23..fbd38d80f1ac 100644 --- a/tools/tracing/rtla/src/common.c +++ b/tools/tracing/rtla/src/common.c @@ -53,6 +53,7 @@ static void set_signals(struct common_params *params) */ int common_parse_options(int argc, char **argv, struct common_params *common) { + struct trace_events *tevent; int saved_state = optind; int c; @@ -61,11 +62,12 @@ int common_parse_options(int argc, char **argv, struct common_params *common) {"cgroup", optional_argument, 0, 'C'}, {"debug", no_argument, 0, 'D'}, {"duration", required_argument, 0, 'd'}, + {"event", required_argument, 0, 'e'}, {0, 0, 0, 0} }; opterr = 0; - c = getopt_long(argc, argv, "c:C::Dd:", long_options, NULL); + c = getopt_long(argc, argv, "c:C::Dd:e:", long_options, NULL); opterr = 1; switch (c) { @@ -86,6 +88,15 @@ int common_parse_options(int argc, char **argv, struct common_params *common) if (!common->duration) fatal("Invalid -d duration"); break; + case 'e': + tevent = trace_event_alloc(optarg); + if (!tevent) + fatal("Error alloc trace event"); + + if (common->events) + tevent->next = common->events; + common->events = tevent; + break; default: optind = saved_state; return 0; diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c index f34c88fd57e2..8b3eab6092bb 100644 --- a/tools/tracing/rtla/src/osnoise_hist.c +++ b/tools/tracing/rtla/src/osnoise_hist.c @@ -463,7 +463,6 @@ static struct common_params *osnoise_hist_parse_args(int argc, char *argv[]) { struct osnoise_params *params; - struct trace_events *tevent; int retval; int c; char *trace_output = NULL; @@ -493,7 +492,6 @@ static struct common_params {"stop", required_argument, 0, 's'}, {"stop-total", required_argument, 0, 'S'}, {"trace", optional_argument, 0, 't'}, - {"event", required_argument, 0, 'e'}, {"threshold", required_argument, 0, 'T'}, {"no-header", no_argument, 0, '0'}, {"no-summary", no_argument, 0, '1'}, @@ -511,7 +509,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:b:e:E:hH:p:P:r:s:S:t::T:01234:5:6:7:", + c = getopt_long(argc, argv, "a:b:E:hH:p:P:r:s:S:t::T:01234:5:6:7:", long_options, NULL); /* detect the end of the options. */ @@ -537,16 +535,6 @@ static struct common_params params->common.hist.bucket_size >= 1000000) fatal("Bucket size needs to be > 0 and <= 1000000"); break; - case 'e': - tevent = trace_event_alloc(optarg); - if (!tevent) - fatal("Error alloc trace event"); - - if (params->common.events) - tevent->next = params->common.events; - - params->common.events = tevent; - break; case 'E': params->common.hist.entries = get_llong_from_str(optarg); if (params->common.hist.entries < 10 || diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c index 695c6ecf0098..47aac00e2848 100644 --- a/tools/tracing/rtla/src/osnoise_top.c +++ b/tools/tracing/rtla/src/osnoise_top.c @@ -315,7 +315,6 @@ static void osnoise_top_usage(struct osnoise_params *params) struct common_params *osnoise_top_parse_args(int argc, char **argv) { struct osnoise_params *params; - struct trace_events *tevent; int retval; int c; char *trace_output = NULL; @@ -339,7 +338,6 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) while (1) { static struct option long_options[] = { {"auto", required_argument, 0, 'a'}, - {"event", required_argument, 0, 'e'}, {"house-keeping", required_argument, 0, 'H'}, {"help", no_argument, 0, 'h'}, {"period", required_argument, 0, 'p'}, @@ -362,7 +360,7 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:e:hH:p:P:qr:s:S:t::T:0:1:2:3:", + c = getopt_long(argc, argv, "a:hH:p:P:qr:s:S:t::T:0:1:2:3:", long_options, NULL); /* Detect the end of the options. */ @@ -381,16 +379,6 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) if (!trace_output) trace_output = "osnoise_trace.txt"; - break; - case 'e': - tevent = trace_event_alloc(optarg); - if (!tevent) - fatal("Error alloc trace event"); - - if (params->common.events) - tevent->next = params->common.events; - params->common.events = tevent; - break; case 'h': case '?': diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c index d625dbe44676..32424e2bd34a 100644 --- a/tools/tracing/rtla/src/timerlat_hist.c +++ b/tools/tracing/rtla/src/timerlat_hist.c @@ -761,7 +761,6 @@ static struct common_params *timerlat_hist_parse_args(int argc, char *argv[]) { struct timerlat_params *params; - struct trace_events *tevent; int auto_thresh; int retval; int c; @@ -805,7 +804,6 @@ static struct common_params {"user-threads", no_argument, 0, 'u'}, {"kernel-threads", no_argument, 0, 'k'}, {"user-load", no_argument, 0, 'U'}, - {"event", required_argument, 0, 'e'}, {"no-irq", no_argument, 0, '0'}, {"no-thread", no_argument, 0, '1'}, {"no-header", no_argument, 0, '2'}, @@ -829,7 +827,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:b:e:E:hH:i:knp:P:s:t::T:uU0123456:7:8:9\1\2:\3:", + c = getopt_long(argc, argv, "a:b:E:hH:i:knp:P:s:t::T:uU0123456:7:8:9\1\2:\3:", long_options, NULL); /* detect the end of the options. */ @@ -858,16 +856,6 @@ static struct common_params params->common.hist.bucket_size >= 1000000) fatal("Bucket size needs to be > 0 and <= 1000000"); break; - case 'e': - tevent = trace_event_alloc(optarg); - if (!tevent) - fatal("Error alloc trace event"); - - if (params->common.events) - tevent->next = params->common.events; - - params->common.events = tevent; - break; case 'E': params->common.hist.entries = get_llong_from_str(optarg); if (params->common.hist.entries < 10 || diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index 95e949f49cbd..928d887e0c2e 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -533,7 +533,6 @@ static struct common_params *timerlat_top_parse_args(int argc, char **argv) { struct timerlat_params *params; - struct trace_events *tevent; long long auto_thresh; int retval; int c; @@ -561,7 +560,6 @@ static struct common_params while (1) { static struct option long_options[] = { {"auto", required_argument, 0, 'a'}, - {"event", required_argument, 0, 'e'}, {"help", no_argument, 0, 'h'}, {"house-keeping", required_argument, 0, 'H'}, {"irq", required_argument, 0, 'i'}, @@ -593,7 +591,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:e:hH:i:knp:P:qs:t::T:uU0:1:2:345:6:7:", + c = getopt_long(argc, argv, "a:hH:i:knp:P:qs:t::T:uU0:1:2:345:6:7:", long_options, NULL); /* detect the end of the options. */ @@ -630,15 +628,6 @@ static struct common_params /* set aa_only to avoid parsing the trace */ params->common.aa_only = 1; break; - case 'e': - tevent = trace_event_alloc(optarg); - if (!tevent) - fatal("Error alloc trace event"); - - if (params->common.events) - tevent->next = params->common.events; - params->common.events = tevent; - break; case 'h': case '?': timerlat_top_usage(); From 5cc90b14ee54591b890ad026ad5e01b2960c3a31 Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Tue, 9 Dec 2025 12:00:46 +0200 Subject: [PATCH 17/30] tools/rtla: Consolidate -P/--priority option parsing Each rtla tool duplicates parsing of -P/--priority. Migrate the option parsing from individual tools to the common_parse_options(). Signed-off-by: Costa Shulyupin Link: https://lore.kernel.org/r/20251209100047.2692515-7-costa.shul@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/common.c | 8 +++++++- tools/tracing/rtla/src/osnoise_hist.c | 9 +-------- tools/tracing/rtla/src/osnoise_top.c | 9 +-------- tools/tracing/rtla/src/timerlat_hist.c | 9 +-------- tools/tracing/rtla/src/timerlat_top.c | 9 +-------- 5 files changed, 11 insertions(+), 33 deletions(-) diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c index fbd38d80f1ac..90f1bbb7e189 100644 --- a/tools/tracing/rtla/src/common.c +++ b/tools/tracing/rtla/src/common.c @@ -63,11 +63,12 @@ int common_parse_options(int argc, char **argv, struct common_params *common) {"debug", no_argument, 0, 'D'}, {"duration", required_argument, 0, 'd'}, {"event", required_argument, 0, 'e'}, + {"priority", required_argument, 0, 'P'}, {0, 0, 0, 0} }; opterr = 0; - c = getopt_long(argc, argv, "c:C::Dd:e:", long_options, NULL); + c = getopt_long(argc, argv, "c:C::Dd:e:P:", long_options, NULL); opterr = 1; switch (c) { @@ -97,6 +98,11 @@ int common_parse_options(int argc, char **argv, struct common_params *common) tevent->next = common->events; common->events = tevent; break; + case 'P': + if (parse_prio(optarg, &common->sched_param) == -1) + fatal("Invalid -P priority"); + common->set_sched = 1; + break; default: optind = saved_state; return 0; diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c index 8b3eab6092bb..6e66726766a1 100644 --- a/tools/tracing/rtla/src/osnoise_hist.c +++ b/tools/tracing/rtla/src/osnoise_hist.c @@ -487,7 +487,6 @@ static struct common_params {"house-keeping", required_argument, 0, 'H'}, {"help", no_argument, 0, 'h'}, {"period", required_argument, 0, 'p'}, - {"priority", required_argument, 0, 'P'}, {"runtime", required_argument, 0, 'r'}, {"stop", required_argument, 0, 's'}, {"stop-total", required_argument, 0, 'S'}, @@ -509,7 +508,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:b:E:hH:p:P:r:s:S:t::T:01234:5:6:7:", + c = getopt_long(argc, argv, "a:b:E:hH:p:r:s:S:t::T:01234:5:6:7:", long_options, NULL); /* detect the end of the options. */ @@ -556,12 +555,6 @@ static struct common_params if (params->period > 10000000) fatal("Period longer than 10 s"); break; - case 'P': - retval = parse_prio(optarg, ¶ms->common.sched_param); - if (retval == -1) - fatal("Invalid -P priority"); - params->common.set_sched = 1; - break; case 'r': params->runtime = get_llong_from_str(optarg); if (params->runtime < 100) diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c index 47aac00e2848..7ac992ec7439 100644 --- a/tools/tracing/rtla/src/osnoise_top.c +++ b/tools/tracing/rtla/src/osnoise_top.c @@ -341,7 +341,6 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) {"house-keeping", required_argument, 0, 'H'}, {"help", no_argument, 0, 'h'}, {"period", required_argument, 0, 'p'}, - {"priority", required_argument, 0, 'P'}, {"quiet", no_argument, 0, 'q'}, {"runtime", required_argument, 0, 'r'}, {"stop", required_argument, 0, 's'}, @@ -360,7 +359,7 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:hH:p:P:qr:s:S:t::T:0:1:2:3:", + c = getopt_long(argc, argv, "a:hH:p:qr:s:S:t::T:0:1:2:3:", long_options, NULL); /* Detect the end of the options. */ @@ -395,12 +394,6 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) if (params->period > 10000000) fatal("Period longer than 10 s"); break; - case 'P': - retval = parse_prio(optarg, ¶ms->common.sched_param); - if (retval == -1) - fatal("Invalid -P priority"); - params->common.set_sched = 1; - break; case 'q': params->common.quiet = 1; break; diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c index 32424e2bd34a..99b416ccfc5b 100644 --- a/tools/tracing/rtla/src/timerlat_hist.c +++ b/tools/tracing/rtla/src/timerlat_hist.c @@ -797,7 +797,6 @@ static struct common_params {"irq", required_argument, 0, 'i'}, {"nano", no_argument, 0, 'n'}, {"period", required_argument, 0, 'p'}, - {"priority", required_argument, 0, 'P'}, {"stack", required_argument, 0, 's'}, {"thread", required_argument, 0, 'T'}, {"trace", optional_argument, 0, 't'}, @@ -827,7 +826,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:b:E:hH:i:knp:P:s:t::T:uU0123456:7:8:9\1\2:\3:", + c = getopt_long(argc, argv, "a:b:E:hH:i:knp:s:t::T:uU0123456:7:8:9\1\2:\3:", long_options, NULL); /* detect the end of the options. */ @@ -886,12 +885,6 @@ static struct common_params if (params->timerlat_period_us > 1000000) fatal("Period longer than 1 s"); break; - case 'P': - retval = parse_prio(optarg, ¶ms->common.sched_param); - if (retval == -1) - fatal("Invalid -P priority"); - params->common.set_sched = 1; - break; case 's': params->print_stack = get_llong_from_str(optarg); break; diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index 928d887e0c2e..027aad1b639f 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -565,7 +565,6 @@ static struct common_params {"irq", required_argument, 0, 'i'}, {"nano", no_argument, 0, 'n'}, {"period", required_argument, 0, 'p'}, - {"priority", required_argument, 0, 'P'}, {"quiet", no_argument, 0, 'q'}, {"stack", required_argument, 0, 's'}, {"thread", required_argument, 0, 'T'}, @@ -591,7 +590,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:hH:i:knp:P:qs:t::T:uU0:1:2:345:6:7:", + c = getopt_long(argc, argv, "a:hH:i:knp:qs:t::T:uU0:1:2:345:6:7:", long_options, NULL); /* detect the end of the options. */ @@ -652,12 +651,6 @@ static struct common_params if (params->timerlat_period_us > 1000000) fatal("Period longer than 1 s"); break; - case 'P': - retval = parse_prio(optarg, ¶ms->common.sched_param); - if (retval == -1) - fatal("Invalid -P priority"); - params->common.set_sched = 1; - break; case 'q': params->common.quiet = 1; break; From 0576be469ef18a9f3460f6f207183033ae8b90c5 Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Tue, 9 Dec 2025 12:00:47 +0200 Subject: [PATCH 18/30] tools/rtla: Consolidate -H/--house-keeping option parsing Each rtla tool duplicates parsing of -H/--house-keeping. Migrate the option parsing from individual tools to the common_parse_options(). Signed-off-by: Costa Shulyupin Link: https://lore.kernel.org/r/20251209100047.2692515-8-costa.shul@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/common.c | 8 +++++++- tools/tracing/rtla/src/osnoise_hist.c | 9 +-------- tools/tracing/rtla/src/osnoise_top.c | 9 +-------- tools/tracing/rtla/src/timerlat_hist.c | 9 +-------- tools/tracing/rtla/src/timerlat_top.c | 9 +-------- 5 files changed, 11 insertions(+), 33 deletions(-) diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c index 90f1bbb7e189..6f64c1fc1b62 100644 --- a/tools/tracing/rtla/src/common.c +++ b/tools/tracing/rtla/src/common.c @@ -63,12 +63,13 @@ int common_parse_options(int argc, char **argv, struct common_params *common) {"debug", no_argument, 0, 'D'}, {"duration", required_argument, 0, 'd'}, {"event", required_argument, 0, 'e'}, + {"house-keeping", required_argument, 0, 'H'}, {"priority", required_argument, 0, 'P'}, {0, 0, 0, 0} }; opterr = 0; - c = getopt_long(argc, argv, "c:C::Dd:e:P:", long_options, NULL); + c = getopt_long(argc, argv, "c:C::Dd:e:H:P:", long_options, NULL); opterr = 1; switch (c) { @@ -98,6 +99,11 @@ int common_parse_options(int argc, char **argv, struct common_params *common) tevent->next = common->events; common->events = tevent; break; + case 'H': + common->hk_cpus = 1; + if (parse_cpu_set(optarg, &common->hk_cpu_set)) + fatal("Error parsing house keeping CPUs"); + break; case 'P': if (parse_prio(optarg, &common->sched_param) == -1) fatal("Invalid -P priority"); diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c index 6e66726766a1..705c73d55102 100644 --- a/tools/tracing/rtla/src/osnoise_hist.c +++ b/tools/tracing/rtla/src/osnoise_hist.c @@ -484,7 +484,6 @@ static struct common_params {"auto", required_argument, 0, 'a'}, {"bucket-size", required_argument, 0, 'b'}, {"entries", required_argument, 0, 'E'}, - {"house-keeping", required_argument, 0, 'H'}, {"help", no_argument, 0, 'h'}, {"period", required_argument, 0, 'p'}, {"runtime", required_argument, 0, 'r'}, @@ -508,7 +507,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:b:E:hH:p:r:s:S:t::T:01234:5:6:7:", + c = getopt_long(argc, argv, "a:b:E:hp:r:s:S:t::T:01234:5:6:7:", long_options, NULL); /* detect the end of the options. */ @@ -544,12 +543,6 @@ static struct common_params case '?': osnoise_hist_usage(); break; - case 'H': - params->common.hk_cpus = 1; - retval = parse_cpu_set(optarg, ¶ms->common.hk_cpu_set); - if (retval) - fatal("Error parsing house keeping CPUs"); - break; case 'p': params->period = get_llong_from_str(optarg); if (params->period > 10000000) diff --git a/tools/tracing/rtla/src/osnoise_top.c b/tools/tracing/rtla/src/osnoise_top.c index 7ac992ec7439..d54d47947fb4 100644 --- a/tools/tracing/rtla/src/osnoise_top.c +++ b/tools/tracing/rtla/src/osnoise_top.c @@ -338,7 +338,6 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) while (1) { static struct option long_options[] = { {"auto", required_argument, 0, 'a'}, - {"house-keeping", required_argument, 0, 'H'}, {"help", no_argument, 0, 'h'}, {"period", required_argument, 0, 'p'}, {"quiet", no_argument, 0, 'q'}, @@ -359,7 +358,7 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:hH:p:qr:s:S:t::T:0:1:2:3:", + c = getopt_long(argc, argv, "a:hp:qr:s:S:t::T:0:1:2:3:", long_options, NULL); /* Detect the end of the options. */ @@ -383,12 +382,6 @@ struct common_params *osnoise_top_parse_args(int argc, char **argv) case '?': osnoise_top_usage(params); break; - case 'H': - params->common.hk_cpus = 1; - retval = parse_cpu_set(optarg, ¶ms->common.hk_cpu_set); - if (retval) - fatal("Error parsing house keeping CPUs"); - break; case 'p': params->period = get_llong_from_str(optarg); if (params->period > 10000000) diff --git a/tools/tracing/rtla/src/timerlat_hist.c b/tools/tracing/rtla/src/timerlat_hist.c index 99b416ccfc5b..4e8c38a61197 100644 --- a/tools/tracing/rtla/src/timerlat_hist.c +++ b/tools/tracing/rtla/src/timerlat_hist.c @@ -792,7 +792,6 @@ static struct common_params {"auto", required_argument, 0, 'a'}, {"bucket-size", required_argument, 0, 'b'}, {"entries", required_argument, 0, 'E'}, - {"house-keeping", required_argument, 0, 'H'}, {"help", no_argument, 0, 'h'}, {"irq", required_argument, 0, 'i'}, {"nano", no_argument, 0, 'n'}, @@ -826,7 +825,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:b:E:hH:i:knp:s:t::T:uU0123456:7:8:9\1\2:\3:", + c = getopt_long(argc, argv, "a:b:E:hi:knp:s:t::T:uU0123456:7:8:9\1\2:\3:", long_options, NULL); /* detect the end of the options. */ @@ -865,12 +864,6 @@ static struct common_params case '?': timerlat_hist_usage(); break; - case 'H': - params->common.hk_cpus = 1; - retval = parse_cpu_set(optarg, ¶ms->common.hk_cpu_set); - if (retval) - fatal("Error parsing house keeping CPUs"); - break; case 'i': params->common.stop_us = get_llong_from_str(optarg); break; diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index 027aad1b639f..f5a809344913 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -561,7 +561,6 @@ static struct common_params static struct option long_options[] = { {"auto", required_argument, 0, 'a'}, {"help", no_argument, 0, 'h'}, - {"house-keeping", required_argument, 0, 'H'}, {"irq", required_argument, 0, 'i'}, {"nano", no_argument, 0, 'n'}, {"period", required_argument, 0, 'p'}, @@ -590,7 +589,7 @@ static struct common_params if (common_parse_options(argc, argv, ¶ms->common)) continue; - c = getopt_long(argc, argv, "a:hH:i:knp:qs:t::T:uU0:1:2:345:6:7:", + c = getopt_long(argc, argv, "a:hi:knp:qs:t::T:uU0:1:2:345:6:7:", long_options, NULL); /* detect the end of the options. */ @@ -631,12 +630,6 @@ static struct common_params case '?': timerlat_top_usage(); break; - case 'H': - params->common.hk_cpus = 1; - retval = parse_cpu_set(optarg, ¶ms->common.hk_cpu_set); - if (retval) - fatal("Error parsing house keeping CPUs"); - break; case 'i': params->common.stop_us = get_llong_from_str(optarg); break; From 2a3a25336b1ba632a0a98249a7d4bbee454065aa Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Wed, 24 Dec 2025 14:50:56 +0200 Subject: [PATCH 19/30] tools/rtla: Deduplicate cgroup path opening code Both set_pid_cgroup() and set_comm_cgroup() functions contain identical code for opening the cgroup.procs file. Extract this common code into a new helper function open_cgroup_procs() to reduce code duplication and improve maintainability. Signed-off-by: Costa Shulyupin Link: https://lore.kernel.org/r/20251224125058.1771519-1-costa.shul@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/utils.c | 65 +++++++++++++++++----------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c index 9cf5a0098e9a..0b84e02b13df 100644 --- a/tools/tracing/rtla/src/utils.c +++ b/tools/tracing/rtla/src/utils.c @@ -784,27 +784,27 @@ static int get_self_cgroup(char *self_cg, int sizeof_self_cg) } /* - * set_comm_cgroup - Set cgroup to pid_t pid + * open_cgroup_procs - Open the cgroup.procs file for the given cgroup * - * If cgroup argument is not NULL, the threads will move to the given cgroup. - * Otherwise, the cgroup of the calling, i.e., rtla, thread will be used. + * If cgroup argument is not NULL, the cgroup.procs file for that cgroup + * will be opened. Otherwise, the cgroup of the calling, i.e., rtla, thread + * will be used. * * Supports cgroup v2. * - * Returns 1 on success, 0 otherwise. + * Returns the file descriptor on success, -1 otherwise. */ -int set_pid_cgroup(pid_t pid, const char *cgroup) +static int open_cgroup_procs(const char *cgroup) { char cgroup_path[MAX_PATH - strlen("/cgroup.procs")]; char cgroup_procs[MAX_PATH]; - char pid_str[24]; int retval; int cg_fd; retval = find_mount("cgroup2", cgroup_path, sizeof(cgroup_path)); if (!retval) { err_msg("Did not find cgroupv2 mount point\n"); - return 0; + return -1; } if (!cgroup) { @@ -812,7 +812,7 @@ int set_pid_cgroup(pid_t pid, const char *cgroup) sizeof(cgroup_path) - strlen(cgroup_path)); if (!retval) { err_msg("Did not find self cgroup\n"); - return 0; + return -1; } } else { snprintf(&cgroup_path[strlen(cgroup_path)], @@ -824,6 +824,29 @@ int set_pid_cgroup(pid_t pid, const char *cgroup) debug_msg("Using cgroup path at: %s\n", cgroup_procs); cg_fd = open(cgroup_procs, O_RDWR); + if (cg_fd < 0) + return -1; + + return cg_fd; +} + +/* + * set_pid_cgroup - Set cgroup to pid_t pid + * + * If cgroup argument is not NULL, the threads will move to the given cgroup. + * Otherwise, the cgroup of the calling, i.e., rtla, thread will be used. + * + * Supports cgroup v2. + * + * Returns 1 on success, 0 otherwise. + */ +int set_pid_cgroup(pid_t pid, const char *cgroup) +{ + char pid_str[24]; + int retval; + int cg_fd; + + cg_fd = open_cgroup_procs(cgroup); if (cg_fd < 0) return 0; @@ -853,8 +876,6 @@ int set_pid_cgroup(pid_t pid, const char *cgroup) */ int set_comm_cgroup(const char *comm_prefix, const char *cgroup) { - char cgroup_path[MAX_PATH - strlen("/cgroup.procs")]; - char cgroup_procs[MAX_PATH]; struct dirent *proc_entry; DIR *procfs; int retval; @@ -866,29 +887,7 @@ int set_comm_cgroup(const char *comm_prefix, const char *cgroup) return 0; } - retval = find_mount("cgroup2", cgroup_path, sizeof(cgroup_path)); - if (!retval) { - err_msg("Did not find cgroupv2 mount point\n"); - return 0; - } - - if (!cgroup) { - retval = get_self_cgroup(&cgroup_path[strlen(cgroup_path)], - sizeof(cgroup_path) - strlen(cgroup_path)); - if (!retval) { - err_msg("Did not find self cgroup\n"); - return 0; - } - } else { - snprintf(&cgroup_path[strlen(cgroup_path)], - sizeof(cgroup_path) - strlen(cgroup_path), "%s/", cgroup); - } - - snprintf(cgroup_procs, MAX_PATH, "%s/cgroup.procs", cgroup_path); - - debug_msg("Using cgroup path at: %s\n", cgroup_procs); - - cg_fd = open(cgroup_procs, O_RDWR); + cg_fd = open_cgroup_procs(cgroup); if (cg_fd < 0) return 0; From 648634d17c813b35da775982662e56ea8ce750de Mon Sep 17 00:00:00 2001 From: Wander Lairson Costa Date: Tue, 6 Jan 2026 08:49:39 -0300 Subject: [PATCH 20/30] rtla: Introduce for_each_action() helper The for loop to iterate over the list of actions is used in more than one place. To avoid code duplication and improve readability, introduce a for_each_action() helper macro. Replace the open-coded for loops with the new helper. Signed-off-by: Wander Lairson Costa Link: https://lore.kernel.org/r/20260106133655.249887-4-wander@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/actions.c | 6 ++++-- tools/tracing/rtla/src/actions.h | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/tracing/rtla/src/actions.c b/tools/tracing/rtla/src/actions.c index 8945aee58d51..31bc98db9228 100644 --- a/tools/tracing/rtla/src/actions.c +++ b/tools/tracing/rtla/src/actions.c @@ -32,7 +32,9 @@ void actions_destroy(struct actions *self) { /* Free any action-specific data */ - for (struct action *action = self->list; action < self->list + self->len; action++) { + struct action *action; + + for_each_action(self, action) { if (action->type == ACTION_SHELL) free(action->command); if (action->type == ACTION_TRACE_OUTPUT) @@ -223,7 +225,7 @@ actions_perform(struct actions *self) int pid, retval; const struct action *action; - for (action = self->list; action < self->list + self->len; action++) { + for_each_action(self, action) { switch (action->type) { case ACTION_TRACE_OUTPUT: retval = save_trace_to_file(self->trace_output_inst, action->trace_output); diff --git a/tools/tracing/rtla/src/actions.h b/tools/tracing/rtla/src/actions.h index a4f9b570775b..fb77069c972b 100644 --- a/tools/tracing/rtla/src/actions.h +++ b/tools/tracing/rtla/src/actions.h @@ -42,6 +42,11 @@ struct actions { struct tracefs_instance *trace_output_inst; }; +#define for_each_action(actions, action) \ + for ((action) = (actions)->list; \ + (action) < (actions)->list + (actions)->len; \ + (action)++) + void actions_init(struct actions *self); void actions_destroy(struct actions *self); int actions_add_trace_output(struct actions *self, const char *trace_output); From 7e9dfccf8f11c26208211457c4597a466135b56a Mon Sep 17 00:00:00 2001 From: Wander Lairson Costa Date: Tue, 6 Jan 2026 08:49:40 -0300 Subject: [PATCH 21/30] rtla: Replace atoi() with a robust strtoi() The atoi() function does not perform error checking, which can lead to undefined behavior when parsing invalid or out-of-range strings. This can cause issues when parsing user-provided numerical inputs, such as signal numbers, PIDs, or CPU lists. To address this, introduce a new strtoi() helper function that safely converts a string to an integer. This function validates the input and checks for overflows, returning a negative value on failure. Replace all calls to atoi() with the new strtoi() function and add proper error handling to make the parsing more robust and prevent potential issues. Signed-off-by: Wander Lairson Costa Link: https://lore.kernel.org/r/20260106133655.249887-5-wander@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/actions.c | 7 +++--- tools/tracing/rtla/src/utils.c | 40 ++++++++++++++++++++++++++++---- tools/tracing/rtla/src/utils.h | 2 ++ 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/tools/tracing/rtla/src/actions.c b/tools/tracing/rtla/src/actions.c index 31bc98db9228..ace9965ebd55 100644 --- a/tools/tracing/rtla/src/actions.c +++ b/tools/tracing/rtla/src/actions.c @@ -181,12 +181,13 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn) /* Takes two arguments, num (signal) and pid */ while (token != NULL) { if (strlen(token) > 4 && strncmp(token, "num=", 4) == 0) { - signal = atoi(token + 4); + if (strtoi(token + 4, &signal)) + return -1; } else if (strlen(token) > 4 && strncmp(token, "pid=", 4) == 0) { if (strncmp(token + 4, "parent", 7) == 0) pid = -1; - else - pid = atoi(token + 4); + else if (strtoi(token + 4, &pid)) + return -1; } else { /* Invalid argument */ return -1; diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c index 0b84e02b13df..748b86e6c2cc 100644 --- a/tools/tracing/rtla/src/utils.c +++ b/tools/tracing/rtla/src/utils.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "utils.h" @@ -127,16 +128,18 @@ int parse_cpu_set(char *cpu_list, cpu_set_t *set) nr_cpus = sysconf(_SC_NPROCESSORS_CONF); for (p = cpu_list; *p; ) { - cpu = atoi(p); - if (cpu < 0 || (!cpu && *p != '0') || cpu >= nr_cpus) + if (strtoi(p, &cpu)) + goto err; + if (cpu < 0 || cpu >= nr_cpus) goto err; while (isdigit(*p)) p++; if (*p == '-') { p++; - end_cpu = atoi(p); - if (end_cpu < cpu || (!end_cpu && *p != '0') || end_cpu >= nr_cpus) + if (strtoi(p, &end_cpu)) + goto err; + if (end_cpu < cpu || end_cpu >= nr_cpus) goto err; while (isdigit(*p)) p++; @@ -337,6 +340,7 @@ int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr) struct dirent *proc_entry; DIR *procfs; int retval; + int pid; if (strlen(comm_prefix) >= MAX_PATH) { err_msg("Command prefix is too long: %d < strlen(%s)\n", @@ -356,8 +360,12 @@ int set_comm_sched_attr(const char *comm_prefix, struct sched_attr *attr) if (!retval) continue; + if (strtoi(proc_entry->d_name, &pid)) { + err_msg("'%s' is not a valid pid", proc_entry->d_name); + goto out_err; + } /* procfs_is_workload_pid confirmed it is a pid */ - retval = __set_sched_attr(atoi(proc_entry->d_name), attr); + retval = __set_sched_attr(pid, attr); if (retval) { err_msg("Error setting sched attributes for pid:%s\n", proc_entry->d_name); goto out_err; @@ -999,3 +1007,25 @@ char *parse_optional_arg(int argc, char **argv) return NULL; } } + +/* + * strtoi - convert string to integer with error checking + * + * Returns 0 on success, -1 if conversion fails or result is out of int range. + */ +int strtoi(const char *s, int *res) +{ + char *end_ptr; + long lres; + + if (!*s) + return -1; + + errno = 0; + lres = strtol(s, &end_ptr, 0); + if (errno || *end_ptr || lres > INT_MAX || lres < INT_MIN) + return -1; + + *res = (int) lres; + return 0; +} diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h index ed7618842e82..974f7e0188c0 100644 --- a/tools/tracing/rtla/src/utils.h +++ b/tools/tracing/rtla/src/utils.h @@ -3,6 +3,7 @@ #include #include #include +#include /* * '18446744073709551615\0' @@ -81,6 +82,7 @@ static inline int set_deepest_cpu_idle_state(unsigned int cpu, unsigned int stat static inline int have_libcpupower_support(void) { return 0; } #endif /* HAVE_LIBCPUPOWER_SUPPORT */ int auto_house_keeping(cpu_set_t *monitored_cpus); +__attribute__((__warn_unused_result__)) int strtoi(const char *s, int *res); #define ns_to_usf(x) (((double)x/1000)) #define ns_to_per(total, part) ((part * 100) / (double)total) From 9bf942f3c370c9b3af639df04cb5f34daf512dab Mon Sep 17 00:00:00 2001 From: Wander Lairson Costa Date: Tue, 6 Jan 2026 08:49:44 -0300 Subject: [PATCH 22/30] rtla: Use standard exit codes for result enum The result enum defines custom values for PASSED, ERROR, and FAILED. These values correspond to standard exit codes EXIT_SUCCESS and EXIT_FAILURE. Update the enum to use the standard macros EXIT_SUCCESS and EXIT_FAILURE to improve readability and adherence to standard C practices. The FAILED value is implicitly assigned EXIT_FAILURE + 1, so there is no need to assign an explicit value. Signed-off-by: Wander Lairson Costa Link: https://lore.kernel.org/r/20260106133655.249887-9-wander@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/utils.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/tracing/rtla/src/utils.h b/tools/tracing/rtla/src/utils.h index 974f7e0188c0..f7c2a52a0ab5 100644 --- a/tools/tracing/rtla/src/utils.h +++ b/tools/tracing/rtla/src/utils.h @@ -4,6 +4,7 @@ #include #include #include +#include /* * '18446744073709551615\0' @@ -88,7 +89,7 @@ __attribute__((__warn_unused_result__)) int strtoi(const char *s, int *res); #define ns_to_per(total, part) ((part * 100) / (double)total) enum result { - PASSED = 0, /* same as EXIT_SUCCESS */ - ERROR = 1, /* same as EXIT_FAILURE, an error in arguments */ - FAILED = 2, /* test hit the stop tracing condition */ + PASSED = EXIT_SUCCESS, + ERROR = EXIT_FAILURE, + FAILED, /* test hit the stop tracing condition */ }; From d849f3af1cc7a53e3b150a9bbade8f9629445b36 Mon Sep 17 00:00:00 2001 From: Wander Lairson Costa Date: Tue, 6 Jan 2026 08:49:45 -0300 Subject: [PATCH 23/30] rtla: Remove redundant memset after calloc The actions struct is allocated using calloc, which already returns zeroed memory. The subsequent memset call to zero the 'present' member is therefore redundant. Signed-off-by: Wander Lairson Costa Link: https://lore.kernel.org/r/20260106133655.249887-10-wander@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/actions.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/tracing/rtla/src/actions.c b/tools/tracing/rtla/src/actions.c index ace9965ebd55..d9c1db5d97d4 100644 --- a/tools/tracing/rtla/src/actions.c +++ b/tools/tracing/rtla/src/actions.c @@ -19,8 +19,6 @@ actions_init(struct actions *self) self->len = 0; self->continue_flag = false; - memset(&self->present, 0, sizeof(self->present)); - /* This has to be set by the user */ self->trace_output_inst = NULL; } From f3cc3e4b5116929ebff27c3b0a565b34ae4969b3 Mon Sep 17 00:00:00 2001 From: Wander Lairson Costa Date: Tue, 6 Jan 2026 08:49:47 -0300 Subject: [PATCH 24/30] rtla: Remove unused headers Remove unused includes for and to clean up the code and reduce unnecessary dependencies. Signed-off-by: Wander Lairson Costa Link: https://lore.kernel.org/r/20260106133655.249887-12-wander@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/osnoise_hist.c | 1 - tools/tracing/rtla/src/timerlat.c | 1 - tools/tracing/rtla/src/timerlat_top.c | 1 - tools/tracing/rtla/src/trace.c | 1 - 4 files changed, 4 deletions(-) diff --git a/tools/tracing/rtla/src/osnoise_hist.c b/tools/tracing/rtla/src/osnoise_hist.c index 705c73d55102..9d70ea34807f 100644 --- a/tools/tracing/rtla/src/osnoise_hist.c +++ b/tools/tracing/rtla/src/osnoise_hist.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c index 8f6cf55f4a94..8f8811f7a13b 100644 --- a/tools/tracing/rtla/src/timerlat.c +++ b/tools/tracing/rtla/src/timerlat.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c index f5a809344913..284b74773c2b 100644 --- a/tools/tracing/rtla/src/timerlat_top.c +++ b/tools/tracing/rtla/src/timerlat_top.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include diff --git a/tools/tracing/rtla/src/trace.c b/tools/tracing/rtla/src/trace.c index 69cbc48d53d3..b8be3e28680e 100644 --- a/tools/tracing/rtla/src/trace.c +++ b/tools/tracing/rtla/src/trace.c @@ -2,7 +2,6 @@ #define _GNU_SOURCE #include #include -#include #include #include #include From a0890f9dbd24b302d327fe7dad9b9c5be0e278aa Mon Sep 17 00:00:00 2001 From: Wander Lairson Costa Date: Tue, 6 Jan 2026 08:49:48 -0300 Subject: [PATCH 25/30] rtla: Fix NULL pointer dereference in actions_parse The actions_parse() function uses strtok() to tokenize the trigger string, but does not check if the returned token is NULL before passing it to strcmp(). If the trigger parameter is an empty string or contains only delimiter characters, strtok() returns NULL, causing strcmp() to dereference a NULL pointer and crash the program. This issue can be triggered by malformed user input or edge cases in trigger string parsing. Add a NULL check immediately after the strtok() call to validate that a token was successfully extracted before using it. If no token is found, the function now returns -1 to indicate a parsing error. Signed-off-by: Wander Lairson Costa Link: https://lore.kernel.org/r/20260106133655.249887-13-wander@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/actions.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/tracing/rtla/src/actions.c b/tools/tracing/rtla/src/actions.c index d9c1db5d97d4..a42615011962 100644 --- a/tools/tracing/rtla/src/actions.c +++ b/tools/tracing/rtla/src/actions.c @@ -141,6 +141,8 @@ actions_parse(struct actions *self, const char *trigger, const char *tracefn) strcpy(trigger_c, trigger); token = strtok(trigger_c, ","); + if (!token) + return -1; if (strcmp(token, "trace") == 0) type = ACTION_TRACE_OUTPUT; From 02689ae385c5e84874620947ac010cf7b4950375 Mon Sep 17 00:00:00 2001 From: Wander Lairson Costa Date: Tue, 6 Jan 2026 08:49:50 -0300 Subject: [PATCH 26/30] rtla: Add generated output files to gitignore The rtla tool generates various output files during testing and execution, including custom trace outputs and histogram data. These files are artifacts of running the tool with different options and should not be tracked in version control. Add gitignore entries for custom_filename.txt, osnoise_irq_noise_hist.txt, osnoise_trace.txt, and timerlat_trace.txt to prevent accidentally committing these generated files. This aligns with the existing pattern of ignoring build artifacts and generated headers like *.skel.h. Signed-off-by: Wander Lairson Costa Link: https://lore.kernel.org/r/20260106133655.249887-15-wander@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/.gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/tracing/rtla/.gitignore b/tools/tracing/rtla/.gitignore index 1a394ad26cc1..4d39d64ac08c 100644 --- a/tools/tracing/rtla/.gitignore +++ b/tools/tracing/rtla/.gitignore @@ -5,3 +5,7 @@ fixdep feature FEATURE-DUMP *.skel.h +custom_filename.txt +osnoise_irq_noise_hist.txt +osnoise_trace.txt +timerlat_trace.txt From af2962d68b970b15d8910be2b0386b4f147ed78b Mon Sep 17 00:00:00 2001 From: Wander Lairson Costa Date: Tue, 6 Jan 2026 08:49:51 -0300 Subject: [PATCH 27/30] rtla: Make stop_tracing variable volatile The stop_tracing global variable is accessed from both the signal handler context and the main program flow without synchronization. This creates a potential race condition where compiler optimizations could cache the variable value in registers, preventing the signal handler's updates from being visible to other parts of the program. Add the volatile qualifier to stop_tracing in both common.c and common.h to ensure all accesses to this variable bypass compiler optimizations and read directly from memory. This guarantees that when the signal handler sets stop_tracing, the change is immediately visible to the main program loop, preventing potential hangs or delayed shutdown when termination signals are received. Signed-off-by: Wander Lairson Costa Link: https://lore.kernel.org/r/20260106133655.249887-16-wander@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/common.c | 2 +- tools/tracing/rtla/src/common.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/tracing/rtla/src/common.c b/tools/tracing/rtla/src/common.c index 6f64c1fc1b62..ceff76a62a30 100644 --- a/tools/tracing/rtla/src/common.c +++ b/tools/tracing/rtla/src/common.c @@ -10,7 +10,7 @@ #include "common.h" struct trace_instance *trace_inst; -int stop_tracing; +volatile int stop_tracing; static void stop_trace(int sig) { diff --git a/tools/tracing/rtla/src/common.h b/tools/tracing/rtla/src/common.h index ef17ea5be540..7602c5593ef5 100644 --- a/tools/tracing/rtla/src/common.h +++ b/tools/tracing/rtla/src/common.h @@ -54,7 +54,7 @@ struct osnoise_context { }; extern struct trace_instance *trace_inst; -extern int stop_tracing; +extern volatile int stop_tracing; struct hist_params { char no_irq; From 33e3c807ab22bd4002640c8fe47fa30fd4f44ca0 Mon Sep 17 00:00:00 2001 From: Wander Lairson Costa Date: Tue, 6 Jan 2026 08:49:52 -0300 Subject: [PATCH 28/30] rtla: Ensure null termination after read operations in utils.c Add explicit null termination and buffer initialization for read() operations in procfs_is_workload_pid() and get_self_cgroup() functions. The read() system call does not null-terminate the data it reads, and when the buffer is filled to capacity, subsequent string operations will read past the buffer boundary searching for a null terminator. In procfs_is_workload_pid(), explicitly set buffer[MAX_PATH-1] to '\0' to ensure the buffer is always null-terminated before passing it to strncmp(). In get_self_cgroup(), use memset() to zero the path buffer before reading, which ensures null termination when retval is less than MAX_PATH. Additionally, set path[MAX_PATH-1] to '\0' after the read to handle the case where the buffer is filled completely. These defensive buffer handling practices prevent potential buffer overruns and align with the ongoing buffer safety improvements across the rtla codebase. Signed-off-by: Wander Lairson Costa Link: https://lore.kernel.org/r/20260106133655.249887-17-wander@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/utils.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c index 748b86e6c2cc..5273745bc8df 100644 --- a/tools/tracing/rtla/src/utils.c +++ b/tools/tracing/rtla/src/utils.c @@ -317,6 +317,7 @@ static int procfs_is_workload_pid(const char *comm_prefix, struct dirent *proc_e if (retval <= 0) return 0; + buffer[MAX_PATH-1] = '\0'; retval = strncmp(comm_prefix, buffer, strlen(comm_prefix)); if (retval) return 0; @@ -750,6 +751,7 @@ static int get_self_cgroup(char *self_cg, int sizeof_self_cg) if (fd < 0) return 0; + memset(path, 0, sizeof(path)); retval = read(fd, path, MAX_PATH); close(fd); @@ -757,6 +759,7 @@ static int get_self_cgroup(char *self_cg, int sizeof_self_cg) if (retval <= 0) return 0; + path[MAX_PATH-1] = '\0'; start = path; start = strstr(start, ":"); From fb8b8183208d8efe824e8d2c73fb1ab5ad1191fd Mon Sep 17 00:00:00 2001 From: Wander Lairson Costa Date: Tue, 6 Jan 2026 08:49:53 -0300 Subject: [PATCH 29/30] rtla: Fix parse_cpu_set() return value documentation Correct the return value documentation for parse_cpu_set() function in utils.c. The comment incorrectly stated that the function returns 1 on success and 0 on failure, but the actual implementation returns 0 on success and 1 on failure, following the common error-on-nonzero convention used throughout the codebase. This documentation fix ensures that developers reading the code understand the correct return value semantics and prevents potential misuse of the function's return value in conditional checks. Signed-off-by: Wander Lairson Costa Link: https://lore.kernel.org/r/20260106133655.249887-18-wander@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/utils.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c index 5273745bc8df..18986a5aed3c 100644 --- a/tools/tracing/rtla/src/utils.c +++ b/tools/tracing/rtla/src/utils.c @@ -113,7 +113,7 @@ void get_duration(time_t start_time, char *output, int output_size) * Receives a cpu list, like 1-3,5 (cpus 1, 2, 3, 5), and then set * filling cpu_set_t argument. * - * Returns 1 on success, 0 otherwise. + * Returns 0 on success, 1 otherwise. */ int parse_cpu_set(char *cpu_list, cpu_set_t *set) { From 6ea8a206108fe8b5940c2797afc54ae9f5a7bbdd Mon Sep 17 00:00:00 2001 From: Costa Shulyupin Date: Mon, 12 Jan 2026 21:26:41 +0200 Subject: [PATCH 30/30] rtla: Fix parse_cpu_set() bug introduced by strtoi() The patch 'Replace atoi() with a robust strtoi()' introduced a bug in parse_cpu_set(), which relies on partial parsing of the input string. The function parses CPU specifications like '0-3,5' by incrementing a pointer through the string. strtoi() rejects strings with trailing characters, causing parse_cpu_set() to fail on any CPU list with multiple entries. Restore the original use of atoi() in parse_cpu_set(). Fixes: 7e9dfccf8f11 ("rtla: Replace atoi() with a robust strtoi()") Signed-off-by: Costa Shulyupin Reviewed-by: Masami Hiramatsu (Google) Link: https://lore.kernel.org/r/20260112192642.212848-2-costa.shul@redhat.com Signed-off-by: Tomas Glozar --- tools/tracing/rtla/src/utils.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tools/tracing/rtla/src/utils.c b/tools/tracing/rtla/src/utils.c index 18986a5aed3c..0da3b2470c31 100644 --- a/tools/tracing/rtla/src/utils.c +++ b/tools/tracing/rtla/src/utils.c @@ -128,18 +128,16 @@ int parse_cpu_set(char *cpu_list, cpu_set_t *set) nr_cpus = sysconf(_SC_NPROCESSORS_CONF); for (p = cpu_list; *p; ) { - if (strtoi(p, &cpu)) - goto err; - if (cpu < 0 || cpu >= nr_cpus) + cpu = atoi(p); + if (cpu < 0 || (!cpu && *p != '0') || cpu >= nr_cpus) goto err; while (isdigit(*p)) p++; if (*p == '-') { p++; - if (strtoi(p, &end_cpu)) - goto err; - if (end_cpu < cpu || end_cpu >= nr_cpus) + end_cpu = atoi(p); + if (end_cpu < cpu || (!end_cpu && *p != '0') || end_cpu >= nr_cpus) goto err; while (isdigit(*p)) p++;