Skip to content

perf(gfx1201): enable AlpineQ R4/R8 Q8 verifier — +37.6% long-context DFlash decode - #748

Merged
Kaden-Schutt merged 1 commit into
warpfront:betafrom
HUSRCF:perf/gfx1201-multi-row-verifier
Sep 13, 2026
Merged

Kaden-Schutt merged 1 commit into
warpfront:betafrom
HUSRCF:perf/gfx1201-multi-row-verifier

Conversation

@HUSRCF

@HUSRCF HUSRCF commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Extend AlpineQ's R4/R8 Q8 multi-row verifier from #741 to exact gfx1201, based on real R9700 measurement. This changes only the Rust admission/launcher predicates and keeps the existing kernel source, arithmetic, reducer, and AlpineQ/Kaden attribution unchanged.

On the pinned 21,550-token Qwen3.8-27B XT fixture, the contributor measurement improved median DFlash decode from 23.7 to 32.6 tok/s (+37.6%).

Kaden-Schutt independently reproduced the result during maintainer review on a second R9700 (exact gfx1201, HIP 7.15). That measurement found 26.3 tok/s on the existing batched DFlash verifier and 39.3 tok/s with R4/R8 (+49.4%). The added plain-AR anchor measured 32.6 tok/s: the existing DFlash route was 19.3% slower than AR, while R4/R8 was 20.6% faster than AR.

The claim is therefore that this change repairs the long-context verifier bottleneck on the measured gfx1201 fixture, taking DFlash from a net loss to a net win over AR. It does not claim that DFlash universally outperforms AR; draft acceptance and workload remain material.

Which surface(s) does this touch?

  • kernel — crates/rdna-compute
  • arch crate(s): hipfire-arch-qwen35
  • load
  • serve
  • crates/hipfire-quantize / quant formats
  • control plane
  • docs / CI / scripts only (the PR includes supporting env documentation and a historical checkpoint)
  • policy files

The route remains fail-closed to exact gfx1100/gfx1201, Q8 KV, head dimension 128/256, sequential non-tree batches of 4..32 rows, logical context above 4096, and graph capture off. Other cases retain the established batched attention path.

Performance evidence

Hardware: Radeon AI PRO R9700, exact gfx1201, wave32, HIP 7.14.

Target SHA-256: 9f91556f7e0431a077d03756a7102d0154108757289e6e5fe9a2d204c0c9eeb7

Draft SHA-256: d0a74a232a0e2166d889f823e91e0fbf778d21dd9668d7de055cdecb065401bc

Prompt MD5: b4d0b63cddcac872648ddf3cdd92cac2 (21,550 actual tokens)

Fresh-process order was off,on,on,off,off,on; HIPFIRE_FA_PERTOKEN_MIN_CTX was the only arm delta. Both arms used Q8 VMM KV, DFlash, graph capture off, a ten-second DPM warmup, greedy sampling, and 200 output tokens.

route samples (tok/s) median delta
existing batched 24.6, 23.7, 23.3 23.7 —
R4/R8 multi-row 32.6, 32.6, 32.5 32.6 +37.6%

All six runs had identical output MD5 b501ab0e0102889bd63537f2006d4f61, tau 1.80, 71 cycles, and 200 emitted tokens.

Independent maintainer re-measurement

Kaden-Schutt independently repeated the benchmark during maintainer review on a second Radeon AI PRO R9700 (exact gfx1201, HIP 7.15). The run used the same pinned target, draft and prompt; Q8 VMM KV; max_seq=65536; greedy sampling; HIPFIRE_VERIFY_GRAPH=0; one unrecorded warmup; and fresh processes for every sample. Three plain-AR anchors were added to the declared arm order.

route samples (tok/s) median relative to AR
plain AR (--spec off) 32.6, 32.6, 32.6 32.6 —
DFlash, existing batched verifier 26.4, 26.3, 26.3 26.3 -19.3%
DFlash, R4/R8 multi-row verifier 39.3, 39.3, 39.3 39.3 +20.6%

