{"id":19713088,"url":"https://github.com/zz85/profile-bee","last_synced_at":"2026-02-22T10:20:43.875Z","repository":{"id":62819274,"uuid":"548793008","full_name":"zz85/profile-bee","owner":"zz85","description":"🐝🦀🔥 An ebpf based CPU profiler written in Rust ","archived":false,"fork":false,"pushed_at":"2026-02-06T13:38:58.000Z","size":444,"stargazers_count":40,"open_issues_count":7,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-06T21:24:43.682Z","etag":null,"topics":["aya","ebpf","profile","rust"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zz85.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-10-10T07:32:00.000Z","updated_at":"2026-01-14T00:49:46.000Z","dependencies_parsed_at":"2025-04-29T18:46:50.542Z","dependency_job_id":null,"html_url":"https://github.com/zz85/profile-bee","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/zz85/profile-bee","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zz85%2Fprofile-bee","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zz85%2Fprofile-bee/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zz85%2Fprofile-bee/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zz85%2Fprofile-bee/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zz85","download_url":"https://codeload.github.com/zz85/profile-bee/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zz85%2Fprofile-bee/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29401589,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-13T06:24:03.484Z","status":"ssl_error","status_checked_at":"2026-02-13T06:23:12.830Z","response_time":78,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aya","ebpf","profile","rust"],"created_at":"2024-11-11T22:19:33.788Z","updated_at":"2026-02-22T10:20:43.859Z","avatar_url":"https://github.com/zz85.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## About\n\nProfile Bee is an eBPF-based CPU profiler that ships as a single binary — no BCC, libbpf, or perf tooling needed on the target host. Built with Rust and [aya](https://aya-rs.dev/).\n\n![Architecture](https://raw.githubusercontent.com/zz85/profile-bee/main/docs/architecture-sketch.png)\n\n- Just `cargo install`, `sudo probee --tui`, and you're looking at a live flamegraph — no package manager dance, no Python dependencies, no separate visualization step\n- Walks stacks directly in the kernel via frame pointers (fast, the default) or DWARF unwind tables (for those `-O2` binaries everyone ships without frame pointers)\n- Attaches to perf events, kprobes, uprobes, or tracepoints — auto-discovers uprobe targets with glob and regex matching\n- Demangles Rust and C++ symbols out of the box\n- Outputs to interactive TUI, SVG, HTML, JSON, stackcollapse, or a real-time web server — whatever fits your workflow\n\n## Screenshots\n\nReal-time TUI flamegraphs\n![TUI Screenshot](https://raw.githubusercontent.com/zz85/profile-bee/main/docs/tui-self-profile-screenshot.png)\n\nReal-time Web-based flamegraphs\n![Web interface](https://raw.githubusercontent.com/zz85/profile-bee/main/docs/probee-web.png)\n\n\n## Install\n\n### Option 1: Shell Installer (Recommended)\n\nDownload and install the latest release with a single command:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/zz85/profile-bee/main/install.sh | bash\n```\n\nOr with wget:\n\n```bash\nwget -qO- https://raw.githubusercontent.com/zz85/profile-bee/main/install.sh | bash\n```\n\nThis installs pre-built binaries to `~/.local/bin`. No Rust toolchain required.\n\n### Option 2: Cargo Install\n\n```bash\ncargo install profile-bee\n```\n\nInstalls `probee` and `pbee` (short alias). No nightly Rust required — a prebuilt eBPF binary is bundled. Requires root to run (eBPF).\n\n## Quick Start\n\n```bash\n# Interactive TUI flamegraph (live, system-wide)\nsudo probee --tui\n\n# Profile a specific command\nsudo probee --tui --cmd \"my-application\"\n\n# Generate an SVG flamegraph\nsudo probee --svg flamegraph.svg --time 5000\n\n# Profile a command with args\nsudo probee --svg output.svg -- ./my-binary arg1 arg2\n\n# Real-time flamegraphs via web server\nsudo probee --serve --skip-idle\n\n# Trace function calls with uprobe\nsudo probee --uprobe malloc --time 1000 --svg malloc.svg\n\n# Off-CPU profiling — find where threads block\nsudo probee --off-cpu --tui -- ./my-server\n```\n\nRun `probee` with no arguments or `probee --help` for the full list of options and examples.\n\n## Features\n\n- **Interactive TUI** — real-time flamegraph viewer with vim-style navigation, search, zoom, and mouse support (click, scroll, double-click to zoom)\n- **Off-CPU profiling** (`--off-cpu`) — trace context switches via `finish_task_switch` kprobe to find where threads block on I/O, locks, or sleep. Configurable block-time filters.\n- **Multiple output formats** — SVG, HTML, JSON (d3), and [stackcollapse](https://www.speedscope.app/) format\n- **Frame pointer unwinding** (default) — fast eBPF-based stack walking via `bpf_get_stackid`\n- **DWARF unwinding** (`--dwarf`) — profiles `-O2`/`-O3` binaries without frame pointers using `.eh_frame` tables loaded into eBPF maps\n- **Smart uprobes** — GDB-style symbol resolution with glob, regex, demangled name matching, and multi-attach\n- **kprobe \u0026 tracepoint** support — profile kernel functions and tracepoint events\n- **Real-time web server** (`--serve`) — live flamegraph updates over HTTP with interactive controls\n- **Automatic termination** — stops when `--pid` target or `--cmd` process exits\n- **Rust \u0026 C++ demangling** — via gimli/blazesym\n- **BPF-based aggregation** — stack counting in kernel to reduce userspace data transfer\n- **Group by CPU** — per-core flamegraph breakdown\n\n---\n\n## Detailed Usage\n\n### Output Formats\n\n```bash\n# SVG flamegraph\nsudo probee --svg profile.svg --frequency 999 --time 5000\n\n# HTML flamegraph\nsudo probee --time 5000 --html flamegraphs.html\n\n# Stackcollapse format (compatible with speedscope, flamegraph.pl)\nsudo probee --collapse profile.txt --frequency 999 --time 10000\n\n# All output formats at once\nsudo probee --time 5000 --html out.html --json out.json --collapse out.txt --svg out.svg\n\n# Grouped by CPU\nsudo probee --svg profile.svg --frequency 999 --time 2000 --group-by-cpu\n```\n\n### Targeting\n\n```bash\n# Profile specific PID (auto-stops when process exits)\nsudo probee --pid \u003cpid\u003e --svg output.svg --time 10000\n\n# Profile specific CPU core\nsudo probee --cpu 0 --svg output.svg --time 5000\n\n# Profile a command\nsudo probee --svg output.svg -- ./my-binary arg1 arg2\n\n# Real-time flamegraphs via web server\nsudo probee --time 5000 --serve --skip-idle --stream-mode 1\n# Then open http://localhost:8000/ and click \"realtime-updates\"\n```\n\n### Kprobe \u0026 Tracepoint\n\n```bash\n# Profile kernel function calls\nsudo probee --kprobe vfs_write --time 200 --svg kprobe.svg\n\n# Profile tracepoint events\nsudo probee --tracepoint tcp:tcp_probe --time 200 --svg tracepoint.svg\n```\n\n### Smart Uprobe Targeting\n\nProfile-bee supports GDB-style symbol resolution for uprobes. Instead of manually specifying which library a function lives in, you provide a probe spec and the tool auto-discovers matching symbols across all loaded ELF binaries.\n\n```bash\n# Auto-discover library\nsudo probee --uprobe malloc --time 1000 --svg malloc.svg\n\n# Multiple probes at once\nsudo probee --uprobe malloc --uprobe 'ret:free' --time 1000 --svg alloc.svg\n\n# Glob matching — trace all pthread functions\nsudo probee --uprobe 'pthread_*' --time 1000 --svg pthread.svg\n\n# Regex matching\nsudo probee --uprobe '/^sql_.*query/' --pid 1234 --time 2000 --svg sql.svg\n\n# Demangled C++/Rust name matching\nsudo probee --uprobe 'std::vector::push_back' --pid 1234 --time 1000 --svg vec.svg\n\n# Source file and line number (requires DWARF debug info)\nsudo probee --uprobe 'main.c:42' --pid 1234 --time 1000 --svg source.svg\n\n# Explicit library prefix\nsudo probee --uprobe libc:malloc --time 1000 --svg malloc.svg\n\n# Absolute path to binary\nsudo probee --uprobe '/usr/lib/libc.so.6:malloc' --time 1000 --svg malloc.svg\n\n# Return probe (uretprobe)\nsudo probee --uprobe ret:malloc --time 1000 --svg malloc_ret.svg\n\n# Function with offset\nsudo probee --uprobe malloc+0x10 --time 1000 --svg malloc_offset.svg\n\n# Scope to a specific PID\nsudo probee --uprobe malloc --uprobe-pid 12345 --time 1000 --svg malloc_pid.svg\n\n# Discovery mode — list matching symbols without attaching\nsudo probee --list-probes 'pthread_*' --pid 1234\n```\n\n**Probe spec syntax:**\n\n| Syntax | Example | Description |\n|--------|---------|-------------|\n| `function` | `malloc` | Exact match, auto-discover library |\n| `lib:function` | `libc:malloc` | Explicit library name prefix |\n| `/path:function` | `/usr/lib/libc.so.6:malloc` | Absolute path prefix |\n| `ret:function` | `ret:malloc` | Return probe (uretprobe) |\n| `function+offset` | `malloc+0x10` | Function with byte offset |\n| `glob_pattern` | `pthread_*` | Glob matching (`*`, `?`, `[...]`) |\n| `/regex/` | `/^sql_.*query/` | Regex matching |\n| `Namespace::func` | `std::vector::push_back` | Demangled C++/Rust name match |\n| `file.c:line` | `main.c:42` | Source location (requires DWARF) |\n\n**Resolution order:**\n1. If `--pid` or `--uprobe-pid` is set, scans `/proc/\u003cpid\u003e/maps` for all mapped executables\n2. Otherwise, scans system libraries via `ldconfig` cache and standard paths\n3. For each candidate ELF, reads `.symtab` and `.dynsym` symbol tables\n4. Demangled matching uses both Rust and C++ demanglers\n5. Source locations are resolved via gimli `.debug_line` parsing\n\n**Multi-attach:** If a spec matches multiple symbols (e.g. `pthread_*` matching 20 functions), uprobes are attached to all of them.\n\n---\n\n## TUI Mode\n\nThe interactive terminal flamegraph viewer is included by default (forked and adapted from [flamelens](https://github.com/YS-L/flamelens)).\n\n```bash\n# Interactive TUI with a command\nsudo probee --tui --cmd \"your-command\"\n\n# Live profiling of a running process\nsudo probee --tui --pid \u003cpid\u003e --time 30000\n\n# With DWARF unwinding for optimized binaries\nsudo probee --tui --dwarf --cmd \"./optimized-binary\"\n\n# Build without TUI support\ncargo build --release --no-default-features\n```\n\n**Key Bindings:**\n\n| Key | Action |\n|-----|--------|\n| `hjkl` / arrows | Navigate cursor |\n| `Enter` | Zoom into selected frame |\n| `Esc` | Reset zoom |\n| `/` | Search frames with regex |\n| `#` | Highlight selected frame |\n| `n` / `N` | Next / previous match |\n| `z` | Freeze / unfreeze live updates |\n| `q` or `Ctrl+C` | Quit |\n\n---\n\n## Stack Unwinding\n\nProfile Bee supports two methods for stack unwinding. Both run the actual stack walking in eBPF (kernel space) for performance. Symbolization always happens in userspace.\n\n### Frame Pointer Method (default)\n\nUses the kernel's `bpf_get_stackid` to walk the frame pointer chain. Works out of the box for binaries compiled with frame pointers:\n- Rust: `RUSTFLAGS=\"-Cforce-frame-pointers=yes\"`\n- C/C++: `-fno-omit-frame-pointer` flag\n\n### DWARF Method (`--dwarf`)\n\nHandles binaries compiled without frame pointers (the default for most `-O2`/`-O3` builds). Use `--dwarf` to enable DWARF-based stack unwinding.\n\n**How it works:**\n1. At startup, userspace parses `/proc/[pid]/maps` and `.eh_frame` sections from each executable mapping\n2. Pre-evaluates DWARF CFI rules into a flat `UnwindEntry` table (PC → CFA rule + RA rule)\n3. Loads the table into eBPF maps before profiling begins\n4. At sample time, the eBPF program binary-searches the table and walks the stack using CFA computation + `bpf_probe_read_user`\n5. A background thread polls for newly loaded libraries (e.g. via `dlopen`) and updates the unwind tables at runtime\n\nThis is the same approach used by [parca-agent](https://github.com/parca-dev/parca-agent) and other production eBPF profilers.\n\n```bash\n# Enable DWARF unwinding for a no-frame-pointer binary\nsudo probee --dwarf --svg output.svg --time 5000 -- ./my-optimized-binary\n\n# Frame pointer unwinding (the default)\nsudo probee --svg output.svg --time 5000 -- ./my-fp-binary\n```\n\n**Note**: For symbol resolution, you still need debug information:\n- Rust: Add `-g` flag when compiling\n- C/C++: Compile with debug symbols (`-g` flag)\n\n**Limitations:** Max 8 executable mappings per process, 131K unwind table entries per binary (up to 64 binaries), up to 165 frame depth (via tail-call chaining; legacy fallback: 21 frames). x86_64 only. Libraries loaded via dlopen are detected within ~1 second.\n\nSee [docs/dwarf_unwinding_design.md](docs/dwarf_unwinding_design.md) for architecture details, and [Polar Signals' article on profiling without frame pointers](https://www.polarsignals.com/blog/posts/2022/11/29/profiling-without-frame-pointers) for background.\n\n---\n\n## Limitations\n\n- Linux only (requires eBPF support)\n- DWARF unwinding: x86_64 only, see limits above\n- Interpreted / JIT stack traces not yet supported\n- [VDSO](https://man7.org/linux/man-pages/man7/vdso.7.html) `.eh_frame` parsed for DWARF unwinding; VDSO symbolization not yet supported\n\n## Development\n\n### Prerequisites\n\n1. Install stable and nightly Rust: `rustup install stable nightly`\n2. Install bpf-linker: `cargo install bpf-linker`\n\n### Build\n\n```bash\n# Build eBPF program (requires nightly)\ncargo xtask build-ebpf\n\n# Build userspace (uses fresh eBPF build if available, otherwise prebuilt)\ncargo build --release\n\n# Run\ncargo xtask run\n```\n\nTo perform a release build of the eBPF program, use `cargo xtask build-ebpf --release`. You may also change the target architecture with the `--target` flag.\n\nMore documentation in the [docs](docs) directory.\n\n### Alternatives\n\n- [perf](https://perf.wiki.kernel.org/) + [Cargo flamegraph](https://github.com/flamegraph-rs/flamegraph)\n- [BCC profile](https://github.com/iovisor/bcc/blob/master/tools/profile.py)\n- [parca-agent](https://github.com/parca-dev/parca-agent) — always-on eBPF profiling in Go\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzz85%2Fprofile-bee","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzz85%2Fprofile-bee","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzz85%2Fprofile-bee/lists"}