[Perf][Hybrid] Vectorize _copy_mamba_state_block to uint64 for temporal - #48110
Merged
Merged
Conversation
tdoublep
reviewed
Jul 13, 2026
The _copy_mamba_state_block copies temporal and conv states using 1 byte load and store, leaving most of the HBM bandwidth on the floor. Temporal states are 20-30x the size of the conv states depending on the model. This commit switches to uint64 loads/stores for the temporal states. MambaSpecDecodeGPUContext now asserts base pointer and block stride are both 8B-aligned at setup. Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com> Co-authored-by: Claude <noreply@anthropic.com>
fuscof-ibm
force-pushed
the
postprocess_vectorize
branch
from
July 17, 2026 17:41
9256ed0 to
731d1ca
Compare
tdoublep
enabled auto-merge (squash)
July 17, 2026 19:32
4 tasks
Closed
7 tasks
4 tasks
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.
Purpose
PR #40172 introduced the postprocess_mamba_fused_kernel in MRV1 to copy states in hybrid models when prefix caching is enabled in align mode (and under MTP). Every accepted draft step that crosses a block boundary triggers a full sweep of
(num_reqs × total_states)state copies — for Qwen/Qwen3.5-9B that's 24 linear-attention layers × (conv + temporal) = 48 state copies per accepted step, ~2 MiB temporal + ~80 KiB conv per block. Temporal states are 20–30× the size of conv states and dominate the copy size.A later PR #42406 refactored the kernel to reuse the copy mechanism, now delegated to the _copy_mamba_state_block to support align mode prefix caching in MRv2.
The current copy body issues 1-byte loads and stores and it is not capable of exploiting the hardware leaving most HBM bandwidth on the floor: the kernel tops out at ~62 % of HBM3 peak on H100 and ~33 % of HBM3e peak on GB200.
This PR switches the temporal-state copy to
uint64loads/stores (8× wider transactions per instruction).bf16/fp16/fp32 temporal states with contiguous inner dims are 8-byte aligned, therefore we can issue
uint64loads/store. To make every issued address safe by construction,MambaSpecDecodeGPUContextnow asserts at setup that the temporal-state base pointer and per-block stride are both 8-byte aligned; so the assert is a cheap guardrail rather than a fallback path. The conv path is untouched.Net effect: the kernel becomes HBM-bandwidth-bound — ~82–84 % of peak on H100 from
reqs≥16and up to ~74 % on GB200 fromreqs≥32. For smaller number of requests (reqs=1–8) is up to ~5.9–6.5× on both H100 and GB200.End-to-end on GB200 with MTP this shows up as +0.75 % / +2.97 % / +1.48 % output throughput and correspondingly lower median and P99 TPOT at concurrencies 32 / 64 / 128, with MTP acceptance unchanged.
Test Plan
Microbenchmark
Developed a microbenchmark harness bench_copy_mamba_state_block.py,
which isolates
_copy_mamba_state_blockbehind a minimal Triton wrapper launched atthe production grid (num_reqs, 48) using Qwen/Qwen3.5-9B's real state layout
(24 linear layers × conv+temporal, tp=1, num_spec=2),
with each request assigned distinct src/dst block ids so L2 can't mask DRAM traffic.
Each request corresponds to 49.88 MiB of copies: 24 temporal (float32) and 24 SD conv (bfloat16).
We sweep the num_req to
{1, 4, 8, 16, 32, 64, 128}using two GPU architectures:End-to-end serving
vllm bench serveagainstvllm servewith MTP and prefix caching enabled (which exercises the state copies):vllm serve \ --model Qwen/Qwen3.5-9B \ -tp 1 -pp 1 -dp 1 \ --language-model-only \ --reasoning-parser qwen3 \ --speculative-config '{"method":"qwen3_next_mtp","num_speculative_tokens":2}' \ --enable-prefix-cachingBenchmark workload:
Workload:
--dataset-name random,INPUT_LEN=500,OUTPUT_LEN=5330,NUM_PROMPTS=500.The workload is chosen to exercise the
_copy_mamba_state_blockwhich happens when a block is crossed.For Qwen3.5-9B the block size is 533. The output length is chosen to be 10x the block size.
Hardware: NVIDIA GB200. Concurrency sweep
{32, 64, 128}. At each concurrency we ran the benchmark 4 times per branch and discarded the 1st run to strip warmup/JIT effects; reported numbers aggregate the remaining 3 runs, with std devs computed as sample std dev (n−1).Branches compared:
main—4e5ca89cpostprocess_vectorize—9256ed051Test Result
Microbenchmarks raw results
microbenchmark_h100.md
microbenchmark_gb200.md
E2E raw results:
final_results_gb200_128.txt
final_results_gb200_32.txt
final_results_gb200_64.txt
Microbenchmark — kernel throughput
H100 (HBM3, ~3.35 TB/s peak):
PR saturates HBM from
reqs≥16(~82–84% of peak). MAIN caps at 62% of peak.GB200 (HBM3e, ~8 TB/s peak):
PR reaches ~74% of peak at
reqs=32. MAIN caps at 33% of peak.Microbenchmark — kernel latency
H100 (avg kernel latency, µs):
A near-constant ~800 µs saving at low
reqs(fixed overhead removed), growing to ~1.7 ms atreqs=128as the workload becomes bandwidth-heavy.GB200 (avg kernel latency, µs):
Absolute saving grows monotonically with
reqs(1.20 → 2.82 ms).Cross-platform takeaways:
reqs(reqs=1–8) uplift is ~5.9–6.5× on both GPUs : sub-350 µs on PR vs 0.96–1.53 ms on MAIN.reqs≥16(~84% peak); on GB200 it reaches ~74% atreqs=32.End-to-end serving (GB200)
Steady-state:
P99 tails:
Analysis.
conc=32: +0.75 % throughput, ~0.9 % lower median TPOTconc=64: +2.97 % throughput, ~4.0 % lower median TPOTconc=128: +1.48 % throughput, ~1.3 % lower median TPOTconc=64. Atconc=32the step is still GPU-idle-bound so a faster kernel moves the wall clock only slightly; atconc=128the GPU is closer to saturation so the copy is a smaller share of the step. Mid-concurrency is where this kernel is on the critical path.Summary
_copy_mamba_state_blockgoes from ~33 % to ~73% of HBM peak in GB200 and from ~62% to ~85% of HBM peak in the H100. On both H100 and GB200 there for the low request range there is a substantial speedup in kernel latency: ~5.9–6.5× speedup forreqs=1and ~3.5x - 5.6x forreqs=8for H100 and GB200 respectively.End-to-end on GB200 with MTP speculative decoding this shows up as +0.75 % / +2.97 % / +1.48 % output throughput and correspondingly lower median and P99 TPOT at concurrencies 32 / 64 / 128.
MTP acceptance is unaffected as expected.
AI assistance disclosure
AI assistance was used for microbenchmark scaffolding.
Duplicate-work check. Before opening this PR, the following searches returned no open PR targeting the
_copy_mamba_state_blocktemporal-copy path:PR #40172 introduced the kernel and PR #42406 refactored dispatch; this PR is the first change to widen the temporal load/store transactions.
Essential Elements of an Effective PR Description Checklist
supported_models.mdandexamplesfor a new model.