diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-03 14:05:38 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-03 14:05:38 -0400 |
| commit | 32b551d43781dc7b8ac4587ca2ba1554b0cbd5e5 (patch) | |
| tree | d1cab6bcc35e461610cd5dfcf3f51ba679a576fc /debug/risc-v-gsp-rm-vm/gpgpu-sim/scripts | |
| parent | fa71f1b53b524e5f6c6c1fbff1088d610b9f3236 (diff) | |
| download | open-iov-32b551d43781dc7b8ac4587ca2ba1554b0cbd5e5.tar.gz open-iov-32b551d43781dc7b8ac4587ca2ba1554b0cbd5e5.zip | |
vgsp: host CUDA bridge + sema release recovery; greeneye simulator wave
- kernel: gsp_cuda_bridge (QMD launch capture, debugfs job/out/done, param+output resolution cached from inline writes), sema drain fixes (never hold/starve a channel), GR ring autopin + counter autoreg, per-page push reads, counter-derive gate; module builds clean
- tools/cuda-bridge: CUDA driver-API daemon executing mail/vadd kernels on the physical GPU, CUBB2/CBD2 v2 protocol, layout check + self-tests
- tools/guest-diag + tools/cuda-ab: scanner/pin fixes, victory push-only mode
- debug/risc-v-gsp-rm-vm: Phase S simulator wave (GSP device model, boot ladder, triage/re-demo harnesses, docs 30-41), GPGPU-sim scaffolding
- STATE-CURRENT/docs updates
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/gpgpu-sim/scripts')
| -rwxr-xr-x | debug/risc-v-gsp-rm-vm/gpgpu-sim/scripts/config_sanity.py | 278 | ||||
| -rwxr-xr-x | debug/risc-v-gsp-rm-vm/gpgpu-sim/scripts/run_sim.sh | 109 |
2 files changed, 387 insertions, 0 deletions
diff --git a/debug/risc-v-gsp-rm-vm/gpgpu-sim/scripts/config_sanity.py b/debug/risc-v-gsp-rm-vm/gpgpu-sim/scripts/config_sanity.py new file mode 100755 index 0000000..052695e --- /dev/null +++ b/debug/risc-v-gsp-rm-vm/gpgpu-sim/scripts/config_sanity.py @@ -0,0 +1,278 @@ +#!/usr/bin/env python3 +"""config_sanity.py -- stdlib-only sanity check for the TU104 scaffold config. + +Parses gpgpu-sim/configs/turing-tu104-2080super/gpgpusim.config and asserts +that the key device knobs and the machine-checkable `# SPEC:` markers are +present and internally consistent: + + * SM count : n_clusters x n_cores_per_cluster == 48 + * compute capability : major.minor == 7.5, PTX force max capability == 75 + * memory type : GDDR6 (burst length 16, QDR freq ratio 4) + * memory capacity : SPEC vram_gib == 8 (documentation-only; GPGPU-Sim + 4.x has no VRAM capacity knob) + * L2 size : sets x bsize x assoc x n_mem x n_sub == 4 MiB + * bandwidth : buswidth x freq_ratio x DRAM clock x n_mem == 496 GB/s + * clocks : base 1650 MHz, DRAM 3875 MHz (15.5 Gbps / 4) + +This is a scaffold consistency test, not a calibration: passing says the file +internally encodes the published TU104 numbers, NOT that the simulator models +TU104 accurately. Exit code 0 = all checks pass; 1 = at least one mismatch; +2 = usage/parse error. + +Usage: + python3 gpgpu-sim/scripts/config_sanity.py [--config PATH] [--quiet] +""" + +from __future__ import annotations + +import argparse +import re +import sys +from pathlib import Path + +EXPECTED_SPECS = { + "sm_count": "48", + "memory_type": "GDDR6", + "vram_gib": "8", + "bus_width_bits": "256", + "bandwidth_gbps": "496", + "l2_mib": "4", + "rops": "64", + "tmus": "192", + "base_mhz": "1650", + "boost_mhz": "1815", + "compute_capability": "7.5", +} + +DEFAULT_CONFIG = ( + Path(__file__).resolve().parents[1] + / "configs" + / "turing-tu104-2080super" + / "gpgpusim.config" +) +ICNT_NAME = "config_turing_islip.icnt" + + +def parse_config(path: Path) -> tuple[dict[str, str], dict[str, str]]: + """Return (options, spec_markers) parsed from a gpgpusim.config file.""" + opts: dict[str, str] = {} + specs: dict[str, str] = {} + for raw in path.read_text(encoding="utf-8").splitlines(): + spec = re.match(r"^\s*#\s*SPEC:\s*([A-Za-z0-9_]+)\s*=\s*(\S+)\s*$", raw) + if spec: + specs[spec.group(1)] = spec.group(2) + line = raw.split("#", 1)[0].strip() + if not line or not line.startswith("-"): + continue + parts = line.split(None, 1) + opts[parts[0]] = parts[1].strip() if len(parts) > 1 else "" + return opts, specs + + +class Checker: + def __init__(self, quiet: bool = False) -> None: + self.quiet = quiet + self.passed = 0 + self.failures: list[str] = [] + + def check(self, name: str, condition: bool, detail: str) -> None: + if condition: + self.passed += 1 + if not self.quiet: + print(f"PASS: {name}: {detail}") + else: + self.failures.append(f"{name}: {detail}") + print(f"FAIL: {name}: {detail}") + + def note(self, text: str) -> None: + if not self.quiet: + print(f"NOTE: {text}") + + +def parse_int(opts: dict[str, str], key: str) -> int | None: + try: + return int(opts[key], 0) + except (KeyError, ValueError): + return None + + +def parse_l2(opts: dict[str, str]) -> tuple[int, int, int] | None: + """Parse '<nsets>:<bsize>:<assoc>' from -gpgpu_cache:dl2 S:... .""" + m = re.match(r"^S:(\d+):(\d+):(\d+)", opts.get("-gpgpu_cache:dl2", "")) + if not m: + return None + return int(m.group(1)), int(m.group(2)), int(m.group(3)) + + +def run_checks(config_path: Path, quiet: bool = False) -> int: + if not config_path.is_file(): + print(f"config_sanity: ERROR: config not found: {config_path}", file=sys.stderr) + return 2 + + opts, specs = parse_config(config_path) + c = Checker(quiet=quiet) + + # 1. spec markers ------------------------------------------------------ + for key, expected in EXPECTED_SPECS.items(): + actual = specs.get(key) + c.check( + f"SPEC {key}", + actual == expected, + f"expected {expected}, got {actual!r}", + ) + + # 2. SMs / compute capability ----------------------------------------- + clusters = parse_int(opts, "-gpgpu_n_clusters") + cores = parse_int(opts, "-gpgpu_n_cores_per_cluster") + sm_count = None if clusters is None or cores is None else clusters * cores + c.check( + "SM count", + sm_count == int(EXPECTED_SPECS["sm_count"]), + f"n_clusters({clusters}) x n_cores_per_cluster({cores}) = {sm_count}," + f" expected {EXPECTED_SPECS['sm_count']}", + ) + cc = f"{opts.get('-gpgpu_compute_capability_major', '?')}." \ + f"{opts.get('-gpgpu_compute_capability_minor', '?')}" + c.check( + "compute capability", + cc == EXPECTED_SPECS["compute_capability"], + f"{cc}, expected {EXPECTED_SPECS['compute_capability']}", + ) + c.check( + "PTX force max capability", + parse_int(opts, "-gpgpu_ptx_force_max_capability") == 75, + f"{opts.get('-gpgpu_ptx_force_max_capability', '(missing)')}, expected 75 (sm_75)", + ) + + # 3. clocks / GDDR6 / memory geometry --------------------------------- + clocks = opts.get("-gpgpu_clock_domains", "").split(":") + dram_mhz = None + if len(clocks) == 4: + try: + dram_mhz = float(clocks[3]) + except ValueError: + dram_mhz = None + c.check( + "DRAM clock", + dram_mhz == 3875.0, + f"{clocks[3] if len(clocks) == 4 else clocks}, expected 3875.0 MHz (15.5 Gbps / 4)", + ) + c.check( + "base core clock", + len(clocks) == 4 and clocks[0] == "1650.0", + f"{clocks[0] if clocks else '(missing)'}, expected 1650.0 MHz", + ) + c.check( + "memory type GDDR6", + specs.get("memory_type") == "GDDR6" + and parse_int(opts, "-gpgpu_dram_burst_length") == 16 + and parse_int(opts, "-dram_data_command_freq_ratio") == 4, + "burst_length=" + f"{opts.get('-gpgpu_dram_burst_length', '(missing)')}, " + "freq_ratio=" + f"{opts.get('-dram_data_command_freq_ratio', '(missing)')}" + " (GDDR6 expected: 16 / 4)", + ) + c.check( + "memory chips per controller", + parse_int(opts, "-gpgpu_n_mem_per_ctrlr") == 1, + f"{opts.get('-gpgpu_n_mem_per_ctrlr', '(missing)')}, expected 1 (upstream Turing convention)", + ) + c.check( + "VRAM capacity marker (documentation-only)", + specs.get("vram_gib") == "8", + "SPEC vram_gib=" + f"{specs.get('vram_gib')!r}; GPGPU-Sim 4.x has no VRAM capacity knob," + " so 8 GiB is recorded as a spec marker only", + ) + + # 4. L2 size consistency ---------------------------------------------- + n_mem = parse_int(opts, "-gpgpu_n_mem") + n_sub = parse_int(opts, "-gpgpu_n_sub_partition_per_mchannel") + l2 = parse_l2(opts) + l2_mib = None + if l2 and n_mem and n_sub: + sets, bsize, assoc = l2 + l2_mib = sets * bsize * assoc * n_mem * n_sub / (1024 * 1024) + spec_l2 = float(EXPECTED_SPECS["l2_mib"]) + c.check( + "L2 size", + l2_mib == spec_l2, + f"dl2({l2}) x n_mem({n_mem}) x n_sub({n_sub}) = {l2_mib} MiB," + f" expected {spec_l2} MiB", + ) + + # 5. bandwidth consistency -------------------------------------------- + buswidth = parse_int(opts, "-gpgpu_dram_buswidth") + ratio = parse_int(opts, "-dram_data_command_freq_ratio") + bw_gbps = None + if None not in (buswidth, ratio, dram_mhz, n_mem): + bw_gbps = buswidth * ratio * dram_mhz * 1e6 * n_mem / 1e9 + spec_bw = float(EXPECTED_SPECS["bandwidth_gbps"]) + c.check( + "modeled bandwidth", + bw_gbps == spec_bw, + f"buswidth({buswidth} B) x ratio({ratio}) x DRAM({dram_mhz} MHz)" + f" x n_mem({n_mem}) = {bw_gbps} GB/s, expected {spec_bw} GB/s", + ) + bw_bits_ok = False + if n_mem and buswidth: + bw_bits_ok = ( + specs.get("bus_width_bits") == "256" + and int(EXPECTED_SPECS["bus_width_bits"]) // (8 * n_mem) == buswidth + ) + c.check( + "bus width marker", + bw_bits_ok, + f"SPEC bus_width_bits={specs.get('bus_width_bits')!r}, modeled" + f" buswidth={buswidth} B x n_mem={n_mem} (expected {EXPECTED_SPECS['bus_width_bits']} bits" + f" = {buswidth} B x {n_mem} modules)", + ) + + # 6. informational markers not modeled by GPGPU-Sim 4.x --------------- + for key, label in (("rops", "ROPs"), ("tmus", "TMUs"), ("boost_mhz", "boost clock")): + c.check( + f"SPEC {key} present", + specs.get(key) == EXPECTED_SPECS[key], + f"{label}: {specs.get(key)!r} (expected {EXPECTED_SPECS[key]});" + " recorded for documentation, not a simulator knob", + ) + + # 7. sibling interconnect file (not used with -network_mode 2) ------- + icnt = config_path.parent / ICNT_NAME + c.check( + "interconnect config present", + icnt.is_file(), + f"{icnt}", + ) + + total = c.passed + len(c.failures) + print( + f"config_sanity: {c.passed}/{total} checks passed" + + (f", {len(c.failures)} failed" if c.failures else "") + ) + if c.failures: + for failure in c.failures: + print(f"config_sanity: FAILED -> {failure}", file=sys.stderr) + return 1 + print("config_sanity: OK (scaffold consistency only; no accuracy claim)") + return 0 + + +def main(argv: list[str] | None = None) -> int: + parser = argparse.ArgumentParser( + description="Sanity-check the GreenEye-GPGPU-Sim TU104 scaffold config." + ) + parser.add_argument( + "--config", + type=Path, + default=DEFAULT_CONFIG, + help=f"path to gpgpusim.config (default: {DEFAULT_CONFIG})", + ) + parser.add_argument("--quiet", action="store_true", help="only print failures and summary") + args = parser.parse_args(argv) + return run_checks(args.config, quiet=args.quiet) + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/debug/risc-v-gsp-rm-vm/gpgpu-sim/scripts/run_sim.sh b/debug/risc-v-gsp-rm-vm/gpgpu-sim/scripts/run_sim.sh new file mode 100755 index 0000000..85dd11e --- /dev/null +++ b/debug/risc-v-gsp-rm-vm/gpgpu-sim/scripts/run_sim.sh @@ -0,0 +1,109 @@ +#!/usr/bin/env bash +# run_sim.sh -- run a CUDA binary on the GreenEye-GPGPU-Sim TU104 scaffold. +# +# Substitutes the CUDA runtime with GPGPU-Sim's libcudart.so via +# LD_LIBRARY_PATH (the mechanism documented in the upstream README, "Step 3: +# Run"), points the simulator at the tracked TU104 scaffold config, and +# executes the binary from a dedicated run directory so simulator output does +# not pollute the source tree. +# +# Development-only tooling: it simulates; it never touches GPU hardware, +# kernel modules, mdev, or a guest. +# +# Usage: +# ./run_sim.sh [--workdir DIR] [--build-type release|debug] <cuda-binary> [args...] +# +# Prerequisites: ./setup.sh has completed a build, and the binary was linked +# with `--cudart shared` so it resolves libcudart.so dynamically. +# +# Outputs (in the work directory, default gpgpu-sim/build/run/): +# gpgpusim.config -> symlink to the tracked TU104 config +# config_turing_islip.icnt -> symlink to the tracked interconnect config +# gpgpusim_out.txt, gpgpu_inst_stats.txt, ... (upstream simulator outputs) +set -euo pipefail + +HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +UPSTREAM="$HERE/upstream" +DEFAULT_CONFIG_DIR="$HERE/configs/turing-tu104-2080super" +CONFIG_NAME="gpgpusim.config" +ICNT_NAME="config_turing_islip.icnt" +BUILD_TYPE="${GPGPUSIM_BUILD_TYPE:-release}" +WORKDIR="${GPGPUSIM_RUN_DIR:-$HERE/build/run}" +CONFIG_DIR="$DEFAULT_CONFIG_DIR" + +die() { echo "run_sim.sh: ERROR: $*" >&2; exit 1; } + +usage() { + cat <<'EOF' +Usage: run_sim.sh [--workdir DIR] [--build-type release|debug] \ + [--config-dir DIR] <cuda-binary> [args...] + + --workdir DIR directory the binary runs in (default gpgpu-sim/build/run) + --build-type TYPE release (default) or debug + --config-dir DIR config directory to use (default configs/turing-tu104-2080super) + -h, --help this help + +The binary must be dynamically linked against libcudart (link with +"--cudart shared"); LD_LIBRARY_PATH is replaced with the GPGPU-Sim runtime +so no recompilation for the simulator is needed. +EOF +} + +while [ $# -gt 0 ]; do + case "$1" in + --workdir) WORKDIR="${2:-}"; shift ;; + --build-type) BUILD_TYPE="${2:-}"; shift ;; + --config-dir) CONFIG_DIR="${2:-}"; shift ;; + -h|--help) usage; exit 0 ;; + --) shift; break ;; + -*) usage >&2; exit 2 ;; + *) break ;; + esac + shift +done + +[ $# -ge 1 ] || { usage >&2; exit 2; } +[ -n "$WORKDIR" ] || die "--workdir requires a value" +[ -n "$CONFIG_DIR" ] || die "--config-dir requires a value" +case "$BUILD_TYPE" in release|debug) ;; *) die "unknown build type '$BUILD_TYPE'" ;; esac + +BIN="$1"; shift + +case "$BIN" in + */*) + [ -e "$BIN" ] || die "binary not found: $BIN" + BIN="$(cd "$(dirname "$BIN")" && pwd)/$(basename "$BIN")" + ;; + *) + resolved="$(command -v "$BIN" || true)" + [ -n "$resolved" ] || die "binary '$BIN' not found in PATH" + BIN="$resolved" + ;; +esac + +[ -d "$CONFIG_DIR" ] || die "config dir not found: $CONFIG_DIR" +[ -f "$CONFIG_DIR/$CONFIG_NAME" ] || die "missing $CONFIG_DIR/$CONFIG_NAME" + +LIBDIR="$(find "$UPSTREAM/lib" -maxdepth 3 -type d -name "$BUILD_TYPE" 2>/dev/null | sort | head -n 1 || true)" +[ -n "$LIBDIR" ] || die "no GPGPU-Sim runtime library dir under $UPSTREAM/lib; run ./setup.sh first" +if ! ls "$LIBDIR"/libcudart.so* >/dev/null 2>&1; then + echo "run_sim.sh: WARNING: no libcudart.so in $LIBDIR; the binary may load the system CUDA runtime" >&2 +fi + +mkdir -p "$WORKDIR" +ln -sfn "$CONFIG_DIR/$CONFIG_NAME" "$WORKDIR/$CONFIG_NAME" +if [ -f "$CONFIG_DIR/$ICNT_NAME" ]; then + ln -sfn "$CONFIG_DIR/$ICNT_NAME" "$WORKDIR/$ICNT_NAME" +fi + +export GPGPUSIM_ROOT="$UPSTREAM" +export LD_LIBRARY_PATH="$LIBDIR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" +export CUDA_INSTALL_PATH="${CUDA_INSTALL_PATH:-/usr/local/cuda}" + +echo "run_sim.sh: binary : $BIN" +echo "run_sim.sh: config : $CONFIG_DIR/$CONFIG_NAME" +echo "run_sim.sh: workdir : $WORKDIR" +echo "run_sim.sh: runtime libs: $LIBDIR" + +cd "$WORKDIR" +exec "$BIN" "$@" |
