Skip to content

Commit 4eaf0b5

Browse files
anakryikoAlexei Starovoitov
authored andcommitted
selftest/bpf: Fmod_ret prog and implement test_overhead as part of bench
Add fmod_ret BPF program to existing test_overhead selftest. Also re-implement user-space benchmarking part into benchmark runner to compare results. Results with ./bench are consistently somewhat lower than test_overhead's, but relative performance of various types of BPF programs stay consisten (e.g., kretprobe is noticeably slower). This slowdown seems to be coming from the fact that test_overhead is single-threaded, while benchmark always spins off at least one thread for producer. This has been confirmed by hacking multi-threaded test_overhead variant and also single-threaded bench variant. Resutls are below. run_bench_rename.sh script from benchs/ subdirectory was used to produce results for ./bench. Single-threaded implementations =============================== /* bench: single-threaded, atomics */ base : 4.622 ± 0.049M/s kprobe : 3.673 ± 0.052M/s kretprobe : 2.625 ± 0.052M/s rawtp : 4.369 ± 0.089M/s fentry : 4.201 ± 0.558M/s fexit : 4.309 ± 0.148M/s fmodret : 4.314 ± 0.203M/s /* selftest: single-threaded, no atomics */ task_rename base 4555K events per sec task_rename kprobe 3643K events per sec task_rename kretprobe 2506K events per sec task_rename raw_tp 4303K events per sec task_rename fentry 4307K events per sec task_rename fexit 4010K events per sec task_rename fmod_ret 3984K events per sec Multi-threaded implementations ============================== /* bench: multi-threaded w/ atomics */ base : 3.910 ± 0.023M/s kprobe : 3.048 ± 0.037M/s kretprobe : 2.300 ± 0.015M/s rawtp : 3.687 ± 0.034M/s fentry : 3.740 ± 0.087M/s fexit : 3.510 ± 0.009M/s fmodret : 3.485 ± 0.050M/s /* selftest: multi-threaded w/ atomics */ task_rename base 3872K events per sec task_rename kprobe 3068K events per sec task_rename kretprobe 2350K events per sec task_rename raw_tp 3731K events per sec task_rename fentry 3639K events per sec task_rename fexit 3558K events per sec task_rename fmod_ret 3511K events per sec /* selftest: multi-threaded, no atomics */ task_rename base 3945K events per sec task_rename kprobe 3298K events per sec task_rename kretprobe 2451K events per sec task_rename raw_tp 3718K events per sec task_rename fentry 3782K events per sec task_rename fexit 3543K events per sec task_rename fmod_ret 3526K events per sec Note that the fact that ./bench benchmark always uses atomic increments for counting, while test_overhead doesn't, doesn't influence test results all that much. Signed-off-by: Andrii Nakryiko <andriin@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: John Fastabend <john.fastabend@gmail.com> Acked-by: Yonghong Song <yhs@fb.com> Link: https://lore.kernel.org/bpf/20200512192445.2351848-4-andriin@fb.com
1 parent 8e7c2a0 commit 4eaf0b5

File tree

6 files changed

+240
-2
lines changed

6 files changed

+240
-2
lines changed

tools/testing/selftests/bpf/Makefile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,10 +411,12 @@ $(OUTPUT)/test_cpp: test_cpp.cpp $(OUTPUT)/test_core_extern.skel.h $(BPFOBJ)
411411
$(OUTPUT)/bench_%.o: benchs/bench_%.c bench.h
412412
$(call msg,CC,,$@)
413413
$(CC) $(CFLAGS) -c $(filter %.c,$^) $(LDLIBS) -o $@
414+
$(OUTPUT)/bench_rename.o: $(OUTPUT)/test_overhead.skel.h
414415
$(OUTPUT)/bench.o: bench.h testing_helpers.h
415416
$(OUTPUT)/bench: LDLIBS += -lm
416417
$(OUTPUT)/bench: $(OUTPUT)/bench.o $(OUTPUT)/testing_helpers.o \
417-
$(OUTPUT)/bench_count.o
418+
$(OUTPUT)/bench_count.o \
419+
$(OUTPUT)/bench_rename.o
418420
$(call msg,BINARY,,$@)
419421
$(CC) $(LDFLAGS) -o $@ $(filter %.a %.o,$^) $(LDLIBS)
420422

tools/testing/selftests/bpf/bench.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,10 +297,24 @@ const struct bench *bench = NULL;
297297

298298
extern const struct bench bench_count_global;
299299
extern const struct bench bench_count_local;
300+
extern const struct bench bench_rename_base;
301+
extern const struct bench bench_rename_kprobe;
302+
extern const struct bench bench_rename_kretprobe;
303+
extern const struct bench bench_rename_rawtp;
304+
extern const struct bench bench_rename_fentry;
305+
extern const struct bench bench_rename_fexit;
306+
extern const struct bench bench_rename_fmodret;
300307

