Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bench: add hash maps test results #80

Merged
merged 2 commits into from
Nov 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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=0
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
Loading