[review] mstan #270 - cosim: key checkpoints on retired-instruction count, not guest cycles - #4
Conversation
The cycle-keyed design hashed+parked at the first cosim_instr boundary AFTER the stride cycle was crossed; the two backends can reach that crossing at different retirement positions, so the oracle compared different architectural states (observed as a +5-cycle park skew and phantom CPU-register divergences mid-CPS). Checkpoints are now taken inside cosim_instr, keyed on the retirement count itself (a branch and its delay slot retire as one event in both backends). Checkpoint k = state after k*stride retirements in BOTH instances by construction. The guest-cycle clock stays inside the state hash, so real cycle-accounting drift is still detected -- now pinned to an exact instruction window instead of corrupting the alignment. cosim.py: stride/--max/--start-cycle now in retirement units; the cycle skew warning is now reported as a real timing divergence. launch() gives instance B its own exe (the mods root is exe-dir-relative, so a shared exe races on mods/state.toml publish regardless of cwd separation) and refuses a stale COSIM_CWD_B exe. Gates on CMR2 (SLUS-01222): compiled/compiled and interp/interp both clean over 100M retirements with identical cross-pair chains; injected 1-bit RAM fault detected at the next checkpoint.
There was a problem hiding this comment.
2 issues found across 2 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="tools/cosim.py">
<violation number="1" location="tools/cosim.py:57">
P2: When custom ports do not match the `4600`/`4601` suffix convention, this condition assigns B's isolated executable to the wrong instance or neither instance. Pass an explicit B-role flag into `launch()` instead of inferring the role from the numeric port.</violation>
<violation number="2" location="tools/cosim.py:63">
P2: When B's executable is missing or stale, this new exception occurs after A starts but before cleanup begins, leaving A orphaned. Move both launches inside the cleanup scope or terminate A whenever the B launch fails.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| cwd = CWD | ||
| exe = EXE | ||
| cwd_b = os.environ.get("COSIM_CWD_B", "") | ||
| if cwd_b and port != 4600 and str(port).endswith("1"): |
There was a problem hiding this comment.
P2: When custom ports do not match the 4600/4601 suffix convention, this condition assigns B's isolated executable to the wrong instance or neither instance. Pass an explicit B-role flag into launch() instead of inferring the role from the numeric port.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tools/cosim.py, line 57:
<comment>When custom ports do not match the `4600`/`4601` suffix convention, this condition assigns B's isolated executable to the wrong instance or neither instance. Pass an explicit B-role flag into `launch()` instead of inferring the role from the numeric port.</comment>
<file context>
@@ -42,6 +46,27 @@ def tail_file(path, max_bytes=8192):
+ cwd = CWD
+ exe = EXE
+ cwd_b = os.environ.get("COSIM_CWD_B", "")
+ if cwd_b and port != 4600 and str(port).endswith("1"):
+ cwd = cwd_b
+ exe_b = os.environ.get("COSIM_EXE_B",
</file context>
| os.path.join(cwd_b, os.path.basename(EXE))) | ||
| if not os.path.isfile(exe_b): | ||
| raise RuntimeError( | ||
| f"instance B exe not found: {exe_b} — copy the freshly built " |
There was a problem hiding this comment.
P2: When B's executable is missing or stale, this new exception occurs after A starts but before cleanup begins, leaving A orphaned. Move both launches inside the cleanup scope or terminate A whenever the B launch fails.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tools/cosim.py, line 63:
<comment>When B's executable is missing or stale, this new exception occurs after A starts but before cleanup begins, leaving A orphaned. Move both launches inside the cleanup scope or terminate A whenever the B launch fails.</comment>
<file context>
@@ -42,6 +46,27 @@ def tail_file(path, max_bytes=8192):
+ os.path.join(cwd_b, os.path.basename(EXE)))
+ if not os.path.isfile(exe_b):
+ raise RuntimeError(
+ f"instance B exe not found: {exe_b} — copy the freshly built "
+ f"exe into COSIM_CWD_B (its mods/ root is exe-dir-relative)")
+ if os.path.getmtime(exe_b) < os.path.getmtime(EXE) - 1:
</file context>
|
Review complete. The corresponding upstream PR was merged: mstan#270 Closing this fork review without merge. Its immutable base, discussion, and commit history remain available as evidence. |
Purpose
This is a review-only retrofit for the already-open upstream PR mstan/psxrecomp#270.
Do not merge this PR. The AI reviewer must inspect this exact diff before the next upstream update.
Identity
47bda8172e43fdba1879c1a5885904a265c567f64aebb349da131e74bab1007e91aab08ab5615055pr/cosim-icount-checkpointsReview gate
Classify each finding as valid, invalid, or uncertain. A valid finding requires a correction, a regression, and repeated validation. An uncertain finding blocks the next upstream update.
Developed with AI assistance; validated as described (test evidence in PR body). AI writes the code and the PR, but I always test before I send something up. Happy to iterate on this process with your feedback.
Summary by cubic
Cosim checkpoints now key on retired instruction count instead of guest cycles, so both instances always hash the same architectural position and cycle-skew phantom divergences are gone.
cosim.pystride/--max/--start-cyclenow count retired instructions; cycle skew at a checkpoint is reported as a real timing divergence.launch()gives instance B its own exe (the mods root is exe-dir-relative) and refuses a staleCOSIM_CWD_Bcopy.PSX_COSIM_STRIDEandPSX_COSIM_START_CYCLEnow use retirement counts, not guest cycles.Written for commit 4aebb34. Summary will update on new commits.