Skip to content

Commit

Permalink
add new benchmark
Browse files Browse the repository at this point in the history
  • Loading branch information
yunwei37 committed Nov 15, 2023
1 parent e4d87b8 commit cf1ec55
Show file tree
Hide file tree
Showing 38 changed files with 747 additions and 608 deletions.
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ build: ## build the package
cd tools/cli-rs && cargo build

release: ## build the package
cmake -Bbuild -DBPFTIME_ENABLE_UNIT_TESTING=0 -DCMAKE_BUILD_TYPE:STRING=Release
cmake -Bbuild -DBPFTIME_ENABLE_UNIT_TESTING=0 \
-DCMAKE_BUILD_TYPE:STRING=Release \
-DBPFTIME_ENABLE_LTO=1
cmake --build build --config Release --target install
cd tools/cli-rs && cargo build --release

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ package.json
*.skel.yaml
package.yaml
ecli
bootstrap
.output
opensnoop
victim
dump*
test
uretprobe
bpf-syscall-bench
101 changes: 101 additions & 0 deletions benchmark/bpf-syscall/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
OUTPUT := .output
CLANG ?= clang
LIBBPF_SRC := $(abspath ../../third_party/libbpf/src)
BPFTOOL_SRC := $(abspath ../../third_party/bpftool/src)
LIBBPF_OBJ := $(abspath $(OUTPUT)/libbpf.a)
BPFTOOL_OUTPUT ?= $(abspath $(OUTPUT)/bpftool)
BPFTOOL ?= $(BPFTOOL_OUTPUT)/bootstrap/bpftool
ARCH ?= $(shell uname -m | sed 's/x86_64/x86/' \
| sed 's/arm.*/arm/' \
| sed 's/aarch64/arm64/' \
| sed 's/ppc64le/powerpc/' \
| sed 's/mips.*/mips/' \
| sed 's/riscv64/riscv/' \
| sed 's/loongarch64/loongarch/')
VMLINUX := ../../third_party/vmlinux/$(ARCH)/vmlinux.h
# Use our own libbpf API headers and Linux UAPI headers distributed with
# libbpf to avoid dependency on system-wide headers, which could be missing or
# outdated
INCLUDES := -I$(OUTPUT) -I../../third_party/libbpf/include -I../../third_party/libbpf/include/uapi -I$(dir $(VMLINUX))
CFLAGS := -g -Wall
ALL_LDFLAGS := $(LDFLAGS) $(EXTRA_LDFLAGS)

APPS = bpf-syscall-bench # minimal minimal_legacy kprobe fentry usdt sockfilter tc ksyscall

CARGO ?= $(shell which cargo)
ifeq ($(strip $(CARGO)),)
BZS_APPS :=
else
BZS_APPS := # profile
APPS += $(BZS_APPS)
# Required by libblazesym
ALL_LDFLAGS += -lrt -ldl -lpthread -lm
endif

# Get Clang's default includes on this system. We'll explicitly add these dirs
# to the includes list when compiling with `-target bpf` because otherwise some
# architecture-specific dirs will be "missing" on some architectures/distros -
# headers such as asm/types.h, asm/byteorder.h, asm/socket.h, asm/sockios.h,
# sys/cdefs.h etc. might be missing.
#
# Use '-idirafter': Don't interfere with include mechanics except where the
# build would have failed anyways.
CLANG_BPF_SYS_INCLUDES ?= $(shell $(CLANG) -v -E - </dev/null 2>&1 \
| sed -n '/<...> search starts here:/,/End of search list./{ s| \(/.*\)|-idirafter \1|p }')

ifeq ($(V),1)
Q =
msg =
else
Q = @
msg = @printf ' %-8s %s%s\n' \
"$(1)" \
"$(patsubst $(abspath $(OUTPUT))/%,%,$(2))" \
"$(if $(3), $(3))";
MAKEFLAGS += --no-print-directory
endif

define allow-override
$(if $(or $(findstring environment,$(origin $(1))),\
$(findstring command line,$(origin $(1)))),,\
$(eval $(1) = $(2)))
endef

$(call allow-override,CC,$(CROSS_COMPILE)cc)
$(call allow-override,LD,$(CROSS_COMPILE)ld)

.PHONY: all
all: $(APPS)

