diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..eca74f0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +output-image +venv +.vscode diff --git a/bpf_progs/Makefile b/bpf_progs/Makefile index f14e4b2..20cc16c 100644 --- a/bpf_progs/Makefile +++ b/bpf_progs/Makefile @@ -4,11 +4,11 @@ ALL_NATIVE_PROGS = $(patsubst %.bpf.c,%.native,$(shell ls *.bpf.c)) all: $(ALL_EBPF_PROGS) $(ALL_NATIVE_PROGS) %.bpf.o: %.bpf.c - clang -Wall -O2 -target bpf -c -o $@ $< + clang -Wall -O3 -target bpf -c -o $@ $< %.bpf.bin: %.bpf.o llvm-objcopy -j .text -O binary $< $@ %.native: %.bpf.c native_wrapper.c - clang -Wall -O2 -o $@ $^ + clang -Wall -O3 -o $@ $^ clean: rm -rf *.bpf.o *.bpf.bin *.native diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f048409 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,11 @@ +contourpy==1.1.0 +cycler==0.11.0 +fonttools==4.42.0 +kiwisolver==1.4.4 +matplotlib==3.7.2 +numpy==1.25.2 +packaging==23.1 +Pillow==10.0.0 +pyparsing==3.0.9 +python-dateutil==2.8.2 +six==1.16.0 diff --git a/run_benchmark.py b/run_benchmark.py index e01f724..d840ece 100644 --- a/run_benchmark.py +++ b/run_benchmark.py @@ -3,6 +3,9 @@ import subprocess import os import multiprocessing +import matplotlib.pyplot as plt +import shutil + PROGS_DIR = Path("./bpf_progs") EXECUTABLES = ["./bpftime-ubpf", "./bpftime-llvm", ""] @@ -21,32 +24,22 @@ class RunArgs(TypedDict): name: str -def run_single(runtime: str, bpf_prog: str, memory: Optional[str], name: str) -> RunResult: +def run_single( + runtime: str, bpf_prog: str, memory: Optional[str], name: str +) -> RunResult: if runtime == "": command_line = [bpf_prog.replace(".bpf.bin", ".native")] if memory: command_line.append(memory) else: - command_line = [runtime, bpf_prog] + ([memory] - if memory else []) - ret = subprocess.run(command_line, text=True, - capture_output=True, check=True) + command_line = [runtime, bpf_prog] + ([memory] if memory else []) + ret = subprocess.run(command_line, text=True, capture_output=True, check=True) jit, exec, ret = (int(x) for x in ret.stdout.strip().split(" ")) - return { - "exec_usage": exec, - "jit_usage": jit, - "result": ret, - "name": name - } + return {"exec_usage": exec, "jit_usage": jit, "result": ret, "name": name} def run_multiple_wrapper(cfg: RunArgs): - ret = { - "exec_usage": 0, - "jit_usage": 0, - "result": [], - "name": cfg["name"] - } + ret = {"exec_usage": 0, "jit_usage": 0, "result": [], "name": cfg["name"]} for _ in range(5): r = run_single(**cfg) ret["exec_usage"] += r["exec_usage"] @@ -58,32 +51,68 @@ def run_multiple_wrapper(cfg: RunArgs): def main(): - all_tests = [ - - ] + all_tests = [] for bpf_prog in os.listdir(PROGS_DIR): if bpf_prog.endswith(".bpf.bin"): name = bpf_prog.replace(".bpf.bin", "") - memory_file = str(PROGS_DIR/(name+".mem")) - all_tests.append({ - "name": name, - "bpf_prog": str(PROGS_DIR/bpf_prog), - "memory": memory_file if os.path.exists(memory_file) else None - }) + memory_file = str(PROGS_DIR / (name + ".mem")) + all_tests.append( + { + "name": name, + "bpf_prog": str(PROGS_DIR / bpf_prog), + "memory": memory_file if os.path.exists(memory_file) else None, + } + ) print("TESTS") print("--------------") for item in all_tests: print(item["name"]) print("--------------") print(f"Loaded {len(all_tests)} tests") + test_results = [] for runtime in EXECUTABLES: print(f"Testing {runtime}") with multiprocessing.Pool() as pool: results = pool.map( - run_multiple_wrapper, ({**x, "runtime": runtime} for x in all_tests)) + run_multiple_wrapper, ({**x, "runtime": runtime} for x in all_tests) + ) + test_results.append(results) for item in results: print( - f"TEST <{item['name']}> JIT {item['jit_usage']/10**6}ms EXEC {item['exec_usage']/10**6}ms RET {item['result']}") + f"TEST <{item['name']}> JIT {item['jit_usage']/10**6}ms EXEC {item['exec_usage']/10**6}ms RET {item['result']}" + ) + images_out = Path("output-image") + shutil.rmtree(images_out, ignore_errors=True) + os.mkdir(images_out) + for test_line in zip(*test_results): + jit_values = [x["jit_usage"] for x in test_line] + exec_values = [x["exec_usage"] for x in test_line] + name = test_line[0]["name"] + + plt.figure() + plt.bar(EXECUTABLES, exec_values, 0.35, label="Execution", color="orange") + plt.ylabel("Time (nanoseconds)") + plt.title(f'Time usage on example "{name}"') + plt.legend() + plt.savefig(images_out / f"{name}.execution.png") + plt.clf() + + plt.figure() + plt.bar(EXECUTABLES, jit_values, 0.35, label="Compilation", color="blue") + plt.bar( + EXECUTABLES, + exec_values, + 0.35, + bottom=jit_values, + label="Execution", + color="orange", + ) + plt.ylabel("Time (nanoseconds)") + plt.title(f'Time usage on example "{name}"') + plt.legend() + plt.savefig(images_out / f"{name}.png") + plt.clf() + print("Visualized images are in output-images") if __name__ == "__main__":