[K3 Perf] Optimize k3 mamba metadata preparation, 6.6~7.6x kernel performance improvement - #52388
Conversation
Signed-off-by: yewentao256 <zhyanwentao@126.com>
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.
Tip: disable this comment in your organization's Code Review settings.
|
/ci run |
|
✅ Triggered Buildkite CI #83973 for commit |
|
This pull request has merge conflicts that must be resolved before it can be |
Signed-off-by: yewentao256 <zhyanwentao@126.com>
|
/ci run |
|
✅ Triggered Buildkite CI #84243 for commit |
|
/ci run |
|
✅ Triggered Buildkite CI #84383 for commit |
|
Hi @yewentao256, the pre-commit checks have failed. Please run: uv pip install pre-commit>=4.5.1
pre-commit install
pre-commit run --all-filesThen, commit the changes and push to your branch. For future commits, |
|
/ci run |
|
✅ Triggered Buildkite CI #84443 for commit |
| assert self.mamba_aligned_state_indices is not None, ( | ||
| "Aligned Mamba state indices must be precomputed" | ||
| ) |
There was a problem hiding this comment.
Apparently when VLLM_USE_V2_MODEL_RUNNER=0 and mamba_cache_mode == "align", the V1 model runner will hit this. Could you take a look?
| # offsets = torch.arange(1 + num_speculative_blocks, dtype=torch.int32) | ||
| # indices = (start[:, None] + offsets).to(torch.int64) | ||
| # block_table_tensor = torch.gather(block_table, 1, indices) | ||
| block_table_tensor = _mamba_get_block_table_tensor( |
There was a problem hiding this comment.
Wondering if there's any cleanup we can do now, or in the future once MRV1 goes away -- Can we remove _mamba_get_block_table_tensor?
There was a problem hiding this comment.
Let's keep it for now as fallback will need it, I also add a TODO to remove them when MRv2 is used by default.
Signed-off-by: yewentao256 <zhyanwentao@126.com>
|
/ci run |
|
✅ Triggered Buildkite CI #85384 for commit |
…formance improvement (vllm-project#52388) Signed-off-by: yewentao256 <zhyanwentao@126.com> Signed-off-by: khushali9 <khushali.desai9@gmail.com>
…formance improvement (vllm-project#52388) Signed-off-by: yewentao256 <zhyanwentao@126.com>
…formance improvement (vllm-project#52388) Signed-off-by: yewentao256 <zhyanwentao@126.com> Signed-off-by: mikeshawcode <michaelwshaw2@gmail.com>
…formance improvement (vllm-project#52388) Signed-off-by: yewentao256 <zhyanwentao@126.com> Signed-off-by: mikeshawcode <michaelwshaw2@gmail.com>
Purpose
Optimize Kimi K3 Mamba
alignmetadata preparation by computing aligned state indices for all KV-cache groups in one Triton launch.Before:
After:
Test
Acc covered in current unit tests
Perf can be seen in this AI generated script
from types import SimpleNamespace import torch from vllm.models.kimi_k3.nvidia.kda_metadata import ( _mamba_get_block_table_tensor, ) from vllm.triton_utils import triton from vllm.v1.worker.mamba_utils import ( get_aligned_state_indices_multi_group_kernel, ) # Decode-only benchmark: one token per request, so tokens == batch size. TOKENS = [1, 2, 4, 8, 16, 32, 64, 128, 256] NUM_GROUPS = 4 BLOCK_SIZE = 32 MAX_BLOCKS = 1024 BLOCK_ROWS = 32 DEVICE = "cuda" def main() -> None: max_tokens = max(TOKENS) seq_lens = torch.randint( 1, BLOCK_SIZE * MAX_BLOCKS + 1, (max_tokens,), dtype=torch.int32, device=DEVICE, ) block_tables = [ torch.randint( 0, 1_000_000, (max_tokens, MAX_BLOCKS), dtype=torch.int32, device=DEVICE, ) for _ in range(NUM_GROUPS) ] block_table_ptrs = torch.tensor( [table.data_ptr() for table in block_tables], dtype=torch.int64, device=DEVICE, ) output = torch.empty((NUM_GROUPS, max_tokens, 1), dtype=torch.int32, device=DEVICE) spec = SimpleNamespace(block_size=BLOCK_SIZE, num_speculative_blocks=0) print("tokens old (us) new (us) saved (us) speedup") for tokens in TOKENS: current_seq_lens = seq_lens[:tokens] def old( tokens: int = tokens, current_seq_lens: torch.Tensor = current_seq_lens, ) -> None: for table in block_tables: _mamba_get_block_table_tensor( table[:tokens], current_seq_lens, spec, "align" ) def new( tokens: int = tokens, current_seq_lens: torch.Tensor = current_seq_lens, ) -> None: get_aligned_state_indices_multi_group_kernel[ (triton.cdiv(tokens, BLOCK_ROWS),) ]( block_table_ptrs, current_seq_lens, output, block_tables[0].stride(0), current_seq_lens.stride(0), output.stride(0), output.stride(1), output.stride(2), tokens, CACHE_BLOCK_SIZE=BLOCK_SIZE, NUM_GROUPS=NUM_GROUPS, BLOCK_GROUPS=triton.next_power_of_2(NUM_GROUPS), NUM_STATE_SLOTS=1, BLOCK_STATE_SLOTS=1, BLOCK_ROWS=BLOCK_ROWS, num_warps=1, ) expected = torch.stack( [ _mamba_get_block_table_tensor( table[:tokens], current_seq_lens, spec, "align" ) for table in block_tables ] ) new() torch.testing.assert_close(output[:, :tokens], expected) old_us = triton.testing.do_bench(old, warmup=100, rep=500) * 1000 new_us = triton.testing.do_bench(new, warmup=100, rep=500) * 1000 print( f"{tokens:>6} {old_us:>8.2f} {new_us:>8.2f} " f"{old_us - new_us:>10.2f} {old_us / new_us:>7.2f}x" ) if __name__ == "__main__": main()And we get
tokens old (us) new (us) saved (us) speedup 1 49.76 7.12 42.65 6.99x 2 48.91 7.14 41.77 6.85x 4 48.40 7.14 41.26 6.78x 8 50.25 7.12 43.12 7.05x 16 48.42 7.12 41.30 6.80x 32 47.47 7.12 40.35 6.67x 64 50.72 7.12 43.60 7.12x 128 49.79 7.13 42.66 6.98x 256 53.86 7.13 46.72 7.55x