301308
static const struct bench *benchs[] = {
302309
&bench_count_global,
303310
&bench_count_local,
311+
&bench_rename_base,
312+
&bench_rename_kprobe,
313+
&bench_rename_kretprobe,
314+
&bench_rename_rawtp,
315+
&bench_rename_fentry,
316+
&bench_rename_fexit,
317+
&bench_rename_fmodret,
304318
};
305319

306320
static void setup_benchmark()
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (c) 2020 Facebook */
3+
#include <fcntl.h>
4+
#include "bench.h"
5+
#include "test_overhead.skel.h"
6+
7+
/* BPF triggering benchmarks */
8+
static struct ctx {
9+
struct test_overhead *skel;
10+
struct counter hits;
11+
int fd;
12+
} ctx;
13+
14+
static void validate()
15+
{
16+
if (env.producer_cnt != 1) {
17+
fprintf(stderr, "benchmark doesn't support multi-producer!\n");
18+
exit(1);
19+
}
20+
if (env.consumer_cnt != 1) {
21+
fprintf(stderr, "benchmark doesn't support multi-consumer!\n");
22+
exit(1);
23+
}
24+
}
25+
26+
static void *producer(void *input)
27+
{
28+
char buf[] = "test_overhead";
29+
int err;
30+
31+
while (true) {
32+
err = write(ctx.fd, buf, sizeof(buf));
33+
if (err < 0) {
34+
fprintf(stderr, "write failed\n");
35+
exit(1);
36+
}
37+
atomic_inc(&ctx.hits.value);
38+
}
39+
}
40+
41+
static void measure(struct bench_res *res)
42+
{
43+
res->hits = atomic_swap(&ctx.hits.value, 0);
44+
}
45+
46+
static void setup_ctx()
47+
{
48+
setup_libbpf();
49+
50+
ctx.skel = test_overhead__open_and_load();
51+
if (!ctx.skel) {
52+
fprintf(stderr, "failed to open skeleton\n");
53+
exit(1);
54+
}
55+
56+
ctx.fd = open("/proc/self/comm", O_WRONLY|O_TRUNC);
57+
if (ctx.fd < 0) {
58+
fprintf(stderr, "failed to open /proc/self/comm: %d\n", -errno);
59+
exit(1);
60+
}
61+
}
62+
63+
static void attach_bpf(struct bpf_program *prog)
64+
{
65+
struct bpf_link *link;
66+
67+
link = bpf_program__attach(prog);
68+
if (IS_ERR(link)) {
69+
fprintf(stderr, "failed to attach program!\n");
70+
exit(1);
71+
}
72+
}
73+
74+
static void setup_base()
75+
{
76+
setup_ctx();
77+
}
78+
79+
static void setup_kprobe()
80+
{
81+
setup_ctx();
82+
attach_bpf(ctx.skel->progs.prog1);
83+
}
84+
85+
static void setup_kretprobe()
86+
{
87+
setup_ctx();
88+
attach_bpf(ctx.skel->progs.prog2);
89+
}
90+
91+
static void setup_rawtp()
92+
{
93+
setup_ctx();
94+
attach_bpf(ctx.skel->progs.prog3);
95+
}
96+
97+
static void setup_fentry()
98+
{
99+
setup_ctx();
100+
attach_bpf(ctx.skel->progs.prog4);
101+
}
102+
103+
static void setup_fexit()
104+
{
105+
setup_ctx();
106+
attach_bpf(ctx.skel->progs.prog5);
107+
}
108+
109+
static void setup_fmodret()
110+
{
111+
setup_ctx();
112+
attach_bpf(ctx.skel->progs.prog6);
113+
}
114+
115+
static void *consumer(void *input)
116+
{
117+
return NULL;
118+
}
119+
120+
const struct bench bench_rename_base = {
121+
.name = "rename-base",
122+
.validate = validate,
123+
.setup = setup_base,
124+
.producer_thread = producer,
125+
.consumer_thread = consumer,
126+
.measure = measure,
127+
.report_progress = hits_drops_report_progress,
128+
.report_final = hits_drops_report_final,
129+
};
130+
131+
const struct bench bench_rename_kprobe = {
132+
.name = "rename-kprobe",
133+
.validate = validate,
134+
.setup = setup_kprobe,
135+
.producer_thread = producer,
136+
.consumer_thread = consumer,
137+
.measure = measure,
138+
.report_progress = hits_drops_report_progress,
139+
.report_final = hits_drops_report_final,
140+
};
141+
142+
const struct bench bench_rename_kretprobe = {
143+
.name = "rename-kretprobe",
144+
.validate = validate,
145+
.setup = setup_kretprobe,
146+
.producer_thread = producer,
147+
.consumer_thread = consumer,
148+
.measure = measure,
149+
.report_progress = hits_drops_report_progress,
150+
.report_final = hits_drops_report_final,
151+
};
152+
153+
const struct bench bench_rename_rawtp = {
154+
.name = "rename-rawtp",
155+
.validate = validate,
156+
.setup = setup_rawtp,
157+
.producer_thread = producer,
158+
.consumer_thread = consumer,
159+
.measure = measure,
160+
.report_progress = hits_drops_report_progress,
161+
.report_final = hits_drops_report_final,
162+
};
163+
164+
const struct bench bench_rename_fentry = {
165+
.name = "rename-fentry",
166+
.validate = validate,
167+
.setup = setup_fentry,
168+
.producer_thread = producer,
169+
.consumer_thread = consumer,
170+
.measure = measure,
171+
.report_progress = hits_drops_report_progress,
172+
.report_final = hits_drops_report_final,
173+
};
174+
175+
const struct bench bench_rename_fexit = {
176+
.name = "rename-fexit",
177+
.validate = validate,
178+
.setup = setup_fexit,
179+
.producer_thread = producer,
180+
.consumer_thread = consumer,
181+
.measure = measure,
182+
.report_progress = hits_drops_report_progress,
183+
.report_final = hits_drops_report_final,
184+
};
185+
186+
const struct bench bench_rename_fmodret = {
187+
.name = "rename-fmodret",
188+
.validate = validate,
189+
.setup = setup_fmodret,
190+
.producer_thread = producer,
191+
.consumer_thread = consumer,
192+
.measure = measure,
193+
.report_progress = hits_drops_report_progress,
194+
.report_final = hits_drops_report_final,
195+
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/bash
2+
3+
set -eufo pipefail
4+
5+
for i in base kprobe kretprobe rawtp fentry fexit fmodret
6+
do
7+
summary=$(sudo ./bench -w2 -d5 -a rename-$i | tail -n1 | cut -d'(' -f1 | cut -d' ' -f3-)
8+
printf "%-10s: %s\n" $i "$summary"
9+
done

tools/testing/selftests/bpf/prog_tests/test_overhead.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ void test_test_overhead(void)
6161
const char *raw_tp_name = "raw_tp/task_rename";
6262
const char *fentry_name = "fentry/__set_task_comm";
6363
const char *fexit_name = "fexit/__set_task_comm";
64+
const char *fmodret_name = "fmod_ret/__set_task_comm";
6465
const char *kprobe_func = "__set_task_comm";
6566
struct bpf_program *kprobe_prog, *kretprobe_prog, *raw_tp_prog;
66-
struct bpf_program *fentry_prog, *fexit_prog;
67+
struct bpf_program *fentry_prog, *fexit_prog, *fmodret_prog;
6768
struct bpf_object *obj;
6869
struct bpf_link *link;
6970
int err, duration = 0;
@@ -96,6 +97,10 @@ void test_test_overhead(void)
9697
if (CHECK(!fexit_prog, "find_probe",
9798
"prog '%s' not found\n", fexit_name))
9899
goto cleanup;
100+
fmodret_prog = bpf_object__find_program_by_title(obj, fmodret_name);
101+
if (CHECK(!fmodret_prog, "find_probe",
102+
"prog '%s' not found\n", fmodret_name))
103+
goto cleanup;
99104

100105
err = bpf_object__load(obj);
101106
if (CHECK(err, "obj_load", "err %d\n", err))
@@ -142,6 +147,13 @@ void test_test_overhead(void)
142147
goto cleanup;
143148
test_run("fexit");
144149
bpf_link__destroy(link);
150+
151+
/* attach fmod_ret */
152+
link = bpf_program__attach_trace(fmodret_prog);
153+
if (CHECK(IS_ERR(link), "attach fmod_ret", "err %ld\n", PTR_ERR(link)))
154+
goto cleanup;
155+
test_run("fmod_ret");
156+
bpf_link__destroy(link);
145157
cleanup:
146158
prctl(PR_SET_NAME, comm, 0L, 0L, 0L);
147159
bpf_object__close(obj);

tools/testing/selftests/bpf/progs/test_overhead.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,10 @@ int BPF_PROG(prog5, struct task_struct *tsk, const char *buf, bool exec)
3939
return !tsk;
4040
}
4141

42+
SEC("fmod_ret/__set_task_comm")
43+
int BPF_PROG(prog6, struct task_struct *tsk, const char *buf, bool exec)
44+
{
45+
return !tsk;
46+
}
47+
4248
char _license[] SEC("license") = "GPL";

0 commit comments

Comments
 (0)