# rmharness - host RM oracle integration for risc-v-gsp-rm-debugger `rmharness` wires the Open-IOV host RM userspace tools (`rmtool`, `rmtop`, `rmq`) into the risc-v-gsp-rm-debugger workflow so host ground truth can be captured next to simulator sessions and compared later (docs/06-ACCURACY.md M1/M6). All three tools are **read-only**: they query the host RM through `/dev/nvidiactl` control ioctls plus `/proc` and `/sys` reads. The harness never loads/unloads modules, never binds/unbinds the driver, never creates mdevs, never claims the GPU and never touches `/sys/fs/pstore`. ## Tools | wrapper | tool | what it is for | |---|---|---| | `rmtool.sh` | `tools/rmtool` | CLI oracle: GPU/engine inventory, VRAM/heap/BAR1 stats, allowlisted NV2080 controls, GPU timer sampling | | `rmtop.sh` | `tools/rmtop` | ncurses dashboard; `--once` renders the same panels as table/json/csv for capture | | `rmq.sh` | `tools/rmq` | the original host RM oracle (device info tables); unmodified | ## Layout ``` rmharness/ README.md this file rmtool.sh rmtop.sh rmq.sh build-if-needed wrappers (pass arguments through) harness.sh run a wrapper, capture stdout/stderr, record a session tests/test_rmharness_plugin.py fake-`ge` plugin import/registration check ``` The risc-v-gsp-rm-debugger plugin lives next to the other bundled plugins: `plugins/rmharness_plugin.py` (REPL commands `rmtool`, `rmtop`, `rmq`). ## Build and smoke The wrappers build their tool on first use. To build explicitly: ```bash make -C tools/rmtool make -C tools/rmtop make -C tools/rmq # already existed; unchanged ``` Safe smoke checks (no RM ioctl, no device access): ```bash ./rmharness/rmtool.sh --help ./rmharness/rmtool.sh --version ./rmharness/rmtool.sh gpu list # reads /proc/driver/nvidia only ./rmharness/rmtool.sh gpu topology # reads /sys/bus/pci only ./rmharness/rmtop.sh --once # read-only RM queries (see note) ``` `rmtop --once` and `gpu info`/`engine list`/`mem stats`/`sample timer` open a short-lived RM client (exactly what `nvidia-smi` does) and issue read-only controls. They do not disturb a running CUDA job. If the driver is not bound they fail cleanly. Commands that would allocate or mutate anything are refused by the tools themselves. ## Capturing into a risc-v-gsp-rm-debugger session ```bash cd debug/risc-v-gsp-rm-vm ./rmharness/harness.sh --session dumps/my-run --name before \ -- rmtool engine list --format=json ./rmharness/harness.sh --session dumps/my-run -- rmtop --once ``` `harness.sh` runs the wrapper, streams stdout/stderr through, writes the captured streams to `/blobs/`, and appends one line to `/events.jsonl`: ```json {"type": "rm_harness_run", "tool": "rmtool", "argv": [...], "exit": 0, "duration_s": 0.02, "stdout": {"path": "blobs/...", "size": 123, "sha256": "..."}, "stderr": {...}, "readonly": true} ``` Recording is additive: existing sessions are never rewritten. If the directory has no `session.json`, a minimal `greeneye-session/1` one is created. The event `t` field is `0.0` for externally recorded runs; use `start`/`end` for wall-clock ordering. ## Plugin `plugins/rmharness_plugin.py` registers REPL commands that run the wrappers and record the output through the live recorder: ``` risc-v-gsp-rm-debugger> rmtool gpu list risc-v-gsp-rm-debugger> rmtool mem stats --format=json risc-v-gsp-rm-debugger> rmtop --once risc-v-gsp-rm-debugger> rmq ``` Arguments naming write operations (`alloc`, `map`, `pin`, `start`, ...) are refused and recorded as `rm_harness_skip`. With a null recorder the plugin still runs and prints; it just does not persist. Check it without QEMU: ```bash python3 rmharness/tests/test_rmharness_plugin.py ``` ## Not implemented / not run * `rmq` device-info tables (`FIFO_GET_DEVICE_INFO_TABLE`) and `nv2080 class list` return `NV_ERR_INSUFFICIENT_PERMISSIONS` / `NV_ERR_NOT_SUPPORTED` for an unprivileged client on this driver; the tools report the status instead of escalating. * `rmtool channel/context/resserve/cudasw/resman/gsp` and sampling of clocks/power/thermal are documented but not implemented in the minimal read-only build; they return a clear "not implemented / refused" status. * Nothing in this harness was validated against a live migration or a second GPU; multi-GPU selection (`-d N`) uses RM `deviceId` = minor.