R4/R8 improved DFlash throughput by 49.4% relative to the existing batched verifier. Both DFlash arms retained tau 1.80 and 71 cycles, reproducing the contributor run's draft behaviour exactly. The absolute rates differ between hosts, but the direction and mechanism reproduce independently.

This AR anchor corrects an omission in the original PR description: the existing long-context DFlash route was slower than plain AR on this fixture. The new route turns that net loss into a measured win.

The gfx1201 kernel oracle measured R4/R8 speedups of 2.08x/2.49x at context 32,768. Worst relative output error across head dimensions 128/256 and contexts through 32K was 4.765e-7 (limit 1e-3). All entries compiled with zero private scratch/spills.

Test plan

  • ./scripts/no-gpu-ci.sh — local run reaches five pre-existing mq4c_repack fixture failures shared with clean beta; required CI is left to report independently
  • cargo build --release clean
  • cargo test --lib --workspace — claim-scoped crate suites were run instead
  • hipfire-arch-qwen35: 193 passed, 4 ignored
  • rdna-compute: 244 passed
  • test_kernels: 16/16 on gfx1201
  • test_kernelsQA --expected-arch gfx1201: 16/16
  • serve_harness.py battery: 5/5 coherent; zero empty, runaway, attractor, or retrieval failures. Full JSON is posted in the evidence comment immediately below.
  • LongBench-v2 hard-30, prompt_think, temperature 1.0, uncapped xhigh thinking, 64K output ceiling: 30/30 natural stops, zero runtime/output-health failures; longest output 14,940 tokens. This is quality soak evidence, not a performance A/B.
  • Independent maintainer re-measurement on a second gfx1201 R9700: R4/R8 reproduced at +49.4% over the existing DFlash verifier and +20.6% over plain AR.
  • Maintainer serve_harness.py --mode session validation: 8/8 turns completed normally across 7.1K–36.9K contexts, with prefix-cache hits on every continuation and zero empty, runaway or token-attractor outputs. The t7/t8 literal dedupe retrieval misses were inspected and were benign naming differences (hash_file / find_duplicates), not coherence failures.
  • crate maps, env-doc scan, rustfmt, fmt-bomb, and diff checks

The multi-row route is excluded during graph capture and retained/PM4 replay, so this PR makes no Redline performance or parity claim.

Full fixture-bound measurements and ISA resources are recorded in docs/perf-checkpoints/2026-09-11-gfx1201-qwen38-multirow-verifier.md.

Hardware validation request (optional)

Manual claim-matched hardware evidence is provided above; no additional automation route is requested.

How this merges (direct review)

Merge authority remains direct maintainer review plus the required CI checks. This measurement is a promotion candidate for exact gfx1201 routing, not a registry admission or universal gfx12 claim.

Architecture-trait change?

No.

Extend AlpineQ's warpfront#741 route to exact gfx1201 after R9700 validation, without changing the kernel source or existing attribution. Unsupported architectures and captured/retained routes continue to fail closed to the established batched path.

Canonical 21,550-token XT fresh-process A/B: 23.7 -> 32.6 tok/s median (+37.6%), with identical 200-token output, tau 1.80, and 71 cycles across all six samples. Kernel oracle speedups reach 2.08x/2.49x for R4/R8 at 32K; worst relative error is 4.765e-7 and all entries compile with zero private scratch/spills.

Validated on Radeon AI PRO R9700 gfx1201: test_kernels 16/16, test_kernelsQA 16/16, qwen35 193/193, rdna-compute 244/244, native five-prompt serve battery 5/5 coherent, and LongBench-v2 hard-30 with 64K output ceiling 30/30 completed without runtime or output-health failures.

Signed-off-by: HUSRCF <shuang886@connect.hkust-gz.edu.cn>
@HUSRCF

HUSRCF commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

