Skip to content

Commit 510f54f

Browse files
Donglin PengKernel Patches Daemon
authored andcommitted
btf: Optimize type lookup with binary search
Improve btf_find_by_name_kind() performance by adding binary search support for sorted types. Falls back to linear search for compatibility. Cc: Eduard Zingerman <[email protected]> Cc: Alexei Starovoitov <[email protected]> Cc: Andrii Nakryiko <[email protected]> Cc: Alan Maguire <[email protected]> Cc: Song Liu <[email protected]> Cc: Xiaoqin Zhang <[email protected]> Signed-off-by: Donglin Peng <[email protected]> Signed-off-by: Donglin Peng <[email protected]>
1 parent a2c3cce commit 510f54f

File tree

1 file changed

+107
-10
lines changed

1 file changed

+107
-10
lines changed

kernel/bpf/btf.c

Lines changed: 107 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@
192192
*/
193193
#define BTF_MAX_SIZE (16 * 1024 * 1024)
194194

195+
#define BTF_NEED_SORT_CHECK ((u32)-1)
196+
195197
#define for_each_member_from(i, from, struct_type, member) \
196198
for (i = from, member = btf_type_member(struct_type) + from; \
197199
i < btf_type_vlen(struct_type); \
@@ -259,6 +261,7 @@ struct btf {
259261
void *nohdr_data;
260262
struct btf_header hdr;
261263
u32 nr_types; /* includes VOID for base BTF */
264+
u32 nr_sorted_types; /* exclude VOID for base BTF */
262265
u32 types_size;
263266
u32 data_size;
264267
refcount_t refcnt;
@@ -494,6 +497,11 @@ static bool btf_type_is_modifier(const struct btf_type *t)
494497
return false;
495498
}
496499

500+
static int btf_start_id(const struct btf *btf)
501+
{
502+
return btf->start_id + (btf->base_btf ? 0 : 1);
503+
}
504+
497505
bool btf_type_is_void(const struct btf_type *t)
498506
{
499507
return t == &btf_void;
@@ -544,24 +552,110 @@ u32 btf_nr_types(const struct btf *btf)
544552
return total;
545553
}
546554

555+
/* Performs binary search within specified type ID range to find the leftmost
556+
* BTF type matching the given name. The search assumes types are sorted by
557+
* name in lexicographical order within the specified range.
558+
*
559+
* Return: Type ID of leftmost matching type, or -ENOENT if not found
560+
*/
561+
static s32 btf_find_by_name_kind_bsearch(const struct btf *btf, const char *name,
562+
s32 start_id, s32 end_id)
563+
{
564+
const struct btf_type *t;
565+
const char *tname;
566+
s32 l, r, m, lmost = -ENOENT;
567+
int ret;
568+
569+
l = start_id;
570+
r = end_id;
571+
while (l <= r) {
572+
m = l + (r - l) / 2;
573+
t = btf_type_by_id(btf, m);
574+
tname = btf_name_by_offset(btf, t->name_off);
575+
ret = strcmp(tname, name);
576+
if (ret < 0) {
577+
l = m + 1;
578+
} else {
579+
if (ret == 0)
580+
lmost = m;
581+
r = m - 1;
582+
}
583+
}
584+
585+
return lmost;
586+
}
587+
588+
/* Searches for a BTF type with the specified name and kind. The function
589+
* first recursively searches in the base BTF (if present), then searches
590+
* in the current BTF using either binary search (if types are sorted)
591+
* or linear search.
592+
*
593+
* Binary search is used when types are name-sorted (nr_sorted_types > 0).
594+
* After finding a name match, it scans forward to find the first type
595+
* that also matches the specified kind. Linear search is used for unsorted
596+
* types, checking each type sequentially.
597+
*
598+
* Return: Type ID of matching type on success, -ENOENT if not found
599+
*/
547600
s32 btf_find_by_name_kind(const struct btf *btf, const char *name, u8 kind)
548601
{
602+
const struct btf *base_btf = btf_base_btf(btf);;
549603
const struct btf_type *t;
550604
const char *tname;
551-
u32 i, total;
605+
int err = -ENOENT;
552606

553-
total = btf_nr_types(btf);
554-
for (i = 1; i < total; i++) {
555-
t = btf_type_by_id(btf, i);
556-
if (BTF_INFO_KIND(t->info) != kind)
557-
continue;
607+
if (base_btf) {
608+
err = btf_find_by_name_kind(base_btf, name, kind);
609+
if (err > 0)
610+
goto out;
611+
}
558612

559-
tname = btf_name_by_offset(btf, t->name_off);
560-
if (!strcmp(tname, name))
561-
return i;
613+
if (btf->nr_sorted_types != BTF_NEED_SORT_CHECK) {
614+
/* binary search */
615+
bool skip_first;
616+
s32 start_id, end_id;;
617+
int ret;
618+
619+
start_id = btf_start_id(btf);
620+
end_id = start_id + btf->nr_sorted_types - 1;
621+
ret = btf_find_by_name_kind_bsearch(btf, name, start_id, end_id);
622+
if (ret < 0)
623+
goto out;
624+
skip_first = true;
625+
do {
626+
t = btf_type_by_id(btf, ret);
627+
if (BTF_INFO_KIND(t->info) != kind) {
628+
if (skip_first) {
629+
skip_first = false;
630+
continue;
631+
}
632+
} else if (skip_first) {
633+
return ret;
634+
}
635+
tname = btf_name_by_offset(btf, t->name_off);
636+
if (!strcmp(tname, name))
637+
return ret;
638+
else
639+
break;
640+
} while (++ret <= end_id);
641+
} else {
642+
/* linear search */
643+
u32 i, total;
644+
645+
total = btf_nr_types(btf);
646+
for (i = btf_start_id(btf); i < total; i++) {
647+
t = btf_type_by_id(btf, i);
648+
if (BTF_INFO_KIND(t->info) != kind)
649+
continue;
650+
651+
tname = btf_name_by_offset(btf, t->name_off);
652+
if (!strcmp(tname, name))
653+
return i;
654+
}
562655
}
563656

564-
return -ENOENT;
657+
out:
658+
return err;
565659
}
566660

567661
s32 bpf_find_btf_id(const char *name, u32 kind, struct btf **btf_p)
@@ -5791,6 +5885,7 @@ static struct btf *btf_parse(const union bpf_attr *attr, bpfptr_t uattr, u32 uat
57915885
goto errout;
57925886
}
57935887
env->btf = btf;
5888+
btf->nr_sorted_types = BTF_NEED_SORT_CHECK;
57945889

57955890
data = kvmalloc(attr->btf_size, GFP_KERNEL | __GFP_NOWARN);
57965891
if (!data) {
@@ -6210,6 +6305,7 @@ static struct btf *btf_parse_base(struct btf_verifier_env *env, const char *name
62106305
btf->data = data;
62116306
btf->data_size = data_size;
62126307
btf->kernel_btf = true;
6308+
btf->nr_sorted_types = BTF_NEED_SORT_CHECK;
62136309
snprintf(btf->name, sizeof(btf->name), "%s", name);
62146310

62156311
err = btf_parse_hdr(env);
@@ -6327,6 +6423,7 @@ static struct btf *btf_parse_module(const char *module_name, const void *data,
63276423
btf->start_id = base_btf->nr_types;
63286424
btf->start_str_off = base_btf->hdr.str_len;
63296425
btf->kernel_btf = true;
6426+
btf->nr_sorted_types = BTF_NEED_SORT_CHECK;
63306427
snprintf(btf->name, sizeof(btf->name), "%s", module_name);
63316428

63326429
btf->data = kvmemdup(data, data_size, GFP_KERNEL | __GFP_NOWARN);

0 commit comments

Comments
 (0)