Quantifying the Code-Size Overhead of eBPF JIT Compilation
Abstract
eBPF allows user-defined programs to safely extend Linux kernel functionality at runtime, but its final machine code comes from a compilation pipeline that differs from native targets, and how efficient that pipeline is has no clear reference point. Our work constructs one: using the standard LLVM x86 backend as an approximate best case for code-generation quality, we compile nearly identical source through both the eBPF path (with kernel JIT) and a native path. We hold source logic, optimization level, and build configuration equal, so the two differ only in their backend target and can be compared fairly by code size. Applying this to Cilium datapath programs, the two pipelines stay nearly identical through the frontend and midend, which isolates the overhead almost entirely to backend code generation, where the eBPF output contains 27.6% more instructions and is 16.6% larger in bytes. The baseline then lets us attribute the gap to a few recurring causes (operand widening, address computation, memory copies, register pressure) and categorize each by root cause, as coming from the eBPF instruction set or from a less mature backend, or a mix of both. This pinpoints where the overhead occurs and provides a method to measure it for other eBPF workloads and backends. Because eBPF code runs in hot kernel paths, this overhead is worth reducing, and the baseline offers a stable reference for measuring how far eBPF code generation is from native quality and tracking that gap as backends mature, for other projects and workloads.