diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-06 23:02:45 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-06 23:02:45 -0400 |
| commit | 00765678d59423669fcad6fe56cce9be9bb352e6 (patch) | |
| tree | 7b06fe7d361f3526f47c92d0f26c483b626c4768 /tools/gr-regs/reg_sampler.py | |
| parent | d0a1ca21d24b4d05385d95eefa9930e505206b8f (diff) | |
| download | open-iov-00765678d59423669fcad6fe56cce9be9bb352e6.tar.gz open-iov-00765678d59423669fcad6fe56cce9be9bb352e6.zip | |
tools: durable BAR0 GR register sampler + analyzer (gr-regs/)
reg_sampler.py: high-rate read-only MMIO sampler for the physical GPU's
PGRAPH/FECS/SKED/PFIFO registers (FECS current-context valid + pointer,
SKED CWD table occupancy/activity, GRFIFO, FE QMD-virt, PMC_ENABLE) with
analyze_regs.py for value distributions and transition timelines. Recorded
ground truth and register semantics in tools/gr-regs/README.md. Used to
capture the live distro-driver CUDA reference (FECS VALID=1, CWD table
0x3f002000 while running) and to observe the ladder's forwarded launch
(CWD entry + SKED processing after the mode-35 lane enable).
Diffstat (limited to 'tools/gr-regs/reg_sampler.py')
| -rw-r--r-- | tools/gr-regs/reg_sampler.py | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/tools/gr-regs/reg_sampler.py b/tools/gr-regs/reg_sampler.py new file mode 100644 index 0000000..af2cc97 --- /dev/null +++ b/tools/gr-regs/reg_sampler.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +# reg_sampler.py - read-only BAR0 register sampler for GR/FECS/SKED ground truth. +# +# Purpose +# Sample the physical GPU's PGRAPH/FECS/SKED/PFIFO registers at high rate +# while a GR launch is in flight, so the engine-side state transitions +# (context load, CWD table occupancy, SKED activity, GRFIFO progress) are +# observable without the driver's help. Used to capture the ground-truth +# behaviour of a working CUDA channel (distro driver) and to inspect the +# ladder's forwarded launches. +# +# Safety +# Read-only MMIO. Safe to run while any driver owns the device. Needs root +# (resource0 mmap). Do not run concurrently with a driver rebind/FLR. +# +# Usage +# sudo python3 reg_sampler.py <seconds> <Hz> <outfile> [label] +# python3 analyze_regs.py <outfile> # value distribution + transitions +# +# Notes +# - The sampler writes one TSV line per sample: t and one u32 per register. +# - `badfxxxx` values are the GPU returning its "bad fence/clock-gated" +# pattern during driver handoff windows; filter them in analysis. +# - Offset source: kernel/gsp_phys_booter.c reg-probe table (TU104). +import mmap +import os +import struct +import sys +import time + +DEV = "/sys/bus/pci/devices/0000:01:00.0/resource0" +REGS = [ + (0x000200, "PMC_ENABLE"), + (0x400700, "PGRAPH_STATUS"), + (0x400504, "GRFIFO_STATUS"), + (0x400704, "TRAPPED_ADDR"), + (0x400708, "TRAPPED_DATA_LO"), + (0x404000, "FE_HWW_ESR"), + (0x407020, "SKED_HWW_ESR"), + (0x407040, "SKED_STATUS_0"), + (0x407054, "SKED_ACTIVITY"), + (0x407060, "CWD_TABLE_0"), + (0x407064, "CWD_TABLE_1"), + (0x407068, "CWD_TABLE_2"), + (0x40706C, "CWD_TABLE_3"), + (0x409008, "FECS_IRQSTAT"), + (0x409100, "FECS_CPUCTL"), + (0x409400, "FECS_CTXSW_STATUS_1"), + (0x409b00, "FECS_CURRENT_CTX"), + (0x409b04, "FECS_NEW_CTX"), + (0x409c00, "FECS_CTXSW_STATUS_FE_0"), + (0x409c18, "FECS_HOST_INT_STATUS"), + (0x409040, "FECS_MAILBOX0"), + (0x409044, "FECS_MAILBOX1"), + (0x40a300, "FE_QMD_VIRT_BASEA_0"), + (0x40a304, "FE_QMD_VIRT_BASEA_1"), + (0x40a400, "FE_QMD_VIRT_BASEB_0"), + (0x40a500, "FE_QMD_VIRT_CONTROL_0"), + (0x40a504, "FE_QMD_VIRT_CONTROL_1"), + (0x40a508, "FE_QMD_VIRT_CONTROL_2"), + (0x40a50c, "FE_QMD_VIRT_CONTROL_3"), + (0x41a040, "GPCCS_MAILBOX0"), + (0x41a100, "GPCCS_CPUCTL"), +] + + +def main(): + secs = float(sys.argv[1]) + hz = float(sys.argv[2]) + out = sys.argv[3] + label = sys.argv[4] if len(sys.argv) > 4 else "sample" + fd = os.open(DEV, os.O_RDONLY | os.O_SYNC) + m = mmap.mmap(fd, 0x1000000, mmap.MAP_SHARED, mmap.PROT_READ) + period = 1.0 / hz + t0 = time.monotonic() + n = 0 + with open(out, "w") as f: + f.write("# %s t=%.3f\n" % (label, t0)) + f.write("# ts " + " ".join(nm for _, nm in REGS) + "\n") + while time.monotonic() - t0 < secs: + ts = time.monotonic() - t0 + vals = [struct.unpack_from("<I", m, off)[0] for off, _ in REGS] + f.write("%.6f " % ts + " ".join("%08x" % v for v in vals) + "\n") + n += 1 + dt = period - (time.monotonic() - t0 - ts) + if dt > 0: + time.sleep(dt) + print("samples=%d" % n) + + +if __name__ == "__main__": + main() |
