Skip to content

HIP: refuse --drafter until the engine runs DFlash2 - #1044

Open
ThinkOffApp wants to merge 5 commits into
ashhart:mainfrom
ThinkOffApp:hip-refuses-drafter
Open

ThinkOffApp wants to merge 5 commits into
ashhart:mainfrom
ThinkOffApp:hip-refuses-drafter

Conversation

@ThinkOffApp

Copy link
Copy Markdown
Contributor

For #1001 (1.1.1). Branch ThinkOffApp:hip-refuses-drafter, on main at 76aafcf2. One commit.

What and why

The HIP server accepted --drafter and then did not use it. Qwen3.8-27B ran at about 12.9 tok/s on gfx1151 with DFlash2 and without it, and the receipt could not say whether a drafter had run. Issue #1001 asks for a clear refusal until HIP supports it. On main the HIP engine still has no DFlash2 path: nothing under zig/src/hip* or the Qwen3.5 HIP backend reads Open.drafter. Its own MTP-head drafting (--mtp-drafts) is separate, and this PR does not change it.

  • serve --drafter on HIP is refused before anything loads, on every rank: --drafter: the HIP engine runs no DFlash2 drafter yet; serve without --drafter. The check is first in checkGroup (zig/src/native/hip.zig), which ready() runs before the device, the policy or the group, so a follower rank refuses too.
  • tensorfold benchmark on rocm refuses a named --drafter before any serve child starts: --drafter: the HIP engine runs no DFlash2 drafter yet, so a rocm run takes none; --drafter none runs without it. Nothing is saved, and no .tensorfold directory is made.
  • --drafter auto on rocm passes no drafter. On a checkpoint with its own drafter, such as Qwen3.8-27B, the run says This run passes no drafter: the HIP engine runs no DFlash2 drafter yet., so the receipt's drafter_repo_id is null. On mlx and cuda, auto works as before.
  • Docs: docs/community-benchmarks.md (the --drafter paragraph) and docs/recipes/qwen3.8-27b.md.

When HIP gets DFlash2, removing the refusal line and the rocm case in autoDrafter brings back the old flow. The tests below will then fail on purpose, as a reminder to replace them with tests that the drafter runs.

Tests

Host tests on an M-series Mac, CPU only, Zig 0.17.0, zig build test -Dcpu=apple_m1 --summary all:

Tree Build steps Server unit tests HIP native host tests (zig/src/native/hip.zig)
main 76aafcf2 292/292; 4305 of 4321 passed, 16 skipped 428 3
this branch 920d1348 292/292, all passed 429 (+1) 4 (+1)

Full count on this branch: 4308 of 4324, with the same 16 skips. The server binary runs twice in zig build test. All three PRs for #1001 also build and pass together on one merged tree.

  • hip.test."--drafter is refused before any load, on every rank, until the HIP engine runs a drafter": rank 0, and a follower (--tp 2 --rank 1), are both refused with the message.
  • benchmark_run_test."a rocm run refuses a named --drafter before any serve child, and auto names no drafter on rocm": a repo ID and a directory as --drafter both exit 1 with the message. The fake server gets no request, and no pid file, args file or .tensorfold directory is made. autoDrafter names DFlash2 on cuda and none on rocm or with --serial.

Negative controls. With the checkGroup line removed, the HIP test fails. With the benchmark refusal and the rocm case in autoDrafter removed, the benchmark test fails in both server test binaries. With them back, all tests pass.

GPU receipts

Measured on 18 Oct 2026 on a Bosgame M5 (AMD Ryzen AI MAX+ 395, Radeon 8060S, gfx1151). The source was main 76aafcf2 with the three #1001 branches merged (5906a3f7, 920d1348, 1b4b2d7b; merge 7b84f909), built with zig build native-hip -Dhip-arch=gfx1151 ... -Doptimize=ReleaseFast, Zig 0.17.0. tensorfold-native sha256 e279e29a54b56dc81ff70985f8c4cffaa0d9aff4a7456a234eb7247667492247. Checkpoints were pulled into the Hugging Face cache at pinned revisions: TensorFold/Qwen3.8-27B-MLX-4bit@70ae7fac... and TensorFold/Qwen3.6-35B-A3B-MLX-4bit-MTP@f84b054c.... z-lab/Qwen3.8-27B-DFlash2 is cached at 50307d4c.... The machine's own LLM service was stopped for the run.

