[PATCH bpf-next v9 04/10] libbpf: Optimize type lookup with binary search for sorted BTF

Donglin Peng posted 10 patches 2 months ago
There is a newer version of this series
[PATCH bpf-next v9 04/10] libbpf: Optimize type lookup with binary search for sorted BTF
Posted by Donglin Peng 2 months ago
From: pengdonglin <pengdonglin@xiaomi.com>

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.

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: Ihor Solodrai <ihor.solodrai@linux.dev>
Cc: Xiaoqin Zhang <zhangxiaoqin@xiaomi.com>
Signed-off-by: pengdonglin <pengdonglin@xiaomi.com>
---
 tools/lib/bpf/btf.c | 103 ++++++++++++++++++++++++++++++++++----------
 1 file changed, 80 insertions(+), 23 deletions(-)

diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
index 26ebc0234b9b..7f150c869bf6 100644
--- a/tools/lib/bpf/btf.c
+++ b/tools/lib/bpf/btf.c
@@ -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 sorted_start_id;
 	/* if not NULL, points to the base BTF on top of which the current
 	 * split BTF is based
 	 */
@@ -897,46 +899,98 @@ 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_by_name_bsearch(const struct btf *btf, const char *name,
+						__s32 start_id, __s32 end_id)
 {
-	__u32 i, nr_types = btf__type_cnt(btf);
-
-	if (!strcmp(type_name, "void"))
-		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;
+	const struct btf_type *t;
+	const char *tname;
+	__s32 l, r, m, lmost = -ENOENT;
+	int ret;
+
+	l = start_id;
+	r = end_id;
+	while (l <= r) {
+		m = l + (r - l) / 2;
+		t = btf_type_by_id(btf, m);
+		tname = btf__str_by_offset(btf, t->name_off);
+		ret = strcmp(tname, name);
+		if (ret < 0) {
+			l = m + 1;
+		} else {
+			if (ret == 0)
+				lmost = m;
+			r = m - 1;
+		}
 	}
 
-	return libbpf_err(-ENOENT);
+	return lmost;
 }
 
 static __s32 btf_find_by_name_kind(const struct btf *btf, int start_id,
 				   const char *type_name, __u32 kind)
 {
-	__u32 i, nr_types = btf__type_cnt(btf);
+	const struct btf_type *t;
+	const char *tname;
+	__s32 idx;
+
+	if (start_id < btf->start_id) {
+		idx = btf_find_by_name_kind(btf->base_btf, start_id,
+			type_name, kind);
+		if (idx >= 0)
+			return idx;
+		start_id = btf->start_id;
+	}
 
-	if (kind == BTF_KIND_UNKN || !strcmp(type_name, "void"))
+	if (kind == BTF_KIND_UNKN || strcmp(type_name, "void") == 0)
 		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->sorted_start_id > 0) {
+		__s32 end_id = btf__type_cnt(btf) - 1;
+
+		/* skip anonymous types */
+		start_id = max(start_id, btf->sorted_start_id);
+		idx = btf_find_by_name_bsearch(btf, type_name, start_id, end_id);
+		if (unlikely(idx < 0))
+			return libbpf_err(-ENOENT);
+
+		if (unlikely(kind == -1))
+			return idx;
+
+		t = btf_type_by_id(btf, idx);
+		if (likely(BTF_INFO_KIND(t->info) == kind))
+			return idx;
+
+		for (idx++; idx <= end_id; idx++) {
+			t = btf__type_by_id(btf, idx);
+			tname = btf__str_by_offset(btf, t->name_off);
+			if (strcmp(tname, type_name) != 0)
+				return libbpf_err(-ENOENT);
+			if (btf_kind(t) == kind)
+				return idx;
+		}
+	} else {
+		__u32 i, total;
 
-		if (btf_kind(t) != kind)
-			continue;
-		name = btf__name_by_offset(btf, t->name_off);
-		if (name && !strcmp(type_name, name))
-			return i;
+		total = btf__type_cnt(btf);
+		for (i = start_id; i < total; i++) {
+			t = btf_type_by_id(btf, i);
+			if (kind != -1 && btf_kind(t) != kind)
+				continue;
+			tname = btf__str_by_offset(btf, t->name_off);
+			if (tname && strcmp(tname, type_name) == 0)
+				return i;
+		}
 	}
 
 	return libbpf_err(-ENOENT);
 }
 
+/* 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)
+{
+	return btf_find_by_name_kind(btf, btf->start_id, type_name, -1);
+}
+
 __s32 btf__find_by_name_kind_own(const struct btf *btf, const char *type_name,
 				 __u32 kind)
 {
@@ -1006,6 +1060,7 @@ static struct btf *btf_new_empty(struct btf *base_btf)
 	btf->fd = -1;
 	btf->ptr_sz = sizeof(void *);
 	btf->swapped_endian = false;
+	btf->sorted_start_id = 0;
 
 	if (base_btf) {
 		btf->base_btf = base_btf;
@@ -1057,6 +1112,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->sorted_start_id = 0;
 
 	if (base_btf) {
 		btf->base_btf = base_btf;
@@ -1715,6 +1771,7 @@ static void btf_invalidate_raw_data(struct btf *btf)
 		free(btf->raw_data_swapped);
 		btf->raw_data_swapped = NULL;
 	}
+	btf->sorted_start_id = 0;
 }
 
 /* Ensure BTF is ready to be modified (by splitting into a three memory
-- 
2.34.1
Re: [PATCH bpf-next v9 04/10] libbpf: Optimize type lookup with binary search for sorted BTF
Posted by Eduard Zingerman 1 month, 3 weeks ago
On Mon, 2025-12-08 at 14:23 +0800, Donglin Peng wrote:

[...]

Lgtm, one question below.

>  static __s32 btf_find_by_name_kind(const struct btf *btf, int start_id,
>  				   const char *type_name, __u32 kind)
>  {
> -	__u32 i, nr_types = btf__type_cnt(btf);
> +	const struct btf_type *t;
> +	const char *tname;
> +	__s32 idx;
> +
> +	if (start_id < btf->start_id) {
> +		idx = btf_find_by_name_kind(btf->base_btf, start_id,
> +			type_name, kind);
> +		if (idx >= 0)
> +			return idx;
> +		start_id = btf->start_id;
> +	}
>  
> -	if (kind == BTF_KIND_UNKN || !strcmp(type_name, "void"))
> +	if (kind == BTF_KIND_UNKN || strcmp(type_name, "void") == 0)
>  		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->sorted_start_id > 0) {
> +		__s32 end_id = btf__type_cnt(btf) - 1;
> +
> +		/* skip anonymous types */
> +		start_id = max(start_id, btf->sorted_start_id);
> +		idx = btf_find_by_name_bsearch(btf, type_name, start_id, end_id);
> +		if (unlikely(idx < 0))
> +			return libbpf_err(-ENOENT);
> +
> +		if (unlikely(kind == -1))
> +			return idx;
> +
> +		t = btf_type_by_id(btf, idx);
> +		if (likely(BTF_INFO_KIND(t->info) == kind))
> +			return idx;
> +
> +		for (idx++; idx <= end_id; idx++) {
> +			t = btf__type_by_id(btf, idx);
> +			tname = btf__str_by_offset(btf, t->name_off);
> +			if (strcmp(tname, type_name) != 0)
> +				return libbpf_err(-ENOENT);
> +			if (btf_kind(t) == kind)
                            ^^^^^^^^^^^^^^^^^^^
                Is kind != -1 check missing here?

> +				return idx;
> +		}
> +	} else {
> +		__u32 i, total;
>  
> -		if (btf_kind(t) != kind)
> -			continue;
> -		name = btf__name_by_offset(btf, t->name_off);
> -		if (name && !strcmp(type_name, name))
> -			return i;
> +		total = btf__type_cnt(btf);
> +		for (i = start_id; i < total; i++) {
> +			t = btf_type_by_id(btf, i);
> +			if (kind != -1 && btf_kind(t) != kind)
> +				continue;
> +			tname = btf__str_by_offset(btf, t->name_off);
> +			if (tname && strcmp(tname, type_name) == 0)

Nit: no need for `tname &&` part, as we found out.

> +				return i;
> +		}
>  	}
>  
>  	return libbpf_err(-ENOENT);
>  }
>  
> +/* 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)
> +{
> +	return btf_find_by_name_kind(btf, btf->start_id, type_name, -1);
> +}
> +
>  __s32 btf__find_by_name_kind_own(const struct btf *btf, const char *type_name,
>  				 __u32 kind)
>  {

[...]
Re: [PATCH bpf-next v9 04/10] libbpf: Optimize type lookup with binary search for sorted BTF
Posted by Donglin Peng 1 month, 3 weeks ago
On Wed, Dec 17, 2025 at 7:38 AM Eduard Zingerman <eddyz87@gmail.com> wrote:
>
> On Mon, 2025-12-08 at 14:23 +0800, Donglin Peng wrote:
>
> [...]
>
> Lgtm, one question below.
>
> >  static __s32 btf_find_by_name_kind(const struct btf *btf, int start_id,
> >                                  const char *type_name, __u32 kind)
> >  {
> > -     __u32 i, nr_types = btf__type_cnt(btf);
> > +     const struct btf_type *t;
> > +     const char *tname;
> > +     __s32 idx;
> > +
> > +     if (start_id < btf->start_id) {
> > +             idx = btf_find_by_name_kind(btf->base_btf, start_id,
> > +                     type_name, kind);
> > +             if (idx >= 0)
> > +                     return idx;
> > +             start_id = btf->start_id;
> > +     }
> >
> > -     if (kind == BTF_KIND_UNKN || !strcmp(type_name, "void"))
> > +     if (kind == BTF_KIND_UNKN || strcmp(type_name, "void") == 0)
> >               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->sorted_start_id > 0) {
> > +             __s32 end_id = btf__type_cnt(btf) - 1;
> > +
> > +             /* skip anonymous types */
> > +             start_id = max(start_id, btf->sorted_start_id);
> > +             idx = btf_find_by_name_bsearch(btf, type_name, start_id, end_id);
> > +             if (unlikely(idx < 0))
> > +                     return libbpf_err(-ENOENT);
> > +
> > +             if (unlikely(kind == -1))
> > +                     return idx;
> > +
> > +             t = btf_type_by_id(btf, idx);
> > +             if (likely(BTF_INFO_KIND(t->info) == kind))
> > +                     return idx;
> > +
> > +             for (idx++; idx <= end_id; idx++) {
> > +                     t = btf__type_by_id(btf, idx);
> > +                     tname = btf__str_by_offset(btf, t->name_off);
> > +                     if (strcmp(tname, type_name) != 0)
> > +                             return libbpf_err(-ENOENT);
> > +                     if (btf_kind(t) == kind)
>                             ^^^^^^^^^^^^^^^^^^^
>                 Is kind != -1 check missing here?

The check for kind != -1 is unnecessary here because it has already been
performed earlier in the logic, after btf_find_by_name_bsearch successfully
returned a valid idx. In v8, the implementation of btf_find_by_name_bsearch
was refined for better performance, and when idx > 0, it guarantees that the
name has been matched.

Thank you for the review.
Donglin

>
> > +                             return idx;
> > +             }
> > +     } else {
> > +             __u32 i, total;
> >
> > -             if (btf_kind(t) != kind)
> > -                     continue;
> > -             name = btf__name_by_offset(btf, t->name_off);
> > -             if (name && !strcmp(type_name, name))
> > -                     return i;
> > +             total = btf__type_cnt(btf);
> > +             for (i = start_id; i < total; i++) {
> > +                     t = btf_type_by_id(btf, i);
> > +                     if (kind != -1 && btf_kind(t) != kind)
> > +                             continue;
> > +                     tname = btf__str_by_offset(btf, t->name_off);
> > +                     if (tname && strcmp(tname, type_name) == 0)
>
> Nit: no need for `tname &&` part, as we found out.
>
> > +                             return i;
> > +             }
> >       }
> >
> >       return libbpf_err(-ENOENT);
> >  }
> >
> > +/* 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)
> > +{
> > +     return btf_find_by_name_kind(btf, btf->start_id, type_name, -1);
> > +}
> > +
> >  __s32 btf__find_by_name_kind_own(const struct btf *btf, const char *type_name,
> >                                __u32 kind)
> >  {
>
> [...]
Re: [PATCH bpf-next v9 04/10] libbpf: Optimize type lookup with binary search for sorted BTF
Posted by Eduard Zingerman 1 month, 3 weeks ago
On Wed, 2025-12-17 at 10:32 +0800, Donglin Peng wrote:

[...]

> > > +             if (unlikely(kind == -1))
> > > +                     return idx;
> > > +
> > > +             t = btf_type_by_id(btf, idx);
> > > +             if (likely(BTF_INFO_KIND(t->info) == kind))
> > > +                     return idx;
> > > +
> > > +             for (idx++; idx <= end_id; idx++) {
> > > +                     t = btf__type_by_id(btf, idx);
> > > +                     tname = btf__str_by_offset(btf, t->name_off);
> > > +                     if (strcmp(tname, type_name) != 0)
> > > +                             return libbpf_err(-ENOENT);
> > > +                     if (btf_kind(t) == kind)
> >                             ^^^^^^^^^^^^^^^^^^^
> >                 Is kind != -1 check missing here?
> 
> The check for kind != -1 is unnecessary here because it has already been
> performed earlier in the logic, after btf_find_by_name_bsearch successfully
> returned a valid idx. In v8, the implementation of btf_find_by_name_bsearch
> was refined for better performance, and when idx > 0, it guarantees that the
> name has been matched.
> 
> Thank you for the review.
> Donglin

Ack, missed that, thank you for explaining.
Re: [PATCH bpf-next v9 04/10] libbpf: Optimize type lookup with binary search for sorted BTF
Posted by Donglin Peng 1 month, 3 weeks ago
On Wed, Dec 17, 2025 at 10:32 AM Donglin Peng <dolinux.peng@gmail.com> wrote:
>
> On Wed, Dec 17, 2025 at 7:38 AM Eduard Zingerman <eddyz87@gmail.com> wrote:
> >
> > On Mon, 2025-12-08 at 14:23 +0800, Donglin Peng wrote:
> >
> > [...]
> >
> > Lgtm, one question below.
> >
> > >  static __s32 btf_find_by_name_kind(const struct btf *btf, int start_id,
> > >                                  const char *type_name, __u32 kind)
> > >  {
> > > -     __u32 i, nr_types = btf__type_cnt(btf);
> > > +     const struct btf_type *t;
> > > +     const char *tname;
> > > +     __s32 idx;
> > > +
> > > +     if (start_id < btf->start_id) {
> > > +             idx = btf_find_by_name_kind(btf->base_btf, start_id,
> > > +                     type_name, kind);
> > > +             if (idx >= 0)
> > > +                     return idx;
> > > +             start_id = btf->start_id;
> > > +     }
> > >
> > > -     if (kind == BTF_KIND_UNKN || !strcmp(type_name, "void"))
> > > +     if (kind == BTF_KIND_UNKN || strcmp(type_name, "void") == 0)
> > >               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->sorted_start_id > 0) {
> > > +             __s32 end_id = btf__type_cnt(btf) - 1;
> > > +
> > > +             /* skip anonymous types */
> > > +             start_id = max(start_id, btf->sorted_start_id);
> > > +             idx = btf_find_by_name_bsearch(btf, type_name, start_id, end_id);
> > > +             if (unlikely(idx < 0))
> > > +                     return libbpf_err(-ENOENT);
> > > +
> > > +             if (unlikely(kind == -1))
> > > +                     return idx;
> > > +
> > > +             t = btf_type_by_id(btf, idx);
> > > +             if (likely(BTF_INFO_KIND(t->info) == kind))
> > > +                     return idx;
> > > +
> > > +             for (idx++; idx <= end_id; idx++) {
> > > +                     t = btf__type_by_id(btf, idx);
> > > +                     tname = btf__str_by_offset(btf, t->name_off);
> > > +                     if (strcmp(tname, type_name) != 0)
> > > +                             return libbpf_err(-ENOENT);
> > > +                     if (btf_kind(t) == kind)
> >                             ^^^^^^^^^^^^^^^^^^^
> >                 Is kind != -1 check missing here?
>
> The check for kind != -1 is unnecessary here because it has already been
> performed earlier in the logic, after btf_find_by_name_bsearch successfully
> returned a valid idx. In v8, the implementation of btf_find_by_name_bsearch
> was refined for better performance, and when idx > 0, it guarantees that the
> name has been matched.
>
> Thank you for the review.
> Donglin
>
> >
> > > +                             return idx;
> > > +             }
> > > +     } else {
> > > +             __u32 i, total;
> > >
> > > -             if (btf_kind(t) != kind)
> > > -                     continue;
> > > -             name = btf__name_by_offset(btf, t->name_off);
> > > -             if (name && !strcmp(type_name, name))
> > > -                     return i;
> > > +             total = btf__type_cnt(btf);
> > > +             for (i = start_id; i < total; i++) {
> > > +                     t = btf_type_by_id(btf, i);
> > > +                     if (kind != -1 && btf_kind(t) != kind)
> > > +                             continue;
> > > +                     tname = btf__str_by_offset(btf, t->name_off);
> > > +                     if (tname && strcmp(tname, type_name) == 0)
> >
> > Nit: no need for `tname &&` part, as we found out.

Thanks, I will remove the check in the next version.

> >
> > > +                             return i;
> > > +             }
> > >       }
> > >
> > >       return libbpf_err(-ENOENT);
> > >  }
> > >
> > > +/* 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)
> > > +{
> > > +     return btf_find_by_name_kind(btf, btf->start_id, type_name, -1);
> > > +}
> > > +
> > >  __s32 btf__find_by_name_kind_own(const struct btf *btf, const char *type_name,
> > >                                __u32 kind)
> > >  {
> >
> > [...]
Re: [PATCH bpf-next v9 04/10] libbpf: Optimize type lookup with binary search for sorted BTF
Posted by Eduard Zingerman 1 month, 3 weeks ago
On Tue, 2025-12-16 at 15:38 -0800, Eduard Zingerman wrote:
> On Mon, 2025-12-08 at 14:23 +0800, Donglin Peng wrote:
> 
> [...]
> 
> Lgtm, one question below.
> 
> >  static __s32 btf_find_by_name_kind(const struct btf *btf, int start_id,
> >  				   const char *type_name, __u32 kind)
> >  {
> > -	__u32 i, nr_types = btf__type_cnt(btf);
> > +	const struct btf_type *t;
> > +	const char *tname;
> > +	__s32 idx;
> > +
> > +	if (start_id < btf->start_id) {
> > +		idx = btf_find_by_name_kind(btf->base_btf, start_id,
> > +			type_name, kind);
> > +		if (idx >= 0)
> > +			return idx;
> > +		start_id = btf->start_id;
> > +	}
> >  
> > -	if (kind == BTF_KIND_UNKN || !strcmp(type_name, "void"))
> > +	if (kind == BTF_KIND_UNKN || strcmp(type_name, "void") == 0)
> >  		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->sorted_start_id > 0) {
            ^^^^^^^^^^^^^^^^^^^^^^^^
Also, previous implementation worked for anonymous types, but this one
will not work because of the 'max(start_id, btf->sorted_start_id)', right?
Maybe check that type is not anonymous in the condition above?

> > +		__s32 end_id = btf__type_cnt(btf) - 1;
> > +
> > +		/* skip anonymous types */
> > +		start_id = max(start_id, btf->sorted_start_id);
> > +		idx = btf_find_by_name_bsearch(btf, type_name, start_id, end_id);
> > +		if (unlikely(idx < 0))
> > +			return libbpf_err(-ENOENT);
> > +
> > +		if (unlikely(kind == -1))
> > +			return idx;
> > +
> > +		t = btf_type_by_id(btf, idx);
> > +		if (likely(BTF_INFO_KIND(t->info) == kind))
> > +			return idx;
> > +
> > +		for (idx++; idx <= end_id; idx++) {
> > +			t = btf__type_by_id(btf, idx);
> > +			tname = btf__str_by_offset(btf, t->name_off);
> > +			if (strcmp(tname, type_name) != 0)
> > +				return libbpf_err(-ENOENT);
> > +			if (btf_kind(t) == kind)
>                             ^^^^^^^^^^^^^^^^^^^
>                 Is kind != -1 check missing here?
> 
> > +				return idx;
> > +		}
> > +	} else {
> > +		__u32 i, total;
> >  
> > -		if (btf_kind(t) != kind)
> > -			continue;
> > -		name = btf__name_by_offset(btf, t->name_off);
> > -		if (name && !strcmp(type_name, name))
> > -			return i;
> > +		total = btf__type_cnt(btf);
> > +		for (i = start_id; i < total; i++) {
> > +			t = btf_type_by_id(btf, i);
> > +			if (kind != -1 && btf_kind(t) != kind)
> > +				continue;
> > +			tname = btf__str_by_offset(btf, t->name_off);
> > +			if (tname && strcmp(tname, type_name) == 0)
> 
> Nit: no need for `tname &&` part, as we found out.
> 
> > +				return i;
> > +		}
> >  	}
> >  
> >  	return libbpf_err(-ENOENT);
> >  }
> >  
> > +/* 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)
> > +{
> > +	return btf_find_by_name_kind(btf, btf->start_id, type_name, -1);
> > +}
> > +
> >  __s32 btf__find_by_name_kind_own(const struct btf *btf, const char *type_name,
> >  				 __u32 kind)
> >  {
> 
> [...]
Re: [PATCH bpf-next v9 04/10] libbpf: Optimize type lookup with binary search for sorted BTF
Posted by Donglin Peng 1 month, 3 weeks ago
On Wed, Dec 17, 2025 at 7:43 AM Eduard Zingerman <eddyz87@gmail.com> wrote:
>
> On Tue, 2025-12-16 at 15:38 -0800, Eduard Zingerman wrote:
> > On Mon, 2025-12-08 at 14:23 +0800, Donglin Peng wrote:
> >
> > [...]
> >
> > Lgtm, one question below.
> >
> > >  static __s32 btf_find_by_name_kind(const struct btf *btf, int start_id,
> > >                                const char *type_name, __u32 kind)
> > >  {
> > > -   __u32 i, nr_types = btf__type_cnt(btf);
> > > +   const struct btf_type *t;
> > > +   const char *tname;
> > > +   __s32 idx;
> > > +
> > > +   if (start_id < btf->start_id) {
> > > +           idx = btf_find_by_name_kind(btf->base_btf, start_id,
> > > +                   type_name, kind);
> > > +           if (idx >= 0)
> > > +                   return idx;
> > > +           start_id = btf->start_id;
> > > +   }
> > >
> > > -   if (kind == BTF_KIND_UNKN || !strcmp(type_name, "void"))
> > > +   if (kind == BTF_KIND_UNKN || strcmp(type_name, "void") == 0)
> > >             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->sorted_start_id > 0) {
>             ^^^^^^^^^^^^^^^^^^^^^^^^
> Also, previous implementation worked for anonymous types, but this one
> will not work because of the 'max(start_id, btf->sorted_start_id)', right?

Yes.

> Maybe check that type is not anonymous in the condition above?

Thanks, I will add the check in the next version.

>
> > > +           __s32 end_id = btf__type_cnt(btf) - 1;
> > > +
> > > +           /* skip anonymous types */
> > > +           start_id = max(start_id, btf->sorted_start_id);
> > > +           idx = btf_find_by_name_bsearch(btf, type_name, start_id, end_id);
> > > +           if (unlikely(idx < 0))
> > > +                   return libbpf_err(-ENOENT);
> > > +
> > > +           if (unlikely(kind == -1))
> > > +                   return idx;
> > > +
> > > +           t = btf_type_by_id(btf, idx);
> > > +           if (likely(BTF_INFO_KIND(t->info) == kind))
> > > +                   return idx;
> > > +
> > > +           for (idx++; idx <= end_id; idx++) {
> > > +                   t = btf__type_by_id(btf, idx);
> > > +                   tname = btf__str_by_offset(btf, t->name_off);
> > > +                   if (strcmp(tname, type_name) != 0)
> > > +                           return libbpf_err(-ENOENT);
> > > +                   if (btf_kind(t) == kind)
> >                             ^^^^^^^^^^^^^^^^^^^
> >                 Is kind != -1 check missing here?
> >
> > > +                           return idx;
> > > +           }
> > > +   } else {
> > > +           __u32 i, total;
> > >
> > > -           if (btf_kind(t) != kind)
> > > -                   continue;
> > > -           name = btf__name_by_offset(btf, t->name_off);
> > > -           if (name && !strcmp(type_name, name))
> > > -                   return i;
> > > +           total = btf__type_cnt(btf);
> > > +           for (i = start_id; i < total; i++) {
> > > +                   t = btf_type_by_id(btf, i);
> > > +                   if (kind != -1 && btf_kind(t) != kind)
> > > +                           continue;
> > > +                   tname = btf__str_by_offset(btf, t->name_off);
> > > +                   if (tname && strcmp(tname, type_name) == 0)
> >
> > Nit: no need for `tname &&` part, as we found out.
> >
> > > +                           return i;
> > > +           }
> > >     }
> > >
> > >     return libbpf_err(-ENOENT);
> > >  }
> > >
> > > +/* 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)
> > > +{
> > > +   return btf_find_by_name_kind(btf, btf->start_id, type_name, -1);
> > > +}
> > > +
> > >  __s32 btf__find_by_name_kind_own(const struct btf *btf, const char *type_name,
> > >                              __u32 kind)
> > >  {
> >
> > [...]