Skip to content
  •  
  •  
  •  
5 changes: 3 additions & 2 deletions emulation/rocjitsu/docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,9 @@ or overwrites a pending memory result without a sufficient wait. Results still
execute eagerly. See
[memory wait diagnostics](memory-wait-diagnostics.md) for coverage and the
`memory_wait_diagnostics` setting (`off`, the default, or `warn`).
On gfx1250, this setting also controls XCNT replay-source warnings. Both checks
are disabled by default and enabled together with `memory_wait_diagnostics=warn`.
On gfx1250, XCNT replay-source warnings are independently opt-in through
`xcnt_diagnostics=warn` (default: `off`). Both settings belong in each
`compute_unit` node's `config` array.

### KFD device sections

Expand Down
100 changes: 64 additions & 36 deletions emulation/rocjitsu/docs/memory-wait-diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,20 @@ Reading or overwriting an outstanding destination prints a `memory-wait` warning
with the issuing PC, consuming PC, register, counter, and sufficient wait
threshold. Execution continues with the eager value. The first conflicting access
reports the producer and recovers its readiness to avoid cascading warnings. Each CU
prints at most 16 warnings during its lifetime.

Diagnostics default to `off`. To enable tracking and messages, add this entry to each
prints at most 16 warnings during its lifetime, then one suppression notice.
This budget is per CU, so N active CUs can print up to 17 × N lines for the
same kernel. The budget stays local so a faulty kernel on one CU does not hide
diagnostics from another CU or device. Repeated sites can exhaust this budget
and hide distinct later hazards; the printed set is not exhaustive. Per-CU
diagnostic counts continue after printing is suppressed. Fix reported waits and
rerun to expose later sites. For an unfiltered investigation, a host debugger
breakpoint at `ComputeUnitCore::report_memory_wait` observes every reported
hazard before the output limit is applied.

Registers in diagnostics use the scoreboard's physical numbering. On targets
with an accumulator bank, `v256+n` names `aN` (for example, `v288` is `a32`).

Memory-result diagnostics default to `off`. To enable them, add this entry to each
`compute_unit` node's `config` array:

