bpftime, a full-featured, high-performance eBPF runtime designed to operate in userspace. It offers fast Uprobe and Syscall hook capabilities: Userspace uprobe can be 10x faster than kernel uprobe! and can programmatically hook all syscalls of a process safely and efficiently.
⚠️ Note:bpftimeis actively under development. It's at a very early stage and may contain bugs. The API or design might change in upcoming releases, and it's not yet recommended for production use. See our roadmap for details. We'd love to hear your feedback and suggestions! Please feel free to open an issue or Contact us.
- Uprobe and Syscall hooks based on binary rewriting: Run eBPF programs in userspace, attaching them to Uprobes and Syscall tracepoints: No mannual instrumentation or restart required!. It can
trace,replaceorpatchthe execution of a function,hook,filterorredirectall syscalls of a process safely, and efficiently with an eBPF userspace runtime. - Performance: Experience up to a 10x speedup in Uprobe overhead compared to kernel uprobe and uretprobe.
- Interprocess eBPF Maps: Implement userspace eBPF maps in shared userspace memory for summary aggregation or control plane communication.
- Compatibility: use existing eBPF toolchains like clang and libbpf to develop userspace eBPF without any modifications. Supporting CO-RE via BTF, and offering userspace host function access.
- JIT Support: Benefit from a cross-platform eBPF interpreter and a high-speed JIT compiler powered by LLVM. It also includes a handcrafted x86 JIT in C for limited resources.
- No instrumentation: Can inject eBPF runtime into any running process without the need for a restart or manual recompilation.
vm: The eBPF VM and JIT for eBPF, you can choose from LLVM JIT and a simple JIT/interpreter based on ubpf. It can be built as a standalone library and integrated into other projects.runtime: The userspace runtime for eBPF, including the syscall server and agent, attaching eBPF programs to Uprobes and Syscall tracepoints, and eBPF maps in shared memory.
With bpftime, you can build eBPF applications using familiar tools like clang and libbpf, and execute them in userspace. For instance, the malloc eBPF program traces malloc calls using uprobe and aggregates the counts using a hash map.
You can refer to documents/build-and-test.md for how to build the project.
To get started, you can build and run a libbpf based eBPF program starts with bpftime cli:
make -C example/malloc # Build the eBPF program example
bpftime load ./example/malloc/mallocIn another shell, Run the target program with eBPF inside:
$ bpftime start ./example/malloc/test
Hello malloc!
malloc called from pid 250215
continue malloc...
malloc called from pid 250215You can also dynamically attach the eBPF program with a running process:
$ ./example/malloc/test & echo $! # The pid is 101771
[1] 101771
101771
continue malloc...
continue malloc...And attach to it:
$ sudo bpftime attach 101771 # You may need to run make install in root
Inject: "/root/.bpftime/libbpftime-agent.so"
Successfully injected. ID: 1You can see the output from original program:
$ bpftime load ./example/malloc/malloc
...
12:44:35
pid=247299 malloc calls: 10
pid=247322 malloc calls: 10Alternatively, you can also run our sample eBPF program directly in the kernel eBPF, to see the similar output:
$ sudo example/malloc/malloc
15:38:05
pid=30415 malloc calls: 1079
pid=30393 malloc calls: 203
pid=29882 malloc calls: 1076
pid=34809 malloc calls: 8See documents/usage.md for more details.
We can use the bpftime userspace runtime for:
tracing userspace functions with uprobe: Attach uprobe, uretprobe or all syscall tracepoints(currently x86 only) eBPF programs to a process or a group of processes:malloc: count the malloc calls in libc by pid
tracing all syscalls with tracepointsopensnoop: trace file open or close syscalls in a process
More examples can be found in example dir. More examples are coming soon.
Some examples may not working now, we are fixing it. You can refer to benchmark dir for more working examples.
Left: kernel eBPF | Right: userspace bpftime
The hook implementation is based on binary rewriting and the underly technique is inspired by:
- Userspace function hook: frida-gum
- Syscall hooks: zpoline: a system call hook mechanism based on binary rewriting
see documents/how-it-works.md for details.
How is the performance of userspace uprobe compared to kernel uprobes?
| Probe/Tracepoint Types | Kernel (ns) | Userspace (ns) | Insn Count |
|---|---|---|---|
| Uprobe | 3224.172760 | 314.569110 | 4 |
| Uretprobe | 3996.799580 | 381.270270 | 2 |
| Syscall Tracepoint | 151.82801 | 232.57691 | 4 |
| Embedding runtime | Not avaliable | 110.008430 | 4 |
It can be attached to functions in running process just like the kernel uprobe does.
How is the performance of LLVM JIT/AOT compared to other eBPF userspace runtimes, native code or wasm runtimes?
Across all tests, the LLVM JIT for bpftime consistently showcased superior performance. Both demonstrated high efficiency in integer computations (as seen in log2_int), complex mathematical operations (as observed in prime), and memory operations (evident in memcpy and strcmp). While they lead in performance across the board, each runtime exhibits unique strengths and weaknesses. These insights can be invaluable for users when choosing the most appropriate runtime for their specific use-cases.
see github.com/eunomia-bpf/bpf-benchmark for how we evaluate and details.
Hash map or ring buffer compared to kernel(TODO)
See benchmark dir for detail performance benchmarks.
bpftimeallows you to useclangandlibbpfto build eBPF programs, and run them directly in this runtime. We have tested it with a libbpf version in third_party/libbpf.- Some kernel helpers and kfuncs may not be available in userspace.
- It does not support direct access to kernel data structures or functions like
task_struct.
Refer to documents/available-features.md for more details.
see documents/build-and-test.md for details.
bpftime is continuously evolving with more features in the pipeline:
- An AOT compiler for eBPF can be easily added based on the LLVM IR.
- perf event and ring buffer output support.
- more examples and usecases.
- More map types and distribution maps support.
- More program types support.
Stay tuned for more developments from this promising project! You can find bpftime on GitHub.
This project is licensed under the MIT License.