Skip to content

Fix barrier phase routing and global response tracking - #407

Merged
tinebp merged 5 commits into
masterfrom
fix/gbar-response-phase
Sep 10, 2026
Merged

Fix barrier phase routing and global response tracking#407
tinebp merged 5 commits into
masterfrom
fix/gbar-response-phase

Conversation

@symmetryyyyy

Copy link
Copy Markdown
Collaborator

Summary

Fix two barrier phase hazards in RTL and align SimX with the architectural one-bit phase:

  • qualify the local phase bypass by barrier address, so a write to one barrier slot cannot become the working phase for a different slot;
  • track global-barrier completion per barrier ID, queue completed local arrivals, and apply each global response to the response's barrier ID rather than the current request pipeline address;
  • retain the phase observed by each pending global generation and wake only the warps actually waiting on that barrier ID;
  • keep global responses from overwriting the local barrier state RAM;
  • toggle, rather than increment, the one-bit SimX barrier phase.

The first commit also brings the diagnostic coverage from #402 and #403 into the regression suite, and the second widens the existing asynchronous-global-barrier overlap window.

Root cause

The old RTL reused store_waddr and store_phase_wdata from the request pipeline while retiring an independent global response. Under overlap/backpressure, this could update the wrong barrier slot, corrupt state, or lose a completed request behind the single request register. The old unlock path also used active_warps, which could release scheduler-stalled warps that had never waited on that barrier.

Separately, the working phase register forwarded every phase write without checking whether the write address matched the barrier currently being processed. Back-to-back arrivals to different slots therefore consumed the previous slot's phase.

Before/after evidence

The "before" column is current origin/master with the two diagnostic test commits applied but without the fix.

Regression / configuration Before After
bar_slot_phase, RTL, XLEN64, 1 core / 2 warps, 256 rounds FAIL: warp 1 missed 256/256 phase flips; 256 errors PASS: 0 missed flips; 0 errors
gbar_phase, RTL, XLEN64, 2 cores FAIL: both cores observed 0 -> 0; 2 errors PASS: both cores observed 0 -> 1; 0 errors
strengthened async_gbarrier, RTL, XLEN64, 2 cores FAIL: scheduler timeout/deadlock at cycle 328609 PASS: 49,762 instructions / 67,419 cycles

gbar_phase and bar_slot_phase are deterministic, diagnostic, and non-deadlocking: they always make forward progress and return observed phase/error data to the host. This makes a bad phase an ordinary regression failure rather than a timeout. The widened existing async_gbarrier test separately guards end-to-end liveness under a longer overlap window.

Verification

  • gbar_phase: PASS on XLEN64 SimX, RTL, and XRT simulator (2 cores)
  • bar_slot_phase: PASS on XLEN64 SimX, RTL, and XRT simulator (1 core / 2 warps)
  • gbar_phase: PASS on XLEN32 RTL (2 cores)
  • strengthened async_gbarrier: PASS on XLEN64 RTL (2 cores)
  • existing local async_barrier: PASS on XLEN64 RTL (1 core)
  • python3 ci/testcase.py lint: PASS, 641 cases across 34 categories
  • git diff --check: PASS

This incorporates and supersedes the test-only coverage proposed in #402 and #403.

Fixes #400
Fixes #401

symmetryyyyy and others added 4 commits September 2, 2026 16:09
Add non-deadlocking diagnostics for cross-slot local phase corruption and missing global-barrier phase advancement. Register both tests in the aggregate regression suite and explicit SimX/xrtsim smoke coverage.

Co-Authored-By: RunjiaChen <runjia@u.nus.edu>

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Capture the phase and exact waiters for each pending global-barrier generation, queue completed local arrivals, and route each cluster response directly to its barrier slot. Keep response-only writes out of the barrier state RAM and qualify the working phase bypass by address.

Use one-bit phase toggles in SimX so wait comparisons keep matching the RTL after wraparound.
@tinebp

tinebp commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

Independently reproduced and verified. Branch updated against master (bf1831ca3); #412, which carried the same three commits with bar_slot_phase unregistered, is closed as superseded.

Reproduction on clean master

Isolated worktree at origin/master (bf1831ca3), rv32, 2 cores, 4 warps, 4 threads:

test driver clean master with 9e5f577e2
bar_slot_phase (256 rounds) simx PASS PASS
bar_slot_phase rtlsim FAIL — 512 errors PASS — 0 errors
gbar_phase simx PASS PASS
gbar_phase rtlsim FAIL — 0 -> 0 PASS — 0 errors
async_gbarrier (widened 32 -> 1024) rtlsim PASS

Baseline failure signatures match #402 and #403 exactly:

core 0 warp 1: SLOT PHASE error: 256 of 256 rounds saw a count-1 arrival
               fail to advance its own slot's phase (pre=0 post=0)
core 1 warp 1: SLOT PHASE error: 256 of 256 rounds ...
slot phase errors: 512

core 0: PHASE error: a completed global-barrier generation did not advance the phase (0 -> 0)
core 1: kernel never wrote a phase

Review notes

The design is right. Replacing the active_warps unlock with the recorded gbar_waiters_r brings RTL in line with what SimX's global_resume() already did correctly — it resumes only wait_mask. The request FIFO is bounded safely: at most one pending generation per barrier id (enforced by the RUNTIME_ASSERT), depth 1 << NB_WIDTH >= NUM_BARRIERS, so it cannot overflow. Dropping mask_n = wait_mask from the global wait path is also correct — completion should be decided by arrivals, and a wait could previously satisfy wait_mask == active_warps early.

The SimX change is a larger correctness fix than the commit message suggests. sim/simx/wctl_unit.cpp:123 already masks the phase to & 0x1u before handing it to software, but BarrierUnit::wait() compared the unmasked uint32_t counter against that masked token. From the third generation on, barrier.phase == phase was always false, so wait() stopped blocking entirely. The ^= 1u toggle fixes that, not only parity after wraparound. Worth saying so in the commit message.

ci/testcase.py lint accepts the catalog. Running perf_gate before merge, since the local-barrier phase path changed and sgemm-mc is multi-core.

Follow-ups (not blockers)

  1. sw/kernel/include/vx_barrier.h:29 still documents arrive() as returning a "generation number" and wait() as blocking "until generation > phase". The architectural phase is one bit; this PR makes SimX honest about it but leaves the contract text wrong.
  2. The RTL gains a FIFO in the global-request path with no matching SimX latency model. No model_parity case exercises multi-core global barriers, so the gate cannot observe the gap today.

@tinebp
tinebp merged commit 1cd71c4 into master Sep 10, 2026
87 of 258 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cluster-level Barrier does not update phase information correctly Barrier's phase update mechanism is wrong

2 participants