Skip to content

Qwen3.8-27B serving line: full-precision adoption, captured block-draft speculation, small-M and state-stash tiers - #175

Open
LiangSu8899 wants to merge 44 commits into
feat/hf-kernels-structuresfrom
feat/qwen38-27b
Open

Qwen3.8-27B serving line: full-precision adoption, captured block-draft speculation, small-M and state-stash tiers#175
LiangSu8899 wants to merge 44 commits into
feat/hf-kernels-structuresfrom
feat/qwen38-27b

Conversation

@LiangSu8899

@LiangSu8899 LiangSu8899 commented Aug 15, 2026

Copy link
Copy Markdown
Member

What this adds

Additive serving line for the Qwen3.8-27B host (Qwen3.5 backbone, 48 gated-delta + 16 full-attention layers), in three layers:

Adoption. quantize_on_adopt gains the linear_proj_nvfp4 format: full-precision dense projections pack to the hub NVFP4 layout on adoption, with structural guards (gated-delta layers stay with their own scheme, vocabulary projections are refused by embedding-signature match) and a retained report for every refusal. CPU contract tests included.

Speculation. decode_loop gains a block-draft (DFlash/DSpark family) member, attached via enable_dspark(draft_dir). The round rides the loop's existing graph families: the draft forward is one captured graph (static context K/V, serial Markov head unrolled on device, verify-input assembly in-graph), the gamma+1 verify captures with the gated-delta state snapshot at its head, and rejection rolls back by selection — the verify pass stashes the carried state after every row, so the re-advance graphs reduce to a fixed set of copies. One host sync per round. The draft's attention runs on the vendored fa2 seqused entry (device-side valid-K length, replay-adaptive); draft weights stay bf16 by measurement — both W4A4 and W8A8 arms cost more acceptance than they save and remain env-gated.

Kernel tiers. Two additive native kernels with in-tree bit-exactness checks, mirrored to the kernels repo:

  • a multi-row (M<=16) warp-split NVFP4 GEMM tier over the interleaved-B layout — the 16x8x64 block-scaled atom already computes a 16-row tile, so all rows ride one weight stream at near-GEMV cost;
  • a per-row state-stash arm of the gated-delta from-conv chunk core — stash row s is bit-equal to the final state a re-advance over rows 0..s would store.

The structures layer resolves every tier capability-first: hub artifact, then the local native build, with the tiled/scalar entries always the floor. The whole-prompt WY chain now takes the wmma Gram tier and M>=512 prefill slabs take the cooperative 256-tile tier where the installed artifact carries them.

Measured — standalone decode loop line (RTX 5090)

This line serves the full-precision BF16 checkpoint
(Qwen/Qwen3.8-27B, 52 GB) and quantizes at load time — a different
starting point from the engine adapters below, which adopt the
pre-quantized checkpoint. All rows are from one fresh re-measurement
window, full production form (graphs + compiled step + fused-FFN and
norm-quant producer knives), gates green unless noted:

measured
eager host baseline 20.7–24.6 tok/s
plain loop, short bucket 81.5 tok/s steady, TTFT 35.6 ms
plain loop, 2K bucket 67.5 tok/s steady, TTFT 146.4 ms
+ MTP member, K=6 AL 4.80 (bit-identical to the archived receipt), 120.8 tok/s end-to-end incl. prefill — gates ALL PASS
load-time quantize vs eager 2.06–2.11x end-to-end
rejection rollback 0.27–0.39 ms (by selection, one sync per round)

One open case rides the 2K bucket (teacher-forced agreement 0.936
against a 0.95 gate — the archived balance-band item; it reproduces
exactly, so it is an old open case, not a fresh regression). The
block-draft member's copy-stream and 20K-edit receipts are withheld
until their gate is repaired (it currently fails on a stream-capture
error after the tree moved); re-measured numbers will replace this
note.

Gates: repeat chains bitwise-identical across calls at every stage; the multi-row tier is bit-exact against per-row GEMV across all projection families and M in {2,4,7,8} through the production activation quantizer; the stash rows are bit-exact against prefix re-advance at the kernel level; speculative streams anchor on the loop's own verify.

Companion kernel-package PR: flashrt-project/FlashRT-HF-kernels#11.


Serving-engine adapters (vLLM / SGLang)

Second wave on this branch: the structures layer attaches inside a
serving engine
— no fork, no model conversion, one hook installed
before weight load.

