forked from grate-driver/linux
-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
selftest/bpf: Add BPF triggering benchmark
It is sometimes desirable to be able to trigger BPF program from user-space with minimal overhead. sys_enter would seem to be a good candidate, yet in a lot of cases there will be a lot of noise from syscalls triggered by other processes on the system. So while searching for low-overhead alternative, I've stumbled upon getpgid() syscall, which seems to be specific enough to not suffer from accidental syscall by other apps. This set of benchmarks compares tp, raw_tp w/ filtering by syscall ID, kprobe, fentry and fmod_ret with returning error (so that syscall would not be executed), to determine the lowest-overhead way. Here are results on my machine (using benchs/run_bench_trigger.sh script): base : 9.200 ± 0.319M/s tp : 6.690 ± 0.125M/s rawtp : 8.571 ± 0.214M/s kprobe : 6.431 ± 0.048M/s fentry : 8.955 ± 0.241M/s fmodret : 8.903 ± 0.135M/s So it seems like fmodret doesn't give much benefit for such lightweight syscall. Raw tracepoint is pretty decent despite additional filtering logic, but it will be called for any other syscall in the system, which rules it out. Fentry, though, seems to be adding the least amoung of overhead and achieves 97.3% of performance of baseline no-BPF-attached syscall. Using getpgid() seems to be preferable to set_task_comm() approach from test_overhead, as it's about 2.35x faster in a baseline performance. Signed-off-by: Andrii Nakryiko <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Acked-by: John Fastabend <[email protected]> Acked-by: Yonghong Song <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
- Loading branch information
Showing
5 changed files
with
238 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
/* Copyright (c) 2020 Facebook */ | ||
#include "bench.h" | ||
#include "trigger_bench.skel.h" | ||
|
||
/* BPF triggering benchmarks */ | ||
static struct trigger_ctx { | ||
struct trigger_bench *skel; | ||
} ctx; | ||
|
||
static struct counter base_hits; | ||
|
||
static void trigger_validate() | ||
{ | ||
if (env.consumer_cnt != 1) { | ||
fprintf(stderr, "benchmark doesn't support multi-consumer!\n"); | ||
exit(1); | ||
} | ||
} | ||
|
||
static void *trigger_base_producer(void *input) | ||
{ | ||
while (true) { | ||
(void)syscall(__NR_getpgid); | ||
atomic_inc(&base_hits.value); | ||
} | ||
return NULL; | ||
} | ||
|
||
static void trigger_base_measure(struct bench_res *res) | ||
{ | ||
res->hits = atomic_swap(&base_hits.value, 0); | ||
} | ||
|
||
static void *trigger_producer(void *input) | ||
{ | ||
while (true) | ||
(void)syscall(__NR_getpgid); | ||
return NULL; | ||
} | ||
|
||
static void trigger_measure(struct bench_res *res) | ||
{ | ||
res->hits = atomic_swap(&ctx.skel->bss->hits, 0); | ||
} | ||
|
||
static void setup_ctx() | ||
{ | ||
setup_libbpf(); | ||
|
||
ctx.skel = trigger_bench__open_and_load(); | ||
if (!ctx.skel) { | ||
fprintf(stderr, "failed to open skeleton\n"); | ||
exit(1); | ||
} | ||
} | ||
|
||
static void attach_bpf(struct bpf_program *prog) | ||
{ | ||
struct bpf_link *link; | ||
|
||
link = bpf_program__attach(prog); | ||
if (IS_ERR(link)) { | ||
fprintf(stderr, "failed to attach program!\n"); | ||
exit(1); | ||
} | ||
} | ||
|
||
static void trigger_tp_setup() | ||
{ | ||
setup_ctx(); | ||
attach_bpf(ctx.skel->progs.bench_trigger_tp); | ||
} | ||
|
||
static void trigger_rawtp_setup() | ||
{ | ||
setup_ctx(); | ||
attach_bpf(ctx.skel->progs.bench_trigger_raw_tp); | ||
} | ||
|
||
static void trigger_kprobe_setup() | ||
{ | ||
setup_ctx(); | ||
attach_bpf(ctx.skel->progs.bench_trigger_kprobe); | ||
} | ||
|
||
static void trigger_fentry_setup() | ||
{ | ||
setup_ctx(); | ||
attach_bpf(ctx.skel->progs.bench_trigger_fentry); | ||
} | ||
|
||
static void trigger_fmodret_setup() | ||
{ | ||
setup_ctx(); | ||
attach_bpf(ctx.skel->progs.bench_trigger_fmodret); | ||
} | ||
|
||
static void *trigger_consumer(void *input) | ||
{ | ||
return NULL; | ||
} | ||
|
||
const struct bench bench_trig_base = { | ||
.name = "trig-base", | ||
.validate = trigger_validate, | ||
.producer_thread = trigger_base_producer, | ||
.consumer_thread = trigger_consumer, | ||
.measure = trigger_base_measure, | ||
.report_progress = hits_drops_report_progress, | ||
.report_final = hits_drops_report_final, | ||
}; | ||
|
||
const struct bench bench_trig_tp = { | ||
.name = "trig-tp", | ||
.validate = trigger_validate, | ||
.setup = trigger_tp_setup, | ||
.producer_thread = trigger_producer, | ||
.consumer_thread = trigger_consumer, | ||
.measure = trigger_measure, | ||
.report_progress = hits_drops_report_progress, | ||
.report_final = hits_drops_report_final, | ||
}; | ||
|
||
const struct bench bench_trig_rawtp = { | ||
.name = "trig-rawtp", | ||
.validate = trigger_validate, | ||
.setup = trigger_rawtp_setup, | ||
.producer_thread = trigger_producer, | ||
.consumer_thread = trigger_consumer, | ||
.measure = trigger_measure, | ||
.report_progress = hits_drops_report_progress, | ||
.report_final = hits_drops_report_final, | ||
}; | ||
|
||
const struct bench bench_trig_kprobe = { | ||
.name = "trig-kprobe", | ||
.validate = trigger_validate, | ||
.setup = trigger_kprobe_setup, | ||
.producer_thread = trigger_producer, | ||
.consumer_thread = trigger_consumer, | ||
.measure = trigger_measure, | ||
.report_progress = hits_drops_report_progress, | ||
.report_final = hits_drops_report_final, | ||
}; | ||
|
||
const struct bench bench_trig_fentry = { | ||
.name = "trig-fentry", | ||
.validate = trigger_validate, | ||
.setup = trigger_fentry_setup, | ||
.producer_thread = trigger_producer, | ||
.consumer_thread = trigger_consumer, | ||
.measure = trigger_measure, | ||
.report_progress = hits_drops_report_progress, | ||
.report_final = hits_drops_report_final, | ||
}; | ||
|
||
const struct bench bench_trig_fmodret = { | ||
.name = "trig-fmodret", | ||
.validate = trigger_validate, | ||
.setup = trigger_fmodret_setup, | ||
.producer_thread = trigger_producer, | ||
.consumer_thread = trigger_consumer, | ||
.measure = trigger_measure, | ||
.report_progress = hits_drops_report_progress, | ||
.report_final = hits_drops_report_final, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
#!/bin/bash | ||
|
||
set -eufo pipefail | ||
|
||
for i in base tp rawtp kprobe fentry fmodret | ||
do | ||
summary=$(sudo ./bench -w2 -d5 -a trig-$i | tail -n1 | cut -d'(' -f1 | cut -d' ' -f3-) | ||
printf "%-10s: %s\n" $i "$summary" | ||
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
// Copyright (c) 2020 Facebook | ||
|
||
#include <linux/bpf.h> | ||
#include <asm/unistd.h> | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_tracing.h> | ||
|
||
char _license[] SEC("license") = "GPL"; | ||
|
||
long hits = 0; | ||
|
||
SEC("tp/syscalls/sys_enter_getpgid") | ||
int bench_trigger_tp(void *ctx) | ||
{ | ||
__sync_add_and_fetch(&hits, 1); | ||
return 0; | ||
} | ||
|
||
SEC("raw_tp/sys_enter") | ||
int BPF_PROG(bench_trigger_raw_tp, struct pt_regs *regs, long id) | ||
{ | ||
if (id == __NR_getpgid) | ||
__sync_add_and_fetch(&hits, 1); | ||
return 0; | ||
} | ||
|
||
SEC("kprobe/__x64_sys_getpgid") | ||
int bench_trigger_kprobe(void *ctx) | ||
{ | ||
__sync_add_and_fetch(&hits, 1); | ||
return 0; | ||
} | ||
|
||
SEC("fentry/__x64_sys_getpgid") | ||
int bench_trigger_fentry(void *ctx) | ||
{ | ||
__sync_add_and_fetch(&hits, 1); | ||
return 0; | ||
} | ||
|
||
SEC("fmod_ret/__x64_sys_getpgid") | ||
int bench_trigger_fmodret(void *ctx) | ||
{ | ||
__sync_add_and_fetch(&hits, 1); | ||
return -22; | ||
} |