```json
Expand All @@ -27,9 +38,18 @@ address/data operands, including EXEC and dynamically selected VGPR banks. Readi
a protected source again is allowed. `xcnt-wait` warnings have their own limit of
16 per CU and do not consume the ordinary `memory-wait` warning budget.

XCNT tracking and warnings are enabled by the same `memory_wait_diagnostics`
setting as the completion checks above. Setting it to `off` disables both.
The setting controls diagnostics, not hardware XNACK support.
XCNT tracking and warnings default to `off`. Enable them independently of
memory-result checks by adding this entry to each `compute_unit` node's `config`
array:

```json
{"key": "xcnt_diagnostics", "value": "warn"}
```

The accepted values are `warn` and `off`; invalid values reject the configuration.
This setting has no effect on other architectures. It controls diagnostics, not
hardware XNACK support. Setting `memory_wait_diagnostics=off` leaves an explicitly
enabled XCNT check active; set both options to `off` to disable all wait checking.

VMEM coverage is qualified for `MODE.REPLAY_MODE=1` (bit 25), the multi-group mode
selected by LLVM at kernel entry. VMEM replay sources in single-group mode are
Expand All @@ -52,8 +72,9 @@ visibility are outside this register-source check.

The checker tracks scalar and vector register results from both memory pipelines and
inline producers, including DS permutations and message returns. Store operands are
checked when they consume a pending result. Register checks use executed physical
accesses, including lane masks, byte masks and high VGPRs. Counter-only producers
checked when they consume a pending result. The issuer checks each instruction
before execution, using decoded register numbers and the wave's current EXEC,
register-bank and addressing state. Counter-only producers
contribute to partial waits even without a register result. Implicit SCC consumers and
overwrites (including HWREG aliases), M0 and EXEC message results, wave-sized VCC
accesses, and private address uses of FLAT_SCRATCH are checked too. Preserved scalar
Expand Down Expand Up @@ -102,33 +123,40 @@ unqualified completion classes remain conservative. The checker does not simulat
hardware occupancy or select a latency at which memory becomes visible.

These are known limits, not an exhaustive list. Investigate warnings against the
target's ordering rules; `memory_wait_diagnostics=off` suppresses both classes of
warning when needed. Plugins may overlap with these checks and additionally
target's ordering rules; `memory_wait_diagnostics=off` suppresses memory-result
warnings and `xcnt_diagnostics=off` suppresses replay-source warnings when needed. Plugins may overlap with these checks and additionally
validate hazards such as memory visibility and communication between waves.

## Cost

The scoreboard retains register dependency records, not memory addresses, payloads
or decoded instructions. A byte of shadow state per register rejects unrelated
accesses before any thread-local lookup. The 1,280-byte shadow is present in each
wave slot, including when
tracking is disabled. Detailed records are allocated on first tracked memory issue and
reused across wave slot activations. Retirement clears affected shadow bytes and
restores overlapping live records. Formatting occurs only when reporting a hazard.

When tracking is disabled, a flag fixed at wavefront construction skips register
indexing and shadow loads. The CU also skips register notifications and their region
loops when diagnostics are off and no execution plugins are attached. Attaching a
plugin preserves its register callbacks even with wait checking disabled.

MMA helpers do not access the scoreboard concurrently. The issuer checks an eligible
MMA's operands before publishing it; other executed register accesses are checked within
the issuing thread's instruction scope. Observer snapshots and memory writeback do not
count as instruction consumers.

The slow register check is deliberately out of line: otherwise the compiler can hoist
TLS lookup ahead of the shadow test. Empty instruction scopes skip TLS installation.
Separate result and replay-source bits share the existing shadow byte. Reads ignore
the replay bit, keeping reads of replay-only sources out of the detailed checker.
Relaxed atomic shadow bytes let MMA helpers probe the filter without racing the issuer;
only the issuer accesses dependency records.
## Access planning and cost

The scoreboard retains register dependencies, not memory payloads or cached access
plans. Ordinary elementwise instructions probe decoded register numbers directly.
A 1,280-byte shadow per wave covers physical VGPRs 0–1023 and scalar/special
registers. Separate result and replay bits share each byte. A negative probe skips
the detailed checker; a possible overlap checks the pending records' lane and byte
masks. The shadow is conservative across overlapping records and counter retirement.

The wave stores VGPR bank selection in one byte. An issued dependency records the
physical register number, so a later bank change cannot redirect that dependency.
VCC is wave state with separate low/high word identities. Unordered scalar memory
results require a zero wait; they cannot be made ready by an unrelated partial wait.

Exceptional instructions use shared addressing and lane-selection helpers before
execution. Relative registers and permutations can require M0 or selector values;
FLAT domain selection requires address values. Those control inputs are checked
before being read for planning. Planning does not fire execution-plugin callbacks.
The checks and producer registration precede execution lane loops and async MMA
publication. Only the issuing thread accesses the scoreboard: register accessors,
MMA workers, observer snapshots and memory writeback do not check it.

Lane masks distinguish divergent consumers and pending results across waterfall
iterations. Qualified sub-dword forms also distinguish consumed and written bytes,
without treating preservation of the other bytes as a read. Other sub-dword forms
can conservatively check a whole register. Encoded memory address/data sources keep
their dependencies even when an invalid descriptor or an out-of-bounds address
suppresses the memory effect.

Detailed records are allocated on the first tracked issue and reused across wave
slot activations. Retirement clears affected shadow bytes and restores overlapping
live records. Diagnostic formatting occurs only on a hazard. With both settings
disabled, the issuer skips the checker; execution-plugin callbacks remain independent.
Loading
Loading