Repository navigation
fix(prims-ts): wait for the correction-record TMEM load before releasing its stage in the 2-CTA MLA decode - #9319
Draft
bastianhagedorn wants to merge 1 commit into
Conversation
In the 2-CTA MLA decode kernel, TmemCorrResource.load_corr issued tcgen05.wait::ld before the tcgen05.ld of the 4-word correction record (row_sum, row_max, correction_factor, no_correction). The task runtime releases the correction stage to the softmax warps as soon as the task body returns, and the loaded words are consumed only afterwards (rescale_o, epilogue_store). tcgen05.ld completes asynchronously and is ordered only by tcgen05.wait::ld or a register dependency, so the release could let a softmax warp overwrite the stage while the load is still reading it. Move the wait to right after the load, as the 1-CTA kernel of this backend already does (throughput_latency_1cta/resources/tmem_corr.py). Verified on a B200: compiled SASS now has the releasing SYNCS.ARRIVE wait on the LDTM.x4 scoreboard, no instruction is added, and the output is bitwise identical to the previous build. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: Bastian Hagedorn <bhagedorn@nvidia.com>
Contributor
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. |
1 task done
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
📌 Description
flashinfer/attention/prims_ts/kernels/mla_decode/throughput_2cta/resources.py,TmemCorrResource.load_corr. The correction warps of the 2-CTA MLA decode kernel read the 4-word correction record of the current stage (row_sum,row_max,correction_factor,no_correction) from tensor memory with oneprims.tcgen05_ld(..., num=4).TmemCorrResourceis a 2-stage ring written by the softmax warps (store_corr:tcgen05_stafter the runtime's producer acquire) and consumed by the correction warps; the task runtime releases the stage (anmbarrier.arriveon the stage's empty barrier) as soon asload_corrreturns, and the loaded words are consumed only afterwards:rescale_ovotes onno_correctionand multiplies O bycorrection_factor,epilogue_storereadsrow_sum/row_maxfromfinal_row_stats.The function issued
prims.tcgen05_wait(kind=prims.Tcgen05Wait.LOAD)before the load.tcgen05.ldwrites its destination registers asynchronously; the PTX ISA (tcgen05 instructions, "Asynchronous operations", section 9.7.18.6.4.5 in the 9.x documents) says that the load completes only at atcgen05.wait::ldin the issuing thread and that a register dependency orders only the dependent instruction, "not any other form of ordering". The arrive that releases the stage has no register dependency on the loaded values, so nothing orders it after the load: a softmax warp parked on that barrier may acquire the stage and overwrite the same four columns while the load is still reading them. If that happened, tile t's O rescale would use tile t+2'scorrection_factor/no_correction(a skipped or misapplied rescale), and with a single KV tile the only record feeds the epilogue's normalisation. The wait that was there is not useless, it covers the previous iteration's O loads, which is why it stays, just on the other side of the load.Change: one line,
prims.tcgen05_wait(kind=prims.Tcgen05Wait.LOAD)moved from before the record load to right after it, with a short comment. This is what the 1-CTA kernel of the same backend already does after each of its loads (throughput_latency_1cta/resources/tmem_corr.py). No other behaviour changes.Observed behaviour (B200, compute capability 10.0). The compiled stock kernel shows the gap:
LDTM.x4of the record, then the releasingSYNCS.ARRIVEwith an empty wait mask, then the first consumer (ISETPonno_correction, theFMUL2s bycorrection_factor) waiting the load's scoreboard after the arrive. With the fix the arrive itself waits the scoreboard (watdb=SB0), no instruction is added (same SASS size), and the output is bitwise identical to the unpatched kernel. A sentinel experiment (the softmax warps write a per-tile marker intocorrection_factor, the correction warps record the factor they actually multiply with, plus extra TMEM loads queued in front of the record load and a 10-100 us stall between the release and the first use) read 211.7 M records over 11 800 launches of the unpatched kernel (4 KV-length ranges, non-persistent and CLC persistent schedules) with 0 stale records: in this kernel the refill of a released stage is ordered behind the consumer's first use through the O and P pipelines (the softmax warp acquires P before it stores the record, P is released by the MMA warp after PV, which waits on O, and O is released by the correction warps after they have used the record), at least 2.2 us behind in every measurement. So the race is not observable with the shipped pipeline depths; it would be with a deeper O or P ring or a per-N O pipeline. The fix makes the ordering architectural at no cost.🔍 Related Issues
Same release-before-use shape as #8787 and #8854 (TMEM loads ordered before the release / dealloc in the GDN, MQA-logits and TGV kernels) and NVIDIA/TensorRT-LLM#21849 (the same correction-record load in the Blackwell MLA decode kernels). The vendored copy of this tree in TensorRT-LLM (
tensorrt_llm/_torch/attention/backends/prims_ts) is updated by the paired NVIDIA/TensorRT-LLM#21987, which pins this change through the vendor lock.🚀 Pull Request Checklist
✅ Pre-commit Checks
pre-commitby runningpip install pre-commit(or used your preferred method).pre-commit install.pre-commit run --all-filesand fixed any reported issues. (flashinfer/attention/prims_ts/kernels/is excluded from ruff by.pre-commit-config.yaml; the file compiles.)🧪 Tests
Tests have been added or updated as needed. (No new test: the race needs a deeper O/P pipeline or an injected re-ordering of the refill to become observable; 211.7 M records on a B200 without a stale read, see above.)
All tests are passing (
unittest, etc.). (Not yet run on CI. The kernel compiles with the change; the patched and unpatched kernels produce bitwise identical output on a B200.)This PR requires full-scope CI, not targeted tests (expensive; justify below).
Suggested CI test targets:
tests/attention/test_attention_ts_mla_decode.pyReviewer Notes
The change is the position of one existing
prims.tcgen05_wait(LOAD)call. A library-level alternative would be for the task runtime's consumer release to issuetcgen05.wait::ldbefore releasing a tensor-memory-backed resource; this PR takes the local fix the 1-CTA kernel already uses.🤖 Generated with Claude Code