[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <7xttv65omwux7q4rpjsfety234qqfdmgwezskg4m6rgal4aaq2@r7vpdvfepiro>
Date: Mon, 20 Oct 2025 11:04:35 -0300
From: Wander Lairson Costa <wander@...hat.com>
To: Tomas Glozar <tglozar@...hat.com>
Cc: Steven Rostedt <rostedt@...dmis.org>,
LKML <linux-kernel@...r.kernel.org>, Linux Trace Kernel <linux-trace-kernel@...r.kernel.org>,
John Kacur <jkacur@...hat.com>, Luis Goncalves <lgoncalv@...hat.com>,
Costa Shulyupin <costa.shul@...hat.com>, Crystal Wood <crwood@...hat.com>,
Arnaldo Carvalho de Melo <acme@...nel.org>
Subject: Re: [PATCH 2/4] rtla/timerlat: Add --bpf-action option
On Fri, Oct 17, 2025 at 04:46:48PM +0200, Tomas Glozar wrote:
> 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
> 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 asssign the
> correct BPF program type to it).
>
> Signed-off-by: Tomas Glozar <tglozar@...hat.com>
> ---
> tools/tracing/rtla/src/timerlat.c | 11 ++++++
> tools/tracing/rtla/src/timerlat.h | 2 +-
> tools/tracing/rtla/src/timerlat_bpf.c | 54 ++++++++++++++++++++++++++
> 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, 81 insertions(+), 2 deletions(-)
>
> diff --git a/tools/tracing/rtla/src/timerlat.c b/tools/tracing/rtla/src/timerlat.c
> index b69212874127..6907a323f9ec 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;
> + }
> +
> if (params->mode != TRACING_MODE_BPF) {
> /*
> * In tracefs and mixed mode, timerlat tracer handles stopping
> 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..3c63bf7aa607 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
> */
> @@ -56,6 +60,10 @@ int timerlat_bpf_init(struct timerlat_params *params)
> return err;
> }
>
> + /* Set BPF action program to NULL */
> + prog = NULL;
> + obj = NULL;
> +
> return 0;
> }
>
> @@ -96,6 +104,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 +203,45 @@ 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);
> + return -1;
> + }
> +
> + err = bpf_object__load(obj);
> + if (err) {
> + err_msg("Failed to load BPF action program: %s\n", program_path);
This error path misses the call to to bpf_object__close()
> + return -1;
> + }
> +
> + 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);
> + bpf_object__close(obj);
> + obj = NULL;
> + return -1;
> + }
> +
> + err = timerlat_bpf_set_action(prog);
> + if (err) {
> + err_msg("Failed to register BPF action program: %s\n", program_path);
> + bpf_object__close(obj);
> + obj = NULL;
> + prog = NULL;
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> #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 606c1688057b..5e639cc34f64 100644
> --- a/tools/tracing/rtla/src/timerlat_hist.c
> +++ b/tools/tracing/rtla/src/timerlat_hist.c
> @@ -763,6 +763,7 @@ static void timerlat_hist_usage(char *usage)
> " --deepest-idle-state n: only go down to idle state n on cpus used by timerlat to reduce exit from idle latency",
> " --on-threshold <action>: define action to be executed at latency threshold, multiple are allowed",
> " --on-end <action>: define action to be executed at measurement end, multiple are allowed",
> + " --bpf-action <program>: load and execute BPF program when latency threshold is exceeded",
> NULL,
> };
>
> @@ -853,6 +854,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}
> };
>
> @@ -1062,6 +1064,9 @@ static struct common_params
> exit(EXIT_FAILURE);
> }
> break;
> + case '\7':
> + params->bpf_action_program = optarg;
> + break;
> default:
> timerlat_hist_usage("Invalid option");
> }
> diff --git a/tools/tracing/rtla/src/timerlat_top.c b/tools/tracing/rtla/src/timerlat_top.c
> index fc479a0dcb59..da5d5db1bc17 100644
> --- a/tools/tracing/rtla/src/timerlat_top.c
> +++ b/tools/tracing/rtla/src/timerlat_top.c
> @@ -521,6 +521,7 @@ static void timerlat_top_usage(char *usage)
> " --deepest-idle-state n: only go down to idle state n on cpus used by timerlat to reduce exit from idle latency",
> " --on-threshold <action>: 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 <program>: load and execute BPF program when latency threshold is exceeded",
> NULL,
> };
>
> @@ -603,6 +604,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}
> };
>
> @@ -798,6 +800,9 @@ static struct common_params
> exit(EXIT_FAILURE);
> }
> break;
> + case '\2':
> + params->bpf_action_program = optarg;
> + break;
> default:
> timerlat_top_usage("Invalid option");
> }
> --
> 2.51.0
>
Powered by blists - more mailing lists