How to read these numbers — a fairness note, not a benchmark
claim.
The vLLM/SGLang configurations measured below are not an
exhaustive tuning of either engine, so none of this is a community
performance comparison. Baselines use each engine's documented
serving recipe for this model; both engines have knobs outside my
sweep, and the "maximum context" figures reflect their default
memory accounting under these settings. What the numbers do show is
a hot-pluggable, stackable optimization path — what attaching
adds to an engine as configured, reverting to the untouched host
on detach or refusal. This line is a single-author project, and it
exists because vLLM and SGLang are excellent hosts: everything here
runs through their stacks. If a configuration I did not cover
serves these workloads better, I would genuinely like to hear about
it and will update the numbers — the stock-arm tuning attempts are
recorded in docs/serving_engine_attach.md so they can be
checked and improved on. Measured host checkpoint:
RadixArk/Qwen3.8-27B-NVFP4 (+ RadixArk/Qwen3.8-27B-DSpark draft for
SGLang).

  • adapters/vllm_engine — precision tiers over the host's own
    packs (auto adopts NVFP4 zero-copy and carries the checkpoint's
    FP8 rows to W4; mirror stays faithful per position; w8
    weight-only INT8), consume releases every replaced host weight so
    the KV pool grows by that amount, a spec-verify attention seat
    (opt-in) on the paged BF16-Q/FP8-KV kernel, and a small-M Marlin
    relay for the checkpoint's W4A16 head (2.0x the host's tiled head
    kernel at M<=16). The head relay steps aside automatically under
    speculative decode: the MTP draft shares the target's head, and
    relaying one side of that agreement was measured — paired over ten
    prompts — as a systematic acceptance loss.
  • adapters/sglang_engine — the same seat machinery carried
    across the scheduler's spawn boundary via a written
    sitecustomize, with filesystem-direct kernel loading for
    air-gapped serving containers.
  • docs/serving_engine_attach.md — every configuration in its
    measured form, plus the judging protocol the numbers require
    (paired-by-prompt for speculative arms, multi-boot medians at long
    context, real-text prompts with difference-based decode
    measurement).

Decode across contexts (single RTX 5090, real code/text prompts, greedy; paired fresh baselines)

Decode-only tok/s; spec = MTP K=6 (vLLM) / DSpark (SGLang); 32K vLLM
cells are 3-boot medians.

vLLM

arm 2K code 2K text 32K code 32K text
base 71.8 66.1 68.1 70.3
base + MTP 183.9 132.8 129.9 202.8
attach 84.3 84.2 79.4 79.4
attach + MTP 169.7 141.5 ~200 173–193

SGLang

arm 2K code 2K text 32K code 32K text
base 75.2 75.2 71.5 72.6
base + DSpark 143.8 116.1 205.4 118.2
attach 83.4 83.4 78.9 78.9
attach + DSpark 156.7 132.5 200.6 152.0

Without speculation the attached arms win every cell: +13–27%
(vLLM) and +9–11% (SGLang). Speculative decode columns ride
acceptance-length content variance (greedy continuations differ per
arm); judged on step rate — the column content variance cannot touch
— the attached arms hold +9–13% uniformly. The vLLM 2K spec row
is a paired-by-prompt mean over five prompts; at 32K, code lands
+52% and text −5–15% against the fresh baselines above.

Time to first token

vLLM 2K vLLM 32K SGLang 2K SGLang 32K
base 131 ms 3.43 s 0.14 s 3.55 s
attach 104 ms (−21%) 3.05 s (−11%) 0.12 s (−14%) 3.26 s (−8%)

Long context: the ceiling moves, and decode holds

consume turns the released weight memory into KV capacity. On the
32 GB card that is the difference between cannot serve and serves
at full speed
:

stock vLLM attached
max servable context (engine's own sizing) ~102K (4.5 GB free for KV; native 262144 refused at boot) 262144 — the model's native maximum
KV headroom after weights 4.5 GB 10+ GB
200K-token prompt unservable TTFT 67.6 s, then full-speed decode

Decode along the attached engine's context curve (MTP on, real
prompts, acceptance shown because it rides content):

context code tok/s (AL) text tok/s (AL) step rate
32K ~200 (4.9) 173–193 (4.7) ~41 steps/s
60K 274.9 (6.1) 125.4 (2.9) 43–45
120K 198.7 (3.4) 35.1 (1.1)* 32–45
200K 178.3 (4.6) 175.5 (4.1) 39–43

* the 120K text point is a content effect — that stretch of the
corpus is table/number-dense and the draft stops landing; the step
rate column shows the engine itself does not care.

Step rate is essentially flat from 32K to 200K. The stock engine
cannot reach any of these lengths on this card; the attached engine
serves the model's entire native window at 150+ tok/s decode. This is
enablement, not a percentage: a context band that did not exist on
this hardware now runs at full speed, from the released memory alone.

The same story on SGLang (DSpark serving, identical memory
fraction, real code prompts):

