Skip to content

Commit f967d1e

Browse files
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 <tglozar@redhat.com>
1 parent 8cd0f08 commit f967d1e

6 files changed

Lines changed: 80 additions & 2 deletions

File tree

tools/tracing/rtla/src/timerlat.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,17 @@ timerlat_apply_config(struct osnoise_tool *tool, struct timerlat_params *params)
4848
}
4949
}
5050

51+
/* Check if BPF action program is requested but BPF is not available */
52+
if (params->bpf_action_program) {
53+
if (params->mode == TRACING_MODE_TRACEFS) {
54+
err_msg("BPF actions are not supported in tracefs-only mode\n");
55+
goto out_err;
56+
}
57+
58+
if (timerlat_load_bpf_action_program(params->bpf_action_program))
59+
goto out_err;
60+
}
61+
5162
retval = osnoise_set_timerlat_period_us(tool->context,
5263
params->timerlat_period_us ?
5364
params->timerlat_period_us :

tools/tracing/rtla/src/timerlat.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ struct timerlat_params {
2727
int dump_tasks;
2828
int deepest_idle_state;
2929
enum timerlat_tracing_mode mode;
30+
const char *bpf_action_program;
3031
};
3132

3233
#define to_timerlat_params(ptr) container_of(ptr, struct timerlat_params, common)
@@ -36,4 +37,3 @@ int timerlat_main(int argc, char *argv[]);
3637
int timerlat_enable(struct osnoise_tool *tool);
3738
void timerlat_analyze(struct osnoise_tool *tool, bool stopped);
3839
void timerlat_free(struct osnoise_tool *tool);
39-

tools/tracing/rtla/src/timerlat_bpf.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77

88
static struct timerlat_bpf *bpf;
99

10+
/* BPF object and program for action program */
11+
static struct bpf_object *obj;
12+
static struct bpf_program *prog;
13+
1014
/*
1115
* timerlat_bpf_init - load and initialize BPF program to collect timerlat data
1216
*/
@@ -96,6 +100,11 @@ void timerlat_bpf_detach(void)
96100
void timerlat_bpf_destroy(void)
97101
{
98102
timerlat_bpf__destroy(bpf);
103+
bpf = NULL;
104+
if (obj)
105+
bpf_object__close(obj);
106+
obj = NULL;
107+
prog = NULL;
99108
}
100109

101110
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,
190199
bpf->maps.summary_user,
191200
key, value_irq, value_thread, value_user, cpus);
192201
}
202+
203+
/*
204+
* timerlat_load_bpf_action_program - load and register a BPF action program
205+
*/
206+
int timerlat_load_bpf_action_program(const char *program_path)
207+
{
208+
int err;
209+
210+
obj = bpf_object__open_file(program_path, NULL);
211+
if (!obj) {
212+
err_msg("Failed to open BPF action program: %s\n", program_path);
213+
goto out_err;
214+
}
215+
216+
err = bpf_object__load(obj);
217+
if (err) {
218+
err_msg("Failed to load BPF action program: %s\n", program_path);
219+
goto out_obj_err;
220+
}
221+
222+
prog = bpf_object__find_program_by_name(obj, "action_handler");
223+
if (!prog) {
224+
err_msg("BPF action program must have 'action_handler' function: %s\n",
225+
program_path);
226+
goto out_obj_err;
227+
}
228+
229+
err = timerlat_bpf_set_action(prog);
230+
if (err) {
231+
err_msg("Failed to register BPF action program: %s\n", program_path);
232+
goto out_prog_err;
233+
}
234+
235+
return 0;
236+
237+
out_prog_err:
238+
prog = NULL;
239+
out_obj_err:
240+
bpf_object__close(obj);
241+
obj = NULL;
242+
out_err:
243+
return 1;
244+
}
245+
193246
#endif /* HAVE_BPF_SKEL */

tools/tracing/rtla/src/timerlat_bpf.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ int timerlat_bpf_get_summary_value(enum summary_field key,
3030
long long *value_thread,
3131
long long *value_user,
3232
int cpus);
33-
33+
int timerlat_load_bpf_action_program(const char *program_path);
3434
static inline int have_libbpf_support(void) { return 1; }
3535
#else
3636
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,
5858
{
5959
return -1;
6060
}
61+
static inline int timerlat_load_bpf_action_program(const char *program_path)
62+
{
63+
return -1;
64+
}
6165
static inline int have_libbpf_support(void) { return 0; }
6266
#endif /* HAVE_BPF_SKEL */
6367
#endif /* __bpf__ */

tools/tracing/rtla/src/timerlat_hist.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,7 @@ static void timerlat_hist_usage(void)
746746
" --deepest-idle-state n: only go down to idle state n on cpus used by timerlat to reduce exit from idle latency",
747747
" --on-threshold <action>: define action to be executed at latency threshold, multiple are allowed",
748748
" --on-end <action>: define action to be executed at measurement end, multiple are allowed",
749+
" --bpf-action <program>: load and execute BPF program when latency threshold is exceeded",
749750
NULL,
750751
};
751752

@@ -825,6 +826,7 @@ static struct common_params
825826
{"deepest-idle-state", required_argument, 0, '\4'},
826827
{"on-threshold", required_argument, 0, '\5'},
827828
{"on-end", required_argument, 0, '\6'},
829+
{"bpf-action", required_argument, 0, '\7'},
828830
{0, 0, 0, 0}
829831
};
830832

@@ -1006,6 +1008,9 @@ static struct common_params
10061008
if (retval)
10071009
fatal("Invalid action %s", optarg);
10081010
break;
1011+
case '\7':
1012+
params->bpf_action_program = optarg;
1013+
break;
10091014
default:
10101015
fatal("Invalid option");
10111016
}

tools/tracing/rtla/src/timerlat_top.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,7 @@ static void timerlat_top_usage(void)
518518
" --deepest-idle-state n: only go down to idle state n on cpus used by timerlat to reduce exit from idle latency",
519519
" --on-threshold <action>: define action to be executed at latency threshold, multiple are allowed",
520520
" --on-end: define action to be executed at measurement end, multiple are allowed",
521+
" --bpf-action <program>: load and execute BPF program when latency threshold is exceeded",
521522
NULL,
522523
};
523524

@@ -589,6 +590,7 @@ static struct common_params
589590
{"deepest-idle-state", required_argument, 0, '8'},
590591
{"on-threshold", required_argument, 0, '9'},
591592
{"on-end", required_argument, 0, '\1'},
593+
{"bpf-action", required_argument, 0, '\2'},
592594
{0, 0, 0, 0}
593595
};
594596

@@ -756,6 +758,9 @@ static struct common_params
756758
if (retval)
757759
fatal("Invalid action %s", optarg);
758760
break;
761+
case '\2':
762+
params->bpf_action_program = optarg;
763+
break;
759764
default:
760765
fatal("Invalid option");
761766
}

0 commit comments

Comments
 (0)