CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
103 lines
4.9 KiB
Markdown
103 lines
4.9 KiB
Markdown
# waitcnt-check
|
|
|
|
A standalone validator for `s_wait_*` (wait-count) insertion in **STIR**
|
|
(StinkyTofu IR) dumps. It parses a STIR file, simulates the per-counter
|
|
in-flight queues across the control-flow graph, and reports any consumer
|
|
that reads the result of an asynchronous memory op that has **not** been
|
|
drained by a preceding `s_wait_*`.
|
|
|
|
It is an independent cross-check of the compiler's
|
|
`StinkyWaitCntInsertionPass`: the dataflow model here mirrors
|
|
`shared/stinkytofu/src/transforms/asm/waitcnt/WaitDataflow.cpp`, so a STIR
|
|
that the pass waited correctly should validate clean.
|
|
|
|
## What it checks
|
|
|
|
Each tracked asynchronous memory op completes on one hardware counter, and
|
|
each counter is drained by its own wait instruction:
|
|
|
|
| Counter | Producers | Wait op |
|
|
| ------- | ---------------------------------------------------- | ------------------- |
|
|
| DS | `ds_read` / `ds_load` / `ds_write` / `ds_store` / `ds_atomic` | `s_wait_dscnt` |
|
|
| Buffer | vector `buffer` / `global` / `flat` load + store | `s_wait_loadcnt` |
|
|
| KM | scalar `s_load` / `s_buffer_load` | `s_wait_kmcnt` |
|
|
| Tensor | `tensor_load_to_lds` | `s_wait_tensorcnt` |
|
|
|
|
The validator models, per counter:
|
|
|
|
- **Per-predecessor queues.** Each block keeps one in-flight queue per CFG
|
|
predecessor (not a single union), so a consumer at a join computes the
|
|
strictest required wait as the `min` over paths. Queues are capped at the
|
|
hardware in-flight window (64) so loops converge.
|
|
- **RAW** (consumer reads a register/LDS token still in flight),
|
|
**WAR-on-LDS** and **barrier** ordering against the DS FIFO, plus the
|
|
conservative fallbacks used by the reference pass for untagged memtokens.
|
|
- The **tensor** counter only needs to drain at a barrier (or when there is
|
|
a single wave); see `--num-waves`.
|
|
|
|
When it finds a consumer whose producer is still in flight, it reports a
|
|
`MISSING` violation: the wait the compiler should have emitted is absent (or
|
|
too lenient / placed too late).
|
|
|
|
## Usage
|
|
|
|
```bash
|
|
python3 waitcnt_check.py [options] <file.stir>
|
|
```
|
|
|
|
By default only violations are printed. Example:
|
|
|
|
```bash
|
|
python3 shared/stinkytofu/tools/waitcnt-check/waitcnt_check.py dump_function-after.stir
|
|
```
|
|
|
|
### Options
|
|
|
|
| Option | Description |
|
|
| ------------------- | -------------------------------------------------------------------------------------------- |
|
|
| `--num-waves N` | NumWaves tile config. `0` (default) = multi-wave: the tensor counter only drains at barriers. `1` = tensor drains at every consumer. |
|
|
| `-v`, `--verbose` | Also print the `Wait Instructions` listing (what each `s_wait_*` drained) and `Notes`. |
|
|
| `--quiet` | Print only the one-line summary per function. |
|
|
| `-h`, `--help` | Show help. |
|
|
|
|
### Exit codes
|
|
|
|
| Code | Meaning |
|
|
| ---- | ----------------------------------------- |
|
|
| `0` | PASS — no violations |
|
|
| `1` | FAIL — at least one violation |
|
|
| `2` | Could not read or parse the input file |
|
|
|
|
## Reading a violation
|
|
|
|
Only the **first** violation per counter/queue is reported (one diagnostic
|
|
per `s_wait_*` kind), each followed by a dump of the live queue state:
|
|
|
|
```
|
|
MISSING: Consumer v_wmma_scale_f32_16x16x128_f8f6f4 @ line 1913 in ^label_LoopBeginL
|
|
uses async producer ds_load_b128 @ line 1805 (s_wait_dscnt)
|
|
still in-flight (queue depth=28, needs wait s_wait_dscnt 27)
|
|
Queue dump for s_wait_dscnt at consumer ... in ^label_LoopBeginL:
|
|
required (drains ALL 2 undrained producer(s) this consumer uses): s_wait_dscnt 26
|
|
live queues (DS): 2 per-pred queue(s)
|
|
queue[0] pred=^label_openLoopL_1 depth=28
|
|
idx 0: ds_load_b128 @ line 1805 (drain with s_wait_dscnt 27) <-- undrained producer
|
|
idx 1: ds_load_b64 @ line 1806 (drain with s_wait_dscnt 26) <-- undrained producer
|
|
...
|
|
```
|
|
|
|
- **`needs wait <op> N`** in the headline is per producer: the keep value
|
|
that drains just the op named there (for an op at index `i` in a queue of
|
|
size `n`, that is `n - i - 1`).
|
|
- **`required: <op> N`** is the single wait that drains **every** undrained
|
|
producer the consumer reads — the `min` of the per-producer values. This is
|
|
the value the compiler should have emitted before the consumer.
|
|
- Each queue line shows its source predecessor and, per op, the keep value
|
|
that would drain it; `<-- undrained producer` marks the offending ops.
|
|
|
|
## Notes
|
|
|
|
- The tool is dependency-free (Python 3 standard library only).
|
|
- It reads a STIR text dump as produced by the StinkyTofu asm pipeline; it
|
|
does not require building the compiler.
|