.PHONY: clean
clean:
$(call msg,CLEAN)
$(Q)rm -rf $(OUTPUT) $(APPS)

$(OUTPUT) $(OUTPUT)/libbpf $(BPFTOOL_OUTPUT):
$(call msg,MKDIR,$@)
$(Q)mkdir -p $@

# Build libbpf
$(LIBBPF_OBJ): $(wildcard $(LIBBPF_SRC)/*.[ch] $(LIBBPF_SRC)/Makefile) | $(OUTPUT)/libbpf
$(call msg,LIB,$@)
$(Q)$(MAKE) -C $(LIBBPF_SRC) BUILD_STATIC_ONLY=1 \
OBJDIR=$(dir $@)/libbpf DESTDIR=$(dir $@) \
INCLUDEDIR= LIBDIR= UAPIDIR= \
install

.output/bpf-syscall-bench.o: bpf-syscall-bench.c $(OUTPUT)
$(call msg,CC,$@)
$(Q)$(CC) $(CFLAGS) $(INCLUDES) -c $< -o $@

# Build application binary
$(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) | $(OUTPUT)
$(call msg,BINARY,$@)
$(Q)$(CC) $(CFLAGS) $^ $(ALL_LDFLAGS) -lelf -lz -o $@

# delete failed targets
.DELETE_ON_ERROR:

# keep intermediate (.skel.h, .bpf.o, etc) targets
.SECONDARY:
115 changes: 115 additions & 0 deletions benchmark/bpf-syscall/bpf-syscall-bench.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
/* Copyright (c) 2020 Facebook */
#include <signal.h>
#include <stdio.h>
#include <time.h>
#include <stdint.h>
#include <sys/resource.h>
#include <bpf/libbpf.h>
#include <bpf/bpf.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <stdint.h>
#include "linux/filter.h"

int prog_fd;

// The timespec struct holds seconds and nanoseconds
struct timespec start_time, end_time;

void start_timer()
{
clock_gettime(CLOCK_MONOTONIC_RAW, &start_time);
}

void end_timer()
{
clock_gettime(CLOCK_MONOTONIC_RAW, &end_time);
}

__attribute_noinline__ uint64_t __benchmark_test_function1(const char *a, int b,
uint64_t c)
{
return bpf_prog_test_run_opts(prog_fd, NULL);
}

typedef uint64_t (*benchmark_test_function_t)(const char *, int, uint64_t);

static double get_elapsed_time()
{
long seconds = end_time.tv_sec - start_time.tv_sec;
long nanoseconds = end_time.tv_nsec - start_time.tv_nsec;
if (start_time.tv_nsec > end_time.tv_nsec) { // clock underflow
--seconds;
nanoseconds += 1000000000;
}
printf("Elapsed time: %ld.%09ld seconds\n", seconds, nanoseconds);
return seconds * 1.0 + nanoseconds / 1000000000.0;
}

static double get_function_time(benchmark_test_function_t func, int iter)
{
start_timer();
// test base line
for (int i = 0; i < iter; i++) {
func("hello", i % 4, i);
}
end_timer();
double time = get_elapsed_time();
return time;
}

void do_benchmark_userspace(benchmark_test_function_t func, int iter)
{
double base_line_time;

printf("a[b] + c for %d times\n", iter);
base_line_time = get_function_time(func, iter);
printf("Average time usage %lf ns\n\n",
(base_line_time) / iter * 1000000000.0);
}

#define do_benchmark_func(func, iter) \
do { \
printf("Benchmarking %s\n", #func); \
do_benchmark_userspace(func ,iter); \
} while (0)

int test_run_time()
{
puts("");
struct bpf_insn trival_prog_insns[] = {
BPF_MOV64_IMM(BPF_REG_0, 0),
BPF_EXIT_INSN(),
};
int prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL",
trival_prog_insns, 2, NULL);
if (prog_fd < 0) {
printf("Failed to load BPF program: %s\n", strerror(prog_fd));
exit(1);
}
int iter = 100 * 1000;
do_benchmark_func(__benchmark_test_function1, iter);
return 0;
}

#define warn(...) fprintf(stderr, __VA_ARGS__)

static int libbpf_print_fn(enum libbpf_print_level level, const char *format,
va_list args)
{
return vfprintf(stderr, format, args);
}

int main(int argc, char **argv)
{
/* Set up libbpf errors and debug info callback */
libbpf_set_print(libbpf_print_fn);

test_run_time();

return 0;
}
10 changes: 10 additions & 0 deletions benchmark/hash_map/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.vscode
package.json
*.o
*.skel.json
*.skel.yaml
package.yaml
ecli
.output
test
uprobe
7 changes: 2 additions & 5 deletions benchmark/hash_maps/Makefile → benchmark/hash_map/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ INCLUDES := -I$(OUTPUT) -I../../third_party/libbpf/include/uapi -I$(dir $(VMLINU
CFLAGS := -g -Wall
ALL_LDFLAGS := $(LDFLAGS) $(EXTRA_LDFLAGS)

APPS = opensnoop # minimal minimal_legacy uprobe kprobe fentry usdt sockfilter tc ksyscall
APPS = uprobe # minimal minimal_legacy kprobe fentry usdt sockfilter tc ksyscall

CARGO ?= $(shell which cargo)
ifeq ($(strip $(CARGO)),)
Expand Down Expand Up @@ -66,7 +66,7 @@ $(call allow-override,CC,$(CROSS_COMPILE)cc)
$(call allow-override,LD,$(CROSS_COMPILE)ld)

.PHONY: all
all: $(APPS) victim
all: $(APPS)

.PHONY: clean
clean:
Expand Down Expand Up @@ -136,6 +136,3 @@ $(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) | $(OUTPUT)

# keep intermediate (.skel.h, .bpf.o, etc) targets
.SECONDARY:

victim: victim.cpp
$(CXX) -Wall -g victim.cpp -o victim
42 changes: 42 additions & 0 deletions benchmark/hash_map/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# benchmark of hash maps

- __benchmark_test_function1: hashmap bpf_map_lookup_elem
- __benchmark_test_function2: hashmap bpf_map_delete_elem
- __benchmark_test_function3: hashmap bpf_map_update_elem

run the uprobe:

```console
$ LD_PRELOAD=build/runtime/syscall-server/libbpftime-syscall-server.so benchmark/hash_map/uprobe
manager constructed
global_shm_open_type 0 for bpftime_maps_shm
Closing 3
libbpf: loading object 'uprobe_bpf' from buffer
libbpf: elf: section(2) .symtab, size 120, link 1, flags 0, type=2
...
loaded ebpf program...
...
```

in another terminal, run the benchmark:

```console
$ LD_PRELOAD=build/runtime/agent/libbpftime-agent.so benchmark/test

Benchmarking __benchmark_test_function1
a[b] + c for 100000 times
Elapsed time: 0.038217773 seconds
Average time usage 382.177730 ns

Benchmarking __benchmark_test_function2
a[b] + c for 100000 times
Elapsed time: 0.020004455 seconds
Average time usage 200.044550 ns

Benchmarking __benchmark_test_function3
a[b] + c for 100000 times
Elapsed time: 0.047916014 seconds
Average time usage 479.160140 ns

INFO [34534]: Global shm destructed
```
43 changes: 43 additions & 0 deletions benchmark/hash_map/uprobe.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#define BPF_NO_GLOBAL_DATA
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1024);
__type(key, u32);
__type(value, u64);
} libc_malloc_calls_total SEC(".maps");

SEC("uprobe/benchmark/test:__benchmark_test_function3")
int test_update(struct pt_regs *ctx)
{
u32 key = 0;
u64 value = 0;
bpf_map_update_elem(&libc_malloc_calls_total, &key, &value, 0);

return 0;
}

SEC("uprobe/benchmark/test:__benchmark_test_function2")
int test_delete(struct pt_regs *ctx)
{
u32 key = 0;
u64 value = 0;
bpf_map_delete_elem(&libc_malloc_calls_total, &key);

return 0;
}

SEC("uprobe/benchmark/test:__benchmark_test_function1")
int test_lookup(struct pt_regs *ctx)
{
u32 key = 0;
u64 value = 0;
bpf_map_lookup_elem(&libc_malloc_calls_total, &key);

return 0;
}

char LICENSE[] SEC("license") = "GPL";
Loading

0 comments on commit cf1ec55

Please sign in to comment.