[Perf][Hybrid] 3D-grid tiling of the state-copy Triton kernels - #49436
Merged
tdoublep merged 18 commits intoAug 10, 2026
Merged
Conversation
fuscof-ibm
force-pushed
the
postprocess_vectorize_tiled
branch
from
July 22, 2026 16:06
25f2c3e to
c4f8598
Compare
fuscof-ibm
marked this pull request as ready for review
July 23, 2026 08:00
fuscof-ibm
requested review from
AndreasKaratzas,
WoosukKwon,
mgoin,
njhill,
tlrmchlsmth,
yewentao256 and
zyongye
as code owners
July 23, 2026 08:00
tdoublep
reviewed
Jul 25, 2026
Member
|
@claude review |
fuscof-ibm
force-pushed
the
postprocess_vectorize_tiled
branch
from
July 27, 2026 12:29
8444ec5 to
2d335a2
Compare
Contributor
|
This pull request has merge conflicts that must be resolved before it can be |
Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
Byte-identity check against a torch slice copy across copy_size (0 to
4 MiB), src/dst sub-8B alignment offsets, and NUM_TILES ∈ {1..16}.
Guards the head/body/tail memcpy and tile partitioning shared by the
fused mamba state-copy kernels.
Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
Sweep temporal_tiles ∈ {1, 2, 4, 8, 16, 32} in the V1-copy-spec
equivalence test to guard the u64 body tile partitioning against
off-by-one at the tile boundary, missing head/tail owner, or duplicate
stores when multiple tiles run.
Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
We sweep the number of tiles from 8 to 32 and 16 is the sweet spot for H100/GB200 on Qwen3.5-9B and Nemotron-3-Super-120B-A12B Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
fuscof-ibm
force-pushed
the
postprocess_vectorize_tiled
branch
from
August 4, 2026 18:19
b4d2eec to
2475ea7
Compare
Parametrize test_memcpy_u64_tiled.py on COPY_BLOCK_SIZE ∈ {8, 1024}.
At the production value 1024 the existing copy_size cases (≤ 4 KiB)
collapse to tile 0 under NUM_TILES=16 because per_tile_u64 rounds up to
COPY_BLOCK_SIZE; tiles 1–15 iterate zero times, so the tile-boundary
math is never exercised end-to-end. Adding COPY_BLOCK_SIZE=8 makes the
same copy sizes span all 16 tiles with several inner iterations each,
without inflating tensor allocations (128 KB would have been necessary
with a COPY_BLOCK_SIZE of 1024)
The partitioning arithmetic is COPY_BLOCK_SIZE-agnostic, so testing at
8 proves it for 1024.
Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
Co-authored-by: Claude <noreply@anthropic.com>
fuscof-ibm
force-pushed
the
postprocess_vectorize_tiled
branch
from
August 4, 2026 18:37
2475ea7 to
9ebcaa2
Compare
Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
tdoublep
self-requested a review
August 4, 2026 20:12
Reduces tests/kernels/mamba/test_memcpy_u64_tiled.py from 180 to 120 parametrized cases (~15s GB200 wallclock saved) by dropping redundant crossproduct entries -- under the 40-min mamba kernels CI budget. - Collapse NUM_TILES x COPY_BLOCK_SIZE 2x2 into 3 tuples via joint parametrize: drop (NUM_TILES=1, COPY_BLOCK_SIZE=8). At single-tile the block size is unobservable -- tile partitioning collapses to the full range on tile 0, so (1, 8) is byte-identical to (1, 1024). Kept: (1, 1024), (_TEMPORAL_TILES, 1024), (_TEMPORAL_TILES, 8). - Drop copy_size=17. copy_size=15 already exercises the tail-mask path with 7 tail bytes; the mask is length-agnostic so a 1-byte tail hits the same branch. The (7,7) shared-misalignment pair still covers the head_bytes=1 corner with a non-empty body. Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
…test Halves test_precopy_matches_v1_copy_specs from 144 to 72 parametrized cases in tests/kernels/mamba/test_precopy_mamba_align.py (~16s on a GB200). The inner-memcpy boundary math is still exercised directly in test_memcpy_u64_tiled.py, which parametrizes over both COPY_BLOCK_SIZE values on the device function. Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com>
auto-merge was automatically disabled
August 5, 2026 15:37
Head branch was pushed to by a user without write access
Member
|
/ci retry |
|
✅ No earlier CI build exists for this PR. Use |
Member
|
/ci run |
|
✅ Triggered Buildkite CI #83111 for commit |
Contributor
Author
|
/ci run |
1 similar comment
Member
|
/ci run |
|
✅ Triggered Buildkite CI #83145 for commit |
zyp2014
pushed a commit
to zyp2014/vllm
that referenced
this pull request
Aug 21, 2026
…project#49436) Signed-off-by: Francesco Fusco <ffu@zurich.ibm.com> Co-authored-by: Claude <noreply@anthropic.com>
Aiakos1818
pushed a commit
to Aiakos1818/vllm
that referenced
this pull request
Sep 14, 2026
Ports of upstream PRs that apply to this fork's Qwen3.8-27B GDN + MTP3 stack. Each was rebased by hand onto v0.27.1 + the sm75/qwen3.8 base. - vllm-project#51812 [Bugfix] Align Qwen GDN gates with speculative tokens (v0.28): gather `a`/`b` with the same `spec_token_indx` as mixed_qkv before the fused recurrent update, so a mixed batch (non-spec tokens ahead of spec tokens) no longer feeds another token's gates to the kernel. - vllm-project#56196 [Bugfix] Mamba: store a short prefill chunk's conv state in its own block: with prefix caching a chunk shorter than the conv state wrote its new state through the pointer it read the initial state from, overwriting the shared prefix block. The destination block is now resolved once from `block_idx_last_scheduled_token` and used in every branch. Ported with its regression test. - vllm-project#49436 [Perf] 3D-grid tiling of the state-copy Triton kernels (v0.28): new `_memcpy_u64_tiled` head/body/tail device function partitions the temporal state's u64 body across `_TEMPORAL_TILES=16` CTAs (small-batch HBM fill), lifts the 8B-alignment assert to a warning, and collapses to a single-CTA copy for conv states. Ported with its tests. Not ported: vllm-project#52789 (internal prefill checkpoints for Mamba prefix caching). It is Kimi-K3 KDA only — `num_prefill_checkpoint_blocks` is set solely by `vllm/models/kimi_k3/nvidia/kda.py` under the flashkda backend, so the scheduler/manager infrastructure is inert for GDN models. The analogous capability here is the durable-anchor work in the kv commit. Tests: 149 CPU (host-tier/spill/prefix/mamba-align/api) pass; kernel suites pass on the 2080Ti (memcpy 120, precopy 75, causal_conv1d 156; the 8 float64-reference `varlen` failures are pre-existing on this machine and fail identically without the port). The vllm-project#56196 test fails on the unpatched kernel and passes with it. E2E on the 9.6e9 profile (real NVMe SSD tier): S resident 384,704 -> V0 deep revert cached 350,400 -> T evict -> R SSD restore cached 382,400 (sha db8b8e836881534b, same as the pre-port baseline) -> V2 post-restore revert cached 350,400; stores=3 restores=2.
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
Follow-up to #48110.
#48110 optimized the copy of the states for hybrid models using 64bit load/stores. However the state copy is still underutilizing the HBM memory at small batch and the kernel requires 8B-aligned state tensors.
This PR further improves the performance by adding a 3D grid and lift the hard 8B alignment precondition by using a head/body/tail pattern. Those are the main changes:
uint64body range of each temporal state is partitioned acrossTEMPORAL_TILESCTAs along a newprogram_id(2)axis. Grid goes from(num_reqs, total_states)to(num_reqs, total_states, TEMPORAL_TILES). Small-batch runs (reqs=1..16) now fill the SMs instead of leaving them idle._copy_mamba_state_blockand the same fused launch, withtile_idx > 0early-returning so conv still runs single-CTA (it's ~60–80 KiB per block, compared to 1-4MB of the temporal part)._memcpy_u64_tilednow splits the copy into head (≤7 B to align dst to 8 B) / body (u64-vectorized) / tail (≤7 B). The setup-time asserts become one-timewarning_oncecalls — misalignment is a throughput hint, not a correctness failure._memcpy_u64_tiledsopostprocess_mamba_fused_kernelandprecopy_mamba_align_fused_kernelso both kernel can use it and the 64 aligned copies can be tested in isolation.TEMPORAL_TILES = 16based on a sweep over {8, 16, 32} on GB200 with Qwen3.5-9B and Nemotron-3-Super-120B-A12B.Files touched:
vllm/v1/worker/mamba_utils.py, plus two test files.Net Effect: 3D-grid tiling lifts small-batch kernel bandwidth by 6–7.7× at reqs=1 and pins post-copy throughput at ~72–84% of GB200 HBM3e peak bandwidth across reqs ∈ {1..128} (vs. main's 11–79% swing). End-to-end on Qwen3.5-9B + MTP + prefix caching: +1.1–1.8% output tok/s and −0.7 to −1.6% median TPOT / ITL / E2EL across conc ∈ {16, 32, 64}, with MTP acceptance unchanged and no regressions.
Test Plan
Unit tests (new):
test_memcpy_u64_tiled.py: byte-identity check of_memcpy_u64_tiledvs. a torch slice copy acrosscopy_size∈ [0, 4 KiB], all sub-8B src/dst alignment offsets, andNUM_TILES∈ {1, 16}. Guards head/body/tail correctness and the tile partitioning at the boundaries.test_precopy_mamba_align.py: existing V1-vs-V2 copy-spec equivalence test, now parametrized overTEMPORAL_TILES ∈ {1, 16}.Integration tests (existing hybrid coverage):
Microbenchmark
Reused the benchmarks/bench_copy_mamba_state_block.py developed for #48110 and extended to support a) multiple models and b) the 3D grid launch. In particular we use 36a924e for 3D grids (as in this PR) and 5cce1bc for 2D grid (as in
main).Sweep
num_reqs ∈ {1, 4, 8, 16, 32, 64, 128}on GB200 to confirm tiling improves small-batch throughput without regressing at large batch.End-to-end
Exact same benchmark as in #48110, but using MRv2.
For the
mainwe usevllm bench serveagainstvllm servewith MTP and prefix caching enabled (which exercises the state copies):VLLM_USE_V2_MODEL_RUNNER=1 \ 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
{16,32,64}. 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 runsTest Result
Unit Tests
Unit and integration tests: all passing
Microbenchmark
Raw results:
microbenchmarks_results.txt
Throughput
Peak = ~8 TB/s for GB200 HBM3e
Qwen3.5-9B
On Qwen3.5-9B the PR delivers > 70% of the peak starting from
reqs=4whilemainrequiresreqs=23to achieve that value.Nemotron-3-Super-120B-A12B-NVFP4
Unlike
main, on Nemotron-3-Super this PR achieves an almost flat curve starting fromreqs=1.Kernel Latency
Qwen3.5-9B — Kernel Latency (μs)
This PR is provides lower latencies at all regimes, with larger gains below
reqs=16`.Nemotron-3-Super-120B-A12B-NVFP4 — Kernel Latency (μs)
End-to-end
Raw results:
tiled_16.txt
tiled_32.txt
tiled_64.txt
Values below are
mean ± stddevacross 3 runs (sample stddev, n=3).Δ rows compare PR to main; for latency metrics negative is better, for throughput positive is better.
Summary
Duplicate-work check
Per
AGENTS.md:This PR is a strict follow-on to the earlier
postprocess_mambauint64 vectorization PR — same file, same kernel, but pushes past the single-CTA-per-copy ceiling and drops the alignment precondition. Not duplicating any open work.Tested on MRv2.
Essential Elements of an Effective PR Description Checklist
supported_models.mdandexamplesfor a new model.