summaryrefslogtreecommitdiffstats
path: root/tools/gr-regs/reg_sampler.py
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-06 23:02:45 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-06 23:02:45 -0400
commit00765678d59423669fcad6fe56cce9be9bb352e6 (patch)
tree7b06fe7d361f3526f47c92d0f26c483b626c4768 /tools/gr-regs/reg_sampler.py
parentd0a1ca21d24b4d05385d95eefa9930e505206b8f (diff)
downloadopen-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.py92
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()