mirror of
https://github.com/netdata/libbpf.git
synced 2026-04-12 19:49:07 +08:00
libbpf: Use available_filter_functions_addrs with multi-kprobes
Now that kernel provides a new available_filter_functions_addrs file which can help us avoid the need to cross-validate available_filter_functions and kallsyms, we can improve efficiency of multi-attach kprobes. For example, on my device, the sample program [1] of start time: $ sudo ./funccount "tcp_*" before after 1.2s 1.0s [1]: https://github.com/JackieLiu1/ketones/tree/master/src/funccount Signed-off-by: Jackie Liu <liuyun01@kylinos.cn> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/20230705091209.3803873-2-liu.yun@linux.dev
This commit is contained in:
committed by
Andrii Nakryiko
parent
732c4c6df2
commit
b9c4ad5468
62
src/libbpf.c
62
src/libbpf.c
@@ -10234,6 +10234,12 @@ static const char *tracefs_available_filter_functions(void)
|
|||||||
: TRACEFS"/available_filter_functions";
|
: TRACEFS"/available_filter_functions";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const char *tracefs_available_filter_functions_addrs(void)
|
||||||
|
{
|
||||||
|
return use_debugfs() ? DEBUGFS"/available_filter_functions_addrs"
|
||||||
|
: TRACEFS"/available_filter_functions_addrs";
|
||||||
|
}
|
||||||
|
|
||||||
static void gen_kprobe_legacy_event_name(char *buf, size_t buf_sz,
|
static void gen_kprobe_legacy_event_name(char *buf, size_t buf_sz,
|
||||||
const char *kfunc_name, size_t offset)
|
const char *kfunc_name, size_t offset)
|
||||||
{
|
{
|
||||||
@@ -10650,6 +10656,57 @@ cleanup:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool has_available_filter_functions_addrs(void)
|
||||||
|
{
|
||||||
|
return access(tracefs_available_filter_functions_addrs(), R_OK) != -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int libbpf_available_kprobes_parse(struct kprobe_multi_resolve *res)
|
||||||
|
{
|
||||||
|
const char *available_path = tracefs_available_filter_functions_addrs();
|
||||||
|
char sym_name[500];
|
||||||
|
FILE *f;
|
||||||
|
int ret, err = 0;
|
||||||
|
unsigned long long sym_addr;
|
||||||
|
|
||||||
|
f = fopen(available_path, "re");
|
||||||
|
if (!f) {
|
||||||
|
err = -errno;
|
||||||
|
pr_warn("failed to open %s: %d\n", available_path, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
ret = fscanf(f, "%llx %499s%*[^\n]\n", &sym_addr, sym_name);
|
||||||
|
if (ret == EOF && feof(f))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (ret != 2) {
|
||||||
|
pr_warn("failed to parse available_filter_functions_addrs entry: %d\n",
|
||||||
|
ret);
|
||||||
|
err = -EINVAL;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!glob_match(sym_name, res->pattern))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
err = libbpf_ensure_mem((void **)&res->addrs, &res->cap,
|
||||||
|
sizeof(*res->addrs), res->cnt + 1);
|
||||||
|
if (err)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
res->addrs[res->cnt++] = (unsigned long)sym_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res->cnt == 0)
|
||||||
|
err = -ENOENT;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
fclose(f);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
struct bpf_link *
|
struct bpf_link *
|
||||||
bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog,
|
bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog,
|
||||||
const char *pattern,
|
const char *pattern,
|
||||||
@@ -10686,7 +10743,10 @@ bpf_program__attach_kprobe_multi_opts(const struct bpf_program *prog,
|
|||||||
return libbpf_err_ptr(-EINVAL);
|
return libbpf_err_ptr(-EINVAL);
|
||||||
|
|
||||||
if (pattern) {
|
if (pattern) {
|
||||||
err = libbpf_available_kallsyms_parse(&res);
|
if (has_available_filter_functions_addrs())
|
||||||
|
err = libbpf_available_kprobes_parse(&res);
|
||||||
|
else
|
||||||
|
err = libbpf_available_kallsyms_parse(&res);
|
||||||
if (err)
|
if (err)
|
||||||
goto error;
|
goto error;
|
||||||
addrs = res.addrs;
|
addrs = res.addrs;
|
||||||
|
|||||||
Reference in New Issue
Block a user