Skip to content

[GDN] Write spec conv-state from registers instead of epilogue roll - #551

Open
CySpiegel wants to merge 1 commit into
vllm-project:mainfrom
CySpiegel:gdn-conv-spec-register-writeback
Open

[GDN] Write spec conv-state from registers instead of epilogue roll#551
CySpiegel wants to merge 1 commit into
vllm-project:mainfrom
CySpiegel:gdn-conv-spec-register-writeback

Conversation

@CySpiegel

Copy link
Copy Markdown

Purpose

#544 introduced the sliding-window conv-state convention for the spec-decode causal_conv1d kernel. Its epilogue rebuilds the state line in place after the main loop: an aliased same-pointer shift (which blocks vectorization), a runtime-bounded loop with a per-iteration branch, and K redundant global re-reads of mixed_qkvz.

This PR removes the epilogue entirely. The rolled state's history rows equal the priming window's register slots [1, Width-1), so they are written back immediately after priming (compile-time unrolled, write-only, no aliasing); each draft input is stored to its rolled-state row from the register at load time. State content is bit-identical by construction: history rows are the same values read at priming, and draft rows use the identical mixed_qkvz indexing expression the epilogue read. Edge cases preserved: Width==1 skip, pad-slot skip, num_spec_tokens==1, num_accepted clamp.

Test Plan

  • pytest tests/gdn_attn on BMG hardware (2x Arc B70, oneAPI 2026.0), full scope.
  • benchmark/benchmark_causal_conv1d.py spec workloads, before/after.
  • End-to-end MTP serving (Qwen3.5-class GDN model, TP=2, num_speculative_tokens=1).

Test Result

  • tests/gdn_attn: 1303 passed / 0 failed / 128 skipped — identical to pre-change baseline, including the [GDN] Fix token-indexed conv-state layout in causal_conv1d spec-decode kernel #544 boundary-crossing conv-state tests, the mixed spec/non-spec batch tests, and a bitwise mixed-batch differential. (Run with this change applied atop a fork of current main; the diff is confined to causal_conv1d_spec_kernel.)
  • Microbench spec workloads (bf16, 30 iters): -1% to -4% latency on Qwen3-Next-80B shapes, up to -11% on synthetic shapes; no regression outside noise on any shape.
  • End-to-end MTP serving TPOT: neutral — the kernel is ~64-72 us/call, so this is a codegen/traffic cleanup at kernel level, not an end-to-end win.

Related work

Open PR #476 also optimizes this file (load/store vectorization, batch-id binary search) but targets the pre-#544 version of this function and does not address the epilogue roll. The changes are complementary; happy to coordinate rebase order.


AI-assisted change (Claude Code); reviewed, tested, and submitted by a human.

🤖 Generated with Claude Code

https://claude.ai/code/session_016G7BGjSYFhwRoAFxY7N76a

The vllm-project#544 epilogue rebuilt the state line in place: an aliased same-pointer
shift, a runtime-bounded loop with a per-iteration branch, and K redundant
global re-reads of mixed_qkvz. The rolled state's history rows equal the
priming window's register slots [1, Width-1), and each draft input passes
through a register at load time — write both from registers and drop the
epilogue. State content is bit-identical by construction.

tests/gdn_attn: 1303/0/128 (unchanged, incl. vllm-project#544 boundary tests and the
bitwise mixed-batch differential). benchmark_causal_conv1d spec workloads:
-1..-4% real shapes, to -11% synthetic; end-to-end neutral (~64-72us/call
kernel).

Assisted-by: Claude Code (Claude Fable 5)
Signed-off-by: CySpiegel <56271906+CySpiegel@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016G7BGjSYFhwRoAFxY7N76a
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.

1 participant