[RFC PATCH v2 1/5] btf: search local BTF before base BTF

Donglin Peng posted 5 patches 3 months, 3 weeks ago
There is a newer version of this series
[RFC PATCH v2 1/5] btf: search local BTF before base BTF
Posted by Donglin Peng 3 months, 3 weeks ago
Change btf_find_by_name_kind() to search the local BTF first,
then fall back to the base BTF. This can skip traversing the large
vmlinux BTF when the target type resides in a kernel module's BTF,
thereby significantly improving lookup performance.

In a test searching for the btf_type of function ext2_new_inode
located in the ext2 kernel module:

Before: 408631 ns
After:     499 ns

Performance improvement: ~819x faster

Cc: Eduard Zingerman <eddyz87@gmail.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andrii Nakryiko <andrii.nakryiko@gmail.com>
Cc: Alan Maguire <alan.maguire@oracle.com>
Cc: Song Liu <song@kernel.org>
Signed-off-by: pengdonglin <pengdonglin@xiaomi.com>
Signed-off-by: Donglin Peng <dolinux.peng@gmail.com>
---
 include/linux/btf.h |  1 +
 kernel/bpf/btf.c    | 27 ++++++++++++++++++---------
 2 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/include/linux/btf.h b/include/linux/btf.h
index f06976ffb63f..ddc53a7ac7cd 100644
--- a/include/linux/btf.h
+++ b/include/linux/btf.h
@@ -220,6 +220,7 @@ bool btf_is_module(const struct btf *btf);
 bool btf_is_vmlinux(const struct btf *btf);
 struct module *btf_try_get_module(const struct btf *btf);
 u32 btf_nr_types(const struct btf *btf);
+u32 btf_type_cnt(const struct btf *btf);
 struct btf *btf_base_btf(const struct btf *btf);
 bool btf_type_is_i32(const struct btf_type *t);
 bool btf_type_is_i64(const struct btf_type *t);
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 0de8fc8a0e0b..c414cf37e1bd 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -544,22 +544,31 @@ u32 btf_nr_types(const struct btf *btf)
 	return total;
 }
 
+u32 btf_type_cnt(const struct btf *btf)
+{
+	return btf->start_id + btf->nr_types;
+}
+
 s32 btf_find_by_name_kind(const struct btf *btf, const char *name, u8 kind)
 {
 	const struct btf_type *t;
 	const char *tname;
 	u32 i, total;
 
-	total = btf_nr_types(btf);
-	for (i = 1; i < total; i++) {
-		t = btf_type_by_id(btf, i);
-		if (BTF_INFO_KIND(t->info) != kind)
-			continue;
+	do {
+		total = btf_type_cnt(btf);
+		for (i = btf->start_id; i < total; i++) {
+			t = btf_type_by_id(btf, i);
+			if (BTF_INFO_KIND(t->info) != kind)
+				continue;
 
-		tname = btf_name_by_offset(btf, t->name_off);
-		if (!strcmp(tname, name))
-			return i;
-	}
+			tname = btf_name_by_offset(btf, t->name_off);
+			if (!strcmp(tname, name))
+				return i;
+		}
+
+		btf = btf->base_btf;
+	} while (btf);
 
 	return -ENOENT;
 }
-- 
2.34.1
Re: [RFC PATCH v2 1/5] btf: search local BTF before base BTF
Posted by Eduard Zingerman 3 months, 2 weeks ago
On Mon, 2025-10-20 at 17:39 +0800, Donglin Peng wrote:
> Change btf_find_by_name_kind() to search the local BTF first,
> then fall back to the base BTF. This can skip traversing the large
> vmlinux BTF when the target type resides in a kernel module's BTF,
> thereby significantly improving lookup performance.
> 
> In a test searching for the btf_type of function ext2_new_inode
> located in the ext2 kernel module:
> 
> Before: 408631 ns
> After:     499 ns
> 
> Performance improvement: ~819x faster

[...]

> ---

The flip makes sense, but are we sure that there are no implicit
expectations to return base type in case of a name conflict?

E.g. kernel/bpf/btf.c:btf_parse_struct_metas() takes a pointer to
`btf` instance and looks for types in alloc_obj_fields array by name
(e.g. "bpf_spin_lock"). This will get confused if module declares a
type with the same name. Probably not a problem in this particular
case, but did you inspect other uses?
Re: [RFC PATCH v2 1/5] btf: search local BTF before base BTF
Posted by Donglin Peng 3 months, 2 weeks ago
On Tue, Oct 21, 2025 at 9:06 AM Eduard Zingerman <eddyz87@gmail.com> wrote:
>
> On Mon, 2025-10-20 at 17:39 +0800, Donglin Peng wrote:
> > Change btf_find_by_name_kind() to search the local BTF first,
> > then fall back to the base BTF. This can skip traversing the large
> > vmlinux BTF when the target type resides in a kernel module's BTF,
> > thereby significantly improving lookup performance.
> >
> > In a test searching for the btf_type of function ext2_new_inode
> > located in the ext2 kernel module:
> >
> > Before: 408631 ns
> > After:     499 ns
> >
> > Performance improvement: ~819x faster
>
> [...]
>
> > ---
>
> The flip makes sense, but are we sure that there are no implicit
> expectations to return base type in case of a name conflict?
>
> E.g. kernel/bpf/btf.c:btf_parse_struct_metas() takes a pointer to
> `btf` instance and looks for types in alloc_obj_fields array by name
> (e.g. "bpf_spin_lock"). This will get confused if module declares a
> type with the same name. Probably not a problem in this particular
> case, but did you inspect other uses?