Command Exit What happened
tensorfold-native benchmark TensorFold/Qwen3.8-27B-MLX-4bit --drafter z-lab/Qwen3.8-27B-DFlash2 --output ... 1 tensorfold benchmark: --drafter: the HIP engine runs no DFlash2 drafter yet, so a rocm run takes none; --drafter none runs without it. No receipt was written.
tensorfold-native serve TensorFold/Qwen3.8-27B-MLX-4bit --backend rocm --host 127.0.0.1 --port 8093 --drafter z-lab/Qwen3.8-27B-DFlash2 1 tensorfold: --drafter: the HIP engine runs no DFlash2 drafter yet; serve without --drafter. GPU memory in use was 1,129,906,176 bytes before and 1,129,861,120 after, and both commands finished within the same second. Nothing loaded.
tensorfold-native benchmark TensorFold/Qwen3.8-27B-MLX-4bit (--drafter auto, DFlash2 cached) 0 The run printed This run passes no drafter: the HIP engine runs no DFlash2 drafter yet. The receipt has drafter_repo_id: null, and all 20 attempts were ok (8 m 43 s).

A finding about the earlier gfx1151 report in #1001. The draft counts from the draft-counts PR show that the 27B does draft on HIP, with its own MTP head: 262 tokens drafted and 70 accepted (27%) over the 20 attempts. The HIP policy line is mtp drafts 3 under 0.3, and the checkpoint's config has mtp_num_hidden_layers: 1. So in the earlier 1.0.12 runs "with and without DFlash2", both runs were MTP-drafted and --drafter was ignored. That explains why the timings were equal. It also differs from the pinned gfx1151 receipt (docs/receipts/gfx1151-qwen-833bbfcb), which describes the 27B as having no draft head. We have not looked into why.

Full local receipts and logs (27b-auto.*, 27b-dflash2.log, 27b-serve-drafter.log, the run log with GPU-memory stamps), with SHA-256 sums. They can be attached on request.

The HIP server took --drafter and ignored it: Qwen3.8-27B ran at the same
speed with and without DFlash2 on gfx1151, and the receipt could not say
whether a drafter ran. serve --drafter on HIP is now refused on every rank
before anything loads. tensorfold benchmark on rocm refuses a named --drafter
before it starts, and --drafter auto passes none there and says so, so the
receipt's drafter_repo_id is null.
@ashhart

ashhart commented Oct 18, 2026

Copy link
Copy Markdown
Owner

Thanks @ThinkOffApp; we've reviewed this draft early. The constant refusal reaches both ranks before loading, and the benchmark's named-drafter refusal precedes starting a server. Please change the recipe's “decodes plain”: refusing external DFlash2 still permits the engine's own MTP head. Please attach the negative controls and the refusal logs described in the body so we can check the single diagnostic and before-load behavior on our 1.1.2 build. We'll carry this in 1.1.2 after that correction and our gates.

Posted by Ash's AI Assistant Synthena

The recipe said a HIP serve refuses --drafter and decodes plain. It does not
decode plain: the HIP engine still drafts with the model's MTP head where the
checkpoint has one, and with copies from the stream's own context. The 27B
checkpoint has no MTP head, so on HIP it drafts copies only. The recipe and the
benchmark docs now say so, and name the switches: --mtp-drafts 0 turns off the
MTP head alone, --no-drafts (or benchmark --serial) turns both off. The HIP
test names DFlash2 rather than any drafter.
…ost controls

The gfx1151 run's refusal logs for serve --drafter and benchmark --drafter, each
one line, with the run log that times both inside one second and the script that
produced them. The default run's receipt and draft counts show the 27B still
drafting on HIP with copies, since its checkpoint has no MTP head. Three host
controls take out the serve refusal, the benchmark refusal and the rocm case in
autoDrafter: each fails its test; the restored tree passes 4308 of 4324 with 16
skipped. Sanitized copies: home directories written ~, the box user unnamed.
…--mtp-drafts 0 leaves loaded