context stock server attached server
KV pool (tokens) 34,659 87,128 (2.51x)
32K decode 205.4 tok/s 200.6 tok/s
60K request refused 147.7 tok/s
80K request refused 210.8 tok/s

One multiplier, two engines: the released weight memory scales
whatever context budget the engine's own accounting allows — 102K to
native 262144 on vLLM, 34.7K to 87.1K on SGLang, both about 2.5x
under these configurations. The stock SGLang arm was tuned before this table was written — the
draft card's own flags, a memory-fraction sweep (0.85 / 0.92 / 0.95 /
0.97), CUDA-graph trims, and the hybrid-cache knobs; the full sweep
table is in docs/serving_engine_attach.md. A higher fraction
grows the paper pool to ~56K tokens but 48K requests then fail on
runtime headroom (at both prefill chunk sizes), and neither arm
boots above it — 0.92 is the stable envelope for both arms.
Published higher-context figures for this family come from the model
card's own multi-GPU recipe (tp-size 4); the single-card comparison
above is apples-to-apples, and configurations I missed are welcome.

Speculative memory floors, both engines

The same released memory also carries speculation where the stock
engine is tight: SGLang with the DSpark draft refuses to boot at its
default memory fraction (draft weights leave no room for the KV
pool) and needs 0.90–0.93; the attached engine's freed weights cover
the draft with room to spare.

…bling of the expert-bank door

A checkpoint that ships full-precision linear projections too big for
the card packs each one straight to the Hub NVFP4 layout through the
same seam binder the pre-quantized door uses - no dequant-requant
detour through someone else's grid, and both doors produce the same
executable form. Two families are refused with their reasons on the
receipt: gated-delta state layers belong to their own scheme's packing
and release semantics, and a vocabulary projection is logits-family
precision, an explicit binder decision rather than a bulk side effect.
Native mirrors of the three additive kernel tiers delivered to the hub
packages, plus the harnesses that judge them, so packaging can verify
against this tree directly:

- fp4_w4a4_mma_warpsplit_ilv_sm120: interleaved-B warp-split GEMV and
  its bind-time repack; every block's global B reads become fully
  sequential, 89-91% of the achievable DRAM read roof on the wide
  decode shapes, bit-exact against the base kernel.
- gated_delta_wy_kkt_mma: the WY K*KT chunk as one block per
  (chunk, k-head) with wmma accumulation and group-shared Gram tiles;
  32.8x over the scalar kernel at S=2048, numerics in the bf16
  reduction-order band, same entry surface as the scalar version.
- cutlass_nvfp4_gemm_m256_sm120: 256x128x128 cooperative large-M tier;
  wins every prefill family over the 128-tile baseline. CUTLASS >= 4.5.

csrc/kernels/checks/ carries the three judges: bit-exactness for the
GEMV (including the device repack against a host reference), the
scalar-vs-MMA numeric band and speed for the KKT, and the TFLOPS
receipt for the GEMM tier. Build lines are in each file header.
…irst assembly

