Repository navigation
fix(optimize-memrefs): Keep host-accessed buffers out of slot reuse - #1305
ximzhang-amd wants to merge 3 commits into
Conversation
|
Thanks for opening a PR! This project follows LLVM's incremental-development and AI-tool-use Before requesting review, please check that:
Reviewers are assigned through |
L2 Accuracy Results (EP vs CPU)
Threshold: 0.01 | Run: 7997 - Commit: |
Binary sizesBaseline: run 40617608668 -
MorphiZen EP Performance Results
EPContext Export Performance
EPContext Import Performance
OGA Benchmark Results
OGA Wheel Smoke (Python benchmark_e2e.py)
VLM Benchmark Results
TTFT / TPS vs mainBaseline: run 40617608668 -
Run: 7997 - Commit: |
|
/run-test models=all node=xsjnucstrhalo09 |
|
ROCm GenAI CI finished with result: FAILURE.
|
Program order is not execution order across the host/device boundary: a host memref.store takes effect at once, while the hip op before it has only been enqueued. hip-optimize-memrefs let two host-fed scalars share a slot, so the second store could overwrite the first before the kernel reading it ran. In a GQA decoder the total-sequence-length staging buffer was reused for the next scalar; decode steps after a prefill nondeterministically read the step length, repeating tokens. Buffers the host loads or stores, directly or through a view, now neither take nor donate a slot. They are tiny, so nothing is lost. Co-Authored-By: Claude <noreply@anthropic.com> Made-with: Claude Code
…e out of reuse hip-materialize-host-scalars moves only static host-fed buffers of at most 16 elements to host-mapped scratch, so a larger one stays in the pool and reaches slot reuse whichever of the two passes runs first. Check that hip-optimize-memrefs keeps two 32-element host-fed buffers apart. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Made-with: Claude Code
Whitespace only, as the lintrunner pre-commit hook formats it. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Made-with: Claude Code
840273f to
2199d12
Compare
|
/run-test models=all node=xsjnucstrhalo09 |
|
ROCm GenAI CI finished with result: UNSTABLE.
|
|
|
||
| Value result = allocOp.getResult(); | ||
| if (result.use_empty()) | ||
| if (result.use_empty() || isHostAccessed(result)) |
There was a problem hiding this comment.
We shouldn't be doing this. This pass intended to be a generic pass, why do this pass need to know whether it's a host or device?
There was a problem hiding this comment.
This PR upstreams the fix from https://github.com/AMD-AIG-AI-SOLUTIONS/hip-ir-runtime/blob/1835dd33d2e6247c4fa0672e8d1d217421dcac75/hip-ep-ext/patches/0030-fix-optimize-memrefs-Keep-host-accessed-buffers-out-.patch. #1272 makes a similar change by running MaterializeHostScalars before OptimizeMemRefs, which keeps this pass generic.
I checked that #1272 covers it. The test model has two host-fed shape scalars, each read by a cast queued behind slow matmuls. On main, the first output comes back with the second scalar's value in 20/20 runs. With #1272's reorder alone, all 20 runs are correct, the same as with this PR alone. I also checked a Llama 3.1 8B decoder: with #1272's order, the compiled IR is identical with and without this PR.
Once #1272 is merged, this PR isn't needed, and I'll close it then.
There was a problem hiding this comment.
Just to clarify the changes in the repo that you mentioned is POC and a lot of it is generated by AI. We need to be careful what we upstream. I have been reviewing the code to see what can be upstreamed.
Summary
hip-optimize-memrefsno longer lets a buffer the host loads or stores (directly or through a view) take ordonate a reuse slot.
Related issue or design
Related: #1272, which avoids the same race by pass order; this PR is complementary (see "Relation to #1272"). Backport of the hip-ir-runtime downstream patch 0030 (link under Notes for reviewers).
Why
Program order is not execution order across the host/device boundary: a host
memref.storetakes effect at once,while the hip op before it has only been enqueued. The pass let two host-fed scalars share a slot, so the second
store could overwrite the first before the kernel reading it ran. In a GQA decoder the total-sequence-length
staging buffer was reused for the next scalar; decode steps after a prefill nondeterministically read the step
length, repeating tokens.
What
memref.load/memref.store, also through views) from slot reuse inOptimizeMemRefs.cpp; they are tiny.hip-optimize-memrefs.mlir: two host-fed scalars (the GQA case), and two 32-element host-fedbuffers, too large for
MaterializeHostScalars; note indocs/design/pool-allocs-memory-planning.md.Relation to #1272
OptimizeMemRefs: host-accessed buffers neither take nor donate a slotMaterializeHostScalarsbeforeOptimizeMemRefsMaterializeHostScalarsredirects)Measured with
hip-mlir-opt(Test plan): host store, GPU read, host store, GPU read.mainThe race actually seen (the GQA total-length scalar) is a 1-element buffer, which #1272 also fixes. No model
with a larger host-fed buffer has been seen yet; the second test keeps the pass correct by construction rather
than by pass order. If both land, the scalar case is covered twice, which is harmless.
Test plan
Build environment: Linux, no GPU; base
origin/main93c53c4, LLVM from rocmlirTriton 85f34b1a, TheRock 7.13.0,build.py --hip_arch gfx1151(BUILD_EP=OFF, BUILD_HIP_UNIT_TESTS=ON). Baselinemain: lit 624 pass / 9 unsupported / 0 fail; CTest 134/266 pass, the 132 failures are GPU execution tests (131E2E_Execute_*+HipGpuElfContract) that cannot run without a GPU.main.main'ship-optimize-memrefs(%bmerged into%a) and pass with this branch's.main's passes in fix(compiler): correct memory handling for dynamic shapes #1272's order (hip-materialize-host-scalarsthenhip-optimize-memrefs): the 1-element case moves to host-mapped scratch (offsets 0 and 64) and is fixed;the 32-element case stays in the pool and
%bstill takes%a's slot. With this branch's pass, both arekept apart in either order.
race is timing-dependent). The lit cases above check the slot assignment that causes it.
Notes for reviewers
0030-fix-optimize-memrefs-Keep-host-accessed-buffers-out-.patch
OptimizeMemRefs, also covershost-fed buffers larger than
MaterializeHostScalarstakes, and does not conflict with it.Co-Authored-By: Claude); rebased and described with Claude Code,reviewed by the submitter.
Checklist
docs/design/pool-allocs-memory-planning.md).🤖 Generated with Claude Code