On Mon, Oct 27, 2025 at 04:33:56PM +0100, 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
typo: double "doing" > 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). > > Signed-off-by: Tomas Glozar <[email protected]> > --- > 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 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"); I would just emit a warning to the user and proceed ignoring the bpf action argument. > + 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..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 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 >
