Conversation
…aft and accept path RATCHET-RAISE: daemon_lines 4863 -> 4864, traded for the EP load arm honoring the request's typed mtp policy
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.
Summary
Dense-TP Qwen3.5/3.6 (
tp>1) now serves MTP speculative decode instead of the plain EP AR loop: the MTP head is resolved on rank 0 under the request's typedspeculation.mtp/mtp_kpolicy, the K-step draft is the sharedmtp_draft_chain, verify runs across ranks through the dense-TP capture entry point the DFlash mesh already uses, and accept/rollback is the sharedmtp_shared_verify_accept_rollbackmade generic over anMtpTrunkBackend(slot or mesh), so there is no forked accept path. Two prefill-side changes ride along and apply to tp=1 as well: the dense-TP batched prefill now applies the same Q8 multi-row attend admission as the single-GPU chunk path (it was hard-coded off), and that admission accepts 2..=3 rows by running the ROWS=4 body as onerows_valid-masked group.Measured on Qwen3.8-27B
.mq4+.mtpsidecar, 2x RX 7900 XTX (gfx1100), KV q8/vmm, greedy, thinking off, 256 max tokens, fresh process per cell, two byte-identical passes per cell:Output identity (md5 of
content): short prompt, AR tp1 / AR tp2 / MTP tp1 / MTP tp2 all5c7632f2e098— greedy MTP is lossless on both topologies. At 33k, AR tp1 == AR tp2 (fe957aac1cbe) but MTP tp1 (9aded82f057b) and MTP tp2 (f745696e0a69) differ from AR and from each other: the batched-verify numerics flip near-ties at that depth on either topology. The AR path across TP is exact.Scope of the measurements:
bench_flash_rows --check --rows 2/--rows 3on an R9700 is the check.flash_rows_per_blockpreviously documented 0.85x at 2 rows against the batched tile.bench_flash_rowsat seq 33014 on gfx1100 now gives 1.26x at 2 rows, 1.59x at 3, 1.94x at 4, 2.40x at 8, and 0.83x at 1 (a single row stays on the batched kernel); parity vs the batched kernel is rel 2.5e-7..4.2e-7 at every row count. If 2 rows measures below 1.0x on gfx1201, the floor goes back to 4; nothing else in the PR depends on it.The loader contract is also repaired: the EP load API did not carry
SpecLoadCfg, so aloadrequest'smtp_mode=off/mtp_kwas ignored at tp>1 (only the process-globalmtp_modewas read).specis now threadedload_model_ep_admitted->load_model_ep_qwen35->load_model_tp_qwen35_dense; block-verify drafters (n-gram, DFlash, DSpark) are refused on the mesh at build time, not silently held inert.Which surface(s) does this touch?
crates/rdna-compute/src/attention.rs(flash_rows_per_block: masked ROWS=4 group for 2..=3 rows; no.hipchange)crates/hipfire-loader(rank-0 MTP head under typedSpecLoadCfg,Qwen35DenseTpGuard,free_multion unload),crates/hipfire-daemon/src/main.rs(one argument forwarded)crates/hipfire-generate(route selector: dense-TP + MTP takes the spec route),crates/hipfire-runtime/src/spec.rs(free_multihooks)hipfire-arch-qwen35(mtp_dense_tp.rsnew;mtp_spec.rsMtpTrunkBackendsplit; dense-TP prefill multi-row admission;q8_multirow_attn_admittedfloor 4 -> 2)crates/hipfire-quantize/ quant formatsscripts/leanup-thresholds.txt:daemon_lines4863 -> 4864 (the daemon load arm forwardsspec_cfgto the EP loader; one line). Commit message carriesRATCHET-RAISE: daemon_lines 4863 -> 4864, traded for the EP load arm honoring the request's typed mtp policy; please add theratchet-raiselabel.Test plan
cargo build --release --workspace --all-targets --lockedcleancargo test --lib --workspacepasses (2951 passed, 0 failed)scripts/leanup-ratchets.sh21/21,check-crate-maps.py --checkclean;ratchet-diff.shpasses with the declared raise + labelgeneration_route_matrix_tests::dense_tp_qwen_with_mtp_takes_the_spec_route_only_when_it_can_serve; admission tests updated for the 2..=32 floor;flash_rows_per_blockunit test addedbench_flash_rows --check --rows {1,2,3,4,5,8}on gfx1100, seq 33014: parity rel 2.5e-7..4.2e-7, timings aboveserve_harness.py --mode batteryon hardware: tp2 MTP, tp2 AR, tp1 MTP, and tp2 MTP--mode chain— each 5/5finish=stop, runaway=0, empty=0, attractor=0 (JSON below)redline_daemon_harness.pyonqwen3.5-4b.mq4(kernel bucket): prefill128/512 and decodestable=True, 19 AQL contracts, shadowexact=True gdn_frame_exact=Truespeed-gate.sh: not run; the committed gfx1100 baseline was recorded on another host and does not reproduce here, the fresh-process A/B table above is the perf evidenceno-gpu-ci.sh: Rust half green. The pytest half fails on this NixOS host for reasons outside the diff (/bin/bashintest_kernel_atlas,mq4c_repack.HfqmError, the MQ4R registry golden hash, a fake-cargo exit 126); none of those files are touched.ad10b3d97with the same binary lineage (A/B run):serve-loop-gate.sh --aron qwen3.5:0.8b scores 3/10 on both paths withopen think span at end of generationrefusals (the 0.8B does not close<think>in 400 tokens);agentic-gate.sh --fasthard-fails because the gate sendsgeneratewithoutattempt_id, which the daemon protocol now requires.Artifacts:
qwen3.8-27b.mq4sha2565bb556a6cc84035234995c017c9791aa3951ad1eae4cf8c8172b0eaef399e507;qwen3.8-27b.mtpsha256080e93826210f1d3203906da6318f509ec6d5568d98ee3227c0027bec6549c80. Battery daemon md5db8ffad692c09a9d5deb2d57805c5a59.local serve_harness battery.json — tp2 MTP (qwen3.8-27b.mq4, --tp 2, mtp auto, kv q8/vmm, greedy)
{"finish":"stop","gen":175,"ctx":84,"cached":0,"tau":1.84,"prefill_tok_s":288.7,"decode_tok_s":57.9,"attractor":false,"empty":false,"runaway":false,"saw_done":true,"expected_substrings":[],"retrieval_missing":[],"prompt_md5":"43ca0d15712d3dfb777b51ae76d8fd5f","request_md5":"ff5e95990908c8a89e813b1bae4f7a4a","assistant_content":"```python\ndef merge_sorted(a, b):\n \"\"\"Merge two sorted lists into one sorted list.\"\"\"\n result = []\n i = j = 0\n\n while i < len(a) and j < len(b):\n "} {"finish":"stop","gen":153,"ctx":95,"cached":0,"tau":2.26,"prefill_tok_s":399.4,"decode_tok_s":66.9,"attractor":false,"empty":false,"runaway":false,"saw_done":true,"expected_substrings":[],"retrieval_missing":[],"prompt_md5":"640e0fd4f55996cb175a422f0a12cef5","request_md5":"6c3ccc42c011f74ccd709726718e70c6","assistant_content":"Step 1: Distance at 60 mph for 2.5 hours \n\\(60 \\times 2.5 = 150\\) miles\n\nStep 2: Distance at 40 mph for 1.5 hours \n\\(40 \\times 1.5 = 60\\) miles\n\nStep 3: Total"} {"finish":"stop","gen":174,"ctx":65,"cached":0,"tau":1.73,"prefill_tok_s":332.2,"decode_tok_s":56.5,"attractor":false,"empty":false,"runaway":false,"saw_done":true,"expected_substrings":[],"retrieval_missing":[],"prompt_md5":"8f66b4c97988825bd8e7840aaf44357e","request_md5":"435da7549755fd77b204691f3a9fbc3e","assistant_content":"Earth's seasons are caused mainly by the tilt of its rotational axis relative to its orbital plane. As Earth orbits the Sun, different hemispheres receive varyi"} {"finish":"stop","gen":238,"ctx":73,"cached":0,"tau":1.31,"prefill_tok_s":360.0,"decode_tok_s":49.0,"attractor":false,"empty":false,"runaway":false,"saw_done":true,"expected_substrings":[],"retrieval_missing":[],"prompt_md5":"8fe0ad36f61bcf4992cc9df81cdf3817","request_md5":"ed458c086e56dead1a15e8a74a61aa82","assistant_content":"Old Maren found the brass key tangled in kelp where the tide had clawed the rocks clean. \nIt was warm, though the sea had been freezing all night. \nWhen she t"} {"finish":"stop","gen":198,"ctx":71,"cached":0,"tau":1.8,"prefill_tok_s":355.1,"decode_tok_s":58.2,"attractor":false,"empty":false,"runaway":false,"saw_done":true,"expected_substrings":[],"retrieval_missing":[],"prompt_md5":"8bed8e2d056dc1d47dccae9d32dbecf4","request_md5":"274ff1654412336c1f28a529cb07ebb3","assistant_content":"1. Use clear, descriptive names for variables, functions, and modules.\n2. Keep functions small and focused on a single responsibility.\n3. Write meaningful comme"}tp2 AR control (same prompts, mtp off) and tp1 MTP
{"finish":"stop","gen":175,"tau":null,"decode_tok_s":51.7,"attractor":false,"empty":false,"runaway":false,"saw_done":true,"prompt_md5":"43ca0d15712d3dfb777b51ae76d8fd5f","assistant_content":"```python\ndef merge_sorted(a, b):\n \"\"\"Merge two sorted lists into one sorted list.\"\"\"\n result = []\n i = j = 0\n\n while i < len(a) and j < len(b):\n "} {"finish":"stop","gen":153,"tau":null,"decode_tok_s":53.1,"attractor":false,"empty":false,"runaway":false,"saw_done":true,"prompt_md5":"640e0fd4f55996cb175a422f0a12cef5","assistant_content":"Step 1: Distance at 60 mph for 2.5 hours \n\\(60 \\times 2.5 = 150\\) miles\n\nStep 2: Distance at 40 mph for 1.5 hours \n\\(40 \\times 1.5 = 60\\) miles\n\nStep 3: Total"} {"finish":"stop","gen":174,"tau":null,"decode_tok_s":53.2,"attractor":false,"empty":false,"runaway":false,"saw_done":true,"prompt_md5":"8f66b4c97988825bd8e7840aaf44357e","assistant_content":"Earth's seasons are caused mainly by the tilt of its rotational axis relative to its orbital plane. As Earth orbits the Sun, different hemispheres receive varyi"} {"finish":"stop","gen":238,"tau":null,"decode_tok_s":52.7,"attractor":false,"empty":false,"runaway":false,"saw_done":true,"prompt_md5":"8fe0ad36f61bcf4992cc9df81cdf3817","assistant_content":"Old Maren found the brass key tangled in kelp where the tide had clawed the rocks clean. \nIt was warm, though the sea had been freezing all night. \nWhen she t"} {"finish":"stop","gen":198,"tau":null,"decode_tok_s":53.3,"attractor":false,"empty":false,"runaway":false,"saw_done":true,"prompt_md5":"8bed8e2d056dc1d47dccae9d32dbecf4","assistant_content":"1. Use clear, descriptive names for variables, functions, and modules.\n2. Keep functions small and focused on a single responsibility.\n3. Write meaningful comme"}{"finish":"stop","gen":175,"tau":1.84,"decode_tok_s":64.5,"attractor":false,"empty":false,"runaway":false,"saw_done":true,"prompt_md5":"43ca0d15712d3dfb777b51ae76d8fd5f","assistant_content":"```python\ndef merge_sorted(a, b):\n \"\"\"Merge two sorted lists into one sorted list.\"\"\"\n result = []\n i = j = 0\n\n while i < len(a) and j < len(b):\n "} {"finish":"stop","gen":153,"tau":2.26,"decode_tok_s":74.7,"attractor":false,"empty":false,"runaway":false,"saw_done":true,"prompt_md5":"640e0fd4f55996cb175a422f0a12cef5","assistant_content":"Step 1: Distance at 60 mph for 2.5 hours \n\\(60 \\times 2.5 = 150\\) miles\n\nStep 2: Distance at 40 mph for 1.5 hours \n\\(40 \\times 1.5 = 60\\) miles\n\nStep 3: Total"} {"finish":"stop","gen":174,"tau":1.84,"decode_tok_s":64.9,"attractor":false,"empty":false,"runaway":false,"saw_done":true,"prompt_md5":"8f66b4c97988825bd8e7840aaf44357e","assistant_content":"Earth's seasons are caused mainly by the tilt of its rotational axis relative to its orbital plane. As Earth orbits the Sun, different hemispheres receive varyi"} {"finish":"stop","gen":238,"tau":1.33,"decode_tok_s":55.0,"attractor":false,"empty":false,"runaway":false,"saw_done":true,"prompt_md5":"8fe0ad36f61bcf4992cc9df81cdf3817","assistant_content":"Old Maren found the brass key tangled in kelp where the tide had clawed the rocks clean. \nIt was warm, though the sea had been freezing all night. \nWhen she t"} {"finish":"stop","gen":198,"tau":1.8,"decode_tok_s":64.7,"attractor":false,"empty":false,"runaway":false,"saw_done":true,"prompt_md5":"8bed8e2d056dc1d47dccae9d32dbecf4","assistant_content":"1. Use clear, descriptive names for variables, functions, and modules.\n2. Keep functions small and focused on a single responsibility.\n3. Write meaningful comme"}Hardware validation request (optional)
{ "routes": [ {"mode": "battery", "tag": "qwen3.8:27b"}, {"mode": "chain", "tag": "qwen3.8:27b"} ], "claim": "dense Qwen3.8-27B at tp=2 with the .mtp sidecar drafts on rank 0 and verifies across ranks; greedy output byte-identical to AR on short prompts; tp=1 MTP and AR unchanged; Q8 multi-row admission at 2..=3 rows does not change AR output" }Architecture-trait change?
No.
Carrier::spec_target_guardgains an_ep: &mut Option<EpState>parameter (default impls untouched, every carrier updated);Speculator::free_multi/MtpDrafter::mtp_free_multiare new defaulted methods. TheArchitecturetrait is not touched.