One round = one block-draft forward plus one multi-token verify,
replacing the MTP family's per-token draft chain. The draft is a small
full-attention infill network conditioned on auxiliary features tapped
from five target layers (forward pre-hooks over the loop's own passes);
verify and re-advance ride _fwd_full with the GDN snapshot/rollback
idiom, and the static-cache row mask makes cropping unnecessary.

The geometry that survived measurement: the draft emits one logit row
per noise slot including the seed slot - dropping the seed row, as the
draft checkpoint's own reference implementation does, halves the
acceptance length. The Markov bigram head applies sequentially,
anchored at the seed.

First-assembly receipts: deterministic repeat, coherent output,
acceptance length 3.13 at 48 new tokens. Open case on the record:
acceptance thins with generation depth (2.26 at 96) while the text
stays coherent and easy - not stream hardness, not monotonic state
corruption (rounds recover sporadically); the per-round diagnostic
ladder is written up in the working notes. Graph capture of the round
is the planned second stage, as with the MTP member.
The draft forward is one captured graph: static context K/V take the
block's own keys in place, one masked SDPA covers context and block
siblings, and the serial Markov head unrolls on device. The verify
captures with the gated-delta snapshot at its head; re-advance drops to
the state sublayers alone - the verify already committed the accepted
region's KV and carries the bonus logit at the cut - with rollback
captured at each graph's head. One host sync per round (the arbiter),
verify-input assembly rides inside the draft graph.

Real-source coding stream, decode-only, same card and window: 38 -> 86
tok/s at AL 2.9 against the plain loop's 71; the rewrite-heavy stream
95.6 at AL 3.2. Repeat gate green; round profile identical to the
whole-model re-advance form.
The 16x8x64 block-scaled MMA atom already produces a 16-row output
tile; the M=1 interleaved GEMV feeds it one live row and fifteen rows
of zero ballast. This tier feeds up to 16 live rows through the same
atom, same shared-memory plan, same accumulator budget - B stays the
only DRAM-bound stream, so a multi-row call lands near single-GEMV
cost. The spec-verify shapes (M = block + 1, and the shorter re-advance
prefixes) are the customers.

Measured on the wide decode shapes at M=8: 74-80% of the 1690 GB/s
read roof, 5.3-6.0x over M sequential GEMV calls, 1.16-1.37x over the
plain-B multi-row variant (the interleave advantage grows with M), and
~1.3x over the production tile GEMM's 59% at these shapes. Bit-exact
per row against the M=1 interleaved kernel across all shapes, M in
{1,2,4,7,8,16}, and warp configs (in-tree check included). SFA reads
the production 512B-block layout (row r at tile*512 + r*16); B shares
the M=1 entry's bind-time interleave.
2<=M<=16 activations - the spec-verify block and its re-advance
prefixes - dispatch to the native build's multi-row warp-split GEMM
where the local tree carries it: the 16x8x64 block-scaled atom
computes a full 16-row tile, so all rows ride one weight stream. The
pointer-style native entry registers as a torch custom op with a fake
shim, so the compiled multi-row passes trace through it and the call
lands on the capture stream. Per-shape launch config: deeper stages
hide the strided-B latency the extra A-row loads expose.

Layout compatibility is proven at the quantizer, not assumed: the
production activation quantizer's multi-row SFA block feeds the tier
bit-exactly against per-row GEMV calls across every projection family
and M in {2,4,7,8}. Absence of the native build changes nothing - the
tiled GEMM keeps serving every shape.

Same card, same real-source coding stream: verify pass 21.4 -> 18.3ms,
re-advance tiers 4.0-6.0ms, decode-only 86 -> 96.6 tok/s at AL 2.9
against the plain loop's 71.5; repeat gate green, round profile
identical to the tiled-GEMM form.
The draft's dual-source attention moves off SDPA onto the vendored
fa2 seqused entry: the valid-K length (context + block) lives in a
device buffer the kernel reads at run time, so the captured launch
replays each round's window with no mask and no materialised
attention math - the compiled SDPA path was demoting the masked GQA
form to an expand-clone of the whole context window. Registered as a
custom op with a fake shim so the compiled draft graph traces
through it on the capture stream.

Draft projection precision is decided by measurement, not appetite:
W4A4 through the adoption door costs acceptance (2.93 -> 2.79 on the
real-source coding stream) and W8A8 per-tensor costs the same
(2.80) - a 1.4B draft's weight stream is not the binding constraint,
its prediction quality is. bf16 stays the default; both arms remain
behind FRT_DSPARK_DRAFT_QUANT for streams that judge differently.

Same card, same stream: propose graph 6.95 -> 4.12 ms, decode-only
96.6 -> 100.9 tok/s at AL 2.93 against the plain loop's 71.5; draft
tokens identical to the SDPA form round for round, repeat gate
green.
The from-conv chunk core gains a stash arm: identical recurrence,
gating math, and per-row bf16 state requantisation, with the carried
state after each row additionally written to a stash slab. The stash
write IS the carried requantisation, so row s is bit-equal to the
final state a re-advance over rows 0..s would store - proven at the
kernel level against the plain chunk entry across prefix lengths.

A rejected speculative round then rolls back by selection: pick the
stash row at the accepted length, rebuild the conv window from the
snapshot tail plus the stashed raw rows (the epilogue's own
semantics), and touch no projection at all. The re-advance graphs
drop from forty-eight sublayer re-drives to a fixed set of copies:
4.0-6.0ms -> 0.27-0.39ms per shape, while the verify pass pays 0.4ms
for the stash writes.

The fused layer arms the stash eagerly (before any compiled pass
traces) and only where the native build carries the kernel; absent
that, rejected rounds keep the re-drive form. Same card, same
real-source coding stream: decode-only 100.9 -> 116.4 tok/s at AL
2.97 against the plain loop's 71.5; repeat gate green.
Capability probes now prefer the installed artifact and fall back to
the local native build, tiled/scalar entries always the floor:

- linear_proj: the multi-row warp-split tier resolves hub-first
  (fp4_w4a4_gemm_warpsplit_mrows_bf16, a compile-safe torch op) and
  keeps the native custom-op fallback for local builds.
- gated_delta: the per-row stash arm resolves hub-first
  (gdn_chunk_from_conv_smem_stash_bf16); the whole-prompt WY chain
  takes the wmma Gram tier (gdn_wy_kkt_b64_mma_bf16) where the
  artifact carries it - same signature, same A layout, and the
  measured long-prompt Gram term drops off the profile's top set
  (42.1ms -> 1.3ms class at 2K).
- decode_loop: enable_dspark(draft_dir) attaches the block-draft
  speculative runner as a loop member, mirroring enable_mtp.

Real-source coding stream after the Gram swap: prefill at 5.2K drops
~100ms, decode round unchanged at ~25.5ms (AL moves within band with
the prompt-numerics shift), repeat gate green.
M>=512 activations dispatch to nvfp4_gemm_m256_bf16 where the
artifact carries it - the tier wins every measured prefill family
over the base tile, and the wrapper owns its workspace. Absence
changes nothing.

With the Gram swap and this tier together, the 2K prefill wall drops
214.5 -> 164.8 ms on the 27B host; the decode round and the token
stream are unchanged, repeat gate green.
Sibling projections that read the same normed hidden (the attention
q/k/v trio, the MLP gate/up pair) each quantized their input
separately; inductor does not CSE the custom quantize op, so the same
rows were packed up to three times per site. link_shared_producers
hands each sibling group one identity-keyed cell: a seam reuses the
stored quantization only when its input is the very tensor that
produced it, so a fresh activation can never be served stale data.
quantize_on_adopt links the groups after adoption - the checkpoint's
default execution form. Bit-identical by construction; the sharing
contract (functional activations) is documented on the cell.
A one-shot prompt pass over a deep window overruns the card: the
whole-prompt activations, the GQA repeat-expand of the KV heads, and
the full-rows lm_head each materialize window-sized transients. The
loop (and the block-draft runner) now accept prefill_chunk: the prompt
drives the same offset-mask forward in slices, gated-delta state
carrying across slices through the continuation branch the verify
batches already exercise.

Slice attention routes through a compiled flex_attention arm over an
offset-causal block mask (eager flex is the math fallback and
materializes the score matrix; masked GQA SDPA does the same) - the
mask depends only on slice length and start, so a prompt's handful of
masks replay across layers, chunks and runs. The runner's slices take
the last-row head: nothing in a prompt slice consumes the full-rows
logits. Both arms are flag-gated to chunked loops; established
short-window forms keep their exact paths.

The sliced pass is not bitwise-identical to the one-shot form: two
runs of the FP4 pipeline decorrelate at low mantissa bits (measured
slice-vs-oneshot logits cosine equals the arbiter band squared), so
the equivalence contract is the arbiter gate plus continuation
identity, never bit equality.
nvfp4_balance projection format: the same FP4 band with a
per-input-channel balance fitted on calibrated activation amax, plus
calibrate_gdn_channel_amax - the house Collector observing the two
projection inputs over a caller-supplied real forward. A host layer
without attached calibration keeps the BF16 band (counted, never
raised). Schemes w4a4_balance_decode(_release) select the format;
calibration is the caller's precondition.

Measured on this host family: the out-projection seat cuts its
quantization error 2.5x (the in-projection saturates at 1.3x), but
the end-to-end teacher-forced gate is unchanged - the near-tie token
flips are the aggregate of the whole pipeline's quantization noise,
not the projection grid alone. The arm therefore ships as an explicit
opt-in with this receipt, not as a default.
…ill path

Four additive kernels with native bindings: a SwiGLU activation +
NVFP4 quantize producer (quantize stage transcribed from the
production bf16 quantize kernel, bit-exact against the split chain),
a (1+w)-form RMSNorm + NVFP4 quantize producer, a batched 64x64
unit-lower-triangular inverse for the WY chain (column-independent
forward substitution, identity/tril preparation folded in), and a v2
launch plan for the WY norm/pack + gate-cumsum pair (chunk-parallel
cumsum, bit-exact per chunk). Also exposes the interleaved warp-split
GEMV tiers through the native module.
The gate and up seams concatenate into one merged seam (one weight
stream, one launch per tier) and the activation between them collapses
into the fused silu-mul quantize producer, feeding the down projection
its packed FP4 input directly. The projection seam grows a
tier-dispatched packed-input entry and a measured per-shape launch
config for the decode GEMV.
One thread computes 8 consecutive tokens with the taps rolling through
registers, cutting the packaged kernel's K-fold DRAM re-read of every
input element to (STEPS+K-1)/STEPS; the q/k/v channel split folds into
the store. Tap order and fma chain match the packaged kernel.
The triangular solve routes to the native batched unit-lower inverse
(same forward-substitution recurrence as the batched cuBLAS solve,
identity/tril preparation folded in), the norm/pack + gate-cumsum pair
takes the chunk-parallel v2 launch, and the conv update goes through
the GQA-split variants - the step-batched native arm where the build
carries it, the packaged one otherwise. Projection seams now receive
the caller's tensor instead of a view so an upstream producer's
identity-keyed quantization handoff survives the call.
The (1+w)-form norm computes exactly the host norm and quantizes the
same values in one kernel, publishing packed FP4 + SFA through the
identity-keyed share cell its consumer group already honors; the
normed BF16 tensor still flows through the host graph, so a cell miss
just means the consumer quantizes for itself. Decode-width calls keep
the host norm - the group quantize is cheaper there than a standalone
producer launch. Scale-atom tails are zero-filled: unwritten bytes in
a partial 128-row atom were a measured nondeterminism channel.
…rking

Runtime weights in a mixed-precision engine are packed in formats the
seam cannot read as rows, so binding takes its material from the
source checkpoint the engine loaded (fused modules concatenated in the
engine's own order) and gates each seat on a cosine probe against the
host module it replaces. Optional tiers are parked by tracing them
under a fake mode rather than by name, so an artifact that ships the
missing fake impls lights them up with no code change; the gated-delta
dependency pins the version whose build matrix covers the engine's
runtime.
…P seat

A host that compiles a seam forward for a range of row counts hands
the dispatch a symbolic M, so a tier branch would bake in whichever
side the tracing sample took and run it for every replayed shape. Such
callers now take the tiled GEMM, which serves every M; concrete row
counts keep their tiers. The vLLM adapter gains a fused SwiGLU seat:
the host's MLP is already gate_up -> activation -> down, so the three
steps collapse into one seat where the fused activation-quantize
producer is available, and it parks the two row-count-thresholded
tiers this engine cannot replay safely.
The recurrence gives every value column its own thread, so the columns
now spread across blocks instead of tying block width to the 128
columns, and the column state streams in two passes rather than
sitting in a per-thread array the hardware spills to local memory —
2x on the step's own shape, output bit-identical. The gated norm gains
a variant that also emits its consumer's NVFP4 rows: the output
projection is its only consumer and quantizes what it receives, and
the quantizer's blocks tile a head's lanes exactly, so the whole step
fits in the block that produced the row (bit-identical normed rows,
packed bytes and scales alike).
…oducer

The recurrent step routes to the V-split entry where the build carries
it, and the gated norm hands the output projection packed rows
directly instead of writing a row its only consumer re-reads to
quantize. Buffers for the producer arm are allocated before any
capture so the graph records stable addresses, and the norm weight is
copied detached to keep the op off an autograd edge.

Kernel resolution also stops trusting a single release: a version
range now walks the published tags down to its floor and takes the
newest release whose build matrix covers the caller's torch/CUDA pair.
A publisher adding variants release by release can drop a pair an
older release carried, and a resolver too old to read versions lands
on the repo default regardless — either way the range, not one pinned
tag, is what the dependency actually asked for.
The measured win in the streaming rewrite was never the column split —
it was not spilling the state column to local memory. Splitting the
columns across narrower blocks also moved the q/k norms onto a warp
reduction, which changes their fp32 summation order for a further 0.03
ms/step; the block width goes back to 128 so the whole kernel is
bit-identical to the packaged one, state and output alike, and the
step still stops paying DRAM for state it believes is resident.
The band where the fused producer beats the host norm is a property of
what the compiler folded around that norm, not a constant: at decode
width the host path carries the residual add into the same kernel, and
replacing it there costs more than the quantize it saves (measured
+0.13 ms/step). The threshold stays where the measurement put it and
is now nameable, so the next host can be measured rather than assumed.
A resolver that accepts only an exact major still names the majors it
has when it rejects a range, so take the newest one at or above the
floor from that report instead of probing tags downward. The blind
walk stays as the fallback for a resolver that says nothing.
Each of these three kernels now ships in a published package, and the
packaged entries are torch ops carrying fakes — a host that compiles
the call traces them unaided, and a serving process that cannot load
this build's native extension (different torch/CUDA pair) still gets
the fused form instead of falling back to the split chain. The local
build stays as the second source, wrapped as before.
Version resolution walks releases over the network, and every step of
that walk is an unbounded round trip. A host binding a whole model asks
for the same missing package once per seat, so one unpublished build
variant used to cost that walk hundreds of times over, with the engine
silent throughout. Default the hub timeouts (callers that set their own
keep them) and remember resolution failures for the life of the
process: absence is as cacheable as presence and far more expensive to
re-establish.
A host holding a packed checkpoint does not need the regridding entry
and should not pay it: dequantizing someone else's grid and quantizing
it again with ours replaces their calibration with our packer's
rounding, which is a change of model wearing the costume of an
acceleration. bind_proj_seam_packed adopts the e2m1 bytes by reference
(the block-scale relayout is a permutation, it loses nothing) and
carries a checkpoint's per-tensor factor on each tier's alpha, where
the epilogue is already writing the result; the separate pass it
replaces cost a full-size read-modify-write per projection.

Also let the fp8 no-bias form bind the quantize's return value: on the
traced path the persistent out-buffer is None and the returned tensor
is the only handle to the result. The fused silu-mul hub entry sizes
its outputs at the call site for the same tracing reason: the wrapper's
size helper is a custom op without a fake, and a host tracing on Meta
tensors dies inside it.
A mixed-precision checkpoint is a per-projection decision made with
calibration data, and seating every position at the adapter's default
width overrides that decision silently. Read the choice off what the
host actually holds and honour it: positions already in the seam's
width adopt the host's own tensors by reference (no regrid, no second
copy on the card), FP8 positions get a seat on their own storage (the
engine keeps its weight transposed for its cutlass entry, so the
orientation comes from the layer's declaration, and one transposed
swap leaves total memory unchanged), and unquantized positions are
left alone -- a draft model a checkpoint excluded from quantization
stays excluded, because a speculative host pays for numerics in
acceptance length, not in any number a throughput probe reads.

The auto tier adds one opinion on top: a W8 position is carried to W4,
sourced from the host's own FP8 rows (every FP8 code is exact in BF16,
so no external checkpoint is involved), and the attach report says so
in plain text -- the precision change is the caller's to validate.

