From: Tomas Glozar <tglozar@redhat.com>
To: Steven Rostedt <rostedt@goodmis.org>
Cc: LKML <linux-kernel@vger.kernel.org>,
Linux Trace Kernel <linux-trace-kernel@vger.kernel.org>,
John Kacur <jkacur@redhat.com>,
Luis Goncalves <lgoncalv@redhat.com>,
Costa Shulyupin <costa.shul@redhat.com>,
Crystal Wood <crwood@redhat.com>,
Wander Lairson Costa <wander@redhat.com>,
Arnaldo Carvalho de Melo <acme@kernel.org>,
Tomas Glozar <tglozar@redhat.com>
Subject: [PATCH v2 2/7] rtla/timerlat: Add --bpf-action option
Date: Mon, 27 Oct 2025 15:48:14 +0100 [thread overview]
Message-ID: <20251027144819.1034041-3-tglozar@redhat.com> (raw)
In-Reply-To: <20251027144819.1034041-1-tglozar@redhat.com>
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 assign the
correct BPF program type to it).
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
---
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");
+ 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
next prev parent reply other threads:[~2025-10-27 14:48 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-10-27 14:48 [PATCH v2 0/7] rtla/timerlat: Add --bpf-action option Tomas Glozar
2025-10-27 14:48 ` [PATCH v2 1/7] rtla/timerlat: Support tail call from BPF program Tomas Glozar
2025-10-27 14:48 ` Tomas Glozar [this message]
2025-10-27 14:48 ` [PATCH v2 3/7] rtla/timerlat: Add example for BPF action program Tomas Glozar
2025-10-27 14:48 ` [PATCH v2 4/7] rtla/tests: Test " Tomas Glozar
2025-10-27 15:26 ` Tomas Glozar
2025-10-27 14:48 ` [PATCH v2 5/7] rtla/tests: Run Test::Harness in verbose mode Tomas Glozar
2025-10-27 14:48 ` [PATCH v2 6/7] Documentation/rtla: Rename sample/ to example/ Tomas Glozar
2025-10-27 14:48 ` [PATCH v2 7/7] Documentation/rtla: Document --bpf-action option Tomas Glozar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20251027144819.1034041-3-tglozar@redhat.com \
--to=tglozar@redhat.com \
--cc=acme@kernel.org \
--cc=costa.shul@redhat.com \
--cc=crwood@redhat.com \
--cc=jkacur@redhat.com \
--cc=lgoncalv@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=rostedt@goodmis.org \
--cc=wander@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).