libbpf: Optimize type lookup with binary search for sorted BTF

This patch introduces binary search optimization for BTF type lookups
when the BTF instance contains sorted types.

The optimization significantly improves performance when searching for
types in large BTF instances with sorted types. For unsorted BTF, the
implementation falls back to the original linear search.

Signed-off-by: Donglin Peng <pengdonglin@xiaomi.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20260109130003.3313716-5-dolinux.peng@gmail.com
This commit is contained in:
Donglin Peng
2026-01-09 20:59:56 +08:00
committed by Andrii Nakryiko
parent b7c6c02b5f
commit 1c96b72cb0

View File

@@ -92,6 +92,8 @@ struct btf {
* - for split BTF counts number of types added on top of base BTF.
*/
__u32 nr_types;
/* the start IDs of named types in sorted BTF */
int named_start_id;
/* if not NULL, points to the base BTF on top of which the current
* split BTF is based
*/
@@ -897,44 +899,79 @@ int btf__resolve_type(const struct btf *btf, __u32 type_id)
return type_id;
}
__s32 btf__find_by_name(const struct btf *btf, const char *type_name)
static __s32 btf_find_type_by_name_bsearch(const struct btf *btf, const char *name,
__s32 start_id)
{
__u32 i, nr_types = btf__type_cnt(btf);
const struct btf_type *t;
const char *tname;
__s32 l, r, m;
if (!strcmp(type_name, "void"))
l = start_id;
r = btf__type_cnt(btf) - 1;
while (l <= r) {
m = l + (r - l) / 2;
t = btf_type_by_id(btf, m);
tname = btf__str_by_offset(btf, t->name_off);
if (strcmp(tname, name) >= 0) {
if (l == r)
return r;
r = m;
} else {
l = m + 1;
}
}
return btf__type_cnt(btf);
}
static __s32 btf_find_by_name_kind(const struct btf *btf, int start_id,
const char *type_name, __s32 kind)
{
__u32 nr_types = btf__type_cnt(btf);
const struct btf_type *t;
const char *tname;
__s32 id;
if (start_id < btf->start_id) {
id = btf_find_by_name_kind(btf->base_btf, start_id,
type_name, kind);
if (id >= 0)
return id;
start_id = btf->start_id;
}
if (kind == BTF_KIND_UNKN || strcmp(type_name, "void") == 0)
return 0;
for (i = 1; i < nr_types; i++) {
const struct btf_type *t = btf__type_by_id(btf, i);
const char *name = btf__name_by_offset(btf, t->name_off);
if (name && !strcmp(type_name, name))
return i;
if (btf->named_start_id > 0 && type_name[0]) {
start_id = max(start_id, btf->named_start_id);
id = btf_find_type_by_name_bsearch(btf, type_name, start_id);
for (; id < nr_types; id++) {
t = btf__type_by_id(btf, id);
tname = btf__str_by_offset(btf, t->name_off);
if (strcmp(tname, type_name) != 0)
return libbpf_err(-ENOENT);
if (kind < 0 || btf_kind(t) == kind)
return id;
}
} else {
for (id = start_id; id < nr_types; id++) {
t = btf_type_by_id(btf, id);
if (kind > 0 && btf_kind(t) != kind)
continue;
tname = btf__str_by_offset(btf, t->name_off);
if (strcmp(tname, type_name) == 0)
return id;
}
}
return libbpf_err(-ENOENT);
}
static __s32 btf_find_by_name_kind(const struct btf *btf, int start_id,
const char *type_name, __u32 kind)
/* the kind value of -1 indicates that kind matching should be skipped */
__s32 btf__find_by_name(const struct btf *btf, const char *type_name)
{
__u32 i, nr_types = btf__type_cnt(btf);
if (kind == BTF_KIND_UNKN || !strcmp(type_name, "void"))
return 0;
for (i = start_id; i < nr_types; i++) {
const struct btf_type *t = btf__type_by_id(btf, i);
const char *name;
if (btf_kind(t) != kind)
continue;
name = btf__name_by_offset(btf, t->name_off);
if (name && !strcmp(type_name, name))
return i;
}
return libbpf_err(-ENOENT);
return btf_find_by_name_kind(btf, 1, type_name, -1);
}
__s32 btf__find_by_name_kind_own(const struct btf *btf, const char *type_name,
@@ -1006,6 +1043,7 @@ static struct btf *btf_new_empty(struct btf *base_btf)
btf->fd = -1;
btf->ptr_sz = sizeof(void *);
btf->swapped_endian = false;
btf->named_start_id = 0;
if (base_btf) {
btf->base_btf = base_btf;
@@ -1057,6 +1095,7 @@ static struct btf *btf_new(const void *data, __u32 size, struct btf *base_btf, b
btf->start_id = 1;
btf->start_str_off = 0;
btf->fd = -1;
btf->named_start_id = 0;
if (base_btf) {
btf->base_btf = base_btf;
@@ -1715,6 +1754,7 @@ static void btf_invalidate_raw_data(struct btf *btf)
free(btf->raw_data_swapped);
btf->raw_data_swapped = NULL;
}
btf->named_start_id = 0;
}
/* Ensure BTF is ready to be modified (by splitting into a three memory