The control patches and logs are verbatim tool output, and a patch's context lines must keep
their trailing space to apply, so host-controls/.gitattributes exempts them from git's
whitespace check (the desktop job runs git diff --check over the PR). The README and recipe
now say --mtp-drafts 0 stops the head's drafts while the head still loads, where the engine
looks for a head, and that the benchmark banner is lines 381-382.
@ashhart ashhart mentioned this pull request Oct 19, 2026
@ThinkOffApp

Copy link
Copy Markdown
Contributor Author

Thanks for the review @ashhart . The branch now has three more commits.

Wording: the recipe no longer says the HIP run decodes plain. docs/recipes/qwen3.8-27b.md says serve --drafter is refused before the engine opens the GPU or loads any weights, and that this does not turn off the engine's own drafts: the model's MTP head where the checkpoint has one, and copies from the stream's own context. --mtp-drafts 0 stops the MTP head's drafts alone; --no-drafts turns both off and decodes plain. docs/community-benchmarks.md says a ROCm tensorfold benchmark without a drafter still drafts this way, and that --serial gives a plain run. The HIP test now says "until the HIP engine runs DFlash2". No runtime code changed.

A correction to our description: Qwen3.8-27B at 70ae7fac has no MTP head. Its config says mtp_num_hidden_layers: 1, which we misread as a head, but none of the 2,180 tensors in its index is an mtp tensor, and the HIP engine looks for the tensors, not that field. The 1.0.12 model check reports no draft head. The 262 drafted tokens in the default run were copy drafts, not MTP drafts.

Receipts are in docs/receipts/hip-refuses-drafter/: the two one-line refusal logs, the run log showing both refusals within the same second, the default run's receipt and draft counts, and three host controls (removing the serve refusal, the benchmark refusal, or the rocm case in autoDrafter each makes its test fail) with the restored run. With everything restored the host tests pass: 292 of 292 build steps, 4308 of 4324 tests, 16 skipped (Zig 0.17.0, CPU only). The files are sanitized copies with home paths written as ~, and SHA256SUMS covers every file.

The zig-windows check fails in zig/src/core/digest_key.zig:34 and zig/src/server/speech.zig:279, which this PR does not touch.

ThinkOffApp added a commit to ThinkOffApp/TensorFold that referenced this pull request Oct 19, 2026
… branches merged

The run offered on ashhart#1001, made after the fixes: main 76aafcf with ashhart#1043 (c949cc9),
ashhart#1044 (f2c78ee) and this branch (134a5f4) merged on the box and built for gfx1151.
R1 to R5 repeat the 18 October set; R6 repeats R3 with HIP_VISIBLE_DEVICES=0.

Every receipt names the CPU, the one GPU and the checkpoint; every run's counts match its
printed line, and R5's 20 samples match the server's own log lines, while a count off by
one and a log read one request out of step are refused. Both --drafter calls are refused
before any weights load. The board's validator refuses each receipt as rocm and accepts
it as cuda, as on 18 October.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ThinkOffApp added a commit to ThinkOffApp/TensorFold that referenced this pull request Oct 19, 2026
… branches merged

The run offered on ashhart#1001, made after the fixes: main 76aafcf with ashhart#1043 (c949cc9),
ashhart#1044 (f2c78ee) and this branch (134a5f4) merged on the box and built for gfx1151.
R1 to R5 repeat the 18 October set; R6 repeats R3 with HIP_VISIBLE_DEVICES=0.

Every receipt names the CPU, the one GPU and the checkpoint; every run's counts match its
printed line, and R5's 20 samples match the server's own log lines, while a count off by
one and a log read one request out of step are refused. Both --drafter calls are refused
before any weights load. The board's validator refuses each receipt as rocm and accepts
it as cuda, as on 18 October.
@ThinkOffApp

Copy link
Copy Markdown
Contributor Author

Commits rewritten only to drop tool trailer lines (CONTRIBUTING); every tree is unchanged. Old to new: 920d134 e86a138, 172d008 7ec02a2, 43125a8 1e5ce3e, 0a45f1f 60eb261, f2c78ee 73f50ff.

@ThinkOffApp
ThinkOffApp marked this pull request as ready for review October 19, 2026 20:36
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