diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-02 10:58:21 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-02 10:58:21 -0400 |
| commit | f909a5f822c5c4a4e9526b861d4171f8925f5113 (patch) | |
| tree | ed362021c83569f49b48079a774f05775e84b0bd /debug/risc-v-gsp-rm-vm/harness/value_demos/s02_counter_publication.py | |
| parent | 09f241601423b1ae98e97846ee451768ff8a0a9e (diff) | |
| download | open-iov-f909a5f822c5c4a4e9526b861d4171f8925f5113.tar.gz open-iov-f909a5f822c5c4a4e9526b861d4171f8925f5113.zip | |
debug: green-eye wave 3 - RM harness, local simulator, device map, MCP plugin, value-validation demos, CI pipeline, toolchain docs; add host RM tools rmtool/rmtop
Diffstat (limited to 'debug/risc-v-gsp-rm-vm/harness/value_demos/s02_counter_publication.py')
| -rw-r--r-- | debug/risc-v-gsp-rm-vm/harness/value_demos/s02_counter_publication.py | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/debug/risc-v-gsp-rm-vm/harness/value_demos/s02_counter_publication.py b/debug/risc-v-gsp-rm-vm/harness/value_demos/s02_counter_publication.py new file mode 100644 index 0000000..690f60f --- /dev/null +++ b/debug/risc-v-gsp-rm-vm/harness/value_demos/s02_counter_publication.py @@ -0,0 +1,126 @@ +#!/usr/bin/env python3 +"""s02 - counter publication: which of N slots advanced, and when? + +Real scenario (Handoff-vGPU-IO.md PART 46-64, 2026-09-24..2026-09-29): +``cuCtxCreate`` waits on 20 GR per-channel completion counters. The host saw +the client's releases but could not translate the counter page; for many boots +only 4 of 20 client-visible slots ever moved (PART 49). The exact slot layout +(page VA ``0x20400f000``, slots at ``+0xec0``, 16-byte stride) was only proven +by a raw live page dump (PART 64, 2026-09-29 ~16:55), and the host raced a +~2-3 s pin path against the client's ~2 s GR-phase deadline. Static reading +could not tell which slots were published: the page's GPA changed every boot +and stale translations pointed at the previous client's page (PART 51). + +Analog: post 20 sequential commands and watch the demo's published result +field; prove every slot was observed, with the publish PC recorded per slot. +""" +from __future__ import annotations + +import os + +try: # package import (tests) or direct script execution (run_all) + from . import _common as C +except ImportError: + import sys as _sys + + _sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + import _common as C + +SLOTS = 20 + + +def run() -> dict: + import greeneye as ge + + backend = C.choose_backend("native") + out = C.artifact_dir("s02_counter_publication") + commands = [ + 'ge.launch(kernel=DEMO_ELF, backend="%s")' % backend, + "s.watch(gsp_ctrl+0x40, size=8, kind='w', callback=record pc) # publication", + "for slot in 1..20: write mailbox cmd=5 (STATE); run(duration=0.05)", + "read gsp_ctrl.result after every slot; compare against the expected stage value", + ] + scenario = C.scenario( + ids=[ + "Handoff-vGPU-IO.md PART 49/50 (2026-09-29): only 4/20 counters moved; all 20 reached 1 after the queue fix", + "PART 64 (2026-09-29 ~16:55): raw page dump proves 20 slots at 16-byte stride", + "PART 46/48 (2026-09-29): rescue/sweep latency and tracker waits", + ], + baseline=( + "PARTs 46->64: ~5 days of sessions; PART 49 'only 4 of 20 counters " + "ever moved'; each boot re-derived the slot layout because the " + "counter page GPA changed (PART 51/53)" + ), + projection=( + "on real silicon the 20 slots are per-channel memory pages; the " + "analog publishes 20 logical slots through the same watchpoint " + "shape, one store each" + ), + blocked=True, + device="H2.2 device model + real GSP-RM counter pages", + ) + C.render_banner( + "s02_counter_publication", + "Of the N client-visible slots, which ones advanced, and where was each published?", + "20 GR per-channel completion counters: 4/20 published for days until a live page dump", + scenario["static_baseline"], + commands, + ) + + session = ge.launch(kernel=C.DEMO_ELF, backend=backend, name="vd-s02") + slots = [] + try: + ctrl = session.symbols.lookup("gsp_ctrl") + publishes = [] + session.watch(ctrl + C.CTRL_RESULT, size=8, kind="w", callback=lambda hit: publishes.append(hit.pc)) + session.run(duration=0.25) + before = session.memory.read_u64(ctrl + C.CTRL_RPC_COUNT) + for slot in range(SLOTS): + session.memory.write_u64(ctrl + C.CTRL_MAILBOX, 5) # STATE + session.run(duration=0.05) + value = session.memory.read_u64(ctrl + C.CTRL_RESULT) + slots.append( + { + "slot": slot + 1, + "result": value, + "result_hex": f"{value:#x}", + "published": value in (0x10, 0x20, 0x30, 0x40), + } + ) + after = session.memory.read_u64(ctrl + C.CTRL_RPC_COUNT) + published = [s for s in slots if s["published"]] + payload = { + "success": len(published) == SLOTS and (after - before) == SLOTS, + "backend": backend, + "slots_requested": SLOTS, + "slots_published": len(published), + "rpc_count_delta": after - before, + "watch_stores": len(publishes), + "distinct_values": sorted({s["result_hex"] for s in published}), + "per_slot": slots, + "publish_pcs": sorted(set(publishes)), + "question": f"did all {SLOTS} slots publish, and can each publication be attributed?", + "answer": ( + f"{len(published)}/{SLOTS} slots published ({after - before} dispatcher " + f"completions, {len(publishes)} stores to gsp_ctrl.result, values " + f"{sorted({s['result_hex'] for s in published})}); every store PC is captured, " + "exactly the evidence class that took a live 512-byte page dump on the real path" + ), + "success_criteria": { + "pass": f"{SLOTS}/{SLOTS} slots observed with rpc_count advancing once per slot", + "fail": "any slot does not publish or the count delta disagrees", + }, + "real_case": scenario, + } + C.write_json(os.path.join(out, "counters.json"), payload) + finally: + session.close() + return payload + + +def main() -> int: + return 0 if C.timed_demo(run, C.artifact_dir("s02_counter_publication"))["success"] else 1 + + +if __name__ == "__main__": + raise SystemExit(main()) |