[
{
"request_id": "chatcmpl-3051470-1",
"ctx": 44,
"cached": 0,
"gen": 114,
"finish": "stop",
"think_words": 0,
"ans_words": 47,
"prefill_ms": 16355.2,
"prefill_tok_s": 2.7,
"decode_tok_s": 7.8,
"decode_estimated": false,
"tau": 10.4,
"cycles": 10,
"dflash": true,
"mtp": null,
"mtp_ngram": null,
"ngram_mod_windows": null,
"ngram_mod_drafts": null,
"ngram_mod_accepted": null,
"ngram_mod_accept_rate": null,
"mtp_windows": null,
"ar_windows": null,
"mtp_retired": null,
"mtp_window_timings": null,
"ttft_s": 16.361,
"wall_s": 31.002,
"attractor": false,
"empty": false,
"runaway": false,
"ans_preview": "python\ndef merge_sorted(a, b):\n \"\"\"Merge two sorted lists into a single sorted list.", "assistant_content": "python\ndef merge_sorted(a, b):\n """Merge two sorted lists into a single sorted list."""\n result = []\n i, j = 0, 0\n while i < len(a) and j < len(b):\n if a[i] <= b[j]:\n result.append(a[i])\n i += 1\n else:\n result.append(b[j])\n j += 1\n result.extend(a[i:])\n result.extend(b[j:])\n return result\n", "content": "python\ndef merge_sorted(a, b):\n """Merge two sorted lists into a single sorted list."""\n result = []\n i, j = 0, 0\n while i < len(a) and j < len(b):\n if a[i] <= b[j]:\n result.append(a[i])\n i += 1\n else:\n result.append(b[j])\n j += 1\n result.extend(a[i:])\n result.extend(b[j:])\n return result\n```",
"reasoning_content": "",
"tool_calls": [],
"request_md5": "d08bab610e8fdd2ee686e5c4e552f0a9",
"atem_leak": false,
"prompt_md5": "43ca0d15712d3dfb777b51ae76d8fd5f",
"expected_substrings": [],
"retrieval_missing": []
},
{
"request_id": "chatcmpl-3051470-3",
"ctx": 55,
"cached": 0,
"gen": 349,
"finish": "stop",
"think_words": 0,
"ans_words": 163,
"prefill_ms": 128.8,
"prefill_tok_s": 427.1,
"decode_tok_s": 211.4,
"decode_estimated": false,
"tau": 9.91,
"cycles": 32,
"dflash": true,
"mtp": null,
"mtp_ngram": null,
"ngram_mod_windows": null,
"ngram_mod_drafts": null,
"ngram_mod_accepted": null,
"ngram_mod_accept_rate": null,
"mtp_windows": null,
"ar_windows": null,
"mtp_retired": null,
"mtp_window_timings": null,
"ttft_s": 0.133,
"wall_s": 1.784,
"attractor": false,
"empty": false,
"runaway": false,
"ans_preview": "To find the total distance traveled by the train, we need to calculate the distance for ea",
"assistant_content": "To find the total distance traveled by the train, we need to calculate the distance for each segment of the trip separately and then add them together.\n\nThe formula for distance is:\n$$ \text{Distance} = \text{Speed} \times \text{Time} $$\n\n### Step 1: Calculate the distance of the first segment\n* Speed: 60 mph\n* Time: 2.5 hours\n\n$$ \text{Distance}_1 = 60 \, \text{mph} \times 2.5 \, \text{hours} $$\n$$ \text{Distance}_1 = 150 \, \text{miles} $$\n\n### Step 2: Calculate the distance of the second segment\n* Speed: 40 mph\n* Time: 1.5 hours\n\n$$ \text{Distance}_2 = 40 \, \text{mph} \times 1.5 \, \text{hours} $$\n$$ \text{Distance}_2 = 60 \, \text{miles} $$\n\n### Step 3: Calculate the total distance\nAdd the distances from both segments:\n\n$$ \text{Total Distance} = \text{Distance}_1 + \text{Distance}_2 $$\n$$ \text{Total Distance} = 150 \, \text{miles} + 60 \, \text{miles} $$\n$$ \text{Total Distance} = 210 \, \text{miles} $$\n\n### Final Answer\nThe train traveled a total of 210 miles.",
"content": "To find the total distance traveled by the train, we need to calculate the distance for each segment of the trip separately and then add them together.\n\nThe formula for distance is:\n$$ \text{Distance} = \text{Speed} \times \text{Time} $$\n\n### Step 1: Calculate the distance of the first segment\n* Speed: 60 mph\n* Time: 2.5 hours\n\n$$ \text{Distance}_1 = 60 \, \text{mph} \times 2.5 \, \text{hours} $$\n$$ \text{Distance}_1 = 150 \, \text{miles} $$\n\n### Step 2: Calculate the distance of the second segment\n* Speed: 40 mph\n* Time: 1.5 hours\n\n$$ \text{Distance}_2 = 40 \, \text{mph} \times 1.5 \, \text{hours} $$\n$$ \text{Distance}_2 = 60 \, \text{miles} $$\n\n### Step 3: Calculate the total distance\nAdd the distances from both segments:\n\n$$ \text{Total Distance} = \text{Distance}_1 + \text{Distance}_2 $$\n$$ \text{Total Distance} = 150 \, \text{miles} + 60 \, \text{miles} $$\n$$ \text{Total Distance} = 210 \, \text{miles} $$\n\n### Final Answer\nThe train traveled a total of 210 miles.",
"reasoning_content": "",
"tool_calls": [],
"request_md5": "5e33db09f8777ee5d9abe169966c9ef5",
"atem_leak": false,
"prompt_md5": "640e0fd4f55996cb175a422f0a12cef5",
"expected_substrings": [],
"retrieval_missing": []
},
{
"request_id": "chatcmpl-3051470-5",
"ctx": 25,
"cached": 0,
"gen": 75,
"finish": "stop",
"think_words": 0,
"ans_words": 63,
"prefill_ms": 82.5,
"prefill_tok_s": 303.2,
"decode_tok_s": 72.9,
"decode_estimated": false,
"tau": 2.75,
"cycles": 20,
"dflash": true,
"mtp": null,
"mtp_ngram": null,
"ngram_mod_windows": null,
"ngram_mod_drafts": null,
"ngram_mod_accepted": null,
"ngram_mod_accept_rate": null,
"mtp_windows": null,
"ar_windows": null,
"mtp_retired": null,
"mtp_window_timings": null,
"ttft_s": 0.086,
"wall_s": 1.115,
"attractor": false,
"empty": false,
"runaway": false,
"ans_preview": "The primary cause of Earth's seasons is the tilt of its rotational axis relative to its or",
"assistant_content": "The primary cause of Earth's seasons is the tilt of its rotational axis relative to its orbital plane around the Sun. As Earth orbits the Sun, this tilt causes different hemispheres to receive varying amounts of direct sunlight and daylight hours throughout the year. When a hemisphere is tilted toward the Sun, it experiences summer, while the opposite hemisphere, tilted away, experiences winter.",
"content": "The primary cause of Earth's seasons is the tilt of its rotational axis relative to its orbital plane around the Sun. As Earth orbits the Sun, this tilt causes different hemispheres to receive varying amounts of direct sunlight and daylight hours throughout the year. When a hemisphere is tilted toward the Sun, it experiences summer, while the opposite hemisphere, tilted away, experiences winter.",
"reasoning_content": "",
"tool_calls": [],
"request_md5": "e785b5c79b5b3b28228b609164e8a3fe",
"atem_leak": false,
"prompt_md5": "8f66b4c97988825bd8e7840aaf44357e",
"expected_substrings": [],
"retrieval_missing": []
},
{
"request_id": "chatcmpl-3051470-7",
"ctx": 33,
"cached": 0,
"gen": 156,
"finish": "stop",
"think_words": 0,
"ans_words": 124,
"prefill_ms": 104.3,
"prefill_tok_s": 316.4,
"decode_tok_s": 50.2,
"decode_estimated": false,
"tau": 1.52,
"cycles": 62,
"dflash": true,
"mtp": null,
"mtp_ngram": null,
"ngram_mod_windows": null,
"ngram_mod_drafts": null,
"ngram_mod_accepted": null,
"ngram_mod_accept_rate": null,
"mtp_windows": null,
"ar_windows": null,
"mtp_retired": null,
"mtp_window_timings": null,
"ttft_s": 0.108,
"wall_s": 3.213,
"attractor": false,
"empty": false,
"runaway": false,
"ans_preview": "Elias wiped the salt spray from his goggles, expecting only the usual debris of driftwood ",
"assistant_content": "Elias wiped the salt spray from his goggles, expecting only the usual debris of driftwood and broken glass, but instead, he spotted a sleek, metallic pod half-buried in the wet stones. Curiosity overriding his caution, he pried open the heavy hatch to find not a shipwrecked sailor, but a small, glowing creature with eyes like polished obsidian. The being looked up at him, chirping a sound that seemed to resonate with the rhythm of the crashing waves, and for a moment, the isolation of the lighthouse felt less like a prison and more like a sanctuary. As the sun dipped below the horizon, Elias carefully lifted the strange visitor into his coat, deciding that his nightly routine would now include a new, luminous companion.",
"content": "Elias wiped the salt spray from his goggles, expecting only the usual debris of driftwood and broken glass, but instead, he spotted a sleek, metallic pod half-buried in the wet stones. Curiosity overriding his caution, he pried open the heavy hatch to find not a shipwrecked sailor, but a small, glowing creature with eyes like polished obsidian. The being looked up at him, chirping a sound that seemed to resonate with the rhythm of the crashing waves, and for a moment, the isolation of the lighthouse felt less like a prison and more like a sanctuary. As the sun dipped below the horizon, Elias carefully lifted the strange visitor into his coat, deciding that his nightly routine would now include a new, luminous companion.",
"reasoning_content": "",
"tool_calls": [],
"request_md5": "f5fcd4804f9dd8c3d3b0b25dd6766d5d",
"atem_leak": false,
"prompt_md5": "8fe0ad36f61bcf4992cc9df81cdf3817",
"expected_substrings": [],
"retrieval_missing": []
},
{
"request_id": "chatcmpl-3051470-9",
"ctx": 31,
"cached": 0,
"gen": 79,
"finish": "stop",
"think_words": 0,
"ans_words": 54,
"prefill_ms": 85.2,
"prefill_tok_s": 364.0,
"decode_tok_s": 76.7,
"decode_estimated": false,
"tau": 2.95,
"cycles": 20,
"dflash": true,
"mtp": null,
"mtp_ngram": null,
"ngram_mod_windows": null,
"ngram_mod_drafts": null,
"ngram_mod_accepted": null,
"ngram_mod_accept_rate": null,
"mtp_windows": null,
"ar_windows": null,
"mtp_retired": null,
"mtp_window_timings": null,
"ttft_s": 0.089,
"wall_s": 1.119,
"attractor": false,
"empty": false,
"runaway": false,
"ans_preview": "1. Write descriptive, self-documenting variable and function names.\n2. Keep functions smal",
"assistant_content": "1. Write descriptive, self-documenting variable and function names.\n2. Keep functions small and focused on a single responsibility.\n3. Avoid duplicating logic by adhering to the DRY (Don't Repeat Yourself) principle.\n4. Write comprehensive unit tests to ensure code reliability and ease refactoring.\n5. Maintain consistent code style and formatting across the entire project.",
"content": "1. Write descriptive, self-documenting variable and function names.\n2. Keep functions small and focused on a single responsibility.\n3. Avoid duplicating logic by adhering to the DRY (Don't Repeat Yourself) principle.\n4. Write comprehensive unit tests to ensure code reliability and ease refactoring.\n5. Maintain consistent code style and formatting across the entire project.",
"reasoning_content": "",
"tool_calls": [],
"request_md5": "331d42ec04bcbfb438410aa1f5e6e7e5",
"atem_leak": false,
"prompt_md5": "8bed8e2d056dc1d47dccae9d32dbecf4",
"expected_substrings": [],
"retrieval_missing": []
}
]

@Kaden-Schutt

Copy link
Copy Markdown
Collaborator

Independent re-measurement (maintainer review)

Reproduced the long-context A/B on a second R9700 (exact gfx1201, HIP 7.15) with the PR's recipe — Q8 VMM KV, max_seq=65536, DFlash with the pinned mq4v2 draft (sha256 d0a74a23…), HIPFIRE_VERIFY_GRAPH=0, greedy, 200 output tokens, one unrecorded warmup, fresh process per sample. HIPFIRE_DFLASH_WINDOW / HIPFIRE_DFLASH_CTX_CAP unset, so the draft loads at its declared W=2048 (all-layers sliding), matching the PR's implicit configuration. Prompt benchmarks/prompts/qwen38_issue693_longcode_20676.txt, md5 b4d0b63cddcac872648ddf3cdd92cac2, 21,550 tokens. Candidate is this PR merged onto current beta (5c6db516b), plus a pending review change that also excludes the route during retained/PM4 recording (inert on this path).

Order ar, off, on, on, off, off, on, ar, ar — the PR's declared order with three AR anchors (--spec off) added.

arm decode tok/s (samples) median τ / cycles
AR, no draft (--spec off) 32.6, 32.6, 32.6 32.6 —
DFlash, existing batched route (HIPFIRE_FA_PERTOKEN_MIN_CTX=0) 26.4, 26.3, 26.3 26.3 1.80 / 71
DFlash, R4/R8 multi-row route (=4096, default) 39.3, 39.3, 39.3 39.3 1.80 / 71
  • on vs off: +49.4% (PR: +37.6% from 23.7→32.6). Direction and draft behaviour (τ 1.80, 71 cycles) reproduce exactly; absolute rates are higher on both arms on this host.
  • Disclosure the PR body omits, and a known defect we should state plainly: at 21.5K context, DFlash on the existing batched route is a 19% regression vs. plain AR (26.3 vs 32.6). The "+37.6%" baseline is slower than not speculating at all. The honest framing of this change is that it takes long-context DFlash on gfx1201 from a net loss to a +20.6% net win over AR (39.3 vs 32.6). Please update the summary and the perf-checkpoint to carry the AR anchor.

Coherence (VALIDATION.md serve route, product path): scripts/serve_harness.py --mode session on benchmarks/prompts/session_coding.json (md5 c0d470288bde3f1e54e4bba04da8f8a2), route on, max_seq=131072, registry sampling (T=1.0, xhigh, uncapped think), seed 7. 8/8 turns finished at stop, contexts 7.1K→36.9K (all above the 4096 threshold, 16-row verify batches), prefix cache hit on every turn (cached 7134/14601/21262/25898/32166/33107/36818), zero empty/runaway/attractor, decoded text read and on-task. The harness's literal-substring retrieval gate flagged dedupe absent on t7/t8 — the model named its functions hash_file/find_duplicates; not a coherence failure.

Identities: target sha256 9f91556f…eeb7; hipfire md5 80d89b280a57ecbd5eb1e32e1683e306; daemon md5 6e0e62f447f3f25e3a4a45637ff19d96.

Merge order is being decided alongside #755; this comment is measurement, not disposition.

@Kaden-Schutt
Kaden-Schutt merged commit 5c6db51 into warpfront:beta Sep 13, 2026
6 of 7 checks passed
Kaden-Schutt added a commit that referenced this pull request Sep 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants