From fbb7c9a9ad8d03d5d095ac441a58b37537e0ab8d Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Wed, 6 May 2026 09:35:55 +0300 Subject: add Dockerfile and Rocky Linux 9 build docs Introduces a Docker-based build path so ior can be compiled on any Linux host without a native Rocky 9 toolchain setup: - Dockerfile: Rocky 9 minimal image with Go (version from ARG, default from go.mod), static libelf/libzstd built from source, libbpfgo at v0.9.2-libbpf-1.5.1, and mage; CMD runs mage generate + mage all against the repo root mounted as a volume. - scripts/build-with-docker.sh: reads GO_VERSION from go.mod, passes it as --build-arg to docker build, mounts tracefs and BTF into the container, writes the binary to the repo root. - Magefile.go: adds BuildDocker target that wraps the script. - README.md: simplified to the two build paths (Docker + native) with links to docs/; removed GOTOOLCHAIN=auto throughout. - docs/build-rocky-linux-9.md: full manual Rocky 9 steps, libbpfgo toolchain setup/rollback, compile-once-run-everywhere explanation, and timing semantics. - docs/tui-reference.md: complete TUI hotkey reference, recording mode details, and the .ior.zst vs Parquet trade-off table. - AGENTS.md: removed GOTOOLCHAIN=auto from all build commands. - internal/c/generated_tracepoints.c: regenerated against the host kernel. Co-Authored-By: Claude Sonnet 4.6 --- AGENTS.md | 27 +-- Dockerfile | 75 ++++++++ Magefile.go | 11 ++ README.md | 356 ++++--------------------------------- docs/build-rocky-linux-9.md | 173 ++++++++++++++++++ docs/tui-reference.md | 175 ++++++++++++++++++ internal/c/generated_tracepoints.c | 46 ++--- scripts/build-with-docker.sh | 50 ++++++ 8 files changed, 557 insertions(+), 356 deletions(-) create mode 100644 Dockerfile create mode 100644 docs/build-rocky-linux-9.md create mode 100644 docs/tui-reference.md create mode 100755 scripts/build-with-docker.sh diff --git a/AGENTS.md b/AGENTS.md index 0d65300..11a3618 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -12,22 +12,23 @@ 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 `env GOTOOLCHAIN=auto 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. +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 -env GOTOOLCHAIN=auto mage all # Build everything (BPF objects and Go binary) -env GOTOOLCHAIN=auto mage test # Run all tests -GOTOOLCHAIN=auto TEST_NAME=TestEventloop mage testWithName # Run specific test -env GOTOOLCHAIN=auto mage integrationTest # Build + run integration tests (default parallelism is capped) -GOTOOLCHAIN=auto INTEGRATION_PARALLEL=1 mage integrationTest # Force serial integration tests -env GOTOOLCHAIN=auto mage generate # Generate code (required after modifying tracepoint definitions) -env GOTOOLCHAIN=auto mage bench # Run benchmarks -env GOTOOLCHAIN=auto mage prReview # Run PR review baseline: world + benchProf -env GOTOOLCHAIN=auto mage clean # Clean build artifacts -env GOTOOLCHAIN=auto mage world # Clean + generate + test + build (recommended reset path) -env GOTOOLCHAIN=auto mage demo # Regen demo/ GIFs + screenshots (needs vhs+ttyd, sudo -v warmed) +mage all # Build everything (BPF objects and Go binary) +mage buildDocker # Build ior inside a Rocky Linux 9 container (writes binary to repo root) +mage test # Run all tests +TEST_NAME=TestEventloop mage testWithName # Run specific test +mage integrationTest # Build + run integration tests (default parallelism is capped) +INTEGRATION_PARALLEL=1 mage integrationTest # Force serial integration tests +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 world # Clean + generate + test + build (recommended reset path) +mage demo # Regen demo/ GIFs + screenshots (needs vhs+ttyd, sudo -v warmed) TAPE=07-stream-live mage demoOne # Regen one demo tape only -env GOTOOLCHAIN=auto mage installDemoTools # One-time: install vhs (go install) and ttyd (dnf) +mage installDemoTools # One-time: install vhs (go install) and ttyd (dnf) ``` ## Demo Pipeline diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d190056 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,75 @@ +FROM rockylinux:9-minimal + +# Update GO_VERSION here to upgrade the Go toolchain baked into the image. +ARG GO_VERSION=1.26.2 + +# Install full dnf and plugin support (minimal image ships only microdnf) +RUN microdnf install -y dnf dnf-plugins-core && \ + microdnf clean all + +# Enable CRB (ships zlib-static / glibc-static), EPEL, and the BaseOS source +# repo (provides the elfutils source RPM needed to build libelf.a). +RUN dnf config-manager --set-enabled crb && \ + dnf config-manager --set-enabled baseos-source && \ + dnf install -y epel-release && \ + dnf clean all + +# Build-time toolchain: C compiler, clang/LLVM (for BPF), bpftool, BPF/elf +# headers, static archives for zlib and glibc, and packaging helpers. +RUN dnf install -y \ + gcc clang bpftool \ + elfutils-libelf-devel \ + zlib-static glibc-static libzstd-devel \ + git make cmake wget rpmdevtools && \ + dnf builddep -y elfutils && \ + dnf clean all + +# Install Go from go.dev — Rocky 9 ships an older release, ior needs 1.26+. +RUN wget -q "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" -O /tmp/go.tar.gz && \ + tar -C /usr/local -xf /tmp/go.tar.gz && \ + rm /tmp/go.tar.gz + +ENV PATH="/usr/local/go/bin:/root/go/bin:${PATH}" +ENV GOPATH="/root/go" + +# Build libelf.a from the Rocky 9 elfutils source RPM. +# Rocky 9 does not ship libelf.a (no *-static packages exist in the distro). +RUN mkdir -p /root/src && cd /root && \ + dnf download --source elfutils-libelf && \ + rpm -ivh elfutils-*.src.rpm && \ + tar -C /root/src -xjf rpmbuild/SOURCES/elfutils-*.tar.bz2 && \ + cd /root/src/elfutils-* && \ + ./configure --enable-deterministic-archives --disable-debuginfod --disable-libdebuginfod && \ + make -C lib -j$(nproc) && \ + make -C libelf -j$(nproc) && \ + cp -v libelf/libelf.a /usr/lib64/ && \ + rm -rf /root/src /root/rpmbuild /root/elfutils-*.src.rpm + +# Build libzstd.a from upstream — libzstd-devel does not ship the static archive. +RUN wget -q https://github.com/facebook/zstd/releases/download/v1.5.5/zstd-1.5.5.tar.gz \ + -O /tmp/zstd.tar.gz && \ + tar -C /tmp -xzf /tmp/zstd.tar.gz && \ + make -C /tmp/zstd-1.5.5/lib -j$(nproc) libzstd.a && \ + cp -v /tmp/zstd-1.5.5/lib/libzstd.a /usr/lib64/ && \ + rm -rf /tmp/zstd-1.5.5 /tmp/zstd.tar.gz + +# Clone libbpfgo at the required tag and build the static archive. +# Placed at /git/libbpfgo so it is a sibling of the ior mount at /git/ior, +# matching the default LIBBPFGO=../libbpfgo path used by Magefile.go. +RUN mkdir -p /git && \ + git clone https://github.com/aquasecurity/libbpfgo /git/libbpfgo && \ + git -C /git/libbpfgo checkout v0.9.2-libbpf-1.5.1 && \ + git -C /git/libbpfgo submodule update --init --recursive && \ + make -C /git/libbpfgo libbpfgo-static + +# Install the mage build tool +RUN go install github.com/magefile/mage@latest + +# The ior source tree is mounted at /git/ior at runtime (see build-with-docker.sh). +WORKDIR /git/ior + +# Generate kernel-specific tracepoint code then compile the static ior binary. +# IOR_FORCE_GENERATE=1 skips the strict diff against the committed syscall-coverage +# audit, which was generated on a different kernel build than the container host. +# The container runs as root so bpftool and /sys/kernel/tracing are used directly. +CMD ["sh", "-c", "IOR_FORCE_GENERATE=1 mage generate && mage all"] diff --git a/Magefile.go b/Magefile.go index cf1adfb..e9458b5 100644 --- a/Magefile.go +++ b/Magefile.go @@ -40,6 +40,7 @@ const ( tracepointsResultNew = "internal/c/generated_tracepoints_result.txt.new" tracepointsGoPath = "internal/tracepoints/generated_tracepoints.go" typesGoPath = "internal/types/generated_types.go" + dockerBuildScript = "scripts/build-with-docker.sh" typesHeaderPath = "internal/c/types.h" VMLINUXPath = "internal/c/vmlinux.h" benchProfilesDir = "bench-profiles" @@ -72,6 +73,16 @@ func All() error { return nil } +// BuildDocker builds the ior binary inside a Rocky Linux 9 Docker container +// and writes the resulting static binary to the repo root. The container +// image is built on the first run (~15-20 min) and reused thereafter. +// The Go version baked into the image is taken from go.mod automatically. +// Requires Docker and a host kernel with tracefs and BTF enabled. +// Pass --run to skip the image rebuild and only recompile ior. +func BuildDocker() error { + return sh.RunV("bash", dockerBuildScript) +} + // BpfBuild builds the embedded BPF object used by the Go binary. func BpfBuild() error { if err := ensureVMLINUX(); err != nil { diff --git a/README.md b/README.md index f5fb268..f031fc6 100644 --- a/README.md +++ b/README.md @@ -25,357 +25,73 @@ The demo is fully reproducible: `mage installDemoTools` once, then `sudo -v && m ## Requirements - Go 1.26 or newer (ior relies on cgo via libbpfgo). +- Linux with a BTF-enabled kernel (`/sys/kernel/btf/vmlinux` present). -## Local libbpfgo Toolchain +## Build -`ior` links against a locally built `libbpfgo` checkout. By default -`Magefile.go` expects that checkout at `../libbpfgo` relative to this repo; set -`LIBBPFGO=/absolute/path/to/libbpfgo` if you keep it elsewhere. +### Docker build (recommended — no toolchain setup required) -Pin that checkout to `v0.9.2-libbpf-1.5.1` and rebuild the static artifacts -before running `mage` targets: +Builds the static `ior` binary inside a Rocky Linux 9 container and writes it +to the repo root. Requires only Docker and a Linux host with tracefs and BTF: ```shell -git -C ../libbpfgo checkout v0.9.2-libbpf-1.5.1 -git -C ../libbpfgo submodule update --init --recursive -make -C ../libbpfgo libbpfgo-static +mage buildDocker ``` -Validated commands for this pin: +On first run this takes ~15–20 minutes to build the image. Subsequent runs +reuse the cached image and finish in under a minute. To skip the image build: ```shell -env GOTOOLCHAIN=auto mage world -env GOTOOLCHAIN=auto mage integrationTest +./scripts/build-with-docker.sh --run ``` -Troubleshooting and rollback: +### Native build -- If builds fail with `bpf/bpf.h` missing, re-run the checkout, submodule sync, - and `make libbpfgo-static` commands above, then retry `env GOTOOLCHAIN=auto mage world`. -- Prefer Mage targets over raw `go test` for packages that import `libbpfgo`; - Mage injects the required `CGO_CFLAGS`, `CGO_LDFLAGS`, and `LIBBPFGO` values. -- To roll back to the previous wrapper state, repin `go.mod` to - `github.com/aquasecurity/libbpfgo v0.6.0-libbpf-1.3.0.20240111220235-90dbffffbdab`, - then reset the sibling checkout and rebuild: +`ior` links against a locally built `libbpfgo`. Clone it as a sibling of this +repo and build the static archive once: ```shell -git -C ../libbpfgo checkout 90dbffffbdab +git clone https://github.com/aquasecurity/libbpfgo ../libbpfgo +git -C ../libbpfgo checkout v0.9.2-libbpf-1.5.1 git -C ../libbpfgo submodule update --init --recursive make -C ../libbpfgo libbpfgo-static ``` -## Timing Semantics - -Each reported event pair has two timing counters: - -- `durationNs`: syscall runtime on the same thread (`exit(current) - enter(current)`). -- `durationToPrevNs`: inter-syscall gap on the same thread (`enter(current) - exit(previous)`). - -Important details: - -- `durationToPrevNs` is tracked per `tid` (thread), not globally across all threads. -- The first observed syscall pair for a thread has `durationToPrevNs = 0` because there is no prior exit timestamp. -- `durationToPrevNs` is attributed to the current syscall pair (the one whose `enter` closes the gap). -- There is no separate "idle" pseudo-event bucket; use the `durationToPrev` count field when aggregated flamegraph output should emphasize inter-syscall time. - -## Rocky Linux 9 - -Verified on a fresh Rocky Linux 9.7 install (e.g. kernel `5.14.0-611.5.1.el9_7`, -exact stamp not required). Runs on the **stock RHEL 9 kernel** — no kernel -upgrade needed. One build-time caveat: - -- Rocky 9 ships neither `libelf.a` nor `libzstd.a` (no `*-static` packages). Both have - to be built from source — the elfutils dance is the same as the Fedora section above; - `libzstd.a` needs an extra `make` from the upstream tarball. - -> Historical note. Earlier versions of `ior` typed BPF tracepoint context as -> `struct trace_event_raw_sys_enter`/`_exit` (the BTF-emitted alias). RHEL 9 -> backports an `rt`-tree patch that adds `preempt_lazy_count` to `struct -> trace_entry`, which widens those aliases by 8 bytes and shifts the `args`/`ret` -> offsets — but the actual context the kernel hands the program is still -> `struct syscall_trace_enter`/`_exit`, where the offsets did not move. The -> verifier saw the program reading past `max_ctx_offset` and rejected the -> attach with `EACCES`. `ior` now uses `syscall_trace_*` directly (matching -> the [bcc fix](https://github.com/iovisor/bcc/pull/4920) and inspektor-gadget), -> so the stock kernel works with no workaround. +Then build everything: ```shell -# 1) Enable repos and install build dependencies (CRB ships static libs). -sudo dnf config-manager --set-enabled crb -sudo dnf install -y epel-release -sudo dnf install -y gcc clang bpftool elfutils-libelf-devel zlib-static \ - glibc-static libzstd-devel git make cmake wget rpmdevtools strace bpftrace -sudo dnf builddep -y elfutils - -# 2) Install Go 1.26 from go.dev (Rocky 9 ships only Go 1.25; ior needs 1.26+). -cd /tmp -wget -q https://go.dev/dl/go1.26.2.linux-amd64.tar.gz -sudo tar -C /usr/local -xf go1.26.2.linux-amd64.tar.gz -echo 'export PATH=/usr/local/go/bin:$HOME/go/bin:$PATH' | sudo tee /etc/profile.d/go.sh -source /etc/profile.d/go.sh - -# 3) Build libelf.a from elfutils source (same trick as the Fedora section). -mkdir -p ~/src && cd ~ -dnf download --source elfutils-libelf -rpm -ivh elfutils-*.src.rpm -tar -C ~/src -xjf rpmbuild/SOURCES/elfutils-*.tar.bz2 -cd ~/src/elfutils-* -./configure --enable-deterministic-archives --disable-debuginfod --disable-libdebuginfod -make -C lib -j$(nproc) -make -C libelf -j$(nproc) -sudo cp -v libelf/libelf.a /usr/lib64/ - -# 4) Build libzstd.a from upstream (libzstd-devel does not ship the static archive). -cd /tmp -wget -q https://github.com/facebook/zstd/releases/download/v1.5.5/zstd-1.5.5.tar.gz -tar xzf zstd-1.5.5.tar.gz -make -C zstd-1.5.5/lib -j$(nproc) libzstd.a -sudo cp -v zstd-1.5.5/lib/libzstd.a /usr/lib64/ - -# 5) Clone ior + libbpfgo, pin libbpfgo, build the static archive, install mage. -mkdir -p ~/git -git clone https://codeberg.org/snonux/ior ~/git/ior -git clone https://github.com/aquasecurity/libbpfgo ~/git/libbpfgo -git -C ~/git/libbpfgo checkout v0.9.2-libbpf-1.5.1 -git -C ~/git/libbpfgo submodule update --init --recursive -make -C ~/git/libbpfgo libbpfgo-static -go install github.com/magefile/mage@latest - -# 6) Generate against the live kernel (the syscall-coverage audit is -# kernel-specific; IOR_FORCE_GENERATE skips the strict diff against the -# committed audit which was generated on a different kernel build). -cd ~/git/ior -env IOR_FORCE_GENERATE=1 GOTOOLCHAIN=auto mage generate -env GOTOOLCHAIN=auto mage all - -# 7) Smoke test. -sudo ./ior -plain -duration 5 +mage world ``` -If `./ior -plain -duration 5` prints `Probing for 5s` and a stream of CSV rows, -the install is good. +For Rocky Linux 9 specific steps (building static libelf/libzstd, installing Go +1.26) see [docs/build-rocky-linux-9.md](./docs/build-rocky-linux-9.md). ## Compile once, run everywhere -The full build dance above only has to happen on **one** machine. The resulting -`ior` binary is portable across Linux hosts: `scp ior other-host:/usr/local/bin/` -and run it there. Two reasons it works: - -- The Go binary is compiled with `-extldflags "-static"` and links libbpf, - libelf, libzstd, and zlib as static archives. There is no runtime dependency - on the build host's library versions (a couple of glibc resolver functions — - `getpwnam_r` and friends — fall back to the target's libc, which is fine on - any reasonable distro). -- The BPF object inside the binary is built with libbpf's CO-RE - (Compile-Once, Run-Everywhere) machinery. Field offsets are not baked into - the bytecode; libbpf reads the target kernel's BTF - (`/sys/kernel/btf/vmlinux`) at load time and patches the program for that - kernel. As long as the target ships BTF — true on every Debian, Ubuntu, - Fedora, Arch, RHEL, and now ElRepo `kernel-ml` build at the time of - writing — the same `ior` binary runs without recompilation. - -So in practice: pick one Rocky 9 / Fedora box, do the build dance once, then -distribute the 23 MB binary to wherever you want to trace. The build host needs -all the dev tooling; the trace hosts need only a BTF-enabled kernel and `sudo`. +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. -For the eBPF + CO-RE explanation, see Part 2 of the I/O Riot NG blog series: -[Unveiling I/O Riot NG — Part 2: under the hood](https://foo.zone/gemfeed/unveiling-ior-ng-part-2.html). +See [docs/build-rocky-linux-9.md](./docs/build-rocky-linux-9.md) for the full +explanation. -## TUI Flamegraphs +## TUI -Flamegraphs are available only inside the TUI dashboard. -Use `-fields` to change the stack order and `-count` to choose the metric. -The default stack order is `comm,path,tracepoint` (bottom to top). +Press **H** inside the dashboard to toggle the built-in help panel. Tabs are +reachable with **tab/shift+tab** or number keys **1–6**. Full hotkey reference: +[docs/tui-reference.md](./docs/tui-reference.md). ## Recording Modes -`ior` has four distinct output flows. They are intentionally different: - -| Mode | How to use it | What it writes | Filter behavior | -| --- | --- | --- | --- | -| TUI dashboard | default startup | nothing continuously; data stays in memory unless you export | current TUI/global filters drive what you see | -| TUI CSV snapshot export | press `e` in the dashboard | one `ior-stream-.csv` snapshot of the current filtered stream view | exports only the currently filtered in-memory rows | -| Headless `.ior.zst` export | start with `-flamegraph -name ` | one aggregated native trace artifact written at shutdown | no TUI filter stack; this is the native trace/integration workflow | -| Parquet recording | press `R` in the TUI, or start with `-parquet ` | a streaming Parquet file of traced syscall rows | TUI mode records rows that pass the active TUI filter; headless `-parquet` records all traced rows | - -Important distinction: - -- `.ior.zst` output is an aggregated native artifact, not a row-by-row event log. -- CSV export is a point-in-time snapshot of the ring buffer. -- Parquet recording is a streaming capture from start to stop. -- The ring buffer is capped, so CSV export is not a replacement for Parquet recording or `.ior.zst` output. - -### Headless Native `.ior.zst` Output - -Use `-flamegraph` when you want the native `ior` trace artifact instead of a streaming row log: - -```shell -sudo ./ior -flamegraph -name trace-run -duration 60 -``` - -Native `.ior.zst` behavior: - -- writes one `*.ior.zst` file when the run ends -- stores aggregated counters for repeated syscall/path/process combinations -- is intended for `ior`'s native flamegraph and integration-style workflows -- does not preserve one output row per traced syscall - -### TUI Parquet Recording - -Start a recording from the dashboard with `R`. - -- First `R`: open a filename prompt (`ior-recording-.parquet` by default). -- `Enter`: start recording to that file. -- Second `R`: stop and finalize the active Parquet file. -- Recording stops automatically when you quit the TUI or reselect PID/TID/session scope. - -Lifecycle details: - -- TUI recording uses the active TUI global filter at emission time. -- If a filter change restarts tracing, the recorder stays alive and continues writing matching rows after the restart. -- The dashboard footer shows the active recording path or the last recording error. - -### Headless Parquet Recording - -Use `-parquet` to skip the TUI and stream traced syscall rows directly to a Parquet file: - -```shell -sudo ./ior -parquet trace.parquet -duration 60 -``` - -Headless Parquet mode behavior: - -- skips the TUI completely -- records all traced rows -- rejects content filters such as `-comm`, `-path`, `-pid`, and `-tid` -- cannot be combined with `-plain`, `-flamegraph`, `--testflames`, or `--testliveflames` +`ior` has four distinct output flows: -Use headless mode when you want a full recording, and TUI mode when you want interactive filtering plus optional start/stop recording from the dashboard. - -### Choosing Between `.ior.zst` and Parquet - -Both formats are useful, but they solve different problems: - -| Question | Native `.ior.zst` | Parquet | +| Mode | How to use it | What it writes | | --- | --- | --- | -| Data shape | aggregated counters | one row per traced syscall | -| Write pattern | collect in memory, write one compressed artifact at the end | stream rows continuously while recording | -| Best for | `ior`-native trace artifacts, flamegraph workflows, integration assertions | offline analysis in other tools, long captures, preserving per-event detail | -| Relative write cost | usually lower because repeated events are folded together before file write | usually higher because each traced row is serialized | -| Detail retained | loses original row order and per-event granularity | keeps per-event timing and syscall fields | - -Rule of thumb: - -- choose `.ior.zst` when you want the native `ior` artifact and do not need every traced syscall row preserved -- choose Parquet when you want a full event stream for downstream analysis outside `ior` - -## TUI Navigation - -The TUI interface provides an in‑screen help panel (toggle with **H**) that lists all available keys. Use this help screen to discover navigation shortcuts. - -You can move between dashboard tabs: - -- **tab** – next dashboard tab -- **shift+tab** – previous dashboard tab -- **1** – Overview -- **2** – Syscalls -- **3** – Files -- **4** – Processes -- **5** – Latency+Gaps -- **6** – Stream - -The bottom hint shows `press H for help` when the help is hidden. - - - -The TUI has two key scopes: - -- Global hotkeys: available from dashboard screens. -- Dashboard hotkeys: behavior that depends on the active dashboard tab (especially `6:Stream`). - -Help visibility: - -- `H`: toggle bottom help sections on/off. -- By default, help is hidden and the bottom hint shows `press H for help`. - -### Global Hotkeys - -- `tab`: next dashboard tab. -- `shift+tab`: previous dashboard tab. -- `1`: `Overview` tab. -- `2`: `Syscalls` tab. -- `3`: `Files` tab. -- `4`: `Processes` tab. -- `5`: `Latency+Gaps` tab. -- `6`: `Stream` tab. -- `7`: `Stream` tab (alias). -- `e`: export filtered stream rows to CSV (`ior-stream-.csv`) in current working directory. -- `R`: start or stop Parquet recording from the TUI dashboard. -- `p`: re-open process selector (PID selection flow). -- `t`: open TID selector flow. -- `o`: open probe selection/toggling dialog. -- `r`: refresh dashboard snapshot. -- `q` or `ctrl+c`: quit. - -### Dashboard / Tab-Specific Hotkeys - -- `d` in `3:Files`: toggle directory-grouped files view. -- `s` in sortable table tabs (`2:Syscalls`, `3:Files`, `4:Processes`): sort by the selected column using that table's default direction. -- `S` in sortable table tabs (`2:Syscalls`, `3:Files`, `4:Processes`): reverse-sort by the selected column. -- `j/k` or `up/down` in list-like tabs (`2:Syscalls`, `3:Files`, `4:Processes`): scroll list. - -`left/right` and `h/l` do not switch tabs. In `6:Stream` paused mode they move selected column. - -### 6:Stream Hotkeys and Behavior - -`6:Stream` has two modes: - -- Live mode (`paused=false`): rows update continuously. -- Pause mode (`paused=true`): selection/cell/filter/search/export workflows are enabled. - -Core controls: - -- `space`: toggle live/pause. -- `g`/`G`: jump to top/tail. -- `c`: clear stream filters. -- `f`: open advanced filter modal. -- `j/k` or `up/down`: move selected row in pause mode; scroll in live mode. -- `left/right` or `h/l`: move selected column in pause mode. - -#### Enter-Based Filter Stack (Pause Mode) - -In pause mode, `enter` on the selected cell pushes a new filter onto a stack and immediately re-filters the current ring buffer snapshot. Filters are stackable. - -- String columns use case-insensitive substring match: -- `Comm` -> `comm~` -- `Syscall` -> `syscall~` -- `File` -> `file~` -- Numeric exact match: -- `PID`, `TID`, `FD`, `Ret`, `Bytes` -- Numeric threshold (`>=`): -- `Latency` -> `latency>=selected_value` -- `Gap` -> `gap>=selected_value` - -Undo: - -- `esc` in pause mode pops the most recent filter from the stack (LIFO). -- Repeated `esc` keeps undoing until no stacked filters remain. - -#### Regex Search (Pause Mode) - -- `/`: open regex prompt and search forward. -- `?`: open regex prompt and search backward. -- Search checks all stream columns/fields and wraps around ring-buffer rows. -- `n`: next match in the same direction as last `/` or `?`. -- `N`: previous match (opposite direction). - -#### Stream CSV Export (Pause Mode) - -- `x`: quick export filtered stream rows to CSV (`ior-stream-.csv`). -- `X`: export filtered stream rows to CSV with filename prompt. -- `E`: open last stream-exported CSV in foreground editor (`EDITOR` -> `VISUAL` -> `SUDO_EDITOR` -> fallback `hx`, else `vi`). - -Export behavior: +| TUI dashboard | default startup | nothing — data stays in memory until export | +| TUI CSV snapshot | press `e` | `ior-stream-.csv` of filtered stream | +| Headless `.ior.zst` | `-flamegraph -name ` | aggregated native trace artifact | +| Parquet recording | press `R` in TUI, or `-parquet ` | streaming Parquet file | -- `e` exports a fresh filtered stream snapshot using the current shared TUI filter, even outside paused mode. -- `x`/`X` export the currently paused stream rows, preserving the stream tab's exact paused view. +Full details and the `.ior.zst` vs Parquet trade-off: +[docs/tui-reference.md](./docs/tui-reference.md). diff --git a/docs/build-rocky-linux-9.md b/docs/build-rocky-linux-9.md new file mode 100644 index 0000000..424b78e --- /dev/null +++ b/docs/build-rocky-linux-9.md @@ -0,0 +1,173 @@ +# Building ior on Rocky Linux 9 + +Verified on a fresh Rocky Linux 9.7 install (kernel `5.14.0-611.5.1.el9_7` or +newer). Runs on the **stock RHEL 9 kernel** — no kernel upgrade needed. + +One build-time caveat: Rocky 9 ships neither `libelf.a` nor `libzstd.a` (no +`*-static` packages). Both must be built from source. + +> Historical note. Earlier versions of `ior` typed BPF tracepoint context as +> `struct trace_event_raw_sys_enter`/`_exit` (the BTF-emitted alias). RHEL 9 +> backports an `rt`-tree patch that adds `preempt_lazy_count` to `struct +> trace_entry`, which widens those aliases by 8 bytes and shifts the `args`/`ret` +> offsets — but the actual context the kernel hands the program is still +> `struct syscall_trace_enter`/`_exit`, where the offsets did not move. The +> verifier saw the program reading past `max_ctx_offset` and rejected the +> attach with `EACCES`. `ior` now uses `syscall_trace_*` directly (matching +> the [bcc fix](https://github.com/iovisor/bcc/pull/4920) and inspektor-gadget), +> so the stock kernel works with no workaround. + +## Docker build (no Rocky 9 host required) + +The easiest path — builds entirely inside a container from any Docker-capable +Linux host: + +```shell +mage buildDocker +# or directly: +./scripts/build-with-docker.sh +# skip image rebuild on subsequent runs: +./scripts/build-with-docker.sh --run +``` + +`mage buildDocker` builds a `ior-builder:rocky9` image on first run (~15–20 min), +then runs it with the repo root mounted as a volume so the resulting static +binary lands at `./ior`. + +## Manual build on a Rocky Linux 9 host + +```shell +# 1) Enable repos and install build dependencies (CRB ships static libs). +sudo dnf config-manager --set-enabled crb +sudo dnf install -y epel-release +sudo dnf install -y gcc clang bpftool elfutils-libelf-devel zlib-static \ + glibc-static libzstd-devel git make cmake wget rpmdevtools strace bpftrace +sudo dnf builddep -y elfutils + +# 2) Install Go 1.26 from go.dev (Rocky 9 ships only Go 1.25; ior needs 1.26+). +cd /tmp +wget -q https://go.dev/dl/go1.26.2.linux-amd64.tar.gz +sudo tar -C /usr/local -xf go1.26.2.linux-amd64.tar.gz +echo 'export PATH=/usr/local/go/bin:$HOME/go/bin:$PATH' | sudo tee /etc/profile.d/go.sh +source /etc/profile.d/go.sh + +# 3) Build libelf.a from elfutils source. +mkdir -p ~/src && cd ~ +dnf download --source elfutils-libelf +rpm -ivh elfutils-*.src.rpm +tar -C ~/src -xjf rpmbuild/SOURCES/elfutils-*.tar.bz2 +cd ~/src/elfutils-* +./configure --enable-deterministic-archives --disable-debuginfod --disable-libdebuginfod +make -C lib -j$(nproc) +make -C libelf -j$(nproc) +sudo cp -v libelf/libelf.a /usr/lib64/ + +# 4) Build libzstd.a from upstream (libzstd-devel does not ship the static archive). +cd /tmp +wget -q https://github.com/facebook/zstd/releases/download/v1.5.5/zstd-1.5.5.tar.gz +tar xzf zstd-1.5.5.tar.gz +make -C zstd-1.5.5/lib -j$(nproc) libzstd.a +sudo cp -v zstd-1.5.5/lib/libzstd.a /usr/lib64/ + +# 5) Clone ior + libbpfgo, pin libbpfgo, build the static archive, install mage. +mkdir -p ~/git +git clone https://codeberg.org/snonux/ior ~/git/ior +git clone https://github.com/aquasecurity/libbpfgo ~/git/libbpfgo +git -C ~/git/libbpfgo checkout v0.9.2-libbpf-1.5.1 +git -C ~/git/libbpfgo submodule update --init --recursive +make -C ~/git/libbpfgo libbpfgo-static +go install github.com/magefile/mage@latest + +# 6) Generate against the live kernel and build. +# IOR_FORCE_GENERATE=1 skips the strict diff against the committed audit +# (generated on a different kernel build). +cd ~/git/ior +IOR_FORCE_GENERATE=1 mage generate +mage all + +# 7) Smoke test. +sudo ./ior -plain -duration 5 +``` + +If `./ior -plain -duration 5` prints `Probing for 5s` and a stream of CSV rows, +the install is good. + +## libbpfgo toolchain + +`ior` links against a locally built `libbpfgo` checkout. By default +`Magefile.go` expects that checkout at `../libbpfgo` relative to this repo; set +`LIBBPFGO=/absolute/path/to/libbpfgo` to override. + +Pin that checkout to `v0.9.2-libbpf-1.5.1` and rebuild the static artifacts +before running `mage` targets: + +```shell +git -C ../libbpfgo checkout v0.9.2-libbpf-1.5.1 +git -C ../libbpfgo submodule update --init --recursive +make -C ../libbpfgo libbpfgo-static +``` + +Validated commands for this pin: + +```shell +mage world +mage integrationTest +``` + +Troubleshooting and rollback: + +- If builds fail with `bpf/bpf.h` missing, re-run the checkout, submodule + sync, and `make libbpfgo-static` commands above, then retry + `mage world`. +- Prefer Mage targets over raw `go test` for packages that import `libbpfgo`; + Mage injects the required `CGO_CFLAGS`, `CGO_LDFLAGS`, and `LIBBPFGO` values. +- To roll back to the previous pin, reset to commit `90dbffffbdab` + (`v0.6.0-libbpf-1.3.0.20240111220235-90dbffffbdab`) and rebuild: + +```shell +git -C ../libbpfgo checkout 90dbffffbdab +git -C ../libbpfgo submodule update --init --recursive +make -C ../libbpfgo libbpfgo-static +``` + +## Compile once, run everywhere + +The full build dance above only has to happen on **one** machine. The resulting +`ior` binary is portable across Linux hosts: `scp ior other-host:/usr/local/bin/` +and run it there. + +Two reasons it works: + +- The Go binary is compiled with `-extldflags "-static"` and links libbpf, + libelf, libzstd, and zlib as static archives. There is no runtime dependency + on the build host's library versions (a couple of glibc resolver functions — + `getpwnam_r` and friends — fall back to the target's libc, which is fine on + any reasonable distro). +- The BPF object inside the binary is built with libbpf's CO-RE + (Compile-Once, Run-Everywhere) machinery. Field offsets are not baked into + the bytecode; libbpf reads the target kernel's BTF (`/sys/kernel/btf/vmlinux`) + at load time and patches the program for that kernel. As long as the target + ships BTF — true on every Debian, Ubuntu, Fedora, Arch, RHEL, and ElRepo + `kernel-ml` build at the time of writing — the same `ior` binary runs without + recompilation. + +Pick one Rocky 9 / Fedora box, do the build dance once, then distribute the +23 MB binary to wherever you want to trace. The build host needs all the dev +tooling; the trace hosts need only a BTF-enabled kernel and `sudo`. + +## Timing semantics + +Each reported event pair has two timing counters: + +- `durationNs`: syscall runtime on the same thread (`exit(current) - enter(current)`). +- `durationToPrevNs`: inter-syscall gap on the same thread (`enter(current) - exit(previous)`). + +Important details: + +- `durationToPrevNs` is tracked per `tid` (thread), not globally across all threads. +- The first observed syscall pair for a thread has `durationToPrevNs = 0` because + there is no prior exit timestamp. +- `durationToPrevNs` is attributed to the current syscall pair (the one whose + `enter` closes the gap). +- There is no separate "idle" pseudo-event bucket; use the `durationToPrev` count + field when aggregated flamegraph output should emphasize inter-syscall time. diff --git a/docs/tui-reference.md b/docs/tui-reference.md new file mode 100644 index 0000000..d6a7266 --- /dev/null +++ b/docs/tui-reference.md @@ -0,0 +1,175 @@ +# TUI Reference + +## TUI Flamegraphs + +Flamegraphs are available only inside the TUI dashboard. +Use `-fields` to change the stack order and `-count` to choose the metric. +The default stack order is `comm,path,tracepoint` (bottom to top). + +## Recording Modes + +`ior` has four distinct output flows: + +| Mode | How to use it | What it writes | Filter behavior | +| --- | --- | --- | --- | +| TUI dashboard | default startup | nothing continuously; data stays in memory unless you export | current TUI/global filters drive what you see | +| TUI CSV snapshot export | press `e` in the dashboard | one `ior-stream-.csv` snapshot of the current filtered stream view | exports only the currently filtered in-memory rows | +| Headless `.ior.zst` export | start with `-flamegraph -name ` | one aggregated native trace artifact written at shutdown | no TUI filter stack; this is the native trace/integration workflow | +| Parquet recording | press `R` in the TUI, or start with `-parquet ` | a streaming Parquet file of traced syscall rows | TUI mode records rows that pass the active TUI filter; headless `-parquet` records all traced rows | + +Important distinction: + +- `.ior.zst` output is an aggregated native artifact, not a row-by-row event log. +- CSV export is a point-in-time snapshot of the ring buffer. +- Parquet recording is a streaming capture from start to stop. +- The ring buffer is capped, so CSV export is not a replacement for Parquet recording or `.ior.zst` output. + +### Headless Native `.ior.zst` Output + +Use `-flamegraph` when you want the native `ior` trace artifact instead of a streaming row log: + +```shell +sudo ./ior -flamegraph -name trace-run -duration 60 +``` + +Native `.ior.zst` behavior: + +- writes one `*.ior.zst` file when the run ends +- stores aggregated counters for repeated syscall/path/process combinations +- is intended for `ior`'s native flamegraph and integration-style workflows +- does not preserve one output row per traced syscall + +### TUI Parquet Recording + +Start a recording from the dashboard with `R`. + +- First `R`: open a filename prompt (`ior-recording-.parquet` by default). +- `Enter`: start recording to that file. +- Second `R`: stop and finalize the active Parquet file. +- Recording stops automatically when you quit the TUI or reselect PID/TID/session scope. + +Lifecycle details: + +- TUI recording uses the active TUI global filter at emission time. +- If a filter change restarts tracing, the recorder stays alive and continues writing matching rows after the restart. +- The dashboard footer shows the active recording path or the last recording error. + +### Headless Parquet Recording + +Use `-parquet` to skip the TUI and stream traced syscall rows directly to a Parquet file: + +```shell +sudo ./ior -parquet trace.parquet -duration 60 +``` + +Headless Parquet mode behavior: + +- skips the TUI completely +- records all traced rows +- rejects content filters such as `-comm`, `-path`, `-pid`, and `-tid` +- cannot be combined with `-plain`, `-flamegraph`, `--testflames`, or `--testliveflames` + +Use headless mode when you want a full recording, and TUI mode when you want interactive filtering plus optional start/stop recording from the dashboard. + +### Choosing Between `.ior.zst` and Parquet + +| Question | Native `.ior.zst` | Parquet | +| --- | --- | --- | +| Data shape | aggregated counters | one row per traced syscall | +| Write pattern | collect in memory, write one compressed artifact at the end | stream rows continuously while recording | +| Best for | `ior`-native trace artifacts, flamegraph workflows, integration assertions | offline analysis in other tools, long captures, preserving per-event detail | +| Relative write cost | usually lower because repeated events are folded together before file write | usually higher because each traced row is serialized | +| Detail retained | loses original row order and per-event granularity | keeps per-event timing and syscall fields | + +Rule of thumb: + +- choose `.ior.zst` when you want the native `ior` artifact and do not need every traced syscall row preserved +- choose Parquet when you want a full event stream for downstream analysis outside `ior` + +## TUI Navigation + +The TUI has an in-screen help panel (toggle with **H**) that lists all available +keys. Use it to discover shortcuts without consulting this document. + +Dashboard tabs: + +- **tab** / **shift+tab** — next / previous tab +- **1** — Overview +- **2** — Syscalls +- **3** — Files +- **4** — Processes +- **5** — Latency+Gaps +- **6** — Stream + +The TUI has two key scopes: + +- Global hotkeys: available from any dashboard screen. +- Dashboard hotkeys: behavior that depends on the active tab (especially `6:Stream`). + +### Global Hotkeys + +- `tab` / `shift+tab`: cycle tabs. +- `1`–`6`: jump to tab by number (`7` is an alias for `6`). +- `e`: export filtered stream rows to CSV (`ior-stream-.csv`). +- `R`: start or stop Parquet recording. +- `p`: re-open process selector (PID selection flow). +- `t`: open TID selector flow. +- `o`: open probe selection/toggling dialog. +- `r`: refresh dashboard snapshot. +- `H`: toggle bottom help sections on/off. +- `q` or `ctrl+c`: quit. + +### Dashboard / Tab-Specific Hotkeys + +- `d` in `3:Files`: toggle directory-grouped files view. +- `s` in sortable tabs (`2:Syscalls`, `3:Files`, `4:Processes`): sort by selected column. +- `S` in sortable tabs: reverse-sort by selected column. +- `j/k` or `up/down` in list tabs: scroll list. + +`left/right` and `h/l` do not switch tabs. In `6:Stream` paused mode they move the selected column. + +### 6:Stream Hotkeys and Behavior + +`6:Stream` has two modes: + +- Live mode (`paused=false`): rows update continuously. +- Pause mode (`paused=true`): selection/cell/filter/search/export workflows are enabled. + +Core controls: + +- `space`: toggle live/pause. +- `g`/`G`: jump to top/tail. +- `c`: clear stream filters. +- `f`: open advanced filter modal. +- `j/k` or `up/down`: move selected row (pause) or scroll (live). +- `left/right` or `h/l`: move selected column in pause mode. + +#### Enter-Based Filter Stack (Pause Mode) + +In pause mode, `enter` on the selected cell pushes a filter onto a stack and +immediately re-filters the current ring buffer snapshot. Filters are stackable. + +- String columns use case-insensitive substring match: + - `Comm` → `comm~` + - `Syscall` → `syscall~` + - `File` → `file~` +- Numeric exact match: `PID`, `TID`, `FD`, `Ret`, `Bytes` +- Numeric threshold (`>=`): `Latency` → `latency>=selected_value`, `Gap` → `gap>=selected_value` + +`esc` in pause mode pops the most recent filter (LIFO); repeated `esc` undoes +all stacked filters. + +#### Regex Search (Pause Mode) + +- `/`: search forward; `?`: search backward. +- Search checks all stream columns and wraps around the ring buffer. +- `n` / `N`: next / previous match. + +#### Stream CSV Export (Pause Mode) + +- `x`: quick export filtered stream rows to CSV. +- `X`: export with filename prompt. +- `E`: open last stream-exported CSV in foreground editor (`EDITOR` → `VISUAL` → `SUDO_EDITOR` → `hx` → `vi`). + +`e` (global) exports a fresh filtered snapshot even outside paused mode; `x`/`X` +export the exact paused view. diff --git a/internal/c/generated_tracepoints.c b/internal/c/generated_tracepoints.c index 5bc3110..1633966 100644 --- a/internal/c/generated_tracepoints.c +++ b/internal/c/generated_tracepoints.c @@ -1,7 +1,7 @@ // Code generated - don't change manually! -/// Ignoring sys_enter_accept4 sys_exit_accept4 as possibly not file I/O related /// Ignoring sys_enter_accept sys_exit_accept as possibly not file I/O related +/// Ignoring sys_enter_accept4 sys_exit_accept4 as possibly not file I/O related /// Ignoring sys_enter_acct sys_exit_acct as possibly not file I/O related /// Ignoring sys_enter_add_key sys_exit_add_key as possibly not file I/O related /// Ignoring sys_enter_adjtimex sys_exit_adjtimex as possibly not file I/O related @@ -17,20 +17,20 @@ /// Ignoring sys_enter_clock_gettime sys_exit_clock_gettime as possibly not file I/O related /// Ignoring sys_enter_clock_nanosleep sys_exit_clock_nanosleep as possibly not file I/O related /// Ignoring sys_enter_clock_settime sys_exit_clock_settime as possibly not file I/O related -/// Ignoring sys_enter_clone3 sys_exit_clone3 as possibly not file I/O related /// Ignoring sys_enter_clone sys_exit_clone as possibly not file I/O related +/// Ignoring sys_enter_clone3 sys_exit_clone3 as possibly not file I/O related /// Ignoring sys_enter_connect sys_exit_connect as possibly not file I/O related /// Ignoring sys_enter_delete_module sys_exit_delete_module as possibly not file I/O related -/// Ignoring sys_enter_epoll_create1 sys_exit_epoll_create1 as possibly not file I/O related /// Ignoring sys_enter_epoll_create sys_exit_epoll_create as possibly not file I/O related +/// Ignoring sys_enter_epoll_create1 sys_exit_epoll_create1 as possibly not file I/O related /// Ignoring sys_enter_epoll_ctl sys_exit_epoll_ctl as possibly not file I/O related -/// Ignoring sys_enter_epoll_pwait2 sys_exit_epoll_pwait2 as possibly not file I/O related /// Ignoring sys_enter_epoll_pwait sys_exit_epoll_pwait as possibly not file I/O related +/// Ignoring sys_enter_epoll_pwait2 sys_exit_epoll_pwait2 as possibly not file I/O related /// Ignoring sys_enter_epoll_wait sys_exit_epoll_wait as possibly not file I/O related -/// Ignoring sys_enter_eventfd2 sys_exit_eventfd2 as possibly not file I/O related /// Ignoring sys_enter_eventfd sys_exit_eventfd as possibly not file I/O related -/// Ignoring sys_enter_execveat sys_exit_execveat as possibly not file I/O related +/// Ignoring sys_enter_eventfd2 sys_exit_eventfd2 as possibly not file I/O related /// Ignoring sys_enter_execve sys_exit_execve as possibly not file I/O related +/// Ignoring sys_enter_execveat sys_exit_execveat as possibly not file I/O related /// Ignoring sys_enter_exit sys_exit_exit as possibly not file I/O related /// Ignoring sys_enter_exit_group sys_exit_exit_group as possibly not file I/O related /// Ignoring sys_enter_fanotify_init sys_exit_fanotify_init as possibly not file I/O related @@ -42,13 +42,14 @@ /// Ignoring sys_enter_futex_wait sys_exit_futex_wait as possibly not file I/O related /// Ignoring sys_enter_futex_waitv sys_exit_futex_waitv as possibly not file I/O related /// Ignoring sys_enter_futex_wake sys_exit_futex_wake as possibly not file I/O related +/// Ignoring sys_enter_get_mempolicy sys_exit_get_mempolicy as possibly not file I/O related +/// Ignoring sys_enter_get_robust_list sys_exit_get_robust_list as possibly not file I/O related /// Ignoring sys_enter_getcpu sys_exit_getcpu as possibly not file I/O related /// Ignoring sys_enter_getegid sys_exit_getegid as possibly not file I/O related /// Ignoring sys_enter_geteuid sys_exit_geteuid as possibly not file I/O related /// Ignoring sys_enter_getgid sys_exit_getgid as possibly not file I/O related /// Ignoring sys_enter_getgroups sys_exit_getgroups as possibly not file I/O related /// Ignoring sys_enter_getitimer sys_exit_getitimer as possibly not file I/O related -/// Ignoring sys_enter_get_mempolicy sys_exit_get_mempolicy as possibly not file I/O related /// Ignoring sys_enter_getpeername sys_exit_getpeername as possibly not file I/O related /// Ignoring sys_enter_getpgid sys_exit_getpgid as possibly not file I/O related /// Ignoring sys_enter_getpgrp sys_exit_getpgrp as possibly not file I/O related @@ -59,7 +60,6 @@ /// Ignoring sys_enter_getresgid sys_exit_getresgid as possibly not file I/O related /// Ignoring sys_enter_getresuid sys_exit_getresuid as possibly not file I/O related /// Ignoring sys_enter_getrlimit sys_exit_getrlimit as possibly not file I/O related -/// Ignoring sys_enter_get_robust_list sys_exit_get_robust_list as possibly not file I/O related /// Ignoring sys_enter_getrusage sys_exit_getrusage as possibly not file I/O related /// Ignoring sys_enter_getsid sys_exit_getsid as possibly not file I/O related /// Ignoring sys_enter_getsockname sys_exit_getsockname as possibly not file I/O related @@ -69,8 +69,8 @@ /// Ignoring sys_enter_getuid sys_exit_getuid as possibly not file I/O related /// Ignoring sys_enter_init_module sys_exit_init_module as possibly not file I/O related /// Ignoring sys_enter_inotify_add_watch sys_exit_inotify_add_watch as possibly not file I/O related -/// Ignoring sys_enter_inotify_init1 sys_exit_inotify_init1 as possibly not file I/O related /// Ignoring sys_enter_inotify_init sys_exit_inotify_init as possibly not file I/O related +/// Ignoring sys_enter_inotify_init1 sys_exit_inotify_init1 as possibly not file I/O related /// Ignoring sys_enter_inotify_rm_watch sys_exit_inotify_rm_watch as possibly not file I/O related /// Ignoring sys_enter_ioperm sys_exit_ioperm as possibly not file I/O related /// Ignoring sys_enter_iopl sys_exit_iopl as possibly not file I/O related @@ -98,11 +98,11 @@ /// Ignoring sys_enter_memfd_secret sys_exit_memfd_secret as possibly not file I/O related /// Ignoring sys_enter_migrate_pages sys_exit_migrate_pages as possibly not file I/O related /// Ignoring sys_enter_mincore sys_exit_mincore as possibly not file I/O related -/// Ignoring sys_enter_mknodat sys_exit_mknodat as possibly not file I/O related /// Ignoring sys_enter_mknod sys_exit_mknod as possibly not file I/O related +/// Ignoring sys_enter_mknodat sys_exit_mknodat as possibly not file I/O related +/// Ignoring sys_enter_mlock sys_exit_mlock as possibly not file I/O related /// Ignoring sys_enter_mlock2 sys_exit_mlock2 as possibly not file I/O related /// Ignoring sys_enter_mlockall sys_exit_mlockall as possibly not file I/O related -/// Ignoring sys_enter_mlock sys_exit_mlock as possibly not file I/O related /// Ignoring sys_enter_modify_ldt sys_exit_modify_ldt as possibly not file I/O related /// Ignoring sys_enter_mount sys_exit_mount as possibly not file I/O related /// Ignoring sys_enter_move_mount sys_exit_move_mount as possibly not file I/O related @@ -120,8 +120,8 @@ /// Ignoring sys_enter_msgget sys_exit_msgget as possibly not file I/O related /// Ignoring sys_enter_msgrcv sys_exit_msgrcv as possibly not file I/O related /// Ignoring sys_enter_msgsnd sys_exit_msgsnd as possibly not file I/O related -/// Ignoring sys_enter_munlockall sys_exit_munlockall as possibly not file I/O related /// Ignoring sys_enter_munlock sys_exit_munlock as possibly not file I/O related +/// Ignoring sys_enter_munlockall sys_exit_munlockall as possibly not file I/O related /// Ignoring sys_enter_munmap sys_exit_munmap as possibly not file I/O related /// Ignoring sys_enter_nanosleep sys_exit_nanosleep as possibly not file I/O related /// Ignoring sys_enter_newuname sys_exit_newuname as possibly not file I/O related @@ -130,8 +130,8 @@ /// Ignoring sys_enter_personality sys_exit_personality as possibly not file I/O related /// Ignoring sys_enter_pidfd_open sys_exit_pidfd_open as possibly not file I/O related /// Ignoring sys_enter_pidfd_send_signal sys_exit_pidfd_send_signal as possibly not file I/O related -/// Ignoring sys_enter_pipe2 sys_exit_pipe2 as possibly not file I/O related /// Ignoring sys_enter_pipe sys_exit_pipe as possibly not file I/O related +/// Ignoring sys_enter_pipe2 sys_exit_pipe2 as possibly not file I/O related /// Ignoring sys_enter_pivot_root sys_exit_pivot_root as possibly not file I/O related /// Ignoring sys_enter_pkey_alloc sys_exit_pkey_alloc as possibly not file I/O related /// Ignoring sys_enter_pkey_free sys_exit_pkey_free as possibly not file I/O related @@ -163,11 +163,11 @@ /// Ignoring sys_enter_rt_sigsuspend sys_exit_rt_sigsuspend as possibly not file I/O related /// Ignoring sys_enter_rt_sigtimedwait sys_exit_rt_sigtimedwait as possibly not file I/O related /// Ignoring sys_enter_rt_tgsigqueueinfo sys_exit_rt_tgsigqueueinfo as possibly not file I/O related +/// Ignoring sys_enter_sched_get_priority_max sys_exit_sched_get_priority_max as possibly not file I/O related +/// Ignoring sys_enter_sched_get_priority_min sys_exit_sched_get_priority_min as possibly not file I/O related /// Ignoring sys_enter_sched_getaffinity sys_exit_sched_getaffinity as possibly not file I/O related /// Ignoring sys_enter_sched_getattr sys_exit_sched_getattr as possibly not file I/O related /// Ignoring sys_enter_sched_getparam sys_exit_sched_getparam as possibly not file I/O related -/// Ignoring sys_enter_sched_get_priority_max sys_exit_sched_get_priority_max as possibly not file I/O related -/// Ignoring sys_enter_sched_get_priority_min sys_exit_sched_get_priority_min as possibly not file I/O related /// Ignoring sys_enter_sched_getscheduler sys_exit_sched_getscheduler as possibly not file I/O related /// Ignoring sys_enter_sched_rr_get_interval sys_exit_sched_rr_get_interval as possibly not file I/O related /// Ignoring sys_enter_sched_setaffinity sys_exit_sched_setaffinity as possibly not file I/O related @@ -185,6 +185,10 @@ /// Ignoring sys_enter_sendmmsg sys_exit_sendmmsg as possibly not file I/O related /// Ignoring sys_enter_sendmsg sys_exit_sendmsg as possibly not file I/O related /// Ignoring sys_enter_sendto sys_exit_sendto as possibly not file I/O related +/// Ignoring sys_enter_set_mempolicy sys_exit_set_mempolicy as possibly not file I/O related +/// Ignoring sys_enter_set_mempolicy_home_node sys_exit_set_mempolicy_home_node as possibly not file I/O related +/// Ignoring sys_enter_set_robust_list sys_exit_set_robust_list as possibly not file I/O related +/// Ignoring sys_enter_set_tid_address sys_exit_set_tid_address as possibly not file I/O related /// Ignoring sys_enter_setdomainname sys_exit_setdomainname as possibly not file I/O related /// Ignoring sys_enter_setfsgid sys_exit_setfsgid as possibly not file I/O related /// Ignoring sys_enter_setfsuid sys_exit_setfsuid as possibly not file I/O related @@ -192,8 +196,6 @@ /// Ignoring sys_enter_setgroups sys_exit_setgroups as possibly not file I/O related /// Ignoring sys_enter_sethostname sys_exit_sethostname as possibly not file I/O related /// Ignoring sys_enter_setitimer sys_exit_setitimer as possibly not file I/O related -/// Ignoring sys_enter_set_mempolicy sys_exit_set_mempolicy as possibly not file I/O related -/// Ignoring sys_enter_set_mempolicy_home_node sys_exit_set_mempolicy_home_node as possibly not file I/O related /// Ignoring sys_enter_setns sys_exit_setns as possibly not file I/O related /// Ignoring sys_enter_setpgid sys_exit_setpgid as possibly not file I/O related /// Ignoring sys_enter_setpriority sys_exit_setpriority as possibly not file I/O related @@ -202,10 +204,8 @@ /// Ignoring sys_enter_setresuid sys_exit_setresuid as possibly not file I/O related /// Ignoring sys_enter_setreuid sys_exit_setreuid as possibly not file I/O related /// Ignoring sys_enter_setrlimit sys_exit_setrlimit as possibly not file I/O related -/// Ignoring sys_enter_set_robust_list sys_exit_set_robust_list as possibly not file I/O related /// Ignoring sys_enter_setsid sys_exit_setsid as possibly not file I/O related /// Ignoring sys_enter_setsockopt sys_exit_setsockopt as possibly not file I/O related -/// Ignoring sys_enter_set_tid_address sys_exit_set_tid_address as possibly not file I/O related /// Ignoring sys_enter_settimeofday sys_exit_settimeofday as possibly not file I/O related /// Ignoring sys_enter_setuid sys_exit_setuid as possibly not file I/O related /// Ignoring sys_enter_shmat sys_exit_shmat as possibly not file I/O related @@ -214,8 +214,8 @@ /// Ignoring sys_enter_shmget sys_exit_shmget as possibly not file I/O related /// Ignoring sys_enter_shutdown sys_exit_shutdown as possibly not file I/O related /// Ignoring sys_enter_sigaltstack sys_exit_sigaltstack as possibly not file I/O related -/// Ignoring sys_enter_signalfd4 sys_exit_signalfd4 as possibly not file I/O related /// Ignoring sys_enter_signalfd sys_exit_signalfd as possibly not file I/O related +/// Ignoring sys_enter_signalfd4 sys_exit_signalfd4 as possibly not file I/O related /// Ignoring sys_enter_socket sys_exit_socket as possibly not file I/O related /// Ignoring sys_enter_socketpair sys_exit_socketpair as possibly not file I/O related /// Ignoring sys_enter_splice sys_exit_splice as possibly not file I/O related @@ -229,12 +229,12 @@ /// Ignoring sys_enter_time sys_exit_time as possibly not file I/O related /// Ignoring sys_enter_timer_create sys_exit_timer_create as possibly not file I/O related /// Ignoring sys_enter_timer_delete sys_exit_timer_delete as possibly not file I/O related -/// Ignoring sys_enter_timerfd_create sys_exit_timerfd_create as possibly not file I/O related -/// Ignoring sys_enter_timerfd_gettime sys_exit_timerfd_gettime as possibly not file I/O related -/// Ignoring sys_enter_timerfd_settime sys_exit_timerfd_settime as possibly not file I/O related /// Ignoring sys_enter_timer_getoverrun sys_exit_timer_getoverrun as possibly not file I/O related /// Ignoring sys_enter_timer_gettime sys_exit_timer_gettime as possibly not file I/O related /// Ignoring sys_enter_timer_settime sys_exit_timer_settime as possibly not file I/O related +/// Ignoring sys_enter_timerfd_create sys_exit_timerfd_create as possibly not file I/O related +/// Ignoring sys_enter_timerfd_gettime sys_exit_timerfd_gettime as possibly not file I/O related +/// Ignoring sys_enter_timerfd_settime sys_exit_timerfd_settime as possibly not file I/O related /// Ignoring sys_enter_times sys_exit_times as possibly not file I/O related /// Ignoring sys_enter_tkill sys_exit_tkill as possibly not file I/O related /// Ignoring sys_enter_umask sys_exit_umask as possibly not file I/O related diff --git a/scripts/build-with-docker.sh b/scripts/build-with-docker.sh new file mode 100755 index 0000000..02eb60f --- /dev/null +++ b/scripts/build-with-docker.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# Build the ior binary inside a Rocky Linux 9 container and write it to the +# current directory. The container image is built once and reused on subsequent +# runs. The ior source tree is mounted as a volume so the resulting binary +# lands directly in $(pwd)/ior. +# +# Usage: +# ./build-with-docker.sh # build image + compile ior +# ./build-with-docker.sh --build # force rebuild of the Docker image +# ./build-with-docker.sh --run # skip image build, only compile ior +set -euo pipefail + +IMAGE="ior-builder:rocky9" +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +# Derive the Go version from go.mod so the Docker image always matches the +# minimum toolchain declared by the project. +GO_VERSION="$(grep '^go ' "${REPO_ROOT}/go.mod" | awk '{print $2}')" + +BUILD_IMAGE=true +RUN_BUILD=true + +for arg in "$@"; do + case "$arg" in + --build) BUILD_IMAGE=true; RUN_BUILD=false ;; + --run) BUILD_IMAGE=false; RUN_BUILD=true ;; + esac +done + +if $BUILD_IMAGE; then + echo "==> Building Docker image ${IMAGE} (this takes ~15-20 min on first run)..." + docker build --build-arg "GO_VERSION=${GO_VERSION}" -t "${IMAGE}" "${REPO_ROOT}" + echo "==> Image build complete." +fi + +if $RUN_BUILD; then + echo "==> Compiling ior inside the container..." + # --privileged gives full host capabilities. + # tracefs (/sys/kernel/tracing) and BTF (/sys/kernel/btf) are not auto-mounted + # by Docker even with --privileged, so they are mounted explicitly: + # - /sys/kernel/tracing : mage generate reads available syscall tracepoints + # - /sys/kernel/btf : mage bpfBuild reads vmlinux BTF for vmlinux.h + docker run --rm \ + --privileged \ + -v /sys/kernel/tracing:/sys/kernel/tracing \ + -v /sys/kernel/btf:/sys/kernel/btf \ + -v "${REPO_ROOT}:/git/ior" \ + "${IMAGE}" + echo "==> Done. Binary written to ${REPO_ROOT}/ior" +fi -- cgit v1.2.3