Skip to content

Commit 7c311b7

Browse files
eddyz87anakryiko
authored andcommitted
veristat: Load struct_ops programs only once
libbpf automatically adjusts autoload for struct_ops programs, see libbpf.c:bpf_object_adjust_struct_ops_autoload. For example, if there is a map: SEC(".struct_ops.link") struct sched_ext_ops ops = { .enqueue = foo, .tick = bar, }; Both 'foo' and 'bar' would be loaded if 'ops' autocreate is true, both 'foo' and 'bar' would be skipped if 'ops' autocreate is false. This means that when veristat processes object file with 'ops', it would load 4 programs in total: two programs per each 'process_prog' call. The adjustment occurs at object load time, and libbpf remembers association between 'ops' and 'foo'/'bar' at object open time. The only way to persuade libbpf to load one of two is to adjust map initial value, such that only one program is referenced. This patch does exactly that, significantly reducing time to process object files with big number of struct_ops programs. Signed-off-by: Eduard Zingerman <eddyz87@gmail.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/20250115223835.919989-1-eddyz87@gmail.com
1 parent a8d1c48 commit 7c311b7

File tree

1 file changed

+38
-0
lines changed

1 file changed

+38
-0
lines changed

tools/testing/selftests/bpf/veristat.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,6 +1062,41 @@ static int guess_prog_type_by_ctx_name(const char *ctx_name,
10621062
return -ESRCH;
10631063
}
10641064

1065+
/* Make sure only target program is referenced from struct_ops map,
1066+
* otherwise libbpf would automatically set autocreate for all
1067+
* referenced programs.
1068+
* See libbpf.c:bpf_object_adjust_struct_ops_autoload.
1069+
*/
1070+
static void mask_unrelated_struct_ops_progs(struct bpf_object *obj,
1071+
struct bpf_map *map,
1072+
struct bpf_program *prog)
1073+
{
1074+
struct btf *btf = bpf_object__btf(obj);
1075+
const struct btf_type *t, *mt;
1076+
struct btf_member *m;
1077+
int i, moff;
1078+
size_t data_sz, ptr_sz = sizeof(void *);
1079+
void *data;
1080+
1081+
t = btf__type_by_id(btf, bpf_map__btf_value_type_id(map));
1082+
if (!btf_is_struct(t))
1083+
return;
1084+
1085+
data = bpf_map__initial_value(map, &data_sz);
1086+
for (i = 0; i < btf_vlen(t); i++) {
1087+
m = &btf_members(t)[i];
1088+
mt = btf__type_by_id(btf, m->type);
1089+
if (!btf_is_ptr(mt))
1090+
continue;
1091+
moff = m->offset / 8;
1092+
if (moff + ptr_sz > data_sz)
1093+
continue;
1094+
if (memcmp(data + moff, &prog, ptr_sz) == 0)
1095+
continue;
1096+
memset(data + moff, 0, ptr_sz);
1097+
}
1098+
}
1099+
10651100
static void fixup_obj(struct bpf_object *obj, struct bpf_program *prog, const char *filename)
10661101
{
10671102
struct bpf_map *map;
@@ -1077,6 +1112,9 @@ static void fixup_obj(struct bpf_object *obj, struct bpf_program *prog, const ch
10771112
case BPF_MAP_TYPE_INODE_STORAGE:
10781113
case BPF_MAP_TYPE_CGROUP_STORAGE:
10791114
break;
1115+
case BPF_MAP_TYPE_STRUCT_OPS:
1116+
mask_unrelated_struct_ops_progs(obj, map, prog);
1117+
break;
10801118
default:
10811119
if (bpf_map__max_entries(map) == 0)
10821120
bpf_map__set_max_entries(map, 1);

0 commit comments

Comments
 (0)