fix(qwen35): reclaim prefill scratch after allocation failure - #731
Merged
Merged
Conversation
The rollback ledger stored DeviceBuffer::alias() views, which free_tensor refuses to release. Stage real GpuTensor owners and publish them only after every mandatory/optional allocation succeeds; unwind failures in reverse. GPU fault regression on gfx1151/HIP7.2: warm54 allocations; fail the final allocation and retry. Before:107 fresh allocations (53 buffers lost). After:54, full warm-pool reuse. Default qwen35 lib tests191 passed/1 ignored; the ignored GPU fault test was explicitly run and passed. Scoped clippy completed with existing warnings; crate maps43/43, ratchets21/21 pass. Rebuilt CLI/daemon, verified qwen3.6:27b DFlash factual+5-turn chain and qwen3.6:35b-a3b AR factual:7 turns stop, no empty/runaway/attractor outputs. Matched128-token DFlash request is byte-identical before/after (both hit that explicit cap); separate512-token run completes at148 tokens. Evidence scope: first independent G4 allocation-error fix, not G4 milestone acceptance, numerical/state admission, physical multi-GPU, or performance.
This was referenced Sep 7, 2026
Collaborator
|
Landed in beta merge af39905 after independent review. Exact staged candidate24929bd6 on84fb395 passed the real gfx1201/HIP7.15 injected allocation54 failure+retry regression. Release serve_harness battery on SHA-pinned Qwen3.8 XT9f91556f + draftd0a74a23, q8/vmm,maxseq8192,DFlash on:5/5 stop,0 empty/runaway/attractor, decoded text inspected coherent. Daemon md5f512dc23f954b9f51353e1938f89e148. This is correctness evidence, not a performance claim. |
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.
Scope
First independent G4 error-path ownership fix for #666, based directly on upstream
betaatfebf298a22862b24ab6bb709546499f23f07676b. This PR does not close G4 or promote any device-mesh milestone. No historical #676 stack is replayed.Reproduced defect
PrefillBatchScratch::new_optrecordedDeviceBuffer::alias()handles in its rollback ledger. Those are borrowed buffers;Gpu::free_tensorexplicitly refuses to pool borrowed handles. When a later allocation failed, the partially constructed object dropped its actual owners without freeing them, and the alias-ledger cleanup could not reclaim them.On gfx1151/HIP 7.2, the committed GPU regression warms 54 real allocations, injects failure before the final allocation, and immediately retries construction. Before the fix the fresh-allocation counter increased 54 → 107 (53 reusable buffers lost). After the fix it stays 54; retry reuses the complete warm pool.
Fix
Vec<Option<GpuTensor>>, not aliases.Verification
Source head:
0c76c3470afe8da862b25d7f34b21669ce6dd9d2. CLI/daemon were rebuilt from the final Rust content before committing; the final commit also includes the generated map and changelog. This is narrow PR evidence, not a final-composition milestone receipt.Independent static review: no blocking findings; confirmed each slot's shape/dtype/order/optional predicate and exactly-once publication. That review did not run hardware tests; the runs below were executed separately.
Hardware serving evidence
Halo, gfx1151, HIP 7.2. GPU access serialized using flock. All service binds were
127.0.0.1:11466with isolated temporary homes, not the user's running service.9a6acdc49bcaa6a7b52ac161444cb769204c4c4ceab30cb9ebc118fa9d59a446edde51ec1dac0f2bd42cff5ef1cb894412ab9cdabc8fe5b1be6973f2d2c76ab6510898a04b786c41f3a2fc0e678e9161fb423f33edf3ec8c97b899dd08103d6145ac198243de4700953f0b5af735550cbenchmarks/prompts/bare_factual.txt1d32df5f12c414d3e34c7b35b6611e6cCommon harness settings:
--thinking off --sampling greedy --kv q8 --kv-backend vmm --max-seq 4096 --max-tokens 512 --port 11466; native CLI/daemon paths explicitly supplied usingHIPFIRE_CLI_BIN/HIPFIRE_DAEMON_BIN.Executed
python3 scripts/serve_harness.pyroutes:--model ~/.hipfire/models/qwen3.6-27b.mq4 --tag qwen3.6:27b --draft ~/.hipfire/models/qwen36-27b-dflash-mq4.hfq --dflash on --mode battery --prompt-file benchmarks/prompts/bare_factual.txt.--mode chain, using the committed harness's built-in five-turn chain.--model ~/.hipfire/models/qwen3.6-35b-a3b.mq4 --tag qwen3.6:35b-a3b --dflash off --mode battery --prompt-file benchmarks/prompts/bare_factual.txt.All seven turns finished
stop; zero empty, runaway, attractor or retrieval-miss flags. Full decoded text was read. Dense logs confirm the paired DFlash draft loaded and verify-graph B16 warmup; dense reports havedflash=true. A3B used AR.Additionally, a byte-identical baseline/final dense DFlash request at
--max-tokens128produced byte-identical decoded output (request_md5=6722a9b3ac054aca62181d96ff073e73). Both reached that deliberately small cap and were flagged length/runaway; this is a matched output-preservation observation, not a completed-turn pass. The separate512-token final run completed normally at148 generated tokens.Full decoded final serving responses and request identities (timing omitted; no perf claim)
g4-final-dense, turn 1
Prompt MD5
1d32df5f12c414d3e34c7b35b6611e6c; request MD55cbcaa74134d340a209b9169a0e1eba7; finishstop; generated 148; cached 0.g4-final-chain, turn 1
Prompt MD5
43ca0d15712d3dfb777b51ae76d8fd5f; request MD52c0d12dbd7bb19517b442aa096960a8f; finishstop; generated 168; cached 0.g4-final-chain, turn 2
Prompt MD5
640e0fd4f55996cb175a422f0a12cef5; request MD53b927296b47ce16279c927d23c9e432b; finishstop; generated 206; cached 212.g4-final-chain, turn 3
Prompt MD5
8f66b4c97988825bd8e7840aaf44357e; request MD5b69a6e7dc9976befe1855af6ec920602; finishstop; generated 83; cached 474.g4-final-chain, turn 4
Prompt MD5
8fe0ad36f61bcf4992cc9df81cdf3817; request MD571628f33d18c8e1079e9f0cc023a26bc; finishstop; generated 98; cached 583.g4-final-chain, turn 5
Prompt MD5
8bed8e2d056dc1d47dccae9d32dbecf4; request MD5b56b913784cc2e00e8c079e4dd9fc0f3; finishstop; generated 77; cached 715.g4-final-a3b, turn 1
Prompt MD5
1d32df5f12c414d3e34c7b35b6611e6c; request MD5c511ce1f15475b7f372a6ef247a87dce; finishstop; generated 124; cached 0.Nonclaims / remaining G4 work
Qwen35DecodeBatchStatelate-allocation ledger and broader cleanup-error handling, remain separate G4 obligations. This PR does not claim they are fixed.