Staged release of replaced host weights now actually releases them:
the revert closure used to pin the very tensor it was freeing through
a default argument, which is why a consume pass reported the same
bytes freed whether the staging ran or not.
An air-gapped serving container cannot walk the hub at all: the xet
transport ignores the process proxy and hangs, offline resolution
insists on a complete snapshot when the cache holds only the variant
that was ever downloaded, and pinning the resolver library's version
trades one incompatibility for another. FRT_KERNEL_DIR_<REPO> names the
build variant directory directly and imports it as the package it
already is -- exactly what the resolver would do after its network
walk, minus the walk. The arch check still runs; a wrong variant
refuses the same way a resolved one would.
The sglang hook now routes to the same tier assembly the vllm adapter
runs: the two engines share module lineage down to the quant-method
attribute names, so per-position adoption and the auto tier's W8->W4
carry assemble unchanged, and the engine-specific part of that adapter
stays what it was -- the sitecustomize carrier.

Two host behaviours surfaced by the second engine, fixed where they
belong: a projection seat now falls through attribute reads to the
module it replaced (an engine that planned a fusion around the
projection reads scale attributes off the module object, and a seat
answering only forward turned that into a startup crash far from the
seam); and a merged projection carrying one global factor per
constituent refuses adoption under a single alpha unless the factors
agree -- pretending otherwise would scale one half by the other's
factor.
The verify-attention seat routes speculative verify steps through the
paged BF16-Q/FP8-KV kernel behind a full guard ladder: metadata must
be exactly a single-request causal verify batch on a supported layer
geometry, anything else falls through to the host. Page counts come
from a hook on the prefill wrapper's plan (the device buffers hold the
same values, but reading them there is a host sync per layer, which
stalls the launch pipeline for more than the kernel saves), K/V claims
are as_strided views over the raw cache storage (flattening the
permuted cache view silently copies the whole pool), and capture-time
calls are declined so replayed graphs never bake a stale shape.

The head and draft seats are explicit opt-ins rather than defaults:
the seam's row tiers quantize activations to FP4, and on the logits
family and the proposal path that measurably moves speculative
acceptance — the mechanical step-rate win is paid back with interest.
A checkpoint-packed NVFP4 head can be adopted zero-copy behind
FRT_HEAD_W4A4; a BF16 draft can be re-gridded via draft_precision.
Projection seats now honor the host's return_bias so a bare-tensor
call site is answered in kind.
The host forward the verify-attention seat replaces is not just the
attention call — it is also where the step's new K/V rows enter the
paged cache. Taking the call without that write leaves the tokens'
K/V unwritten: the seat's own kernel reads stale slots for them, and
every later step is missing them as prefix, so the damage compounds
for the rest of the sequence. The seat now performs the host's cache
update before running the kernel, and refuses calls that carry fused
output-quant arguments it does not implement.
The head's verify-step calls are M<=16 logits projections, served by
the host on a tiled kernel sized for prefill. The relay adopts the
checkpoint's own NVFP4 pack into the small-M layout at bind time —
same grid, same dequantized values — and routes calls inside the band
there, host method for everything else. Judged across three boots the
step rate moves +7-8% with acceptance unchanged.

The bind receipt compares against an E2M1 table-decode of the
checkpoint's rows rather than the host's apply: the host quantizes
activations on its own path, so an exact relay still reads ~0.92
against it while sitting at 0.999999 against the rows themselves.

