I/O Riot NG is an experiment with BPF.
  • Go 90.3%
  • C 9.3%
  • Shell 0.2%
  • Dockerfile 0.2%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Paul Buetow da423f13e2 chore: bump version to v1.1.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 08:59:32 +03:00
assets assets: restore flamegraph example svg 2026-03-08 22:36:07 +02:00
cmd refactor: break down functions exceeding 50 lines into smaller helpers 2026-05-13 20:04:48 +03:00
docs update docs and ascii banner 2026-05-07 09:47:05 +03:00
integrationtests task a8: move all binaries under ./cmd/<name>/main.go 2026-04-24 20:36:26 +03:00
internal chore: bump version to v1.1.0 2026-05-14 08:59:32 +03:00
scripts add duration metric, tolerate missing tracepoints, ship el8 build 2026-05-08 19:43:33 +03:00
tools task a8: move all binaries under ./cmd/<name>/main.go 2026-04-24 20:36:26 +03:00
.gitignore add duration metric, tolerate missing tracepoints, ship el8 build 2026-05-08 19:43:33 +03:00
AGENTS.md docs: document -tui-fast-refresh flag in AGENTS.md TUI Behavior section 2026-05-14 08:24:27 +03:00
CLAUDE.md
Dockerfile pin Docker build to linux/amd64 for cross-compilation 2026-05-06 12:27:40 +03:00
Dockerfile.el8 add duration metric, tolerate missing tracepoints, ship el8 build 2026-05-08 19:43:33 +03:00
go.mod Revert "fix: surface rb.Poll errors instead of silently dropping them" 2026-05-13 09:52:04 +03:00
go.sum Revert "fix: surface rb.Poll errors instead of silently dropping them" 2026-05-13 09:52:04 +03:00
Magefile.go refactor: move TraceFilter and tracepoint selector logic out of flags.Config 2026-05-13 19:35:02 +03:00
README.md add duration metric, tolerate missing tracepoints, ship el8 build 2026-05-08 19:43:33 +03:00
recording.json chore: add remaining workspace artifacts 2026-03-06 17:32:09 +02:00

I/O Riot NG (aka ior)

I/O Riot NG is an experiment with BPF. It traces synchronous I/O syscalls and analyses how long each one took. Useful for drawing FlameGraphs like these:

A spiritual successor to one of my previous projects, I/O Riot (https://codeberg.org/snonux/ioriot), which was based on SystemTap and C. The NG is based on Go, C, and BPF (via libbpfgo).

Linux only.

You can read a blog post series about this here: https://foo.zone/gemfeed/2026-05-08-unveiling-ior-ng-part-1.html

Demo

A short guided tour with animated GIFs of every major surface lives in docs/tutorial/tutorial.md. Two teasers:

Startup, the PID picker: sudo ./ior opens a searchable process list. Navigate with arrow keys, filter by typing, press Enter to start tracing. The dashboard appears right after.

Cold start: PID picker, then the dashboard appears

Live flamegraph tab: Once tracing, tab 1 shows a live flamegraph that rebuilds in real time as I/O events arrive. Bars grow and shift with the workload. This is the default landing tab.

Live in-TUI flamegraph rebuilding from real workload

The demo is fully reproducible: mage installDemoTools once, then sudo -v && mage demo regenerates every GIF and screenshot. See the tutorial for the full walkthrough.

Note: mage installDemoTools uses dnf to install ttyd and is only supported on Fedora / RHEL / Rocky / Alma Linux. On other distros install ttyd manually (binary releases are on its GitHub page) and then go install github.com/charmbracelet/vhs@latest for VHS; mage demo will find them on PATH.

Requirements

  • Docker and a Linux host with a BTF-enabled kernel (/sys/kernel/btf/vmlinux present).
  • Go (any 1.x version on PATH) for installing the Mage build tool.

Install Mage

The build orchestration uses Mage. Install the mage binary once before any of the build commands below:

go install github.com/magefile/mage@latest

Make sure $(go env GOPATH)/bin (typically $HOME/go/bin) is on your PATH.

Build

Builds a fully static ior binary inside a Rocky Linux 9 container and writes it to the repo root. No local Go, clang, or libbpfgo setup required:

mage buildDocker

First run takes ~1520 minutes to build the image; subsequent runs reuse the cached image and finish in under a minute. To skip the image rebuild:

./scripts/build-with-docker.sh --run

To target hosts with the older glibc on RHEL/Rocky/Alma 8, build a sibling binary called ior.el8 from a Rocky Linux 8 container:

mage buildDockerEl8

For contributors who need a native build (Fedora / Rocky Linux 9), see docs/build-rocky-linux-9.md and AGENTS.md.

Compile once, run everywhere

Build on one machine, then scp ior other-host:/usr/local/bin/ and run it anywhere. The binary is fully statically linked and uses libbpf CO-RE (Compile-Once, Run-Everywhere) to adapt field offsets to the target kernel's BTF at load time. No recompile per host or kernel version needed.

See docs/build-rocky-linux-9.md for the full explanation.

TUI

Press H inside the dashboard to toggle the built-in help panel. Tabs are reachable with tab/shift+tab or number keys 17. For the full hotkey reference, recording modes, and the .ior.zst vs Parquet trade-off see the tutorial.