Thank you for pointing this out. I haven't checked other use cases yet,
and you're right that this could indeed become a real issue if there are
name conflicts between local and base types. It seems difficult to
prevent this behavior entirely. Do you have any suggestions on how we
should handle such potential conflicts?
Re: [RFC PATCH v2 1/5] btf: search local BTF before base BTF
Posted by Eduard Zingerman 3 months, 2 weeks ago
On Tue, 2025-10-21 at 16:31 +0800, Donglin Peng wrote:
> On Tue, Oct 21, 2025 at 9:06 AM Eduard Zingerman <eddyz87@gmail.com> wrote:
> > 
> > On Mon, 2025-10-20 at 17:39 +0800, Donglin Peng wrote:
> > > Change btf_find_by_name_kind() to search the local BTF first,
> > > then fall back to the base BTF. This can skip traversing the large
> > > vmlinux BTF when the target type resides in a kernel module's BTF,
> > > thereby significantly improving lookup performance.
> > > 
> > > In a test searching for the btf_type of function ext2_new_inode
> > > located in the ext2 kernel module:
> > > 
> > > Before: 408631 ns
> > > After:     499 ns
> > > 
> > > Performance improvement: ~819x faster
> > 
> > [...]
> > 
> > > ---
> > 
> > The flip makes sense, but are we sure that there are no implicit
> > expectations to return base type in case of a name conflict?
> > 
> > E.g. kernel/bpf/btf.c:btf_parse_struct_metas() takes a pointer to
> > `btf` instance and looks for types in alloc_obj_fields array by name
> > (e.g. "bpf_spin_lock"). This will get confused if module declares a
> > type with the same name. Probably not a problem in this particular
> > case, but did you inspect other uses?
> 
> Thank you for pointing this out. I haven't checked other use cases yet,
> and you're right that this could indeed become a real issue if there are
> name conflicts between local and base types. It seems difficult to
> prevent this behavior entirely. Do you have any suggestions on how we
> should handle such potential conflicts?

What are the results of the above benchmark after sorting?
If things are fast enough we might not need to do this change.
Otherwise, each call to btf_find_by_name_kind() should be
inspected. If necessary new APIs can be added to search only in
vmlinux, or only in program, or only in module BTF.
Re: [RFC PATCH v2 1/5] btf: search local BTF before base BTF
Posted by Donglin Peng 3 months, 2 weeks ago
On Tue, Oct 21, 2025 at 11:56 PM Eduard Zingerman <eddyz87@gmail.com> wrote:
>
> On Tue, 2025-10-21 at 16:31 +0800, Donglin Peng wrote:
> > On Tue, Oct 21, 2025 at 9:06 AM Eduard Zingerman <eddyz87@gmail.com> wrote:
> > >
> > > On Mon, 2025-10-20 at 17:39 +0800, Donglin Peng wrote:
> > > > Change btf_find_by_name_kind() to search the local BTF first,
> > > > then fall back to the base BTF. This can skip traversing the large
> > > > vmlinux BTF when the target type resides in a kernel module's BTF,
> > > > thereby significantly improving lookup performance.
> > > >
> > > > In a test searching for the btf_type of function ext2_new_inode
> > > > located in the ext2 kernel module:
> > > >
> > > > Before: 408631 ns
> > > > After:     499 ns
> > > >
> > > > Performance improvement: ~819x faster
> > >
> > > [...]
> > >
> > > > ---
> > >
> > > The flip makes sense, but are we sure that there are no implicit
> > > expectations to return base type in case of a name conflict?
> > >
> > > E.g. kernel/bpf/btf.c:btf_parse_struct_metas() takes a pointer to
> > > `btf` instance and looks for types in alloc_obj_fields array by name
> > > (e.g. "bpf_spin_lock"). This will get confused if module declares a
> > > type with the same name. Probably not a problem in this particular
> > > case, but did you inspect other uses?
> >
> > Thank you for pointing this out. I haven't checked other use cases yet,
> > and you're right that this could indeed become a real issue if there are
> > name conflicts between local and base types. It seems difficult to
> > prevent this behavior entirely. Do you have any suggestions on how we
> > should handle such potential conflicts?
>
> What are the results of the above benchmark after sorting?
> If things are fast enough we might not need to do this change.
> Otherwise, each call to btf_find_by_name_kind() should be
> inspected. If necessary new APIs can be added to search only in
> vmlinux, or only in program, or only in module BTF.

Thanks for the suggestion. I'll run some benchmarks and share my findings.