A 'w8' precision tier joins the projection binder for the draft
band: per-channel weight-only INT8 from the module's dense rows, the
middle ground between BF16's weight stream and W4's rounding.
The engine's MTP draft shares the target's lm_head, and acceptance is
an agreement test between the two. Relaying only the target's head to
the small-M layout changes one side of that agreement: judged paired
over ten prompts the acceptance length lands lower on all ten (about
-0.5) while the step rate gain is smaller than the loss. With a
speculative config present the relay now defaults off; without one it
remains the head's default, where it is pure step-rate.

The paired-by-prompt protocol is the judging change that surfaced
this: single-prompt greedy runs drift to different continuations per
arm and bury systematic acceptance effects in content variance.
Usage for the engine adapters with every configuration in its
measured form: the load-hook window and precision tiers, the
spec-decode head-relay rule, the explicit-KV long-context recipe,
the SGLang sitecustomize/container bridge with the DSpark memory
floor, and the judging protocol the receipts require (paired-by-
prompt for speculative arms, multi-boot medians at long context,
real-text prompts with difference-based decode measurement).
The bind-or-refuse determinants in one place: SM120 for the sm120a
kernel tiers (elsewhere the seats refuse and the host runs
unmodified), the vLLM/SGLang series the adapters read, the torch/CUDA
build variant the published kernels ship for, and the ModelOpt
mixed-precision checkpoint family the adopt tiers expect — with the
re-grid tiers as the road for dense checkpoints. Records the measured
speculative configuration and the single-stream scope of the
receipts.
Same multiplier, second engine: the stock DSpark server's pool is
34,659 tokens and refuses a 60K request; the attached server's pool
is 87,128 (2.51x) and decodes an 80K real prompt at 210.8 tok/s.
Absolute ceilings differ from vLLM's because the hybrid-state cache
and draft KV price each token higher — the released weight memory
multiplies whichever budget the engine's accounting allows.
The guide now opens with what it is and is not: measured hot-plug
configurations on each engine's documented recipe, not an exhaustive
engine tuning and not a community comparison — the ceiling figures
reflect the engines' default memory accounting under these settings.
Names the measured checkpoints (the ModelOpt mixed-precision
quantization of the 27B host, and the DSpark speculator) so the
receipts are reproducible from the hub. The SGLang long-context
receipt becomes a table with the full curve: pool 34,659 vs 87,128
tokens, the stock refusal at 60K, and 147.7 / 210.8 tok/s decode at
60K / 80K on the attached server.
The comparison now states what was tried before it was written: the
draft model card's own serving flags on both arms, a memory-fraction
sweep (a higher fraction grows the paper pool to ~56K tokens but 48K
requests then fail on runtime headroom, and neither arm boots above
it), CUDA-graph trims, and the hybrid-cache knobs — none of which
move the pool, whose 2.25 GB intermediate state cache is insensitive
to all three. Notes that higher published context figures for this
family come from the card's multi-GPU recipe, keeping the single-card
table apples-to-apples.
The disclaimer now says plainly what is owed: these adapters exist
because both engines are excellent hosts, and better configurations
than ours are welcome — the numbers will be updated for them. The
SGLang stock-arm tuning narrative becomes a checkable table: every
configuration attempted, its pool, and what a long request actually
did, with the paper-pool footnote and the stable-envelope conclusion
the comparison table rests on.
Retitled from a disclaimer to what it actually is — a note on how to
read the numbers fairly: not a community benchmark, an exploration of
what hot-plugging adds to each engine as configured. The voice now
matches the project (single author), and the invitation stands: better
configurations are welcome and the numbers will be updated for them.
The guide gains the zero-code-change path for a stock vllm serve: a
sitecustomize on PYTHONPATH installs the load hook behind an env
gate, with the measured server-side receipts (code +7.5%, text +9%,
TTFT -13% against back-to-back stock boots; the spec-decode head rule
carries over unchanged).

The example is the demo built on it: the same serve command twice,
where the stock boot refuses the model's native 262144 context on a
32 GB card and the attached boot serves it — released weight memory
becoming the KV pool — plus a streaming client with a live decode
meter for asking questions of a 200K-token codebase.
One conversation that keeps growing beats one giant prompt on camera:
with prefix caching on, each turn prefills only its increment, so the
demo keeps a conversational pace while the context meter climbs. The
stock arm dies at its ceiling with the server's own 400 printed as
the crash row; the attached arm walks the same turns to the model's
native maximum. Arms are recorded separately (one card cannot hold
two copies of the weights) and the client prints the same table for
both, so the recordings align turn for turn. The race form runs
without speculative decode, which this vLLM series requires for
prefix caching; the one-shot scenes keep the speculative speed
numbers.
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