# What Is the Runtime Component in bpftime? A Deep Dive into Userspace eBPF Execution

> Discover how the bpftime runtime component elevates userspace eBPF execution with its high-performance engine, shared memory, modular backends, and kernel-compatible APIs.

- Repository: [eunomia-bpf/bpftime](https://github.com/eunomia-bpf/bpftime)
- Tags: deep-dive
- Published: 2026-03-01

---

**The runtime component in bpftime is the central userspace eBPF execution engine that provides a high-performance alternative to the kernel eBPF VM through shared-memory infrastructure, modular VM backends, and kernel-compatible APIs.**

The bpftime project (eunomia-bpf/bpftime) enables running eBPF programs entirely in userspace while maintaining compatibility with existing kernel eBPF tooling. Understanding the runtime component in bpftime reveals how the system achieves up to ten-fold performance improvements for many workloads while preserving familiar file-descriptor-based interfaces.

## Shared-Memory Infrastructure

The runtime establishes a **global shared-memory region** backed by Boost.Interprocess that serves as the foundation for all eBPF operations. This architecture, implemented in [`runtime/src/bpftime_shm.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/runtime/src/bpftime_shm.cpp) and [`runtime/src/bpftime_shm_internal.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/runtime/src/bpftime_shm_internal.cpp), stores eBPF objects, map data, and program bytecode in a userspace-accessible region.

The shared-memory system uses file-descriptor-like IDs to index resources, ensuring existing eBPF tools encounter a familiar kernel-style interface without modification. This design enables zero-copy access to eBPF maps across different processes and attachment points.

## Handler-Based Object Management

At the core of object lifecycle management lies the **handler pattern** implemented in [`runtime/src/handler/handler_manager.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/runtime/src/handler/handler_manager.cpp). The `handler_manager` acts as a generic registry that creates, stores, and destroys every eBPF object type.

Each object category maintains dedicated handlers stored as `std::variant` structures in shared memory:

- **prog_handler** – Manages loaded eBPF programs and their metadata
- **map_handler** – Tracks map instances and their configuration
- **link_handler** – Handles attachment links between programs and events

This variant-based storage system allows the runtime to manage heterogeneous eBPF objects within a unified memory region while preserving type safety.

## VM Integration and Execution

The runtime abstracts multiple execution backends through [`runtime/src/bpftime_prog.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/runtime/src/bpftime_prog.cpp). The **bpftime_prog** component loads bytecode, registers helper functions, and executes programs on the chosen VM backend, whether LLVM-JIT for maximum performance or the ubpf interpreter for compatibility.

This abstraction layer allows the same eBPF program to run across different execution engines without recompilation. The runtime handles the complexity of translating kernel eBPF conventions to userspace execution contexts while maintaining program semantics.

## Userspace Map Implementations

Unlike kernel eBPF, which relies on kernel data structures, the runtime provides a **rich collection of userspace-only map types** located under `runtime/src/bpf_map/userspace/`. These implementations include:

- Array and hash maps ([`var_hash_map.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/var_hash_map.cpp))
- Per-CPU variants for multi-core scaling
- Ring buffers and LRU caches
- Specialized structures like LPM-trie and bloom filters
- GPU-accelerated map variants

All map implementations operate directly on the shared memory region, enabling zero-copy access patterns that eliminate kernel-user space boundary crossing overhead.

## Attachment Mechanisms

The runtime offers multiple **attach mechanisms** that mirror kernel eBPF capabilities while operating in userspace. Implemented in `runtime/src/attach/`, these mechanisms include:

- **uprobe/uretprobe** – Function entry and return tracing via Frida
- **syscall tracing** – Interception of system calls at the userspace boundary
- **custom event sources** – Programmatic triggers and synthetic events

These attachment points expose the same API surface that kernel eBPF provides, ensuring tool compatibility while executing within the userspace runtime environment.

## Agent and Syscall Server Architecture

Two critical components extend the runtime's reach into existing processes:

**Agent Library** ([`runtime/agent/agent.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/runtime/agent/agent.cpp)): An injected shared library that intercepts eBPF-related syscalls from target processes. When an application calls `bpf()` syscalls, the agent forwards these requests to the runtime rather than the kernel, enabling transparent migration of eBPF workloads.

**Syscall Server** ([`runtime/syscall-server/syscall_server_main.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/runtime/syscall-server/syscall_server_main.cpp)): A standalone daemon process that provides a compatibility layer for existing eBPF tools. This server responds to intercepted syscalls, maintaining the illusion of kernel eBPF while executing entirely in userspace.

## Working with the Runtime API

The public C API defined in [`runtime/include/bpftime.hpp`](https://github.com/eunomia-bpf/bpftime/blob/main/runtime/include/bpftime.hpp) provides the primary interface for interacting with the runtime component. Below demonstrates creating a map, loading a program, and executing it:

```cpp
#include "bpftime.hpp"

int main() {
    // Initialize the shared memory region (once per process)
    bpftime_initialize_global_shm();

    // Create a hash map: key=uint32_t, value=uint64_t
    bpftime_map_desc_t map_desc{};
    map_desc.map_type = BPF_MAP_TYPE_HASH;
    map_desc.key_size = sizeof(uint32_t);
    map_desc.value_size = sizeof(uint64_t);
    map_desc.max_entries = 1024;
    int map_fd = bpftime_maps_create(&map_desc, nullptr);
    if (map_fd < 0) return -1;

    // Load an eBPF program from an object file
    bpftime_prog_desc_t prog_desc{};
    prog_desc.type = BPF_PROG_TYPE_SOCKET_FILTER;
    prog_desc.file_path = "example.xdp.o";
    int prog_fd = bpftime_progs_create(&prog_desc, nullptr);
    if (prog_fd < 0) return -1;

    // Execute the program directly (for testing)
    uint8_t data[64] = {};
    uint32_t size = sizeof(data);
    int ret = bpftime_prog_test_run(prog_fd, data, size, nullptr, 0);

    // Cleanup
    bpftime_maps_close(map_fd);
    bpftime_progs_close(prog_fd);
    bpftime_remove_global_shm();
    return ret;
}

```

This example illustrates the file-descriptor-based workflow that mirrors kernel eBPF conventions while operating entirely within the userspace runtime.

## Summary

- The **runtime component in bpftime** serves as a complete userspace replacement for the kernel eBPF VM, enabling significant performance improvements through shared-memory architecture.
- **Shared-memory infrastructure** ([`bpftime_shm.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/bpftime_shm.cpp)) provides the foundation for zero-copy map access and object storage using Boost.Interprocess.
- **Handler-based management** ([`handler_manager.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/handler_manager.cpp)) tracks programs, maps, and links as type-safe variants within the global memory region.
- **VM abstraction** ([`bpftime_prog.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/bpftime_prog.cpp)) supports multiple backends including LLVM-JIT and ubpf interpreter for flexible execution.
- **Userspace maps** (`bpf_map/userspace/`) implement kernel-compatible data structures without kernel boundary crossings.
- **Agent and syscall server** components enable transparent interception of eBPF syscalls from existing applications.

## Frequently Asked Questions

### How does the bpftime runtime achieve better performance than kernel eBPF?

The runtime eliminates kernel-user space boundary crossings by implementing eBPF maps and execution entirely in userspace shared memory. According to the eunomia-bpf/bpftime source code, this architecture removes syscall overhead and context switches, delivering up to ten-fold performance improvements for workloads that frequently access maps or trigger programs.

### Can existing eBPF programs run unmodified on the bpftime runtime?

Yes. The runtime maintains API compatibility through file-descriptor-like abstractions and syscall interception. The agent component ([`runtime/agent/agent.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/runtime/agent/agent.cpp)) transparently redirects `bpf()` syscalls from target processes to the runtime, while the handler system preserves object semantics that existing programs expect.

### What VM backends does the bpftime runtime support?

The runtime supports multiple execution engines through the abstraction in [`runtime/src/bpftime_prog.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/runtime/src/bpftime_prog.cpp). Currently, these include an **LLVM-JIT** backend for maximum performance through native code generation, and a **ubpf interpreter** for scenarios requiring simpler dependencies or specific platform compatibility.

### How does the runtime manage memory safety across processes?

The runtime uses **Boost.Interprocess** for cross-process shared memory management, implemented in [`runtime/src/bpftime_shm_internal.cpp`](https://github.com/eunomia-bpf/bpftime/blob/main/runtime/src/bpftime_shm_internal.cpp). The handler pattern stores all objects as `std::variant` types with strict lifecycle management, ensuring type safety while allowing different processes to access the same eBPF maps and programs concurrently.