1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
# AGENTS.md
This file provides guidance to AI coding assistants working with the I/O Riot NG (ior) codebase.
## Build/Test Commands
**Prerequisites**: Ensure `libbpfgo` is cloned at `../libbpfgo` relative to this repository (or set `LIBBPFGO`), pinned to `v0.9.2-libbpf-1.5.1`, and rebuilt with:
```bash
git -C ../libbpfgo checkout v0.9.2-libbpf-1.5.1
git -C ../libbpfgo submodule update --init --recursive
make -C ../libbpfgo libbpfgo-static
```
If builds/tests fail with missing libbpf headers (for example `bpf/bpf.h` not found), rerun the commands above and then run `mage world`. Prefer Mage targets over raw `go test` for packages that import `libbpfgo`; Mage wires the required `CGO_CFLAGS`, `CGO_LDFLAGS`, and `LIBBPFGO` values.
```bash
mage build # Build BPF object + Go binary (all is an alias)
mage buildDocker # Build ior inside a Rocky Linux 9 container (writes binary to repo root)
mage buildDockerEl8 # Build ior inside a Rocky Linux 8 container (writes ior.el8 to repo root)
mage test # Run all tests
mage testRace # Run all tests with the race detector enabled (-race)
TEST_NAME=TestEventloop mage testWithName # Run specific test
mage integrationTest # Build + run integration tests in parallel (parallelism capped to NumCPU)
mage integrationTestSerial # Build + run integration tests one at a time
mage generate # Generate code (required after modifying tracepoint definitions)
mage bench # Run benchmarks
mage prReview # Run PR review baseline: world + benchProf
mage clean # Clean build artifacts
mage mrproper # Clean + remove generated outputs (*.zst, *.svg, *.prof, *.pdf, *.tmp…)
mage world # Clean + generate + test + build (recommended reset path)
mage demo # Regen docs/tutorial/ GIFs + screenshots (needs vhs+ttyd, sudo -v warmed)
TAPE=07-stream-live mage demoOne # Regen one demo tape only
mage installDemoTools # One-time: install vhs (go install) + ttyd (dnf) — Fedora/RHEL/Rocky only
```
## Demo Pipeline
`docs/tutorial/` holds the reproducible TUI demo: 14 [VHS](https://github.com/charmbracelet/vhs) `.tape` files under `docs/tutorial/tapes/` drive every dashboard tab and headless mode, write GIFs and PNGs into `docs/tutorial/assets/`, and the resulting tutorial is `docs/tutorial/tutorial.md`. Background workload is generated by `docs/tutorial/scripts/workload.sh`. `mage demo` is fully headless (no real terminal window) — safe to run in the background while editing code; the only foreground requirement is one `sudo -v` to pre-warm the sudo timestamp.
## Code Generation
**Run `mage generate` before building when tracepoint definitions change!**
A Mage target generates code from Linux kernel tracepoint data:
```bash
mage generate # Generate all code (C and Go)
mage generateTracepointsC # Generate C tracepoint handlers from /sys/kernel/tracing
mage generateTypesGo # Generate Go types from C structs
mage generateTracepointsGo # Generate Go tracepoint list
```
Generated files (do not edit manually):
- `internal/c/generated_tracepoints.c` - BPF C handlers for syscall tracepoints
- `internal/types/generated_types.go` - Go structs matching C structs + type mappings
- `internal/tracepoints/generated_tracepoints.go` - List of available syscall tracepoints
Generator source code:
- `internal/generate/` - Parser, classifier, and code generation logic
## Architecture
- **Entry point**: `cmd/ior/main.go` - Linux-only BPF-based I/O syscall tracer
- **Core packages**: `/internal/event/` (BPF event handling), `/internal/flamegraph/` (FlameGraph generation), `/internal/c/` (BPF programs)
- **Output**: TUI dashboard and TUI flamegraphs (no embedded web flamegraph server mode)
- **TUI package**: `/internal/tui/` contains top-level Bubble Tea orchestration (`tui.go`), shared key map (`keys.go`), and styles (`styles.go`).
- **Dashboard tabs**: `/internal/tui/dashboard/` contains tab renderers (flame/overview/syscalls/files/processes/latency+gaps/stream/non-io) and tab framework model.
- **Export modal**: `/internal/tui/export/model.go` implements the centered modal used for CSV export flow in TUI mode.
## TUI Behavior
- **Default mode** is TUI (`-plain` disables TUI and prints CSV rows to stdout).
- **TUI trace flow** ingests events into the in-memory stats engine; it does **not** continuously write trace rows to disk.
- **File output in TUI** is explicit export only (`e`), writing `ior-stream-<timestamp>.csv` in the current directory from the current filtered stream snapshot.
- **Export toggle flag**: `-tuiExport=true|false` (default `true`) enables or disables TUI stream CSV export at runtime.
- **Tab navigation** supports `tab/shift+tab`, numeric keys `1..8`, and directional keys `left/right` and `h/l`.
- **Non-IO visibility**: dashboard includes a dedicated `Non-IO` tab backed by per-family aggregate rows (`Snapshot.Families`); Non-IO filtering is applied in `internal/tui/dashboard`.
- **When export is disabled**, export key hints are hidden from dashboard help and `e` does not open export modal.
- **Fast-refresh cadence**: `-tui-fast-refresh` (default `250ms`) controls the high-frequency tick interval for the flamegraph and stream tabs; set to `0` to disable high-frequency refresh and fall back to the standard dashboard cadence.
- **Sampling / aggregate-only mode**:
- `-syscall-sampling-families` and `-syscall-sampling-syscalls` control per-family/per-syscall sampling (`0` = aggregate-only, `1` = all events, `N` = 1-in-N).
- Current defaults include aggregate-only (`0`) for `futex`, `futex_wait`, `futex_wake`, `futex_requeue`, `futex_waitv`, and `clock_gettime`.
- In raw output modes (`-plain`, `-flamegraph`, headless `-parquet`) the default aggregate-only rates are automatically promoted to `1` because these modes lack a TUI aggregate sink. User-explicit `-syscall-sampling-syscalls` overrides are preserved.
- **Additional metric dimensions**:
- Address-space extent accumulator: `TotalAddressSpaceBytes` and `AddressSpaceBytesPerSec` in `statsengine.Snapshot`.
- Per-event stream/export field `requested_sleep_ns` (from sleep tracepoints).
## Code Style
- Standard Go conventions with static linking (`-ldflags '-w -extldflags "-static"'`)
- Keep functions under 50 lines, refactor larger code to `/internal/` packages
- Use generated types from `/internal/types/generated_types.go` for kernel-userspace communication
- BPF C code in `/internal/c/ior.bpf.c` should be minimal for verification
- Import style: `"ior/internal/packagename"` for internal packages
- Error handling: Return errors, don't panic except for setup validation
## Rollback
If `v0.9.2-libbpf-1.5.1` stops working, roll the local checkout back to commit
`90dbffffbdab` (module version
`v0.6.0-libbpf-1.3.0.20240111220235-90dbffffbdab`), update `go.mod`/`go.sum`
accordingly, and rebuild:
```bash
git -C ../libbpfgo checkout 90dbffffbdab
git -C ../libbpfgo submodule update --init --recursive
make -C ../libbpfgo libbpfgo-static
```
|