diff --git a/.github/labeler.yml b/.github/labeler.yml
index 2f1a92915..0e511e4fa 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -92,7 +92,6 @@ blackwell:
- changed-files:
- any-glob-to-any-file:
- '**/*nvfp4*'
- - 'python/sglang/kernels/aot/csrc/attention/cutlass_sm100_mla/**/*'
- 'python/sglang/srt/layers/attention/trtllm_mla_backend.py'
- 'python/sglang/srt/layers/attention/trtllm_mha_backend.py'
diff --git a/docs/cookbook/autoregressive/DeepSeek/DeepSeek-V3.mdx b/docs/cookbook/autoregressive/DeepSeek/DeepSeek-V3.mdx
index 61fc53f6d..27c65ca95 100644
--- a/docs/cookbook/autoregressive/DeepSeek/DeepSeek-V3.mdx
+++ b/docs/cookbook/autoregressive/DeepSeek/DeepSeek-V3.mdx
@@ -404,7 +404,7 @@ The spec-v2 overlap scheduler is enabled by default. It improves performance by
DeepSeek V3 uses [Multi-head Latent Attention (MLA)](https://arxiv.org/pdf/2405.04434), an attention mechanism that improves inference efficiency. SGLang implements several optimizations:
- **Weight Absorption:** Reorders matrix multiplications to improve decoding phase efficiency.
-- **MLA Attention Backends:** FA3, Flashinfer, FlashMLA, CutlassMLA, TRTLLM MLA (Blackwell), and Triton. FA3 is the default.
+- **MLA Attention Backends:** FA3, Flashinfer, FlashMLA, TRTLLM MLA (Blackwell), and Triton. FA3 is the default.
- **FP8 Quantization:** W8A8 FP8 and KV Cache FP8, with BMM operators for weight-absorbed MLA in FP8.
- **CUDA Graph & Torch.compile:** Both MLA and MoE support CUDA Graph and Torch.compile for reduced decoding latency.
- **Chunked Prefix Cache:** Increases throughput for long-sequence chunked prefill (FlashAttention3 backend only).
diff --git a/docs/docs/advanced_features/attention_backend.mdx b/docs/docs/advanced_features/attention_backend.mdx
index ef7fcb6f3..04e70b6de 100644
--- a/docs/docs/advanced_features/attention_backend.mdx
+++ b/docs/docs/advanced_features/attention_backend.mdx
@@ -664,15 +664,6 @@ python3 -m sglang.launch_server \
--trust-remote-code
```
-- Cutlass MLA
-```bash Command
-python3 -m sglang.launch_server \
- --tp 8 \
- --model deepseek-ai/DeepSeek-R1 \
- --attention-backend cutlass_mla \
- --trust-remote-code
-```
-
- Ascend
```bash Command
python3 -m sglang.launch_server \
@@ -701,13 +692,6 @@ python3 -m sglang.launch_server \
--attention-backend flex_attention
```
-- Dual Chunk FlashAttention
-```bash Command
-python3 -m sglang.launch_server \
- --model Qwen/Qwen2.5-14B-Instruct-1M \
- --attention-backend dual_chunk_flash_attn
-```
-
- Torch Native
```bash Command
python3 -m sglang.launch_server \
diff --git a/docs/docs/advanced_features/quantization.mdx b/docs/docs/advanced_features/quantization.mdx
index ccbf5526d..befcb4d93 100644
--- a/docs/docs/advanced_features/quantization.mdx
+++ b/docs/docs/advanced_features/quantization.mdx
@@ -89,14 +89,14 @@ The following table summarizes quantization method support across NVIDIA and AMD
Yes |
Yes |
Yes |
- Uses Triton dequantize on AMD (vs. optimized CUDA kernels on NVIDIA). Uses CANN kernels on Ascend |
+ Uses a JIT-compiled CUDA kernel on NVIDIA, Triton dequantize on AMD. Uses CANN kernels on Ascend |
gptq |
+ No |
+ No |
Yes |
- Yes |
- Yes |
- Uses Triton or vLLM kernels on AMD. Uses CANN kernels on Ascend |
+ Removed on NVIDIA and AMD GPUs — use gptq_marlin instead. Uses CANN kernels on Ascend. Still supported on Intel CPUs with AMX |
compressed-tensors |
diff --git a/docs/docs/advanced_features/server_arguments.mdx b/docs/docs/advanced_features/server_arguments.mdx
index f6080eeee..a10536533 100644
--- a/docs/docs/advanced_features/server_arguments.mdx
+++ b/docs/docs/advanced_features/server_arguments.mdx
@@ -1418,19 +1418,19 @@ Please consult the documentation below and [server_args.py](https://github.com/s
`--attention-backend` |
Choose the kernels for attention layers. |
`None` |
- triton, torch_native, flex_attention, dsa, nsa, dsv4, compressed, cutlass_mla, fa3, fa4, flashinfer, flashmla, trtllm_mla, cutedsl_mla, tokenspeed_mla, trtllm_mha, dual_chunk_flash_attn, aiter, wave, intel_amx, ascend, intel_xpu |
+ triton, torch_native, flex_attention, dsa, nsa, dsv4, compressed, fa3, fa4, flashinfer, flashmla, trtllm_mla, cutedsl_mla, tokenspeed_mla, trtllm_mha, aiter, wave, intel_amx, ascend, intel_xpu |
| `--prefill-attention-backend` |
Choose the kernels for prefill attention layers (have priority over --attention-backend). |
`None` |
- triton, torch_native, flex_attention, dsa, nsa, dsv4, compressed, cutlass_mla, fa3, fa4, flashinfer, flashmla, trtllm_mla, cutedsl_mla, tokenspeed_mla, trtllm_mha, dual_chunk_flash_attn, aiter, wave, intel_amx, ascend, intel_xpu |
+ triton, torch_native, flex_attention, dsa, nsa, dsv4, compressed, fa3, fa4, flashinfer, flashmla, trtllm_mla, cutedsl_mla, tokenspeed_mla, trtllm_mha, aiter, wave, intel_amx, ascend, intel_xpu |
| `--decode-attention-backend` |
Choose the kernels for decode attention layers (have priority over --attention-backend). |
`None` |
- triton, torch_native, flex_attention, dsa, nsa, dsv4, compressed, cutlass_mla, fa3, fa4, flashinfer, flashmla, trtllm_mla, cutedsl_mla, tokenspeed_mla, trtllm_mha, dual_chunk_flash_attn, aiter, wave, intel_amx, ascend, intel_xpu |
+ triton, torch_native, flex_attention, dsa, nsa, dsv4, compressed, fa3, fa4, flashinfer, flashmla, trtllm_mla, cutedsl_mla, tokenspeed_mla, trtllm_mha, aiter, wave, intel_amx, ascend, intel_xpu |
| `--sampling-backend` |
diff --git a/examples/runtime/engine/offline_batch_inference_qwen_1m.py b/examples/runtime/engine/offline_batch_inference_qwen_1m.py
deleted file mode 100644
index 5505bf7b4..000000000
--- a/examples/runtime/engine/offline_batch_inference_qwen_1m.py
+++ /dev/null
@@ -1,71 +0,0 @@
-"""
-Usage:
-python3 offline_batch_inference.py
-"""
-
-from urllib.request import urlopen
-
-import sglang as sgl
-
-
-def load_prompt() -> str:
- # Test cases with various lengths can be found at:
- #
- # https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen2.5-1M/test-data/64k.txt
- # https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen2.5-1M/test-data/200k.txt
- # https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen2.5-1M/test-data/600k.txt
- # https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen2.5-1M/test-data/1m.txt
-
- with urlopen(
- "https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen2.5-1M/test-data/64k.txt",
- timeout=5,
- ) as response:
- prompt = response.read().decode("utf-8")
- return prompt
-
-
-# Processing the prompt.
-def process_requests(llm: sgl.Engine, prompts: list[str]) -> None:
- # Create a sampling params object.
- sampling_params = {
- "temperature": 0.7,
- "top_p": 0.8,
- "top_k": 20,
- "repetition_penalty": 1.05,
- "max_new_tokens": 256,
- }
- # Generate texts from the prompts.
- outputs = llm.generate(prompts, sampling_params)
- # Print the outputs.
- for output in outputs:
- prompt_token_ids = output["meta_info"]["prompt_tokens"]
- generated_text = output["text"]
- print(f"Prompt length: {prompt_token_ids}, Generated text: {generated_text!r}")
-
-
-# Create an LLM.
-def initialize_engine() -> sgl.Engine:
- llm = sgl.Engine(
- model_path="Qwen/Qwen2.5-7B-Instruct-1M",
- context_length=1048576,
- page_size=256,
- attention_backend="dual_chunk_flash_attn",
- tp_size=4,
- disable_radix_cache=True,
- enable_mixed_chunk=False,
- enable_torch_compile=False,
- chunked_prefill_size=131072,
- mem_fraction_static=0.6,
- log_level="DEBUG",
- )
- return llm
-
-
-def main():
- llm = initialize_engine()
- prompt = load_prompt()
- process_requests(llm, [prompt])
-
-
-if __name__ == "__main__":
- main()
diff --git a/python/sglang/kernels/aot/CMakeLists.txt b/python/sglang/kernels/aot/CMakeLists.txt
index 26943a769..4db9b4b15 100644
--- a/python/sglang/kernels/aot/CMakeLists.txt
+++ b/python/sglang/kernels/aot/CMakeLists.txt
@@ -256,9 +256,7 @@ endif()
# NOTE: Please sort the filenames alphabetically
set(SOURCES
"csrc/allreduce/custom_all_reduce.cu"
- "csrc/attention/cutlass_mla_kernel.cu"
"csrc/attention/merge_attn_states.cu"
- "csrc/attention/vertical_slash_index.cu"
"csrc/common_extension.cc"
"csrc/elementwise/activation.cu"
"csrc/elementwise/concat_mla.cu"
@@ -271,13 +269,11 @@ set(SOURCES
"csrc/expert_specialization/es_sm100_mxfp8_blockscaled.cu"
"csrc/expert_specialization/es_sm100_mxfp8_blockscaled_group_quant.cu"
- "csrc/gemm/awq_kernel.cu"
"csrc/gemm/fp8_gemm_kernel.cu"
"csrc/gemm/int8_gemm_kernel.cu"
"csrc/gemm/per_token_group_quant_8bit.cu"
"csrc/gemm/per_token_group_quant_8bit_v2.cu"
"csrc/gemm/per_token_quant_fp8.cu"
- "csrc/gemm/gptq/gptq_kernel.cu"
"csrc/grammar/apply_token_bitmask_inplace_cuda.cu"
"csrc/infllm_v2/max_pooling.cu"
@@ -306,12 +302,6 @@ set(SOURCES
"${repo-flashinfer_SOURCE_DIR}/csrc/norm.cu"
"${repo-flashinfer_SOURCE_DIR}/csrc/renorm.cu"
-
- "${repo-flash-attention_SOURCE_DIR}/csrc/flash_attn/src/flash_fwd_sparse_hdim128_bf16_causal_sm80.cu"
- "${repo-flash-attention_SOURCE_DIR}/csrc/flash_attn/src/flash_fwd_sparse_hdim128_bf16_sm80.cu"
- "${repo-flash-attention_SOURCE_DIR}/csrc/flash_attn/src/flash_fwd_sparse_hdim128_fp16_causal_sm80.cu"
- "${repo-flash-attention_SOURCE_DIR}/csrc/flash_attn/src/flash_fwd_sparse_hdim128_fp16_sm80.cu"
- "${repo-flash-attention_SOURCE_DIR}/csrc/flash_attn/flash_sparse_api.cpp"
)
set(INCLUDES
diff --git a/python/sglang/kernels/aot/benchmark/bench_awq_dequant.py b/python/sglang/kernels/aot/benchmark/bench_awq_dequant.py
deleted file mode 100644
index cb22ba07f..000000000
--- a/python/sglang/kernels/aot/benchmark/bench_awq_dequant.py
+++ /dev/null
@@ -1,151 +0,0 @@
-import itertools
-import os
-from typing import List, Tuple
-
-import torch
-import triton
-import triton.testing
-from sgl_kernel import awq_dequantize
-
-from sglang.utils import is_in_ci
-
-# Optional vLLM import
-try:
- from vllm import _custom_ops as ops
-
- VLLM_AVAILABLE = True
-except ImportError:
- ops = None
- VLLM_AVAILABLE = False
-
-IS_CI = is_in_ci()
-
-
-def vllm_awq_dequantize(
- qweight: torch.Tensor, scales: torch.Tensor, qzeros: torch.Tensor
-) -> Tuple[torch.Tensor, torch.Tensor]:
- if not VLLM_AVAILABLE:
- # Fallback to SGLang implementation
- return sglang_awq_dequantize(qweight, scales, qzeros)
- return ops.awq_dequantize(qweight, scales, qzeros, 0, 0, 0)
-
-
-def sglang_awq_dequantize(
- qweight: torch.Tensor, scales: torch.Tensor, qzeros: torch.Tensor
-) -> Tuple[torch.Tensor, torch.Tensor]:
-
- return awq_dequantize(qweight, scales, qzeros)
-
-
-def calculate_diff(qweight_row: int, qweight_col: int):
- """Calculate difference between VLLM and SGLang implementations."""
- device = torch.device("cuda")
- qweight = torch.randint(
- 0,
- torch.iinfo(torch.int32).max,
- (qweight_row, qweight_col),
- dtype=torch.int32,
- device=device,
- )
- group_size = qweight_row
- scales_row = qweight_row // group_size
- scales_col = qweight_col * 8
- scales = torch.rand(scales_row, scales_col, dtype=torch.float16, device=device)
- qzeros = torch.randint(
- 0,
- torch.iinfo(torch.int32).max,
- (scales_row, qweight_col),
- dtype=torch.int32,
- device=device,
- )
-
- if not VLLM_AVAILABLE:
- print("⚠️ vLLM not available, skipping comparison")
- return
-
- vllm_out = vllm_awq_dequantize(qweight, scales, qzeros)
- sglang_out = sglang_awq_dequantize(qweight, scales, qzeros)
-
- output_diff = torch.abs(vllm_out.float() - sglang_out.float()).mean().item()
-
- if torch.allclose(
- vllm_out.to(torch.float32), sglang_out.to(torch.float32), rtol=1e-3, atol=1e-5
- ):
- print("✅ All implementations match")
- else:
- print("❌ Implementations differ")
-
-
-# CI environment uses simplified parameters
-if IS_CI:
- qweight_row_range = [128] # Single row size for CI
- qweight_cols_range = [16] # Single column size for CI
-else:
- qweight_row_range = [3584, 18944, 128, 256, 512, 1024]
- qweight_cols_range = [448, 576, 4736, 16, 32, 64, 128]
-
-configs = list(itertools.product(qweight_row_range, qweight_cols_range))
-
-
-@triton.testing.perf_report(
- triton.testing.Benchmark(
- x_names=["qweight_row", "qweight_col"],
- x_vals=configs,
- line_arg="provider",
- line_vals=["vllm", "sglang"] if VLLM_AVAILABLE else ["sglang"],
- line_names=["VLLM", "SGL Kernel"] if VLLM_AVAILABLE else ["SGL Kernel"],
- styles=[("blue", "-"), ("green", "-")] if VLLM_AVAILABLE else [("green", "-")],
- ylabel="us",
- plot_name="awq-dequantize-performance",
- args={},
- )
-)
-def benchmark(qweight_row, qweight_col, provider):
- dtype = torch.float16
- device = torch.device("cuda")
- qweight = torch.randint(
- 0,
- torch.iinfo(torch.int32).max,
- (qweight_row, qweight_col),
- dtype=torch.int32,
- device=device,
- )
- group_size = qweight_row
- scales_row = qweight_row // group_size
- scales_col = qweight_col * 8
- scales = torch.rand(scales_row, scales_col, dtype=torch.float16, device=device)
- qzeros = torch.randint(
- 0,
- torch.iinfo(torch.int32).max,
- (scales_row, qweight_col),
- dtype=torch.int32,
- device=device,
- )
-
- quantiles = [0.5, 0.2, 0.8]
-
- if provider == "vllm":
- if not VLLM_AVAILABLE:
- return (0, 0, 0)
- fn = lambda: vllm_awq_dequantize(
- qweight.clone(), scales.clone(), qzeros.clone()
- )
- elif provider == "sglang":
- fn = lambda: sglang_awq_dequantize(
- qweight.clone(), scales.clone(), qzeros.clone()
- )
-
- ms, min_ms, max_ms = triton.testing.do_bench_cudagraph(fn, quantiles=quantiles)
-
- return 1000 * ms, 1000 * max_ms, 1000 * min_ms
-
-
-if __name__ == "__main__":
- # Simplify for CI environment
- if IS_CI:
- qweight_row, qweight_col = 128, 16 # Smaller values for CI
- else:
- qweight_row, qweight_col = 3584, 448
-
- calculate_diff(qweight_row=qweight_row, qweight_col=qweight_col)
- benchmark.run(print_data=True)
diff --git a/python/sglang/kernels/aot/benchmark/bench_cutlass_mla.py b/python/sglang/kernels/aot/benchmark/bench_cutlass_mla.py
deleted file mode 100644
index 9d24443f6..000000000
--- a/python/sglang/kernels/aot/benchmark/bench_cutlass_mla.py
+++ /dev/null
@@ -1,173 +0,0 @@
-import argparse
-import copy
-import itertools
-import os
-
-import torch
-import triton
-from sgl_kernel import cutlass_mla_decode, cutlass_mla_get_workspace_size
-
-from sglang.srt.utils import get_device_capability
-from sglang.utils import is_in_ci
-
-IS_CI = is_in_ci()
-
-# CI environment uses simplified parameters
-if IS_CI:
- bs_range = [1] # Single batch size for CI
- qlen_range = [64] # Single sequence length for CI
-else:
- bs_range = [1, 8, 32, 64, 128, 256]
- qlen_range = [1, 64, 128, 256, 512, 1024, 2048, 4096, 8192]
-
-configs = list(itertools.product(bs_range, qlen_range))
-
-
-@triton.testing.perf_report(
- triton.testing.Benchmark(
- x_names=["batch_size", "seq_len"],
- x_vals=configs,
- x_log=False,
- line_arg="provider",
- line_vals=[
- "128 heads",
- "64 heads",
- "32 heads",
- "16 heads",
- ],
- line_names=[
- "128 heads",
- "64 heads",
- "32 heads",
- "16 heads",
- ],
- styles=[("green", "-"), ("green", "--"), ("blue", "-"), ("blue", "--")],
- ylabel="GB/s",
- plot_name="cutlass mla",
- args={},
- )
-)
-def benchmark(batch_size, seq_len, provider, block_size, num_kv_splits):
- d = 576
- dn = 64
- dv = 512
-
- h_q_map = {
- "128": 128,
- "64": 64,
- "32": 32,
- "16": 16,
- }
- parsed_h_q = next(
- (value for key, value in h_q_map.items() if key in provider), None
- )
-
- if parsed_h_q is None:
- raise ValueError(f"Unknown head configuration in provider: {provider}")
- h_q = parsed_h_q
-
- seq_lens = torch.full((batch_size,), seq_len, dtype=torch.int32, device="cuda")
- max_seq_len = seq_lens.max().item()
- block_num = (max_seq_len + block_size - 1) // block_size
-
- # Pad block_num so that small blocks can be packed into full 128-sized CUTLASS tiles.
- # One 128-wide tile can hold (128 // block_size) small blocks.
- pack_factor = 128 // block_size
- block_num = ((block_num + pack_factor - 1) // pack_factor) * pack_factor
-
- qn = (
- torch.randn(h_q, batch_size, d - dn, dtype=torch.bfloat16, device="cuda")
- * 100.0
- )
- qr = torch.randn(batch_size, h_q, dn, dtype=torch.bfloat16, device="cuda") * 100.0
- block_table = torch.randint(
- 0,
- batch_size * block_num,
- (batch_size, block_num),
- dtype=torch.int32,
- device="cuda",
- )
-
- kv_cache = torch.randn(
- block_table.numel(), block_size, d, dtype=torch.bfloat16, device="cuda"
- )
-
- workspace_size = cutlass_mla_get_workspace_size(
- block_num * block_size, batch_size, num_kv_splits=num_kv_splits
- )
- workspace = torch.empty(workspace_size, device="cuda", dtype=torch.uint8)
-
- quantiles = [0.5, 0.2, 0.8]
- ms, min_ms, max_ms = triton.testing.do_bench_cudagraph(
- lambda: cutlass_mla_decode(
- qn.transpose(0, 1),
- qr,
- kv_cache,
- seq_lens,
- block_table,
- workspace,
- 1.44,
- num_kv_splits,
- ),
- quantiles=quantiles,
- )
-
- q_size = qn.numel() * qn.element_size() + qr.numel() * qr.element_size()
-
- gbps = lambda ms: (
- (q_size + q_size * dv / d + kv_cache.numel() * kv_cache.element_size())
- * 1e-9
- / (ms * 1e-3)
- )
- return gbps(ms), gbps(max_ms), gbps(min_ms)
-
-
-if __name__ == "__main__":
- parser = argparse.ArgumentParser()
- parser.add_argument(
- "--block-sizes",
- nargs="+",
- type=int,
- default=[1, 32, 64, 128],
- help="List of batch sizes",
- )
- parser.add_argument(
- "--num-kv-splits",
- nargs="+",
- type=int,
- default=[-1],
- help="List of batch sizes",
- )
- args = parser.parse_args()
-
- # Skip in CI environment or unsupported architectures
- if IS_CI:
- major, minor = get_device_capability()
- if major is None or major < 10: # Requires compute capability 10.0+
- print("Skipping Cutlass MLA benchmark in CI environment")
- if major is not None:
- print(
- f"Cutlass MLA requires compute capability 10.0+, but found {major}.{minor}"
- )
- else:
- print("Could not determine device capability")
- else:
- for block_size in args.block_sizes:
- for kv_split in args.num_kv_splits:
- print(f"block_size={block_size}, num_kv_splits={kv_split}: ")
- benchmark.run(
- print_data=True,
- block_size=block_size,
- num_kv_splits=kv_split,
- )
- print("Benchmark finished!")
- else:
- for block_size in args.block_sizes:
- for kv_split in args.num_kv_splits:
- print(f"block_size={block_size}, num_kv_splits={kv_split}: ")
- benchmark.run(
- print_data=True,
- block_size=block_size,
- num_kv_splits=kv_split,
- )
- print("Benchmark finished!")
diff --git a/python/sglang/kernels/aot/csrc/attention/cutlass_mla_kernel.cu b/python/sglang/kernels/aot/csrc/attention/cutlass_mla_kernel.cu
deleted file mode 100644
index a41779c1b..000000000
--- a/python/sglang/kernels/aot/csrc/attention/cutlass_mla_kernel.cu
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
-Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
-Copyright 2025 SGLang Team. All Rights Reserved.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-==============================================================================*/
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-#include "cutlass_sm100_mla/device/sm100_mla.hpp"
-#include "cutlass_sm100_mla/kernel/sm100_mla_tile_scheduler.hpp"
-#include "utils.h"
-
-// clang-format off
-#if !defined(CUDA_VERSION) || CUDA_VERSION < 12040
-void cutlass_mla_decode(
- torch::Tensor const& out,
- torch::Tensor const& q_nope,
- torch::Tensor const& q_pe,
- torch::Tensor const& kv_c_and_k_pe_cache,
- torch::Tensor const& seq_lens,
- torch::Tensor const& page_table,
- torch::Tensor const& workspace,
- int64_t num_kv_splits) {
- TORCH_CHECK(false, "CUDA version must be >= 12.4 for cutlass_mla_decode");
-}
-int64_t cutlass_mla_get_workspace_size(int64_t max_seq_len, int64_t num_batches, int64_t sm_count, int64_t num_kv_splits) {
- TORCH_CHECK(false, "CUDA version must be >= 12.4 for cutlass_mla_get_workspace_size");
-}
-#else
-
-#define CUTLASS_CHECK(status) \
- { \
- cutlass::Status error = status; \
- TORCH_CHECK(error == cutlass::Status::kSuccess, cutlassGetStatusString(error)); \
- }
-
-using namespace cute;
-using namespace cutlass::fmha::kernel;
-
-template
-struct IsPersistent {
- static const bool value = v;
-};
-
-template >
-struct MlaSm100 {
- using Element = T;
- using ElementAcc = float;
- using ElementOut = T;
-
- using TileShape = Shape<_128, _128, Shape<_512, _64>>;
- using TileShapeH = cute::tuple_element_t<0, TileShape>;
- using TileShapeD = cute::tuple_element_t<2, TileShape>;
-
- // H K (D_latent D_rope) B
- using ProblemShape = cute::tuple;
-
- using StrideQ = cute::tuple; // H D B
- using StrideK = cute::tuple; // K D B
- using StrideO = StrideK; // H D B
- using StrideLSE = cute::tuple<_1, int>; // H B
-
- using TileScheduler =
- std::conditional_t;
-
- using FmhaKernel = cutlass::fmha::kernel::Sm100FmhaMlaKernelTmaWarpspecialized<
- TileShape,
- Element,
- ElementAcc,
- ElementOut,
- ElementAcc,
- TileScheduler,
- /*kIsCpAsync=*/!IsPaged128>;
- using Fmha = cutlass::fmha::device::MLA;
-};
-
-template
-typename T::Fmha::Arguments args_from_options(
- at::Tensor const& out,
- at::Tensor const& q_nope,
- at::Tensor const& q_pe,
- at::Tensor const& kv_c_and_k_pe_cache,
- at::Tensor const& seq_lens,
- at::Tensor const& page_table,
- double sm_scale,
- int64_t num_kv_splits) {
- cutlass::KernelHardwareInfo hw_info;
- hw_info.device_id = q_nope.device().index();
- hw_info.sm_count = cutlass::KernelHardwareInfo::query_device_multiprocessor_count(hw_info.device_id);
-
- int batches = q_nope.size(0);
- int page_count_per_seq = page_table.size(1);
- int page_count_total = kv_c_and_k_pe_cache.size(0);
- int page_size = kv_c_and_k_pe_cache.size(1);
- int max_seq_len = page_size * page_count_per_seq;
- using TileShapeH = typename T::TileShapeH;
- using TileShapeD = typename T::TileShapeD;
- auto problem_shape = cute::make_tuple(TileShapeH{}, max_seq_len, TileShapeD{}, batches);
-
- auto [H, K, D, B] = problem_shape;
- auto [D_latent, D_rope] = D;
-
- float scale = float(sm_scale);
-
- using StrideQ = typename T::StrideQ;
- using StrideK = typename T::StrideK;
- using StrideO = typename T::StrideO;
- using StrideLSE = typename T::StrideLSE;
-
- StrideQ stride_Q_nope = cute::make_tuple(
- static_cast(q_nope.stride(1)), _1{}, static_cast(q_nope.stride(0)));
- StrideQ stride_Q_pe = cute::make_tuple(
- static_cast(q_pe.stride(1)), _1{}, static_cast(q_pe.stride(0)));
-
- StrideK stride_C = cute::make_tuple(
- static_cast(0 + D_latent + D_rope), _1{}, static_cast(page_size * (D_latent + D_rope)));
- StrideLSE stride_PT = cute::make_stride(_1{}, page_count_per_seq);
- StrideLSE stride_LSE = cute::make_tuple(_1{}, 0 + H);
- StrideO stride_O = cute::make_tuple(static_cast(0 + D_latent), _1{}, static_cast(0 + H * D_latent));
-
- using Element = typename T::Element;
- using ElementOut = typename T::ElementOut;
- using ElementAcc = typename T::ElementAcc;
- auto Q_nope_ptr = static_cast(q_nope.data_ptr());
- auto Q_pe_ptr = static_cast(q_pe.data_ptr());
- auto C_ptr = static_cast(kv_c_and_k_pe_cache.data_ptr());
- typename T::Fmha::Arguments arguments{
- problem_shape,
- {scale,
- Q_nope_ptr,
- stride_Q_nope,
- Q_pe_ptr,
- stride_Q_pe,
- C_ptr,
- stride_C,
- C_ptr + D_latent,
- stride_C,
- static_cast(seq_lens.data_ptr()),
- static_cast(page_table.data_ptr()),
- stride_PT,
- page_count_total,
- page_size},
- {static_cast(out.data_ptr()), stride_O, static_cast(nullptr), stride_LSE},
- hw_info,
- // TODO(trevor-m): Change split_kv back to -1 when
- // https://github.com/NVIDIA/cutlass/issues/2274 is fixed. Split_kv=1 will
- // perform worse with larger context length and smaller batch sizes.
- static_cast(num_kv_splits), // split_kv
- nullptr, // is_var_split_kv
- };
- // TODO(kaixih@nvidia): When split_kv=-1 and is_var_split_kv=false, we compute
- // split_kv automatically based on batch size and sequence length to balance
- // workload across available SMs. Consider using var_split_kv for manual
- // control if needed.
- T::Fmha::set_split_kv(arguments);
- return arguments;
-}
-
-template
-void runMla(
- at::Tensor const& out,
- at::Tensor const& q_nope,
- at::Tensor const& q_pe,
- at::Tensor const& kv_c_and_k_pe_cache,
- at::Tensor const& seq_lens,
- at::Tensor const& page_table,
- at::Tensor const& workspace,
- double sm_scale,
- int64_t num_kv_splits,
- cudaStream_t stream) {
- using MlaSm100Type = MlaSm100;
- typename MlaSm100Type::Fmha fmha;
- auto arguments = args_from_options(out, q_nope, q_pe, kv_c_and_k_pe_cache, seq_lens, page_table, sm_scale, num_kv_splits);
-
- CUTLASS_CHECK(fmha.can_implement(arguments));
-
- CUTLASS_CHECK(fmha.initialize(arguments, workspace.data_ptr(), stream));
-
- CUTLASS_CHECK(fmha.run(arguments, workspace.data_ptr(), stream));
-}
-
-#define DISPATCH_BOOL(expr, const_expr, ...) \
- [&]() -> bool { \
- if (expr) { \
- constexpr bool const_expr = true; \
- return __VA_ARGS__(); \
- } else { \
- constexpr bool const_expr = false; \
- return __VA_ARGS__(); \
- } \
- }()
-
-void cutlass_mla_decode(
- torch::Tensor const& out,
- torch::Tensor const& q_nope,
- torch::Tensor const& q_pe,
- torch::Tensor const& kv_c_and_k_pe_cache,
- torch::Tensor const& seq_lens,
- torch::Tensor const& page_table,
- torch::Tensor const& workspace,
- double sm_scale,
- int64_t num_kv_splits) {
- auto sm_version = getSMVersion();
- // On SM103a, half of the accuracy tests are failing.
- TORCH_CHECK(sm_version == 100, "cutlass_mla_decode is only supported on compute capability 10.0, but found sm version ", sm_version);
-
- auto in_dtype = q_nope.dtype();
- at::cuda::CUDAGuard device_guard{(char)q_nope.get_device()};
- const cudaStream_t stream = at::cuda::getCurrentCUDAStream(q_nope.get_device());
- const int page_size = kv_c_and_k_pe_cache.size(1);
-
- // NOTE(alcanderian): IsPersistent has bug with manual split_kv.
- // Kernel will hang if batch is too large with large num_kv_splits. (for example bs=8, num_kv_splits=8)
- // Maybe per batch split kv will fix this.
- DISPATCH_BOOL(page_size == 128, IsPaged128, [&] {
- DISPATCH_BOOL(num_kv_splits <= 1, NotManualSplitKV, [&] {
- if (in_dtype == at::ScalarType::Half) {
- runMla>(
- out, q_nope, q_pe, kv_c_and_k_pe_cache, seq_lens, page_table, workspace, sm_scale, num_kv_splits, stream);
- } else if (in_dtype == at::ScalarType::BFloat16) {
- runMla>(
- out, q_nope, q_pe, kv_c_and_k_pe_cache, seq_lens, page_table, workspace, sm_scale, num_kv_splits, stream);
- } else if (in_dtype == at::ScalarType::Float8_e4m3fn) {
- runMla>(
- out, q_nope, q_pe, kv_c_and_k_pe_cache, seq_lens, page_table, workspace, sm_scale, num_kv_splits, stream);
- } else {
- TORCH_CHECK(false, "Unsupported input data type of MLA");
- }
- return true;
- });
- return true;
- });
-}
-
-int64_t cutlass_mla_get_workspace_size(int64_t max_seq_len, int64_t num_batches, int64_t sm_count, int64_t num_kv_splits) {
- // Workspace size depends on ElementAcc and ElementLSE (same as ElementAcc)
- // which are float, so Element type here doesn't matter.
- using MlaSm100Type = MlaSm100;
-
- // Get split kv. Requires problem shape and sm_count only.
- typename MlaSm100Type::Fmha::Arguments arguments;
- using TileShapeH = typename MlaSm100Type::TileShapeH;
- using TileShapeD = typename MlaSm100Type::TileShapeD;
- arguments.problem_shape =
- cute::make_tuple(TileShapeH{}, static_cast(max_seq_len), TileShapeD{}, static_cast(num_batches));
- // Assumes device 0 when getting sm_count.
- arguments.hw_info.sm_count =
- sm_count <= 0 ? cutlass::KernelHardwareInfo::query_device_multiprocessor_count(/*device_id=*/0) : sm_count;
- arguments.split_kv = static_cast(num_kv_splits);
- MlaSm100Type::Fmha::set_split_kv(arguments);
-
- return MlaSm100Type::Fmha::get_workspace_size(arguments);
-}
-
-#endif
-// clang-format on
diff --git a/python/sglang/kernels/aot/csrc/attention/cutlass_sm100_mla/device/sm100_mla.hpp b/python/sglang/kernels/aot/csrc/attention/cutlass_sm100_mla/device/sm100_mla.hpp
deleted file mode 100644
index dd4ed231b..000000000
--- a/python/sglang/kernels/aot/csrc/attention/cutlass_sm100_mla/device/sm100_mla.hpp
+++ /dev/null
@@ -1,358 +0,0 @@
-/***************************************************************************************************
- * Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * 3. Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- **************************************************************************************************/
-/*!
- \file
- \brief An universal device layer for cutlass 3.x-style kernels.
-*/
-
-// clang-format off
-#pragma once
-
-// common
-#include "cutlass/cutlass.h"
-#include "cutlass/device_kernel.h"
-
-#if !defined(__CUDACC_RTC__)
-#include "cutlass/cluster_launch.hpp"
-#include "cutlass/trace.h"
-#endif // !defined(__CUDACC_RTC__)
-
-#include "../kernel/sm100_fmha_mla_tma_warpspecialized.hpp"
-#include "../kernel/sm100_fmha_mla_reduction.hpp"
-
-////////////////////////////////////////////////////////////////////////////////
-
-namespace cutlass::fmha::device {
-
-using namespace cute;
-using namespace cutlass::fmha::kernel;
-
-
-////////////////////////////////////////////////////////////////////////////////
-////////////////////////////// CUTLASS 3.x API /////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-
-template<
- class Kernel_
->
-class MLA {
-public:
-
- using Kernel = Kernel_;
-
- using ReductionKernel = cutlass::fmha::kernel::Sm100FmhaMlaReductionKernel<
- typename Kernel::ElementOut,
- typename Kernel::ElementAcc,
- typename Kernel::ElementAcc,
- Kernel::TileShapeH::value,
- Kernel::TileShapeL::value,
- 256 /*Max split*/
- >;
-
- /// Argument structure: User API
- using KernelArguments = typename Kernel::Arguments;
- using ReductionArguments = typename ReductionKernel::Arguments;
-
- using Arguments = KernelArguments;
-
- /// Argument structure: Kernel API
- using KernelParams = typename Kernel::Params;
- using ReductionParams = typename ReductionKernel::Params;
- struct Params {
- KernelParams fmha_params;
- ReductionParams reduction_params;
- };
-
-private:
-
- /// Kernel API parameters object
- Params params_;
-
- bool is_initialized(bool set = false) {
- static bool initialized = false;
- if (set) initialized = true;
- return initialized;
- }
-
- static ReductionArguments to_reduction_args(Arguments const& args) {
- auto [H, K, D, B] = args.problem_shape;
- return ReductionArguments{
- nullptr, args.epilogue.ptr_o, nullptr, args.epilogue.ptr_lse,
- args.mainloop.softmax_scale, B, args.split_kv, K, args.mainloop.ptr_seq,
- args.ptr_split_kv, Kernel::TileShapeS::value
- };
- }
-
-public:
-
- /// Access the Params structure
- Params const& params() const {
- return params_;
- }
-
- static void set_split_kv (KernelArguments& args) {
- if (args.split_kv >= 1) return;
- auto [H, K, D, B] = args.problem_shape;
- int sm_count = args.hw_info.sm_count;
- int max_splits = ceil_div(K, 128);
- int sms_per_batch = max(1, sm_count / B);
- int split_heur = min(max_splits, sms_per_batch);
- int waves = ceil_div(B * split_heur, sm_count);
- int k_waves = ceil_div(max_splits, split_heur);
- int split_wave_aware = ceil_div(max_splits, k_waves);
- args.split_kv = split_wave_aware;
- }
-
- /// Determines whether the GEMM can execute the given problem.
- static Status
- can_implement(Arguments const& args) {
- if (! Kernel::can_implement(args)) {
- return Status::kInvalid;
- }
- if (! ReductionKernel::can_implement(to_reduction_args(args))) {
- return Status::kInvalid;
- }
- return Status::kSuccess;
- }
-
- /// Gets the workspace size
- static size_t
- get_workspace_size(Arguments const& args) {
- size_t workspace_bytes = 0;
- workspace_bytes += Kernel::get_workspace_size(args);
- workspace_bytes += ReductionKernel::get_workspace_size(to_reduction_args(args));
- return workspace_bytes;
- }
-
- /// Computes the maximum number of active blocks per multiprocessor
- static int maximum_active_blocks(int /* smem_capacity */ = -1) {
- CUTLASS_TRACE_HOST("MLA::maximum_active_blocks()");
- int max_active_blocks = -1;
- int smem_size = Kernel::SharedStorageSize;
-
- // first, account for dynamic smem capacity if needed
- cudaError_t result;
- if (smem_size >= (48 << 10)) {
- CUTLASS_TRACE_HOST(" Setting smem size to " << smem_size);
- result = cudaFuncSetAttribute(
- device_kernel,
- cudaFuncAttributeMaxDynamicSharedMemorySize,
- smem_size);
- if (cudaSuccess != result) {
- result = cudaGetLastError(); // to clear the error bit
- CUTLASS_TRACE_HOST(
- " cudaFuncSetAttribute() returned error: "
- << cudaGetErrorString(result));
- return -1;
- }
- }
-
- // query occupancy after setting smem size
- result = cudaOccupancyMaxActiveBlocksPerMultiprocessor(
- &max_active_blocks,
- device_kernel,
- Kernel::MaxThreadsPerBlock,
- smem_size);
-
- if (cudaSuccess != result) {
- result = cudaGetLastError(); // to clear the error bit
- CUTLASS_TRACE_HOST(
- " cudaOccupancyMaxActiveBlocksPerMultiprocessor() returned error: "
- << cudaGetErrorString(result));
- return -1;
- }
-
- CUTLASS_TRACE_HOST(" max_active_blocks: " << max_active_blocks);
- return max_active_blocks;
- }
-
- /// Initializes GEMM state from arguments.
- Status
- initialize(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr) {
- CUTLASS_TRACE_HOST("MLA::initialize() - workspace "
- << workspace << ", stream: " << (stream ? "non-null" : "null"));
-
- // Initialize the workspace
- Status status = Kernel::initialize_workspace(args, workspace, stream);
- if (status != Status::kSuccess) {
- return status;
- }
- status = ReductionKernel::initialize_workspace(to_reduction_args(args), workspace, stream);
- if (status != Status::kSuccess) {
- return status;
- }
- KernelParams kernel_params = Kernel::to_underlying_arguments(args, workspace);
-
- ReductionArguments reduction_args = to_reduction_args(args);
- if (reduction_args.split_kv > 1) {
- reduction_args.ptr_oaccum = kernel_params.epilogue.ptr_o_acc;
- reduction_args.ptr_lseaccum = kernel_params.epilogue.ptr_lse_acc;
- }
- ReductionParams reduction_params = ReductionKernel::to_underlying_arguments(reduction_args, workspace);
- // Initialize the Params structure
- params_ = Params {kernel_params, reduction_params};
-
- if (is_initialized()) return Status::kSuccess;
-
- // account for dynamic smem capacity if needed
- // no dynamic smem is needed for reduction kernel
- int smem_size = Kernel::SharedStorageSize;
- if (smem_size >= (48 << 10)) {
- CUTLASS_TRACE_HOST(" Setting smem size to " << smem_size);
- cudaError_t result = cudaFuncSetAttribute(
- device_kernel,
- cudaFuncAttributeMaxDynamicSharedMemorySize,
- smem_size);
- if (cudaSuccess != result) {
- result = cudaGetLastError(); // to clear the error bit
- CUTLASS_TRACE_HOST(" cudaFuncSetAttribute() returned error: " << cudaGetErrorString(result));
- return Status::kErrorInternal;
- }
- }
-
- is_initialized(true);
-
- return Status::kSuccess;
- }
-
- /// Update API is preserved in 3.0, but does not guarantee a lightweight update of params.
- Status
- update(Arguments const& args, void* workspace = nullptr) {
- CUTLASS_TRACE_HOST("MLA()::update() - workspace: " << workspace);
-
- size_t workspace_bytes = get_workspace_size(args);
- if (workspace_bytes > 0 && nullptr == workspace) {
- return Status::kErrorWorkspaceNull;
- }
-
- auto fmha_params = Kernel::to_underlying_arguments(args, workspace);
-
- ReductionArguments reduction_args = to_reduction_args(args);
- if (reduction_args.split_kv > 1) {
- reduction_args.ptr_oaccum = fmha_params.epilogue.ptr_o_acc;
- reduction_args.ptr_lseaccum = fmha_params.epilogue.ptr_lse_acc;
- }
- ReductionParams reduction_params = ReductionKernel::to_underlying_arguments(reduction_args, workspace);
- // Initialize the Params structure
- params_ = Params {fmha_params, reduction_params};
-
- return Status::kSuccess;
- }
-
- /// Primary run() entry point API that is static allowing users to create and manage their own params.
- /// Supplied params struct must be construct by calling Kernel::to_underling_arguments()
- static Status
- run(Params& params, cudaStream_t stream = nullptr) {
- CUTLASS_TRACE_HOST("MLA::run()");
- dim3 const block = Kernel::get_block_shape();
- dim3 const grid = Kernel::get_grid_shape(params.fmha_params);
-
- // configure smem size and carveout
- int smem_size = Kernel::SharedStorageSize;
-
- Status launch_result;
- // Use extended launch API only for mainloops that use it
- if constexpr(Kernel::ArchTag::kMinComputeCapability >= 90) {
- dim3 cluster(cute::size<0>(typename Kernel::ClusterShape{}),
- cute::size<1>(typename Kernel::ClusterShape{}),
- cute::size<2>(typename Kernel::ClusterShape{}));
- void const* kernel = (void const*) device_kernel;
- void* kernel_params[] = {¶ms.fmha_params};
- launch_result = ClusterLauncher::launch(grid, cluster, block, smem_size, stream, kernel, kernel_params);
- }
- else {
- launch_result = Status::kSuccess;
- device_kernel<<>>(params.fmha_params);
- }
-
- cudaError_t result = cudaGetLastError();
- if (cudaSuccess != result or Status::kSuccess != launch_result) {
- //return Status::kSuccess;
- CUTLASS_TRACE_HOST(" Kernel launch failed. Reason: " << result);
- return Status::kErrorInternal;
- }
- if (params.reduction_params.split_kv > 1) {
- // launch reduction kernel
- dim3 const block = ReductionKernel::get_block_shape();
- dim3 const grid = ReductionKernel::get_grid_shape(params.reduction_params);
- device_kernel<<>>(params.reduction_params);
- cudaError_t result = cudaGetLastError();
- if (cudaSuccess == result) {
- return Status::kSuccess;
- }
- else {
- CUTLASS_TRACE_HOST(" Kernel launch failed. Reason: " << result);
- return Status::kErrorInternal;
- }
- }
- else {
- return Status::kSuccess;
- }
- }
-
- //
- // Non-static launch overloads that first create and set the internal params struct of this kernel handle.
- //
-
- /// Launches the kernel after first constructing Params internal state from supplied arguments.
- Status
- run(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr) {
- Status status = initialize(args, workspace, stream);
- if (Status::kSuccess == status) {
- status = run(params_, stream);
- }
- return status;
- }
-
- /// Launches the kernel after first constructing Params internal state from supplied arguments.
- Status
- operator()(Arguments const& args, void* workspace = nullptr, cudaStream_t stream = nullptr) {
- return run(args, workspace, stream);
- }
-
- /// Overload that allows a user to re-launch the same kernel without updating internal params struct.
- Status
- run(cudaStream_t stream = nullptr) {
- return run(params_, stream);
- }
-
- /// Overload that allows a user to re-launch the same kernel without updating internal params struct.
- Status
- operator()(cudaStream_t stream = nullptr) {
- return run(params_, stream);
- }
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-} // namespace cutlass::fmha::device
-
-////////////////////////////////////////////////////////////////////////////////
diff --git a/python/sglang/kernels/aot/csrc/attention/cutlass_sm100_mla/kernel/sm100_fmha_mla_reduction.hpp b/python/sglang/kernels/aot/csrc/attention/cutlass_sm100_mla/kernel/sm100_fmha_mla_reduction.hpp
deleted file mode 100644
index b75870d0c..000000000
--- a/python/sglang/kernels/aot/csrc/attention/cutlass_sm100_mla/kernel/sm100_fmha_mla_reduction.hpp
+++ /dev/null
@@ -1,198 +0,0 @@
-/***************************************************************************************************
- * Copyright (c) 2024 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * 3. Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- **************************************************************************************************/
-
-// clang-format off
-#pragma once
-
-#include "cutlass/cutlass.h"
-#include "cutlass/arch/arch.h"
-#include "cute/tensor.hpp"
-
-namespace cutlass::fmha::kernel {
-
-using namespace cute;
-template<
- class ElementOut,
- class ElementAcc,
- class ElementScale,
- size_t kNumHeads,
- size_t kHeadDimLatent,
- int kMaxSplits
->
-struct Sm100FmhaMlaReductionKernel {
-
- static const int SharedStorageSize = 0;
- static const int MaxThreadsPerBlock = 128;
- static const int MinBlocksPerMultiprocessor = 1;
-
- using ArchTag = cutlass::arch::Sm100;
-
- static_assert(kHeadDimLatent % MaxThreadsPerBlock == 0);
- struct Arguments {
- ElementAcc* ptr_oaccum = nullptr;
- ElementOut* ptr_o = nullptr;
- ElementAcc* ptr_lseaccum = nullptr;
- ElementAcc* ptr_lse = nullptr;
- ElementScale scale = 1.f;
- int num_batches = 0;
- int split_kv = -1;
- int dim_k = -1;
- int* ptr_seq = nullptr;
- int* ptr_split_kv = nullptr;
- int tile_shape_s = 128;
- };
- using Params = Arguments;
-
- static Params to_underlying_arguments(Arguments const& args, void* workspace) {
- return {args.ptr_oaccum, args.ptr_o, args.ptr_lseaccum, args.ptr_lse,
- args.scale, args.num_batches, args.split_kv, args.dim_k, args.ptr_seq,
- args.ptr_split_kv, args.tile_shape_s};
- }
-
- static size_t get_workspace_size(Arguments const& /*args*/) {
- return 0;
- }
-
- static Status initialize_workspace(
- Arguments const& /*args*/, void* /*ws*/, cudaStream_t /*stream*/) {
- return Status::kSuccess;
- }
-
- static dim3 get_grid_shape(Params const& params) {
- return dim3(kNumHeads, 1, params.num_batches);
- }
-
- static dim3 get_block_shape() {
- return dim3(MaxThreadsPerBlock, 1, 1);
- }
-
- static bool can_implement(Arguments const& args) {
- if (args.num_batches <= 0) return false;
- if (args.split_kv <= 0) return false;
- return true;
- }
-
- CUTLASS_DEVICE void operator() (Params const& params, char* smem_raw) {
- if (params.split_kv <= 1) return;
- auto blk_coord = make_coord(blockIdx.x, _0{}, blockIdx.z);
-
- __shared__ ElementAcc sLseScale[kMaxSplits];
- const size_t offset_lseaccum = get<0>(blk_coord) + kNumHeads * params.split_kv * get<2>(blk_coord);
- const size_t offset_lse = get<0>(blk_coord) + kNumHeads * get<2>(blk_coord);
-
- Tensor gLSEaccum = make_tensor(make_gmem_ptr(params.ptr_lseaccum + offset_lseaccum),
- make_shape(params.split_kv), Stride>{});
-
- Tensor gLSE = make_tensor(make_gmem_ptr(params.ptr_lse + offset_lse),
- Shape<_1>{}, Stride<_1>{});
-
- auto dim_k = params.ptr_seq == nullptr ? params.dim_k : params.ptr_seq[get<2>(blk_coord)];
- auto local_split_kv = params.ptr_split_kv == nullptr ? params.split_kv : params.ptr_split_kv[get<2>(blk_coord)];
- auto k_tile_total = ceil_div(dim_k, params.tile_shape_s);
- auto k_tile_per_cta = ceil_div(k_tile_total, local_split_kv);
- local_split_kv = ceil_div(k_tile_total, k_tile_per_cta);
-
- int warp_idx = cutlass::canonical_warp_idx_sync();
- if (warp_idx == 0) {
- constexpr int kNLsePerThread = cute::ceil_div(kMaxSplits, 32);
-
- ElementAcc local_lse[kNLsePerThread];
-
- CUTLASS_PRAGMA_UNROLL
- for (int i = 0; i < kNLsePerThread; ++i) {
- const int split = i * 32 + threadIdx.x;
- local_lse[i] = split < local_split_kv ? gLSEaccum(split) : -std::numeric_limits::infinity();
- }
-
- ElementAcc lse_max = -std::numeric_limits::infinity();
- CUTLASS_PRAGMA_UNROLL
- for (int i = 0; i < kNLsePerThread; ++i) {
- lse_max = max(lse_max, local_lse[i]);
- }
- CUTLASS_PRAGMA_UNROLL
- for (int offset = 16; offset >= 1; offset /= 2) {
- lse_max = max(lse_max, __shfl_xor_sync(0xffffffff, lse_max, offset));
- }
- lse_max = lse_max == -std::numeric_limits::infinity() ? 0.0f : lse_max; // In case all local LSEs are -inf
- lse_max = __shfl_sync(0xffffffff, lse_max, 0);
-
- ElementAcc sum_lse = 0;
- CUTLASS_PRAGMA_UNROLL
- for (int i = 0; i < kNLsePerThread; ++i) {
- sum_lse = sum_lse + expf(local_lse[i] - lse_max);
- }
-
- CUTLASS_PRAGMA_UNROLL
- for (int offset = 16; offset >= 1; offset /= 2) {
- sum_lse = sum_lse + __shfl_xor_sync(0xffffffff, sum_lse, offset);
- }
-
- sum_lse = __shfl_sync(0xffffffff, sum_lse, 0);
-
- ElementAcc global_lse = (sum_lse == 0.f || sum_lse != sum_lse) ? std::numeric_limits::infinity() : logf(sum_lse) + lse_max;
- if (threadIdx.x == 0 and params.ptr_lse != nullptr) {
- gLSE(0) = global_lse;
- }
-
- CUTLASS_PRAGMA_UNROLL
- for (int i = 0; i < kNLsePerThread; ++i) {
- const int split = i * 32 + threadIdx.x;
- if (split < local_split_kv) {
- sLseScale[split] = expf(local_lse[i] - global_lse);
- }
- }
- }
- __syncthreads();
-
- constexpr int Elements = kHeadDimLatent / MaxThreadsPerBlock;
- const size_t offset_oaccum = kHeadDimLatent * params.split_kv * (get<0>(blk_coord) + kNumHeads * get<2>(blk_coord));
- Tensor gOaccum = make_tensor(make_gmem_ptr(params.ptr_oaccum + offset_oaccum),
- Shape>{}, Stride<_1>{});
- ElementAcc local_val[Elements] = {0};
- for (int split = 0; split < local_split_kv; ++split) {
- ElementAcc lse_scale = sLseScale[split];
- CUTLASS_PRAGMA_UNROLL
- for(int i = 0; i < Elements; ++i) {
- local_val[i] += lse_scale * gOaccum(threadIdx.x + MaxThreadsPerBlock * i);
- }
- gOaccum.data() = gOaccum.data() + kHeadDimLatent;
- }
- auto ptr_o_local = params.ptr_o + (get<0>(blk_coord) + get<2>(blk_coord) * kNumHeads) * kHeadDimLatent;
- Tensor gO = make_tensor(make_gmem_ptr(ptr_o_local), Shape>{}, Stride<_1>{});
-
- CUTLASS_PRAGMA_UNROLL
- for(int i = 0; i < Elements; ++i) {
- gO(threadIdx.x + MaxThreadsPerBlock * i) = static_cast(local_val[i]);
- }
- }
-};
-
-} // namespace cutlass::fmha::kernel
diff --git a/python/sglang/kernels/aot/csrc/attention/cutlass_sm100_mla/kernel/sm100_fmha_mla_tma_warpspecialized.hpp b/python/sglang/kernels/aot/csrc/attention/cutlass_sm100_mla/kernel/sm100_fmha_mla_tma_warpspecialized.hpp
deleted file mode 100644
index 9809db84e..000000000
--- a/python/sglang/kernels/aot/csrc/attention/cutlass_sm100_mla/kernel/sm100_fmha_mla_tma_warpspecialized.hpp
+++ /dev/null
@@ -1,2018 +0,0 @@
-/***************************************************************************************************
- * Copyright (c) 2024 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * 3. Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- **************************************************************************************************/
-
-// clang-format off
-#pragma once
-
-#include "cutlass/cutlass.h"
-
-#include "cute/tensor.hpp"
-#include "cute/arch/simd_sm100.hpp"
-
-#include "cutlass/arch/arch.h"
-#include "cutlass/arch/memory_sm80.h"
-#include "cutlass/epilogue/thread/linear_combination.h"
-#include "cutlass/gemm/collective/collective_builder.hpp"
-
-#include "gather_tensor.hpp" // from examples/common
-#include "common/pow_2.hpp"
-
-namespace cutlass::fmha::kernel {
-
-using namespace cute;
-
-template<
- class TileShape,
- class Element_,
- class ElementAcc_,
- class ElementOut_,
- class ElementLSE_,
- class TileScheduler,
-#ifdef CPASYNC
- bool kIsCpAsync = true
-#else
- bool kIsCpAsync = false
-#endif
->
-struct Sm100FmhaMlaKernelTmaWarpspecialized {
-
- using Element = Element_;
- using ElementAcc = ElementAcc_;
- using ElementOut = ElementOut_;
- using ElementLSE = ElementLSE_;
-
- // only 2Sm mode is supported
- static const bool kIs2Sm = true;
- static const int MaxThreadsPerBlock = 256;
- static const int MinBlocksPerMultiprocessor = 1;
- static const int TotalSNum = 2;
- static const int TotalPNum = 2;
- using ArchTag = cutlass::arch::Sm100;
-
- using ClusterShape = cute::conditional_t, Shape<_1, _1, _1>>;
-
- using TileShapeH = tuple_element_t<0, TileShape>;
- using TileShapeS = tuple_element_t<1, TileShape>;
- using TileShapeD = tuple_element_t<2, TileShape>;
-
- using TileShapeL = tuple_element_t<0, TileShapeD>;
- using TileShapeR = tuple_element_t<1, TileShapeD>;
- static_assert(TileShapeL{} % TileShapeR{} == 0, "Rope head dim must divide latent head dim");
-
- using ProblemShape = Shape;
- using TensorStride = Stride;
- using TmemAllocator = cute::conditional_t;
-
- static_assert(TileShapeH{} == 128);
- static const int kWarpsInN = kIs2Sm ? 2 : 1;
-
- static const int kNumComputeWarps = 4;
- static const int kNumLoadWarps = kIsCpAsync ? 2 : 1;
-
- enum class WarpRole {
- kMma = 0x1, kLoad = 0x2, kCompute = 0x3, kLoadPageTable = 0x4, kEmpty=0x0
- };
-
- static const long long unsigned int kWarpAssignment = kIsCpAsync ? 0x4221'3333ull : 0x0021'3333ull;
-
- static CUTLASS_DEVICE WarpRole warp_idx_to_role(int warp_idx) {
- return static_cast((kWarpAssignment >> (4 * warp_idx)) & 0xF);
- }
-
- static const int Alignment = 128 / sizeof_bits_v;
- static const int AlignmentOut = 128 / sizeof_bits_v;
-
- using TileShapeQK = Shape;
- static const int StagesQK = 24 / sizeof(Element); // free parameter
- static const int IterationsQKLatent = decltype(TileShapeL{} / get<2>(TileShapeQK{}))::value;
- static const int IterationsQKRope = decltype(TileShapeR{} / get<2>(TileShapeQK{}))::value;
- static const int IterationsQK = IterationsQKLatent + IterationsQKRope;
-
- using Schedule = cute::conditional_t;
- using CollectiveMmaQK = typename cutlass::gemm::collective::CollectiveBuilder<
- cutlass::arch::Sm100, cutlass::arch::OpClassTensorOp,
- Element, TensorStride, Alignment,
- Element, TensorStride, Alignment,
- ElementAcc,
- TileShapeQK, ClusterShape, cutlass::gemm::collective::StageCount,
- Schedule>::CollectiveOp;
- using TiledMmaQK = typename CollectiveMmaQK::TiledMma;
- using CtaShapeQK = typename CollectiveMmaQK::CtaShape_MNK;
-
- // chosen for unified smem staging between K and V
- using TileShapePV = Shape;
- using TransposeTensorStride = decltype(select<1,0,2>(TensorStride{}));
- static const int StagesPV = StagesQK; // not sure why, but must be at least two. check pipes
- static const int IterationsPV_K = decltype(TileShapeS{} / get<2>(TileShapePV{}))::value;
- static const int IterationsPV_N = decltype(TileShapeL{} / get<1>(TileShapePV{}))::value;
-
- using CollectiveMmaPV = typename cutlass::gemm::collective::CollectiveBuilder<
- cutlass::arch::Sm100, cutlass::arch::OpClassTensorOp,
- Element, TensorStride, Alignment,
- Element, TransposeTensorStride, Alignment,
- ElementAcc,
- TileShapePV, ClusterShape, cutlass::gemm::collective::StageCount,
- Schedule>::CollectiveOp;
- using CtaShapePV = typename CollectiveMmaPV::CtaShape_MNK;
- static_assert(std::is_same_v);
-
- using TiledMmaPV = typename CollectiveMmaPV::TiledMma;
-
- using AtomThrShapeMNK = typename CollectiveMmaQK::AtomThrShapeMNK;
- static_assert(typename CollectiveMmaQK::AtomThrShapeMNK{} == typename CollectiveMmaPV::AtomThrShapeMNK{}, "schedule must match");
-
- static const int StagesPageTable = kIsCpAsync ? StagesPV : 1;
-
- // pipelines from load to mma, PipelineTmaUmmaAsync, stages tbd
- // use expect_tx for Q load
- using PipelineLoadQK = cute::conditional_t, PipelineTmaUmmaAsync>;
- using PipelineLoadPV = PipelineLoadQK;
- // pipeline from mma (Q@K) to softmax, PipelineUmmaAsync, 2 stages
- using PipelineS = PipelineUmmaAsync;
- // pipeline from softmax (P) to mma (bmm2), PipelineUmmaAsync, 2 stages
- using PipelineP = PipelineUmmaConsumerAsync;
- // pipeline from mma to softmax (for rescale), PipelineUmmaAsync, 1 stage
- using PipelineO = PipelineUmmaAsync<1, AtomThrShapeMNK>;
-
- using PipelinePT = PipelineAsync;
-
- struct PipelineStorage {
- alignas(16) typename PipelineLoadQK::SharedStorage load_qk;
- alignas(16) typename PipelineS::SharedStorage mma_s;
- alignas(16) typename PipelineP::SharedStorage p_mma;
- alignas(16) typename PipelineO::SharedStorage mma_o;
- alignas(16) typename PipelinePT::SharedStorage load_page_table;
- };
-
- template
- static CUTE_DEVICE constexpr auto unstageSmemLayout(Layout const& layout, Stages stages = {}) {
- return composition(layout, make_tuple(_, _, _, make_layout(stages)));
- }
-
- using SmemLayoutQ = decltype(unstageSmemLayout(typename CollectiveMmaQK::SmemLayoutA{}, Int{}));
- using SmemLayoutKC = typename CollectiveMmaQK::SmemLayoutB;
- using SmemLayoutVC = typename CollectiveMmaPV::SmemLayoutB;
- using SmemLayoutP = decltype(unstageSmemLayout(typename CollectiveMmaPV::SmemLayoutA{}, make_shape(Int{}, _2{})));
-
- static const int kBytesLoadQ = size(AtomThrShapeMNK{}) * cutlass::bits_to_bytes(cosize(take<0,3>(SmemLayoutQ{})) * cute::sizeof_bits_v);
- static const int kBytesLoadKC = size(AtomThrShapeMNK{}) * cutlass::bits_to_bytes(cosize(take<0,3>(SmemLayoutKC{})) * cute::sizeof_bits_v);
- static const int kBytesLoadVC = size(AtomThrShapeMNK{}) * cutlass::bits_to_bytes(cosize(take<0,3>(SmemLayoutVC{})) * cute::sizeof_bits_v);
- // pre-condition for overlapped smem staging
- static_assert(kBytesLoadKC == kBytesLoadVC);
- static_assert(StagesQK == StagesPV);
-
- static const int kTransactionsBytesLoadQK = kBytesLoadKC;
- static const int kTransactionsBytesLoadExtraQ = kBytesLoadQ;
- static const int kTransactionsBytesLoadPV = kBytesLoadVC;
-
- static const int kNamedBarrierExchange = (int) cutlass::arch::ReservedNamedBarriers::TransformBarrier;
- // This Named Barrier is introduced to solve Q tile loading overwritten issue when enable persistent
- // tile scheduler for FP8 MLA.
- static const int kNamedBarrierEpilogue = (int) cutlass::arch::ReservedNamedBarriers::EpilogueBarrier;
- //
- static const int kNamedBarrierTmemDealloc = (int) cutlass::arch::ReservedNamedBarriers::TmemAllocBarrier;
-
- enum class TmemAllocation : uint32_t {
- kSizeS = TileShapeS::value / kWarpsInN,
- // Overall
- kSizeO = TileShapeL::value / kWarpsInN,
- // Between accumulators we loop over
- kSizeAccO = decltype(get<1>(TileShapePV{}))::value / kWarpsInN,
- kNumS = TotalSNum,
- kNumP = TotalPNum,
- kNumO = 1,
- kS0 = 0,
- kS1 = kS0 + kSizeS,
- kO0 = kS1 + kSizeS,
- kTotal = kO0 + kSizeO
- };
-
- static_assert(static_cast(TmemAllocation::kTotal) <= TmemAllocator::Sm100TmemCapacityColumns, "using too much tmem");
-
- struct TensorStorage {
- // to communicate max and row_sum
- cute::array smem_exchange;
- cute::array smem_page_table;
- alignas(2048) cute::array> smem_q;
- union {
- alignas(2048) cute::array> smem_kc;
- alignas(2048) cute::array> smem_vc;
- };
- alignas(2048) cute::array> smem_p;
- };
-
- struct SharedStorage {
- PipelineStorage pipelines;
- TensorStorage tensors;
- uint32_t tmem_base_ptr;
- };
-
- static const int SharedStorageSize = sizeof(SharedStorage);
- static_assert(SharedStorageSize <= cutlass::arch::sm100_smem_capacity_bytes, "using too much smem");
-
- struct MainloopArguments {
- ElementAcc softmax_scale;
-
- // all tensors strides are (num_heads or seqlen, head_dim, batch)
- // head_dim stride is always 1
- Element* ptr_q_latent;
- TensorStride stride_q_latent;
- Element* ptr_q_rope;
- TensorStride stride_q_rope;
-
- Element* ptr_c_latent;
- TensorStride stride_c_latent;
- Element* ptr_k_rope;
- TensorStride stride_k_rope;
-
- // for paged attention, we interpret what was previously [batch, seqlen]
- // as [page_count, page_size], and index according to page_table
- int* ptr_seq = nullptr;
- int* ptr_page_table = nullptr;
- // page table is [batch, seqlen or similar]
- Stride<_1, int> stride_page_table = {};
- int page_count = 0;
- int page_size = TileShapeS{}; // powers of two if kIsCpAsync, otherwise TileShapeS
- };
-
- struct EpilogueArguments {
- ElementOut* ptr_o = nullptr;
- TensorStride stride_o;
- ElementLSE* ptr_lse = nullptr;
- Stride<_1, int> stride_lse;
- ElementAcc output_scale = 1.0f;
- };
-
- struct Arguments {
- // (num_heads=128, seqlen, (d_latent=512, d_rope=64), batch_count)
- // for paged attention, seqlen is max seqlen
- ProblemShape problem_shape;
- MainloopArguments mainloop;
- EpilogueArguments epilogue;
- KernelHardwareInfo hw_info;
- int split_kv = -1;
- int* ptr_split_kv = nullptr;
- };
-
- using TmaLoadQLatent = typename CollectiveMmaQK::Params::TMA_A;
- using TmaLoadQRope = typename CollectiveMmaQK::Params::TMA_A;
- using TmaLoadCLatent = typename CollectiveMmaQK::Params::TMA_B;
- using TmaLoadKRope = typename CollectiveMmaQK::Params::TMA_B;
- using TmaLoadCLatentTranspose = typename CollectiveMmaPV::Params::TMA_B;
-
- struct MainloopParams {
- TmaLoadQLatent tma_load_q_latent;
- TmaLoadQRope tma_load_q_rope;
- TmaLoadCLatent tma_load_c_latent;
- TmaLoadKRope tma_load_k_rope;
- TmaLoadCLatentTranspose tma_load_c_latent_transpose;
- };
-
- struct EpilogueParams {
- ElementOut* ptr_o = nullptr;
- ElementAcc* ptr_o_acc = nullptr;
- TensorStride stride_o;
- TensorStride stride_o_acc;
- ElementLSE* ptr_lse = nullptr;
- ElementLSE* ptr_lse_acc = nullptr;
- Stride<_1, int> stride_lse;
- Stride<_1, int> stride_lse_acc;
- ElementAcc output_scale = 1.0f;
- };
-
- struct Params {
- ProblemShape problem_shape;
- MainloopArguments mainloop;
- EpilogueParams epilogue;
- MainloopParams mainloop_params;
- typename TileScheduler::Params tile_scheduler;
- int split_kv = -1;
- int* ptr_split_kv = nullptr;
- };
-
- static Params to_underlying_arguments(Arguments const& args, void* workspace) {
- //workspace = nullptr; // let's get an error if one of these needs workspace
-
- auto [H, K, D, B] = args.problem_shape;
- auto [L, R] = D;
-
- int paged_B = B;
- int paged_K = K;
- if (args.mainloop.ptr_page_table != nullptr) {
- paged_B = args.mainloop.page_count;
- paged_K = args.mainloop.page_size;
- }
-
- auto params_qk_latent = CollectiveMmaQK::to_underlying_arguments(
- make_shape(H, K, L, B),
- typename CollectiveMmaQK::Arguments {
- args.mainloop.ptr_q_latent, args.mainloop.stride_q_latent,
- args.mainloop.ptr_c_latent, args.mainloop.stride_c_latent,
- }, nullptr);
-
- auto params_qk_latent_paged = CollectiveMmaQK::to_underlying_arguments(
- make_shape(H, paged_K, L, paged_B),
- typename CollectiveMmaQK::Arguments {
- args.mainloop.ptr_q_latent, args.mainloop.stride_q_latent,
- args.mainloop.ptr_c_latent, args.mainloop.stride_c_latent,
- }, nullptr);
-
- auto params_qk_rope = CollectiveMmaQK::to_underlying_arguments(
- make_shape(H, K, R, B),
- typename CollectiveMmaQK::Arguments {
- args.mainloop.ptr_q_rope, args.mainloop.stride_q_rope,
- args.mainloop.ptr_k_rope, args.mainloop.stride_k_rope,
- }, nullptr);
-
- auto params_qk_rope_paged = CollectiveMmaQK::to_underlying_arguments(
- make_shape(H, paged_K, R, paged_B),
- typename CollectiveMmaQK::Arguments {
- args.mainloop.ptr_q_rope, args.mainloop.stride_q_rope,
- args.mainloop.ptr_k_rope, args.mainloop.stride_k_rope,
- }, nullptr);
-
-
- auto stride_c_latent_transpose = select<1,0,2>(args.mainloop.stride_c_latent);
- auto params_pv_latent = CollectiveMmaPV::to_underlying_arguments(
- make_shape(H, L, paged_K, paged_B),
- typename CollectiveMmaPV::Arguments {
- args.mainloop.ptr_q_latent, args.mainloop.stride_q_latent, // dummy, never used
- args.mainloop.ptr_c_latent, stride_c_latent_transpose,
- }, nullptr);
-
- MainloopParams mainloop_params {
- params_qk_latent.tma_load_a,
- params_qk_rope.tma_load_a,
- params_qk_latent_paged.tma_load_b,
- params_qk_rope_paged.tma_load_b,
- params_pv_latent.tma_load_b
- };
-
- EpilogueParams epilogue_params;
-
- epilogue_params.ptr_o = args.epilogue.ptr_o;
- epilogue_params.stride_o = args.epilogue.stride_o;
- epilogue_params.ptr_lse = args.epilogue.ptr_lse;
- epilogue_params.stride_lse = args.epilogue.stride_lse;
- epilogue_params.output_scale = args.epilogue.output_scale;
-
- if (args.split_kv > 1) {
- ElementAcc* ptr_o_acc = reinterpret_cast(workspace);
- ElementLSE* ptr_lse_acc = reinterpret_cast(ptr_o_acc + H * L * args.split_kv * B);
- epilogue_params.ptr_o_acc = ptr_o_acc;
- epilogue_params.ptr_lse_acc = ptr_lse_acc;
-
- epilogue_params.stride_o_acc = make_tuple(static_cast(0 + L) * args.split_kv, _1{}, static_cast(0 + H * L) * args.split_kv);
- epilogue_params.stride_lse_acc = make_tuple(_1{}, (0 + H) * args.split_kv);
- }
-
- return {args.problem_shape, args.mainloop, epilogue_params, mainloop_params,
- TileScheduler::to_underlying_arguments(args.problem_shape, args.hw_info, ClusterShape{}, args.split_kv), args.split_kv, args.ptr_split_kv};
- }
-
- static size_t get_workspace_size(Arguments const& args) {
- ProblemShape problem_shape = args.problem_shape;
- auto [H, K, D, B] = problem_shape;
- auto [D_latent, D_rope] = D;
- auto split_kv = args.split_kv;
- return (sizeof(ElementAcc) * D_latent + sizeof(ElementLSE)) * H * split_kv * B;
- }
- static Status initialize_workspace(
- Arguments const& /*args*/, void* /*ws*/, cudaStream_t /*stream*/) {
- return Status::kSuccess;
- }
-
- static dim3 get_grid_shape(Params const& params) {
- return TileScheduler::get_grid_shape(params.tile_scheduler);
- }
-
- static dim3 get_block_shape() {
- dim3 block(MaxThreadsPerBlock, 1, 1);
- return block;
- }
-
- static bool can_implement(Arguments const& args) {
- if (kIsCpAsync) {
- if ((args.mainloop.page_size & (args.mainloop.page_size - 1)) != 0) {
- return false;
- }
- if (args.mainloop.page_size > TileShapeS{}) {
- return false;
- }
- }
- else {
- if (args.mainloop.ptr_page_table != nullptr && args.mainloop.page_size != TileShapeS{}) {
- return false;
- }
- }
- if (get<0>(args.problem_shape) != 128) {
- return false;
- }
- if (get<1>(args.problem_shape) <= 0) {
- return false;
- }
- if (args.split_kv <= 0) {
- return false;
- }
- return true;
- }
-
-
- CUTLASS_DEVICE void operator()(Params const& params, char* smem_raw) {
-
- TileScheduler tile_scheduler(params.tile_scheduler);
-
- int warp_idx = cutlass::canonical_warp_idx_sync();
- auto role = warp_idx_to_role(warp_idx);
- uint32_t lane_predicate = cute::elect_one_sync();
-
- uint32_t cta_rank_in_cluster = cute::block_rank_in_cluster();
- int cta_coord_v = cta_rank_in_cluster % size<0>(AtomThrShapeMNK{});
- bool is_mma_leader_cta = cta_coord_v == 0;
-
- if (role == WarpRole::kLoad && lane_predicate && ! kIsCpAsync) {
- prefetch_tma_descriptor(params.mainloop_params.tma_load_q_latent.get_tma_descriptor());
- prefetch_tma_descriptor(params.mainloop_params.tma_load_c_latent.get_tma_descriptor());
- prefetch_tma_descriptor(params.mainloop_params.tma_load_q_rope.get_tma_descriptor());
- prefetch_tma_descriptor(params.mainloop_params.tma_load_k_rope.get_tma_descriptor());
- prefetch_tma_descriptor(params.mainloop_params.tma_load_c_latent_transpose.get_tma_descriptor());
- }
- SharedStorage& shared_storage = *reinterpret_cast(smem_raw);
-
- typename PipelineLoadQK::Params pipeline_load_qk_params;
- if (role == WarpRole::kLoad) {
- pipeline_load_qk_params.role = PipelineLoadQK::ThreadCategory::Producer;
- }
- if (role == WarpRole::kMma) {
- pipeline_load_qk_params.role = PipelineLoadQK::ThreadCategory::Consumer;
- }
- if constexpr (kIsCpAsync) {
- // we can make our life easier by unconditionally loading blocks
- // since we know it'll always be legal
- pipeline_load_qk_params.producer_arv_count = kNumLoadWarps * cutlass::NumThreadsPerWarp * size(AtomThrShapeMNK{});
- }
- else {
- pipeline_load_qk_params.is_leader = lane_predicate && (role == WarpRole::kLoad) && is_mma_leader_cta;
- pipeline_load_qk_params.transaction_bytes = kTransactionsBytesLoadQK;
- }
- pipeline_load_qk_params.initializing_warp = 0;
- PipelineLoadQK pipeline_load_qk(shared_storage.pipelines.load_qk, pipeline_load_qk_params,
- ClusterShape{}, /*barrier init*/ cute::true_type{}, /*mask calc*/cute::false_type{});
-
- typename PipelineS::Params pipeline_mma_s_params;
- if (role == WarpRole::kMma) {
- pipeline_mma_s_params.role = PipelineS::ThreadCategory::Producer;
- }
- if (role == WarpRole::kCompute) {
- pipeline_mma_s_params.role = PipelineS::ThreadCategory::Consumer;
- }
- pipeline_mma_s_params.consumer_arv_count = kNumComputeWarps * cutlass::NumThreadsPerWarp * size(AtomThrShapeMNK{});
- pipeline_mma_s_params.initializing_warp = 1;
- PipelineS pipeline_mma_s(
- shared_storage.pipelines.mma_s,
- pipeline_mma_s_params,
- ClusterShape{}, /*barrier init*/ cute::true_type{}, /*mask calc*/cute::false_type{});
-
- typename PipelineP::Params pipeline_p_mma_params;
- if (role == WarpRole::kMma) {
- pipeline_p_mma_params.role = PipelineP::ThreadCategory::Consumer;
- }
- if (role == WarpRole::kCompute) {
- pipeline_p_mma_params.role = PipelineP::ThreadCategory::Producer;
- }
- pipeline_p_mma_params.producer_arv_count = kNumComputeWarps * cutlass::NumThreadsPerWarp * size(AtomThrShapeMNK{});
- pipeline_p_mma_params.consumer_arv_count = 1;
- pipeline_p_mma_params.initializing_warp = 2;
- PipelineP pipeline_p_mma(
- shared_storage.pipelines.p_mma,
- pipeline_p_mma_params,
- ClusterShape{}, /*barrier init*/ cute::true_type{}, /*mask calc*/cute::false_type{});
-
- typename PipelineO::Params pipeline_mma_o_params;
- if (role == WarpRole::kMma) {
- pipeline_mma_o_params.role = PipelineO::ThreadCategory::Producer;
- }
- if (role == WarpRole::kCompute) {
- pipeline_mma_o_params.role = PipelineO::ThreadCategory::Consumer;
- }
- pipeline_mma_o_params.consumer_arv_count = kNumComputeWarps * cutlass::NumThreadsPerWarp * size(AtomThrShapeMNK{});
- pipeline_mma_o_params.initializing_warp = 3;
- PipelineO pipeline_mma_o(
- shared_storage.pipelines.mma_o,
- pipeline_mma_o_params,
- ClusterShape{}, /*barrier init*/ cute::true_type{}, /*mask calc*/cute::false_type{});
-
- typename PipelinePT::Params pipeline_pt_params;
- if (role == WarpRole::kLoad) {
- pipeline_pt_params.role = PipelinePT::ThreadCategory::Consumer;
- }
- if (role == WarpRole::kLoadPageTable) {
- pipeline_pt_params.role = PipelinePT::ThreadCategory::Producer;
- }
- pipeline_pt_params.consumer_arv_count = kNumLoadWarps * cutlass::NumThreadsPerWarp;
- pipeline_pt_params.producer_arv_count = cutlass::NumThreadsPerWarp;
- pipeline_pt_params.initializing_warp = 4;
- PipelinePT pipeline_page_table(
- shared_storage.pipelines.load_page_table,
- pipeline_pt_params);
-
- TmemAllocator tmem_allocator;
-
- pipeline_init_arrive_relaxed(size(ClusterShape{}));
-
- pipeline_load_qk.init_masks(ClusterShape{}); // do we need an update here for 2Sm?
- pipeline_mma_s.init_masks(ClusterShape{});
- pipeline_p_mma.init_masks(ClusterShape{});
- pipeline_mma_o.init_masks(ClusterShape{});
-
- typename PipelineLoadQK::PipelineState pipeline_load_qk_consumer_state;
- typename PipelineLoadQK::PipelineState pipeline_load_qk_producer_state = cutlass::make_producer_start_state();
-
- typename PipelineS::PipelineState pipeline_mma_s_consumer_state;
- typename PipelineS::PipelineState pipeline_mma_s_producer_state = cutlass::make_producer_start_state();
-
- typename PipelineP::PipelineState pipeline_p_mma_consumer_state;
- typename PipelineP::PipelineState pipeline_p_mma_producer_state = cutlass::make_producer_start_state();
-
- typename PipelineO::PipelineState pipeline_mma_o_consumer_state;
- typename PipelineO::PipelineState pipeline_mma_o_producer_state = cutlass::make_producer_start_state();
-
- typename PipelinePT::PipelineState pipeline_pt_consumer_state;
- typename PipelinePT::PipelineState pipeline_pt_producer_state = cutlass::make_producer_start_state();
-
- pipeline_init_wait(size(ClusterShape{}));
-
- if (role == WarpRole::kLoadPageTable) {
- CUTLASS_PRAGMA_NO_UNROLL
- for (; tile_scheduler.is_valid(); ++tile_scheduler) {
- auto blk_coord = tile_scheduler.get_block_coord();
- auto problem_shape = params.problem_shape;
- auto local_split_kv = params.split_kv;
- if (params.mainloop.ptr_seq != nullptr) {
- get<1>(problem_shape) = params.mainloop.ptr_seq[get<2>(blk_coord)];
- if (params.ptr_split_kv != nullptr) {
- local_split_kv = params.ptr_split_kv[get<2>(blk_coord)];
- }
- }
- if (local_split_kv <= get<3>(blk_coord))
- continue;
- load_page_table(
- blk_coord,
- problem_shape,
- params.mainloop,
- shared_storage.tensors,
- pipeline_page_table, pipeline_pt_producer_state,
- local_split_kv
- );
- }
- }
- else if (role == WarpRole::kLoad) {
- if constexpr (kIsCpAsync) {
- CUTLASS_PRAGMA_NO_UNROLL
- for (; tile_scheduler.is_valid(); ++tile_scheduler) {
- auto blk_coord = tile_scheduler.get_block_coord();
- auto problem_shape = params.problem_shape;
- auto local_split_kv = params.split_kv;
- if (params.mainloop.ptr_seq != nullptr) {
- get<1>(problem_shape) = params.mainloop.ptr_seq[get<2>(blk_coord)];
- if (params.ptr_split_kv != nullptr) {
- local_split_kv = params.ptr_split_kv[get<2>(blk_coord)];
- }
- }
- if (local_split_kv <= get<3>(blk_coord))
- continue;
- load_cpasync(
- blk_coord,
- problem_shape,
- params.mainloop,
- params.mainloop_params,
- shared_storage.tensors,
- pipeline_load_qk, pipeline_load_qk_producer_state,
- local_split_kv,
- /* must be shared pipe */
- pipeline_page_table, pipeline_pt_consumer_state
- );
- cutlass::arch::NamedBarrier((kNumComputeWarps + kNumLoadWarps) * NumThreadsPerWarp, kNamedBarrierEpilogue).arrive_and_wait();
- }
- }
- else {
- if (params.mainloop.ptr_page_table != nullptr) {
- CUTLASS_PRAGMA_NO_UNROLL
- for (; tile_scheduler.is_valid(); ++tile_scheduler) {
- auto blk_coord = tile_scheduler.get_block_coord();
- auto problem_shape = params.problem_shape;
- auto local_split_kv = params.split_kv;
- if (params.mainloop.ptr_seq != nullptr) {
- get<1>(problem_shape) = params.mainloop.ptr_seq[get<2>(blk_coord)];
- if (params.ptr_split_kv != nullptr) {
- local_split_kv = params.ptr_split_kv[get<2>(blk_coord)];
- }
- }
- if (local_split_kv <= get<3>(blk_coord))
- continue;
- load_tma* paged= */ true>(
- blk_coord,
- problem_shape,
- params.mainloop,
- params.mainloop_params,
- shared_storage.tensors,
- pipeline_load_qk, pipeline_load_qk_producer_state,
- pipeline_load_qk, pipeline_load_qk_producer_state,
- local_split_kv
- );
- cutlass::arch::NamedBarrier((kNumComputeWarps + kNumLoadWarps) * NumThreadsPerWarp, kNamedBarrierEpilogue).arrive_and_wait();
- }
- }
- else {
- CUTLASS_PRAGMA_NO_UNROLL
- for (; tile_scheduler.is_valid(); ++tile_scheduler) {
- auto blk_coord = tile_scheduler.get_block_coord();
- auto problem_shape = params.problem_shape;
- auto local_split_kv = params.split_kv;
- if (params.mainloop.ptr_seq != nullptr) {
- get<1>(problem_shape) = params.mainloop.ptr_seq[get<2>(blk_coord)];
- if (params.ptr_split_kv != nullptr) {
- local_split_kv = params.ptr_split_kv[get<2>(blk_coord)];
- }
- }
- if (local_split_kv <= get<3>(blk_coord))
- continue;
- load_tma(
- blk_coord,
- problem_shape,
- params.mainloop,
- params.mainloop_params,
- shared_storage.tensors,
- pipeline_load_qk, pipeline_load_qk_producer_state,
- pipeline_load_qk, pipeline_load_qk_producer_state,
- local_split_kv
- );
- cutlass::arch::NamedBarrier((kNumComputeWarps + kNumLoadWarps) * NumThreadsPerWarp, kNamedBarrierEpilogue).arrive_and_wait();
- }
- }
- }
- }
- else if (role == WarpRole::kMma) {
- tmem_allocator.allocate(TmemAllocator::Sm100TmemCapacityColumns, &shared_storage.tmem_base_ptr);
- __syncwarp();
-
- if (is_mma_leader_cta) {
- CUTLASS_PRAGMA_NO_UNROLL
- for (; tile_scheduler.is_valid(); ++tile_scheduler) {
- auto blk_coord = tile_scheduler.get_block_coord();
- auto problem_shape = params.problem_shape;
- auto local_split_kv = params.split_kv;
- if (params.mainloop.ptr_seq != nullptr) {
- get<1>(problem_shape) = params.mainloop.ptr_seq[get<2>(blk_coord)];
- if (params.ptr_split_kv != nullptr) {
- local_split_kv = params.ptr_split_kv[get<2>(blk_coord)];
- }
- }
- if (local_split_kv <= get<3>(blk_coord))
- continue;
- mma(blk_coord,
- problem_shape,
- shared_storage.tensors,
- pipeline_load_qk, pipeline_load_qk_consumer_state,
- pipeline_load_qk, pipeline_load_qk_consumer_state,
- pipeline_mma_s, pipeline_mma_s_producer_state,
- pipeline_p_mma, pipeline_p_mma_consumer_state,
- pipeline_mma_o, pipeline_mma_o_producer_state,
- local_split_kv
- );
- }
- }
-
- //cutlass::arch::NamedBarrier((kNumComputeWarps + 1) * NumThreadsPerWarp, kNamedBarrierTmemDealloc).arrive_and_wait();
-
- //uint32_t free_stage_ptr = shared_storage.tmem_base_ptr;
- //tmem_allocator.free(free_stage_ptr, TmemAllocator::Sm100TmemCapacityColumns);
- }
- else if (role == WarpRole::kCompute) {
- CUTLASS_PRAGMA_NO_UNROLL
- for (; tile_scheduler.is_valid(); ++tile_scheduler) {
- auto blk_coord = tile_scheduler.get_block_coord();
- auto problem_shape = params.problem_shape;
- auto split_kv = params.split_kv;
- auto local_split_kv = split_kv;
- if (params.mainloop.ptr_seq != nullptr) {
- get<1>(problem_shape) = params.mainloop.ptr_seq[get<2>(blk_coord)];
- if (params.ptr_split_kv != nullptr) {
- local_split_kv = params.ptr_split_kv[get<2>(blk_coord)];
- }
- }
- if (local_split_kv <= get<3>(blk_coord))
- continue;
- compute(
- blk_coord,
- problem_shape,
- params.mainloop, // for softmax_scale
- params.epilogue,
- shared_storage.tensors, // for smem_comm
- pipeline_mma_s, pipeline_mma_s_consumer_state,
- pipeline_p_mma, pipeline_p_mma_producer_state,
- pipeline_mma_o, pipeline_mma_o_consumer_state,
- local_split_kv
- );
- }
-
- //cutlass::arch::NamedBarrier((kNumComputeWarps + 1) * NumThreadsPerWarp, kNamedBarrierTmemDealloc).arrive();
- }
-
- cute::cluster_sync();
- cutlass::arch::NamedBarrier((kNumComputeWarps + 1) * NumThreadsPerWarp, kNamedBarrierTmemDealloc).arrive();
- if (role == WarpRole::kMma) {
- uint32_t free_stage_ptr = shared_storage.tmem_base_ptr;
- tmem_allocator.free(free_stage_ptr, TmemAllocator::Sm100TmemCapacityColumns);
- }
- }
-
- template
- CUTLASS_DEVICE void load_page_table(
- BlkCoord const& blk_coord,
- ProblemShape const& problem_shape,
- MainloopArguments const& mainloop_args,
- TensorStorage& shared_tensors,
- PipelinePT& pipeline_page_table,
- typename PipelinePT::PipelineState& pipeline_pt_producer_state, int const& split_kv) {
-
- auto [H, K, D, B] = problem_shape;
- int batch_coord = get<2>(blk_coord);
-
- auto mPT_l = make_tensor(make_gmem_ptr(mainloop_args.ptr_page_table),
- make_shape(mainloop_args.page_count, B),
- mainloop_args.stride_page_table);
- auto mPT = mPT_l(_, batch_coord);
-
- int k_tile_total = ceil_div(K, TileShapeS{});
- int k_tile_per_cta = ceil_div(k_tile_total, split_kv);
- int k_index = get<3>(blk_coord) * k_tile_per_cta; // lower limit
- int k_tile_count = max(0, min(k_tile_total, k_index + k_tile_per_cta) - k_index);
- if (k_tile_count == 0) {
- return;
- }
-
- auto page_size = Pow2{mainloop_args.page_size};
- auto pages_per_tile = Pow2{TileShapeS{} / page_size};
- int thread_idx = threadIdx.x % cutlass::NumThreadsPerWarp;
-
-#if 1
- for (; k_tile_count > 0; ++k_index, --k_tile_count) {
- pipeline_page_table.producer_acquire(pipeline_pt_producer_state);
-
- // assume a single warp
-
- CUTLASS_PRAGMA_UNROLL
- for (int i = 0; i < TileShapeS{}; i += cutlass::NumThreadsPerWarp) {
- int idx = i + thread_idx;
- bool guard = idx < pages_per_tile;
- int smem_idx = pipeline_pt_producer_state.index() * TileShapeS::value + idx;
- int pt_idx = pages_per_tile * k_index + idx;
-
- cutlass::arch::cp_async_zfill(
- &shared_tensors.smem_page_table[smem_idx], &mPT(pt_idx), guard
- );
- }
-
- pipeline_page_table.producer_commit(pipeline_pt_producer_state, cutlass::arch::cpasync_barrier_arrive);
- ++pipeline_pt_producer_state;
- }
-#endif
- }
-
-
- struct Gather {
- int& page_table_stage;
- Pow2 pages_per_tile;
- const int * __restrict__ smem_page_table;
-
- CUTLASS_DEVICE int operator()(int idx) const {
- return smem_page_table[page_table_stage * TileShapeS::value + idx % pages_per_tile];
- }
-
- CUTLASS_DEVICE friend void print(Gather const&) {
- printf("");
- }
-
- };
-
-
- template
- CUTLASS_DEVICE void load_cpasync(
- BlkCoord const& blk_coord,
- ProblemShape const& problem_shape,
- MainloopArguments const& mainloop_args,
- MainloopParams const& mainloop_params,
- TensorStorage& shared_tensors,
- PipelineLoadQK& pipeline_load,
- typename PipelineLoadQK::PipelineState& pipeline_load_producer_state,
- int const& split_kv,
- PipelinePT& pipeline_page_table,
- typename PipelinePT::PipelineState& pipeline_pt_consumer_state) {
-
- auto [H, K, D, B] = problem_shape;
- auto [D_latent, D_rope] = D;
-
- using X = Underscore;
-
- int k_tile_total = ceil_div(K, TileShapeS{});
- int k_tile_per_cta = ceil_div(k_tile_total, split_kv);
- int k_index = get<3>(blk_coord) * k_tile_per_cta; // lower limit
- int k_tile_count = max(0, min(k_tile_total, k_index + k_tile_per_cta) - k_index);
- if (k_tile_count == 0) {
- return;
- }
-
- // partition all tensors
- auto mQL = make_tensor(make_gmem_ptr(mainloop_args.ptr_q_latent), make_shape(H, D_latent, B), mainloop_args.stride_q_latent);
- auto mQR = make_tensor(make_gmem_ptr(mainloop_args.ptr_q_rope), make_shape(H, D_rope, B), mainloop_args.stride_q_rope);
-
- int paged_B = mainloop_args.page_count;
- auto paged_K = Pow2{mainloop_args.page_size};
- auto mPT_l = make_tensor(make_gmem_ptr(mainloop_args.ptr_page_table), make_shape(paged_B, B), mainloop_args.stride_page_table);
-
- int batch_coord = get<2>(blk_coord);
- auto mPT = mPT_l(_, batch_coord);
-
- auto gQL = local_tile(mQL, TileShapeQK{}, make_coord(_,_,_), Step<_1, X, _1>{});
- auto gQR = local_tile(mQR, TileShapeQK{}, make_coord(_,_,_), Step<_1, X, _1>{});
-
- ThrMMA cta_mma_qk = TiledMmaQK{}.get_slice(get<0>(blk_coord) % size(AtomThrShapeMNK{}));
- ThrMMA cta_mma_pv = TiledMmaPV{}.get_slice(get<0>(blk_coord) % size(AtomThrShapeMNK{}));
-
- auto tSgQL = cta_mma_qk.partition_A(gQL);
- auto tSgQR = cta_mma_qk.partition_A(gQR);
-
- Tensor sQ = make_tensor(make_smem_ptr(shared_tensors.smem_q.begin()), SmemLayoutQ{});
- Tensor sKC = make_tensor(make_smem_ptr(shared_tensors.smem_kc.begin()), SmemLayoutKC{});
- Tensor sVC = make_tensor(make_smem_ptr(shared_tensors.smem_vc.begin()), SmemLayoutVC{});
-
- auto make_copy_for = [](auto sT) {
- auto rT_a = sT.layout()(_, _, _, _0{});
- auto rT = make_ordered_layout(shape(rT_a), stride(rT_a));
- auto threads = Int{};
- auto values = Int{};
- return make_cotiled_copy(
- Copy_Atom, Element>{},
- make_ordered_layout(
- make_shape(threads, values),
- make_stride(_1{}, _0{})),
- rT);
- };
-
- // like cute::copy, but makes sure we do all page table lookups first
- auto copy_split = [](auto atom, auto src, auto dst) {
- auto src_v = group_modes<1, rank_v>(src);
- auto dst_v = group_modes<1, rank_v>(dst);
-
- auto src_v_ptrs = make_tensor(size<1>(src_v));
- for (int i = 0; i < size<1>(src_v); i++) {
- src_v_ptrs(i) = &src_v(_0{}, i);
- }
-
-
- for (int i = 0; i < size<1>(src_v); i++) {
- auto src_v_i = make_tensor(
- make_gmem_ptr(src_v_ptrs(i)),
- make_shape(shape<0>(src_v)),
- make_stride(make_stride(_1{}, _0{}))
- );
- atom.call(src_v_i, dst_v(_, i));
- }
- };
-
- auto tiled_copy_q = make_copy_for(sQ);
- auto tiled_copy_kc = make_copy_for(sKC);
- auto tiled_copy_vc = make_copy_for(sVC);
-
- auto thr_copy_q = tiled_copy_q.get_thread_slice(threadIdx.x % (kNumLoadWarps * cutlass::NumThreadsPerWarp));
- auto thr_copy_kc = tiled_copy_kc.get_thread_slice(threadIdx.x % (kNumLoadWarps * cutlass::NumThreadsPerWarp));
- auto thr_copy_vc = tiled_copy_vc.get_thread_slice(threadIdx.x % (kNumLoadWarps * cutlass::NumThreadsPerWarp));
-
- auto tQsQ = thr_copy_q.partition_D(sQ);
- auto tQgQL = thr_copy_q.partition_S(tSgQL);
- auto tQgQR = thr_copy_q.partition_S(tSgQR);
-
- auto tKCsKC = thr_copy_kc.partition_D(sKC);
- auto tVCsVC = thr_copy_vc.partition_D(sVC);
-
- auto pipeline_pt_release_state = pipeline_pt_consumer_state;
-
- int page_table_stage = -1;
- Pow2 pages_per_tile{TileShapeS{} / paged_K};
- const int * __restrict__ smem_page_table = shared_tensors.smem_page_table.begin();
- Gather gather{page_table_stage, pages_per_tile, smem_page_table};
-
- auto mCL = make_tensor(
- make_gmem_ptr(mainloop_args.ptr_c_latent),
- ComposedLayout{
- make_layout(
- make_shape(make_shape(paged_K, paged_B), _1{}),
- make_stride(make_stride(get<0>(mainloop_args.stride_c_latent), example::CustomStride(gather, get<2>(mainloop_args.stride_c_latent))), get<1>(mainloop_args.stride_c_latent))),
- make_coord(_0{}, _0{}),
- make_identity_layout(make_shape(paged_K * paged_B, D_latent))});
-
- auto mKR = make_tensor(
- make_gmem_ptr(mainloop_args.ptr_k_rope),
- ComposedLayout{
- make_layout(
- make_shape(make_shape(paged_K, paged_B), _1{}),
- make_stride(make_stride(get<0>(mainloop_args.stride_k_rope), example::CustomStride(gather, get<2>(mainloop_args.stride_k_rope))), get<1>(mainloop_args.stride_k_rope))),
- make_coord(_0{}, _0{}),
- make_identity_layout(make_shape(paged_K * paged_B, D_latent))});
-
- auto mCLT = make_tensor(
- make_gmem_ptr(mainloop_args.ptr_c_latent),
- ComposedLayout{
- make_layout(
- make_shape(_1{}, make_shape(paged_K, paged_B)),
- make_stride(get<1>(mainloop_args.stride_c_latent), make_stride(get<0>(mainloop_args.stride_c_latent), example::CustomStride(gather, get<2>(mainloop_args.stride_c_latent))))),
- make_coord(_0{}, _0{}),
- make_identity_layout(make_shape(D_latent, paged_K * paged_B))});
-
- auto gCL = local_tile(mCL, TileShapeQK{}, make_coord(_,_,_), Step{});
- auto gKR = local_tile(mKR, TileShapeQK{}, make_coord(_,_,_), Step{});
- auto gCLT = local_tile(mCLT, TileShapePV{}, make_coord(_,_,_), Step{});
-
- auto tSgCL = cta_mma_qk.partition_B(gCL);
- auto tSgKR = cta_mma_qk.partition_B(gKR);
- auto tOgCLT = cta_mma_pv.partition_B(gCLT);
-
- auto tKCgCL = thr_copy_kc.partition_S(tSgCL);
- auto tKCgKR = thr_copy_kc.partition_S(tSgKR);
- auto tVCgCLT = thr_copy_vc.partition_S(tOgCLT);
-
- // latent is first in memory, so let's load it first always
- // startup: alternate Q and K, set tx count appropriately, for k_idx = 0
- auto& pipeline_acquire_state = pipeline_load_producer_state;
- auto pipeline_commit_state = pipeline_acquire_state;
- int pipeline_offset = 0;
-
- for (int i = 0; i < StagesPV; i++) {
- cutlass::arch::cp_async_fence();
- }
-
- auto load_stage = [&](auto fn) {
- pipeline_load.producer_acquire(pipeline_acquire_state);
- fn(pipeline_acquire_state.index());
- cutlass::arch::cp_async_fence();
-
- ++pipeline_acquire_state;
- ++pipeline_offset;
-
- if (pipeline_offset == StagesPV - 1) {
- cutlass::arch::cp_async_wait();
- pipeline_load.producer_commit(pipeline_commit_state);
- ++pipeline_commit_state;
- --pipeline_offset;
- }
- };
-
- pipeline_page_table.consumer_wait(pipeline_pt_consumer_state);
- page_table_stage = pipeline_pt_consumer_state.index();
- ++pipeline_pt_consumer_state;
-
- // each Q/K tile consists of rope and latent
- for (int i = 0; i < IterationsQKLatent; i++) {
- load_stage([&](int index) {
- cute::copy(tiled_copy_q, tQgQL(_, _, _, _, _0{}, i, batch_coord), tQsQ(_, _, _, _, i));
- copy_split(tiled_copy_kc, tKCgCL(_, _, _, _, k_index, i), tKCsKC(_, _, _, _, index));
- });
- }
-
- for (int i = 0; i < IterationsQKRope; i++) {
- load_stage([&](int index) {
- cute::copy(tiled_copy_q, tQgQR(_, _, _, _, _0{}, i, batch_coord), tQsQ(_, _, _, _, IterationsQKLatent + i));
- copy_split(tiled_copy_kc, tKCgKR(_, _, _, _, k_index, i), tKCsKC(_, _, _, _, index));
- });
- }
-
- k_index += 1;
- k_tile_count -= 1;
-
- // assume k_tile_count >= 1
- // perform K+Q load here
- CUTLASS_PRAGMA_NO_UNROLL
- while (k_tile_count > 0) {
-
- pipeline_page_table.consumer_wait(pipeline_pt_consumer_state);
- page_table_stage = pipeline_pt_consumer_state.index();
- ++pipeline_pt_consumer_state;
-
- for (int i = 0; i < IterationsQKLatent; i++) {
- load_stage([&](int index) {
- copy_split(tiled_copy_kc, tKCgCL(_, _, _, _, k_index, i), tKCsKC(_, _, _, _, index));
- });
- }
-
- for (int i = 0; i < IterationsQKRope; i++) {
- load_stage([&](int index) {
- copy_split(tiled_copy_kc, tKCgKR(_, _, _, _, k_index, i), tKCsKC(_, _, _, _, index));
- });
- }
-
- page_table_stage = pipeline_pt_release_state.index();
-
- for (int i = 0; i < IterationsPV_K; i++) {
- for (int j = 0; j < IterationsPV_N; j++) {
- load_stage([&](int index) {
- copy_split(tiled_copy_vc, tVCgCLT(_, _, _, _, j, IterationsPV_K * (k_index - 1) + i), tVCsVC(_, _, _, _, index));
- });
- }
- }
-
- pipeline_page_table.consumer_release(pipeline_pt_release_state);
- ++pipeline_pt_release_state;
-
- k_index += 1;
- k_tile_count -= 1;
- }
-
- page_table_stage = pipeline_pt_release_state.index();
-
- for (int i = 0; i < IterationsPV_K; i++) {
- for (int j = 0; j < IterationsPV_N; j++) {
- load_stage([&](int index) {
- copy_split(tiled_copy_vc, tVCgCLT(_, _, _, _, j, IterationsPV_K * (k_index - 1) + i), tVCsVC(_, _, _, _, index));
- });
- }
- }
-
- pipeline_page_table.consumer_release(pipeline_pt_release_state);
- ++pipeline_pt_release_state;
-
- while (pipeline_offset > 0) {
- cutlass::arch::cp_async_fence();
-
- cutlass::arch::cp_async_wait();
- pipeline_load.producer_commit(pipeline_commit_state);
- ++pipeline_commit_state;
- --pipeline_offset;
- }
-
- cutlass::arch::cp_async_wait<0>();
-
- }
-
-
- template
- CUTLASS_DEVICE void load_tma(
- BlkCoord const& blk_coord,
- ProblemShape const& problem_shape,
- MainloopArguments const& mainloop_args,
- MainloopParams const& mainloop_params,
- TensorStorage& shared_tensors,
- PipelineLoadQK& pipeline_load_qk,
- typename PipelineLoadQK::PipelineState& pipeline_load_qk_producer_state,
- PipelineLoadPV& pipeline_load_pv,
- typename PipelineLoadPV::PipelineState& pipeline_load_pv_producer_state,
- int const& split_kv) {
-
- auto [H, K, D, B] = problem_shape;
- auto [D_latent, D_rope] = D;
-
- int k_tile_total = ceil_div(K, TileShapeS{});
- int k_tile_per_cta = ceil_div(k_tile_total, split_kv);
- int k_index = get<3>(blk_coord) * k_tile_per_cta; // lower limit
- int k_tile_count = max(0, min(k_tile_total, k_index + k_tile_per_cta) - k_index);
- if (k_tile_count == 0) {
- return;
- }
-
- using X = Underscore;
-
- // partition all tensors
- auto mQL = mainloop_params.tma_load_q_latent.get_tma_tensor(make_shape(H, D_latent, B));
- auto mQR = mainloop_params.tma_load_q_rope.get_tma_tensor(make_shape(H, D_rope, B));
-
- int paged_B = B;
- int paged_K = K;
- if constexpr (kIsPaged) {
- paged_B = mainloop_args.page_count;
- paged_K = mainloop_args.page_size;
- }
- auto mPT_l = make_tensor(make_gmem_ptr(mainloop_args.ptr_page_table), make_shape(paged_B, B), mainloop_args.stride_page_table);
-
- auto mCL = mainloop_params.tma_load_c_latent.get_tma_tensor(make_shape(paged_K, D_latent, paged_B));
- auto mKR = mainloop_params.tma_load_k_rope.get_tma_tensor(make_shape(paged_K, D_rope, paged_B));
-
- auto mCLT = mainloop_params.tma_load_c_latent_transpose.get_tma_tensor(make_shape(D_latent, paged_K, paged_B));
-
- auto gQL = local_tile(mQL, TileShapeQK{}, make_coord(_,_,_), Step<_1, X, _1>{});
- auto gQR = local_tile(mQR, TileShapeQK{}, make_coord(_,_,_), Step<_1, X, _1>{});
-
- auto gCL = local_tile(mCL, TileShapeQK{}, make_coord(_,_,_), Step{});
- auto gKR = local_tile(mKR, TileShapeQK{}, make_coord(_,_,_), Step{});
- auto gCLT = local_tile(mCLT, TileShapePV{}, make_coord(_,_,_), Step{});
-
- ThrMMA cta_mma_qk = TiledMmaQK{}.get_slice(get<0>(blk_coord) % size(AtomThrShapeMNK{}));
- ThrMMA cta_mma_pv = TiledMmaPV{}.get_slice(get<0>(blk_coord) % size(AtomThrShapeMNK{}));
-
- auto tSgQL = cta_mma_qk.partition_A(gQL);
- auto tSgQR = cta_mma_qk.partition_A(gQR);
-
- auto tSgCL = cta_mma_qk.partition_B(gCL);
- auto tSgKR = cta_mma_qk.partition_B(gKR);
-
- auto tOgCLT = cta_mma_pv.partition_B(gCLT);
-
- Tensor sQ = make_tensor(make_smem_ptr(shared_tensors.smem_q.begin()), SmemLayoutQ{});
- Tensor sKC = make_tensor(make_smem_ptr(shared_tensors.smem_kc.begin()), SmemLayoutKC{});
- Tensor sVC = make_tensor(make_smem_ptr(shared_tensors.smem_vc.begin()), SmemLayoutVC{});
-
- auto [tQLgQL_mkl, tQsQ] = tma_partition(
- mainloop_params.tma_load_q_latent, _0{}, make_layout(_1{}),
- group_modes<0,3>(sQ), group_modes<0,3>(tSgQL));
-
- auto [tQRgQR_mkl, tQsQ_ignore] = tma_partition(
- mainloop_params.tma_load_q_rope, _0{}, make_layout(_1{}),
- group_modes<0,3>(sQ), group_modes<0,3>(tSgQR));
-
- auto [tCLgCL_nkl, tKCsKC] = tma_partition(
- mainloop_params.tma_load_c_latent, _0{}, make_layout(_1{}),
- group_modes<0,3>(sKC), group_modes<0,3>(tSgCL));
-
- auto [tKRgKR_nkl, tKCsKC_ignore] = tma_partition(
- mainloop_params.tma_load_k_rope, _0{}, make_layout(_1{}),
- group_modes<0,3>(sKC), group_modes<0,3>(tSgKR));
-
- auto [tCLTgCLT_nkl, tVCsVC] = tma_partition(
- mainloop_params.tma_load_c_latent_transpose, _0{}, make_layout(_1{}),
- group_modes<0,3>(sVC), group_modes<0,3>(tOgCLT));
-
- uint16_t mcast_mask = 0;
-
- int batch_coord = get<2>(blk_coord);
- Tensor tQLgQL = tQLgQL_mkl(_, _, _, batch_coord);
- Tensor tQRgQR = tQRgQR_mkl(_, _, _, batch_coord);
-
- auto mPT = mPT_l(_, batch_coord);
-
- Tensor tCLgCL = tCLgCL_nkl(_, _, _, _);
- Tensor tKRgKR = tKRgKR_nkl(_, _, _, _);
-
- // careful: stage and k are swapped here!
- Tensor tCLTgCLT = tCLTgCLT_nkl(_, _, _, _);
-
- // latent is first in memory, so let's load it first always
- // startup: alternate Q and K, set tx count appropriately, for k_idx = 0
-
- // each Q/K tile consists of rope and latent
- for (int i = 0; i < IterationsQKLatent; i++) {
- pipeline_load_qk.producer_expect_transaction(pipeline_load_qk_producer_state, kTransactionsBytesLoadExtraQ);
- pipeline_load_qk.producer_acquire(pipeline_load_qk_producer_state);
- auto tma_barrier = pipeline_load_qk.producer_get_barrier(pipeline_load_qk_producer_state);
-
- if (cute::elect_one_sync()) {
- // expect the extra bytes
- // load_qk ql
- cute::copy(mainloop_params.tma_load_q_latent.with(*tma_barrier, mcast_mask), tQLgQL(_, _0{}, i), tQsQ(_, i));
- // load_qk cl
- if constexpr (kIsPaged) {
- cute::copy(
- mainloop_params.tma_load_c_latent.with(*tma_barrier, mcast_mask),
- tCLgCL(_, _0{}, i, mPT(k_index)),
- tKCsKC(_, pipeline_load_qk_producer_state.index())
- );
- }
- else {
- cute::copy(
- mainloop_params.tma_load_c_latent.with(*tma_barrier, mcast_mask),
- tCLgCL(_, k_index, i, batch_coord),
- tKCsKC(_, pipeline_load_qk_producer_state.index()));
- }
- }
- ++pipeline_load_qk_producer_state;
- }
-
- for (int i = 0; i < IterationsQKRope; i++) {
- pipeline_load_qk.producer_expect_transaction(pipeline_load_qk_producer_state, kTransactionsBytesLoadExtraQ);
- pipeline_load_qk.producer_acquire(pipeline_load_qk_producer_state);
- auto tma_barrier = pipeline_load_qk.producer_get_barrier(pipeline_load_qk_producer_state);
-
- if (cute::elect_one_sync()) {
- // expect the extra bytes
- // load_qk ql
- cute::copy(mainloop_params.tma_load_q_rope.with(*tma_barrier, mcast_mask), tQRgQR(_, _0{}, i), tQsQ(_, i + IterationsQKLatent));
- // load_qk cl
- if constexpr (kIsPaged) {
- cute::copy(
- mainloop_params.tma_load_k_rope.with(*tma_barrier, mcast_mask),
- tKRgKR(_, _0{}, i, mPT(k_index)),
- tKCsKC(_, pipeline_load_qk_producer_state.index())
- );
- }
- else {
- cute::copy(
- mainloop_params.tma_load_k_rope.with(*tma_barrier, mcast_mask),
- tKRgKR(_, k_index, i, batch_coord),
- tKCsKC(_, pipeline_load_qk_producer_state.index()));
- }
- }
- ++pipeline_load_qk_producer_state;
- }
-
- k_index += 1;
- k_tile_count -= 1;
-
- // assume k_tile_count >= 1
- // perform K+Q load here
- CUTLASS_PRAGMA_NO_UNROLL
- while (k_tile_count > 0) {
-
- // perform K load
- for (int i = 0; i < IterationsQKLatent; i++) {
- pipeline_load_qk.producer_acquire(pipeline_load_qk_producer_state);
- auto tma_barrier = pipeline_load_qk.producer_get_barrier(pipeline_load_qk_producer_state);
-
- if (cute::elect_one_sync()) {
- // load_qk cl
- if constexpr (kIsPaged) {
- cute::copy(
- mainloop_params.tma_load_c_latent.with(*tma_barrier, mcast_mask),
- tCLgCL(_, _0{}, i, mPT(k_index)),
- tKCsKC(_, pipeline_load_qk_producer_state.index())
- );
- }
- else {
- cute::copy(
- mainloop_params.tma_load_c_latent.with(*tma_barrier, mcast_mask),
- tCLgCL(_, k_index, i, batch_coord),
- tKCsKC(_, pipeline_load_qk_producer_state.index()));
- }
- }
- ++pipeline_load_qk_producer_state;
- }
-
- for (int i = 0; i < IterationsQKRope; i++) {
- pipeline_load_qk.producer_acquire(pipeline_load_qk_producer_state);
- auto tma_barrier = pipeline_load_qk.producer_get_barrier(pipeline_load_qk_producer_state);
-
- if (cute::elect_one_sync()) {
- // load_qk cl
- if constexpr (kIsPaged) {
- cute::copy(
- mainloop_params.tma_load_k_rope.with(*tma_barrier, mcast_mask),
- tKRgKR(_, _0{}, i, mPT(k_index)),
- tKCsKC(_, pipeline_load_qk_producer_state.index())
- );
- }
- else {
- cute::copy(
- mainloop_params.tma_load_k_rope.with(*tma_barrier, mcast_mask),
- tKRgKR(_, k_index, i, batch_coord),
- tKCsKC(_, pipeline_load_qk_producer_state.index()));
- }
- }
- ++pipeline_load_qk_producer_state;
- }
-
- // prefetch next K load to keep busy while we transpose-load from cache
- const int kPrefetchDistance = 1;
- for (int i = 0; i < IterationsQKLatent; i++) {
- if (cute::elect_one_sync()) {
- if constexpr (kIsPaged) {
- if (k_tile_count > kPrefetchDistance) {
- cute::prefetch(
- mainloop_params.tma_load_c_latent,
- tCLgCL(_, _0{}, i, mPT(k_index + kPrefetchDistance))
- );
- }
- }
- else {
- cute::prefetch(
- mainloop_params.tma_load_c_latent,
- tCLgCL(_, k_index + kPrefetchDistance, i, batch_coord)
- );
- }
- }
- }
-
- for (int i = 0; i < IterationsQKRope; i++) {
- if (cute::elect_one_sync()) {
- if constexpr (kIsPaged) {
- if (k_tile_count > kPrefetchDistance) {
- cute::prefetch(
- mainloop_params.tma_load_k_rope,
- tKRgKR(_, _0{}, i, mPT(k_index + kPrefetchDistance))
- );
- }
- }
- else {
- cute::prefetch(
- mainloop_params.tma_load_k_rope,
- tKRgKR(_, k_index + kPrefetchDistance, i, batch_coord)
- );
- }
- }
- }
-
- // perform V load (k_idx - 1)
-
- for (int i = 0; i < IterationsPV_K; i++) {
- for (int j = 0; j < IterationsPV_N; j++) {
- pipeline_load_pv.producer_acquire(pipeline_load_pv_producer_state);
- auto tma_barrier = pipeline_load_pv.producer_get_barrier(pipeline_load_pv_producer_state);
-
- if (cute::elect_one_sync()) {
- // load_pv cl
- // note the transpose in indices!
- // note we are off-by-one on k_index
- if constexpr (kIsPaged) {
- cute::copy(
- mainloop_params.tma_load_c_latent_transpose.with(*tma_barrier, mcast_mask, cute::TMA::CacheHintSm100::EVICT_FIRST),
- tCLTgCLT(_, j, i, mPT(k_index - 1)),
- tVCsVC(_, pipeline_load_pv_producer_state.index())
- );
- }
- else {
- cute::copy(
- mainloop_params.tma_load_c_latent_transpose.with(*tma_barrier, mcast_mask, cute::TMA::CacheHintSm100::EVICT_FIRST),
- tCLTgCLT(_, j, IterationsPV_K * (k_index - 1) + i, batch_coord),
- tVCsVC(_, pipeline_load_pv_producer_state.index())
- );
- }
- }
- ++pipeline_load_pv_producer_state;
- }
- }
-
- k_index += 1;
- k_tile_count -= 1;
- }
-
- for (int i = 0; i < IterationsPV_K; i++) {
- for (int j = 0; j < IterationsPV_N; j++) {
- pipeline_load_pv.producer_acquire(pipeline_load_pv_producer_state);
- auto tma_barrier = pipeline_load_pv.producer_get_barrier(pipeline_load_pv_producer_state);
-
- if (cute::elect_one_sync()) {
- // load_pv cl
- // note the transpose in indices
- // note we are off-by-one on k_index
-
- if constexpr (kIsPaged) {
- cute::copy(
- mainloop_params.tma_load_c_latent_transpose.with(*tma_barrier, mcast_mask, cute::TMA::CacheHintSm100::EVICT_FIRST),
- tCLTgCLT(_, j, i, mPT(k_index - 1)),
- tVCsVC(_, pipeline_load_pv_producer_state.index())
- );
- }
- else {
- cute::copy(
- mainloop_params.tma_load_c_latent_transpose.with(*tma_barrier, mcast_mask, cute::TMA::CacheHintSm100::EVICT_FIRST),
- tCLTgCLT(_, j, IterationsPV_K * (k_index - 1) + i, batch_coord),
- tVCsVC(_, pipeline_load_pv_producer_state.index())
- );
- }
- }
- ++pipeline_load_pv_producer_state;
- }
- }
- }
-
- template
- CUTLASS_DEVICE void mma(
- BlkCoord const& blk_coord,
- ProblemShape const& problem_shape,
- TensorStorage& shared_tensors,
- PipelineLoadQK& pipeline_load_qk,
- typename PipelineLoadQK::PipelineState& pipeline_load_qk_consumer_state,
- PipelineLoadPV& pipeline_load_pv,
- typename PipelineLoadPV::PipelineState& pipeline_load_pv_consumer_state,
- PipelineS& pipeline_mma_s,
- typename PipelineS::PipelineState& pipeline_mma_s_producer_state,
- PipelineP& pipeline_p_mma,
- typename PipelineP::PipelineState& pipeline_p_mma_consumer_state,
- PipelineO& pipeline_mma_o,
- typename PipelineO::PipelineState& pipeline_mma_o_producer_state,
- int const& split_kv) {
-
- auto [H, K, D, B] = problem_shape;
-
- int k_tile_total = ceil_div(K, TileShapeS{});
- int k_tile_per_cta = ceil_div(k_tile_total, split_kv);
- int k_index = get<3>(blk_coord) * k_tile_per_cta; // lower limit
- int k_tile_count = max(0, min(k_tile_total, k_index + k_tile_per_cta) - k_index);
- if (k_tile_count == 0) {
- return;
- }
-
- // mma init
- Tensor sQ = make_tensor(make_smem_ptr(shared_tensors.smem_q.begin()), SmemLayoutQ{});
- Tensor sKC = make_tensor(make_smem_ptr(shared_tensors.smem_kc.begin()), SmemLayoutKC{});
- Tensor sVC = make_tensor(make_smem_ptr(shared_tensors.smem_vc.begin()), SmemLayoutVC{});
- Tensor sP = make_tensor(make_smem_ptr((Element*) shared_tensors.smem_p.begin()), SmemLayoutP{});
-
- Tensor tSrQ = TiledMmaQK::make_fragment_A(sQ);
- Tensor tSrKC = TiledMmaQK::make_fragment_B(sKC);
- Tensor tOrP = TiledMmaPV::make_fragment_A(sP);
- Tensor tOrVC = TiledMmaPV::make_fragment_B(sVC);
-
- TiledMmaQK tiled_mma_qk;
- TiledMmaPV tiled_mma_pv;
-
- Tensor tStS = partition_fragment_C(tiled_mma_qk, select<0,1>(TileShapeQK{}));
- Tensor tOtO = partition_fragment_C(tiled_mma_pv, select<0,1>(TileShapePV{}));
-
- tiled_mma_pv.accumulate_ = UMMA::ScaleOut::Zero;
-
- pipeline_mma_s.producer_acquire(pipeline_mma_s_producer_state);
-
- // Mma S0 S1 O0 S2 O1 ... Sn On-1 On
- // S0 ownership -- ----- -- --
- // S1 ownership -- ----- ----
- // O ownership -- -- ---- --
-
- tiled_mma_qk.accumulate_ = UMMA::ScaleOut::Zero;
- for (int i = 0; i < IterationsQK; i++) {
- pipeline_load_qk.consumer_wait(pipeline_load_qk_consumer_state);
- int read_stage = pipeline_load_qk_consumer_state.index();
-
- tStS.data() = uint32_t(pipeline_mma_s_producer_state.index() == 0 ? TmemAllocation::kS0 : TmemAllocation::kS1);
-
- CUTLASS_PRAGMA_UNROLL
- for (int k_block = 0; k_block < size<2>(tSrQ); ++k_block) {
- cute::gemm(tiled_mma_qk,
- tSrQ(_,_,k_block,i),
- tSrKC(_,_,k_block,read_stage),
- tStS);
- tiled_mma_qk.accumulate_ = UMMA::ScaleOut::One;
- }
-
- pipeline_load_qk.consumer_release(pipeline_load_qk_consumer_state);
- ++pipeline_load_qk_consumer_state;
- }
-
- pipeline_mma_s.producer_commit(pipeline_mma_s_producer_state);
- ++pipeline_mma_s_producer_state;
-
- k_tile_count -= 1;
-
- CUTLASS_PRAGMA_NO_UNROLL
- while (k_tile_count > 0) {
-
- pipeline_mma_s.producer_acquire(pipeline_mma_s_producer_state);
- tiled_mma_qk.accumulate_ = UMMA::ScaleOut::Zero;
- for (int i = 0; i < IterationsQK; i++) {
- pipeline_load_qk.consumer_wait(pipeline_load_qk_consumer_state);
- int read_stage = pipeline_load_qk_consumer_state.index();
-
- tStS.data() = uint32_t(pipeline_mma_s_producer_state.index() == 0 ? TmemAllocation::kS0 : TmemAllocation::kS1);
-
- CUTLASS_PRAGMA_UNROLL
- for (int k_block = 0; k_block < size<2>(tSrQ); ++k_block) {
- cute::gemm(tiled_mma_qk,
- tSrQ(_,_,k_block,i),
- tSrKC(_,_,k_block,read_stage),
- tStS);
- tiled_mma_qk.accumulate_ = UMMA::ScaleOut::One;
- }
-
- pipeline_load_qk.consumer_release(pipeline_load_qk_consumer_state);
- ++pipeline_load_qk_consumer_state;
- }
-
- pipeline_mma_s.producer_commit(pipeline_mma_s_producer_state);
- ++pipeline_mma_s_producer_state;
-
- pipeline_mma_o.producer_acquire(pipeline_mma_o_producer_state);
- pipeline_p_mma.consumer_wait(pipeline_p_mma_consumer_state);
-
- for (int i = 0; i < IterationsPV_K; i++) {
- auto acc_flag = tiled_mma_pv.accumulate_;
- for (int j = 0; j < IterationsPV_N; j++) {
- pipeline_load_pv.consumer_wait(pipeline_load_pv_consumer_state);
-
- int read_stage = pipeline_load_pv_consumer_state.index();
-
- tOtO.data() = uint32_t(TmemAllocation::kO0) + j * uint32_t(TmemAllocation::kSizeAccO);
- tiled_mma_pv.accumulate_ = acc_flag;
-
- CUTLASS_PRAGMA_UNROLL
- for (int k_block = 0; k_block < size<2>(tOrP); ++k_block) {
- cute::gemm(tiled_mma_pv,
- tOrP(_,_,k_block, make_coord(i, pipeline_p_mma_consumer_state.index())),
- tOrVC(_,_,k_block,read_stage),
- tOtO);
- tiled_mma_pv.accumulate_ = UMMA::ScaleOut::One;
- }
-
- pipeline_load_pv.consumer_release(pipeline_load_pv_consumer_state);
- ++pipeline_load_pv_consumer_state;
- }
- }
-
- pipeline_p_mma.consumer_release(pipeline_p_mma_consumer_state);
- ++pipeline_p_mma_consumer_state;
- pipeline_mma_o.producer_commit(pipeline_mma_o_producer_state);
- ++pipeline_mma_o_producer_state;
-
- --k_tile_count;
- }
-
- pipeline_mma_o.producer_acquire(pipeline_mma_o_producer_state);
- pipeline_p_mma.consumer_wait(pipeline_p_mma_consumer_state);
-
- for (int i = 0; i < IterationsPV_K; i++) {
- auto acc_flag = tiled_mma_pv.accumulate_;
- for (int j = 0; j < IterationsPV_N; j++) {
- pipeline_load_pv.consumer_wait(pipeline_load_pv_consumer_state);
-
- int read_stage = pipeline_load_pv_consumer_state.index();
-
- tOtO.data() = uint32_t(TmemAllocation::kO0) + j * uint32_t(TmemAllocation::kSizeAccO);
- tiled_mma_pv.accumulate_ = acc_flag;
-
- CUTLASS_PRAGMA_UNROLL
- for (int k_block = 0; k_block < size<2>(tOrP); ++k_block) {
- cute::gemm(tiled_mma_pv,
- tOrP(_,_,k_block, make_coord(i, pipeline_p_mma_consumer_state.index())),
- tOrVC(_,_,k_block,read_stage),
- tOtO);
- tiled_mma_pv.accumulate_ = UMMA::ScaleOut::One;
- }
-
- pipeline_load_pv.consumer_release(pipeline_load_pv_consumer_state);
- ++pipeline_load_pv_consumer_state;
- }
- }
-
- pipeline_p_mma.consumer_release(pipeline_p_mma_consumer_state);
- ++pipeline_p_mma_consumer_state;
- pipeline_mma_o.producer_commit(pipeline_mma_o_producer_state);
- ++pipeline_mma_o_producer_state;
- }
-
-
- template
- CUTLASS_DEVICE void softmax(
- IsLastTile const& is_last_tile,
- ElementAcc& row_max,
- ElementAcc& row_sum,
- ElementAcc& correction_factor,
- ProblemShape const& problem_shape,
- MainloopArguments const& mainloop_args,
- TensorStorage& shared_tensors,
- int k_index,
- uint32_t tmem_s,
- int smem_p_index) {
-
- auto load_op = cute::SM100_TMEM_LOAD_32dp32b32x{};
-
- TiledMmaQK tiled_mma_qk;
-
- Tensor tStS = partition_fragment_C(tiled_mma_qk, select<0,1>(TileShapeQK{}));
- tStS.data() = tmem_s;
-
- CUTE_STATIC_ASSERT_V(shape<1>(tStS) == _1{});
- CUTE_STATIC_ASSERT_V(shape<2>(tStS) == _1{});
- Tensor tAcc = tStS(make_coord(_,_),_0{},_0{});
-
- Tensor cS = make_identity_tensor(take<0,2>(CtaShapeQK{}));
-
- auto tiled_t2r = make_tmem_copy(load_op, tAcc);
- auto thread_idx = threadIdx.x % size(tiled_t2r);
-
- auto thread_t2r = tiled_t2r.get_slice(thread_idx);
- Tensor tTR_cS = thread_t2r.partition_D(cS);
- Tensor tTR_rAcc = make_tensor(shape(tTR_cS));
-
- Tensor tTR_rS_frag = make_tensor(shape(tTR_rAcc));
- const int AlignmentS = 4;
- Tensor tTR_tAcc = thread_t2r.partition_S(tAcc);
- Tensor tTR_rAcc_vec = recast>(tTR_rAcc);
- Tensor tTR_rS_vec = recast>(tTR_rS_frag);
-
- // load s
- copy(tiled_t2r, tTR_tAcc, tTR_rAcc);
-
- if (is_last_tile) {
- for (int i = 0; i < size(tTR_rAcc); i++) {
- if (get<1>(tTR_cS(i)) + TileShapeS{} * k_index >= get<1>(problem_shape)) {
- tTR_rAcc(i) = -std::numeric_limits::infinity();
- }
- }
- }
-
- // max
- ElementAcc row_max_new = row_max;
- CUTLASS_PRAGMA_UNROLL
- for (int i = 0; i < size(tTR_rAcc); i += 1) {
- row_max_new = ::fmax(row_max_new, tTR_rAcc(i));
- }
-
- // for 2x2 dp, reduce here
- if constexpr (kWarpsInN > 1) {
- shared_tensors.smem_exchange[threadIdx.x] = row_max_new;
- cutlass::arch::NamedBarrier(kNumComputeWarps*NumThreadsPerWarp, kNamedBarrierExchange).sync();
- // (64, 2) shape
- int peer_index = (threadIdx.x + 64) % 128;
- row_max_new = cutlass::max(row_max_new, shared_tensors.smem_exchange[peer_index]);
- }
-
-#ifndef B2B
- // find correction factor
- ElementAcc softmax_scale_log2 = mainloop_args.softmax_scale * static_cast(M_LOG2E);
- correction_factor = ::exp2f(softmax_scale_log2 * (row_max - row_max_new));
- row_max = row_max_new;
-
- // softmax
- ElementAcc row_max_scale_log2 = row_max * softmax_scale_log2;
- CUTLASS_PRAGMA_UNROLL
- for (int i = 0; i < size(tTR_rAcc); i++) {
- tTR_rAcc(i) = ::exp2f(softmax_scale_log2 * tTR_rAcc(i) - row_max_scale_log2);
- }
-#endif
-
- // quantize
- cutlass::NumericArrayConverter epilogue_op;
-
- CUTLASS_PRAGMA_UNROLL
- for (int i = 0; i < size(tTR_rAcc_vec); i++) {
- tTR_rS_vec(i) = epilogue_op(tTR_rAcc_vec(i));
- }
-
- Tensor sP = make_tensor(make_smem_ptr((Element*) shared_tensors.smem_p.begin()), SmemLayoutP{})(_, _, _, make_coord(_, smem_p_index));
-
- Tensor tOcP = TiledMmaPV{}.get_slice(_0{}).partition_A(cS);
-
- // have a mapping for each thread to coord
- // find identical mapping to coords for the MMA
- auto l = make_ordered_layout(make_shape(make_shape(_64{}, _2{}), make_shape(_16{}, TileShapeS{} / _32{})), make_stride(make_stride(_0{}, _3{}), make_stride(_1{}, _2{})));
- auto sP_ = as_position_independent_swizzle_tensor(sP);
- copy_aligned(tTR_rS_frag, sP_.compose(l)(threadIdx.x, _));
-
- // sum
- row_sum *= correction_factor;
-
- static_assert(cute::is_same_v);
- auto tTR_rAcc_float2 = recast(tTR_rAcc);
- auto sums = make_tensor(_4{});
- static_assert(size(tTR_rAcc_float2) % size(sums) == 0);
- CUTLASS_PRAGMA_UNROLL
- for (int i = 0; i < size(sums); i++) {
- sums(i) = tTR_rAcc_float2(i);
- }
- CUTLASS_PRAGMA_UNROLL
- for (int i = size(sums); i < size(tTR_rAcc_float2); i += size(sums)) {
- CUTLASS_PRAGMA_UNROLL
- for (int j = 0; j < size(sums); j++) {
- cute::add(sums(j), sums(j), tTR_rAcc_float2(i + j));
- }
- }
- CUTLASS_PRAGMA_UNROLL
- for (int i = 1; i < size(sums); i *= 2) {
- CUTLASS_PRAGMA_UNROLL
- for (int j = 0; j < size(sums); j += 2*i) {
- cute::add(sums(j), sums(j), sums(j+i));
- }
- }
- row_sum += sums(0).x + sums(0).y;
- }
-
-
- CUTLASS_DEVICE void rescale(
- ElementAcc correction_factor,
- uint32_t tmem_o) {
-
- // for b2b gemm, do nothing
-#ifndef B2B
- auto load_op = cute::SM100_TMEM_LOAD_32dp32b32x{};
- auto store_op = TMEM::tmem_load_to_store(load_op);
-
- TiledMmaPV tiled_mma_pv;
-
- Tensor tOtO = partition_fragment_C(tiled_mma_pv, select<0,1>(TileShapePV{}));
- tOtO.data() = tmem_o;
-
- CUTE_STATIC_ASSERT_V(shape<1>(tOtO) == _1{});
- CUTE_STATIC_ASSERT_V(shape<2>(tOtO) == _1{});
- Tensor tAcc = tOtO(make_coord(_,_),_0{},_0{});
-
- auto cta_tiler_pv = take<0,2>(typename CollectiveMmaPV::CtaShape_MNK{});
- Tensor gO = make_tensor(make_gmem_ptr((ElementAcc*) nullptr), cta_tiler_pv, make_stride(0, 0));
-
- auto tiled_t2r = make_tmem_copy(load_op, tAcc);
- auto tiled_r2t = make_tmem_copy(store_op, tAcc);
- auto thread_idx = threadIdx.x % size(tiled_t2r);
-
- auto thread_t2r = tiled_t2r.get_slice(thread_idx);
- auto thread_r2t = tiled_r2t.get_slice(thread_idx);
- Tensor tTR_gO = thread_t2r.partition_D(gO);
- Tensor tTR_rAcc = make_tensor(shape(tTR_gO));
-
- Tensor tTR_tAcc = thread_t2r.partition_S(tAcc);
-
- // load o
- copy(tiled_t2r, tTR_tAcc, tTR_rAcc);
-
- // multiply by correction factor
- float2 correction_factor_vec = make_float2(correction_factor, correction_factor);
- CUTLASS_PRAGMA_UNROLL
- for (int i = 0; i < size(tTR_rAcc); i += 2) {
- float2 in = make_float2(tTR_rAcc(i + 0), tTR_rAcc(i + 1));
- float2 out;
- cute::mul(out, in, correction_factor_vec);
- tTR_rAcc(i + 0) = out.x;
- tTR_rAcc(i + 1) = out.y;
- }
-
- // store o
- copy(tiled_r2t, tTR_rAcc, tTR_tAcc);
-#endif
- }
-
-
- template
- CUTLASS_DEVICE void epilogue(
- ElementAcc& row_max,
- ElementAcc& row_sum,
- BlkCoord const& cta_coord,
- ProblemShape const& problem_shape,
- MainloopArguments const& mainloop_args,
- EpilogueParams const& epilogue_args,
- TensorStorage& shared_tensors,
- uint32_t tmem_o,
- int const& split_kv) {
-
- auto load_op = cute::SM100_TMEM_LOAD_32dp32b32x{};
-
- TiledMmaPV tiled_mma_pv;
-
- Tensor tOtO = TiledMmaPV::make_fragment_C(partition_shape_C(TiledMmaPV{}, take<0, 2>(TileShapePV{})));
- tOtO.data() = tmem_o;
-
- CUTE_STATIC_ASSERT_V(shape<1>(tOtO) == _1{});
- CUTE_STATIC_ASSERT_V(shape<2>(tOtO) == _1{});
- Tensor tAcc = tOtO(make_coord(_,_),_0{},_0{});
-
- auto [H, K, D, B] = problem_shape;
- auto [D_latent, D_rope] = D;
- if (epilogue_args.ptr_o_acc != nullptr) {
- using ElementOutAcc = ElementAcc;
- constexpr auto AlignmentOutAcc = 128 / cute::sizeof_bits_v;
- Tensor mO = make_tensor(make_gmem_ptr(epilogue_args.ptr_o_acc + get<3>(cta_coord) * D_latent), make_shape(H, D_latent, B), epilogue_args.stride_o_acc);
- auto cta_tiler_pv = take<0,2>(typename CollectiveMmaPV::CtaShape_MNK{});
- Tensor gO = local_tile(mO, cta_tiler_pv, take<0,3>(cta_coord));
-
- auto tiled_t2r = make_tmem_copy(load_op, tAcc);
- auto thread_idx = threadIdx.x % size(tiled_t2r);
-
- auto thread_t2r = tiled_t2r.get_slice(thread_idx);
- Tensor tTR_gO = thread_t2r.partition_D(gO);
- Tensor tTR_rAcc = make_tensor(shape(tTR_gO));
-
- Tensor tTR_rO_frag = make_tensor(shape(tTR_rAcc));
- Tensor tTR_rO_src = recast>(coalesce(tTR_rO_frag));
- Tensor tR2G_rO_dst = recast>(coalesce(tTR_gO));
- Tensor tTR_tAcc = thread_t2r.partition_S(tAcc);
-
- copy(tiled_t2r, tTR_tAcc, tTR_rAcc);
-
- cutlass::epilogue::thread::LinearCombination epilogue_op({epilogue_args.output_scale / row_sum});
- CUTLASS_PRAGMA_UNROLL
- for (int i = 0; i < size(tTR_rAcc); i++) {
- tTR_rO_frag(i) = epilogue_op(tTR_rAcc(i));
- }
-
- copy(tTR_rO_src, tR2G_rO_dst);
-
-#ifndef B2B
-
- // compute LSE
- ElementAcc lse = cutlass::fast_log(row_sum) + mainloop_args.softmax_scale * row_max;
-
- // store LSE
- Tensor mLSE = make_tensor(make_gmem_ptr(epilogue_args.ptr_lse_acc + H * get<3>(cta_coord)), make_shape(H, B), epilogue_args.stride_lse_acc);
- Tensor gLSE = local_tile(mLSE, append<3>(cta_tiler_pv, _1{}), take<0,3>(cta_coord), Step<_1, Underscore, _1>{});
- // for 2x2 dp, this must be conditional and the index is wrong
- if (! kIs2Sm || (threadIdx.x < 64))
- {
- gLSE(threadIdx.x) = lse;
- }
- #endif
- }
- else {
- Tensor mO = make_tensor(make_gmem_ptr(epilogue_args.ptr_o), make_shape(H, D_latent, B), epilogue_args.stride_o);
- auto cta_tiler_pv = take<0,2>(typename CollectiveMmaPV::CtaShape_MNK{});
- Tensor gO = local_tile(mO, cta_tiler_pv, take<0,3>(cta_coord));
-
- auto tiled_t2r = make_tmem_copy(load_op, tAcc);
- auto thread_idx = threadIdx.x % size(tiled_t2r);
-
- auto thread_t2r = tiled_t2r.get_slice(thread_idx);
- Tensor tTR_gO = thread_t2r.partition_D(gO);
- Tensor tTR_rAcc = make_tensor(shape(tTR_gO));
-
- Tensor tTR_rO_frag = make_tensor(shape(tTR_rAcc));
- Tensor tTR_rO_src = recast>(coalesce(tTR_rO_frag));
- Tensor tR2G_rO_dst = recast>(coalesce(tTR_gO));
- Tensor tTR_tAcc = thread_t2r.partition_S(tAcc);
-
- copy(tiled_t2r, tTR_tAcc, tTR_rAcc);
-
- cutlass::epilogue::thread::LinearCombination epilogue_op({epilogue_args.output_scale / row_sum});
- CUTLASS_PRAGMA_UNROLL
- for (int i = 0; i < size(tTR_rAcc); i++) {
- tTR_rO_frag(i) = epilogue_op(tTR_rAcc(i));
- }
-
- copy(tTR_rO_src, tR2G_rO_dst);
-
-#ifndef B2B
- if (epilogue_args.ptr_lse != nullptr) {
- // compute LSE
- ElementAcc lse = cutlass::fast_log(row_sum) + mainloop_args.softmax_scale * row_max;
-
- // store LSE
- Tensor mLSE = make_tensor(make_gmem_ptr(epilogue_args.ptr_lse), make_shape(H, B), epilogue_args.stride_lse);
- Tensor gLSE = local_tile(mLSE, append<3>(cta_tiler_pv, _1{}), take<0,3>(cta_coord), Step<_1, Underscore, _1>{});
-
- // for 2x2 dp, this must be conditional and the index is wrong
- if (! kIs2Sm || (threadIdx.x < 64))
- {
- gLSE(threadIdx.x) = lse;
- }
- }
-#endif
- }
- }
-
-
- template
- CUTLASS_DEVICE void compute(
- CtaCoord const& cta_coord,
- ProblemShape const& problem_shape,
- MainloopArguments const& mainloop_args,
- EpilogueParams const& epilogue_args,
- TensorStorage& shared_tensors,
- PipelineS& pipeline_mma_s,
- typename PipelineS::PipelineState& pipeline_mma_s_consumer_state,
- PipelineP& pipeline_p_mma,
- typename PipelineP::PipelineState& pipeline_p_mma_producer_state,
- PipelineO& pipeline_mma_o,
- typename PipelineO::PipelineState& pipeline_mma_o_consumer_state,
- int const& split_kv) {
-
- auto [H, K, D, B] = problem_shape;
-
- int k_tile_total = ceil_div(K, TileShapeS{});
- int k_tile_per_cta = ceil_div(k_tile_total, split_kv);
- int k_index = get<3>(cta_coord) * k_tile_per_cta; // lower limit
- int k_tile_count = max(0, min(k_tile_total, k_index + k_tile_per_cta) - k_index);
- if (k_tile_count == 0) {
-
- // if we return early, we have to make sure we release the load warp
- cutlass::arch::NamedBarrier(
- (kNumComputeWarps + kNumLoadWarps) * NumThreadsPerWarp,
- kNamedBarrierEpilogue
- ).arrive();
-
- return;
- }
- int k_index_final = k_tile_total - 1;
-
- ElementAcc row_max = -std::numeric_limits::infinity();
- ElementAcc row_sum = 0;
- ElementAcc correction_factor = 1;
-
- pipeline_p_mma.producer_acquire(pipeline_p_mma_producer_state);
- pipeline_mma_s.consumer_wait(pipeline_mma_s_consumer_state);
-
- auto dispatch_bool = [](bool b, auto fn) {
- if (b) {
- fn(cute::true_type{});
- }
- else {
- fn(cute::false_type{});
- }
- };
-
- // softmax s0 -> p0
- dispatch_bool(k_index == k_index_final, [&](auto is_last_tile) {
- softmax(
- is_last_tile,
- row_max, row_sum, correction_factor,
- problem_shape, mainloop_args, shared_tensors, k_index,
- uint32_t(pipeline_mma_s_consumer_state.index() == 0 ? TmemAllocation::kS0 : TmemAllocation::kS1),
- pipeline_p_mma_producer_state.index()
- );
- });
-
- k_index += 1;
-
- cutlass::arch::fence_view_async_tmem_load();
- cutlass::arch::fence_view_async_shared();
- pipeline_mma_s.consumer_release(pipeline_mma_s_consumer_state);
- ++pipeline_mma_s_consumer_state;
- pipeline_p_mma.producer_commit(pipeline_p_mma_producer_state);
- ++pipeline_p_mma_producer_state;
-
- k_tile_count -= 1;
-
- CUTLASS_PRAGMA_NO_UNROLL
- while (k_tile_count > 0) {
- pipeline_p_mma.producer_acquire(pipeline_p_mma_producer_state);
- pipeline_mma_s.consumer_wait(pipeline_mma_s_consumer_state);
-
- // softmax s1 -> p1
- dispatch_bool(k_index == k_index_final, [&](auto is_last_tile) {
- softmax(
- is_last_tile,
- row_max, row_sum, correction_factor,
- problem_shape, mainloop_args, shared_tensors, k_index,
- uint32_t(pipeline_mma_s_consumer_state.index() == 0 ? TmemAllocation::kS0 : TmemAllocation::kS1),
- pipeline_p_mma_producer_state.index()
- );
- });
-
- cutlass::arch::fence_view_async_tmem_load();
- cutlass::arch::fence_view_async_shared();
- pipeline_mma_s.consumer_release(pipeline_mma_s_consumer_state);
- ++pipeline_mma_s_consumer_state;
- pipeline_p_mma.producer_commit(pipeline_p_mma_producer_state);
- ++pipeline_p_mma_producer_state;
-
- pipeline_mma_o.consumer_wait(pipeline_mma_o_consumer_state);
-
- // rescale
- CUTLASS_PRAGMA_UNROLL
- for (int j = 0; j < IterationsPV_N; j++) {
- rescale(correction_factor, uint32_t(TmemAllocation::kO0) + j * uint32_t(TmemAllocation::kSizeAccO));
- }
-
- cutlass::arch::fence_view_async_tmem_store();
- pipeline_mma_o.consumer_release(pipeline_mma_o_consumer_state);
- ++pipeline_mma_o_consumer_state;
-
- --k_tile_count;
- k_index += 1;
- }
-
- pipeline_mma_o.consumer_wait(pipeline_mma_o_consumer_state);
-
-#ifdef B2B
- row_sum = 1;
-#else
- if constexpr (kWarpsInN > 1) {
- // reduce row_sum if needed (for 2x2 dp)
- shared_tensors.smem_exchange[threadIdx.x] = row_sum;
- cutlass::arch::NamedBarrier(kNumComputeWarps*NumThreadsPerWarp, kNamedBarrierExchange).sync();
- // (64, 2) shape
- int peer_index = (threadIdx.x + 64) % 128;
- row_sum += shared_tensors.smem_exchange[peer_index];
- }
-#endif
-
- cutlass::arch::NamedBarrier((kNumComputeWarps + kNumLoadWarps) * NumThreadsPerWarp, kNamedBarrierEpilogue).arrive();
-
- // epilogue
- CUTLASS_PRAGMA_UNROLL
- for (int j = 0; j < IterationsPV_N; j++) {
- epilogue(
- row_max, row_sum,
- replace<1>(cta_coord, j), problem_shape,
- mainloop_args, epilogue_args, shared_tensors,
- uint32_t(TmemAllocation::kO0) + j * uint32_t(TmemAllocation::kSizeAccO), split_kv
- );
- }
-
- cutlass::arch::fence_view_async_tmem_load();
- pipeline_mma_o.consumer_release(pipeline_mma_o_consumer_state);
- ++pipeline_mma_o_consumer_state;
- }
-
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-} // namespace cutlass::fmha::kernel
diff --git a/python/sglang/kernels/aot/csrc/attention/cutlass_sm100_mla/kernel/sm100_mla_tile_scheduler.hpp b/python/sglang/kernels/aot/csrc/attention/cutlass_sm100_mla/kernel/sm100_mla_tile_scheduler.hpp
deleted file mode 100644
index 30389e79f..000000000
--- a/python/sglang/kernels/aot/csrc/attention/cutlass_sm100_mla/kernel/sm100_mla_tile_scheduler.hpp
+++ /dev/null
@@ -1,160 +0,0 @@
-/***************************************************************************************************
- * Copyright (c) 2024 - 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
- * SPDX-License-Identifier: BSD-3-Clause
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * 3. Neither the name of the copyright holder nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- **************************************************************************************************/
-
-// clang-format off
-#pragma once
-
-#include "cutlass/cutlass.h"
-#include "cutlass/fast_math.h"
-#include "cutlass/kernel_hardware_info.h"
-
-namespace cutlass::fmha::kernel {
-
-////////////////////////////////////////////////////////////////////////////////
-
-struct Sm100MlaIndividualTileScheduler {
-
- struct Params {
- dim3 grid;
- };
-
- bool valid_ = true;
-
- CUTLASS_DEVICE
- Sm100MlaIndividualTileScheduler(Params const&) {}
-
- template
- static Params to_underlying_arguments(
- ProblemShape const& problem_shape, KernelHardwareInfo hw_info,
- ClusterShape const& cluster_shape, int const& split_kv) {
- using namespace cute;
- dim3 grid(get<0>(cluster_shape), get<3>(problem_shape) /* Batch */, split_kv /*Maximum Split KV*/);
- return Params{ grid };
- }
-
- static dim3 get_grid_shape(Params const& params) {
- return params.grid;
- }
-
- CUTLASS_DEVICE
- bool is_valid() {
- return valid_;
- }
-
- CUTLASS_DEVICE
- auto get_block_coord() {
- using namespace cute;
- return make_coord(blockIdx.x, _0{}, blockIdx.y, blockIdx.z);
- }
-
- CUTLASS_DEVICE
- Sm100MlaIndividualTileScheduler& operator++() {
- valid_ = false;
- return *this;
- }
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-struct Sm100MlaPersistentTileScheduler {
-
- struct Params {
- int num_blocks;
- FastDivmod divmod_m_block;
- FastDivmod divmod_b;
- FastDivmod divmod_split_kv;
- KernelHardwareInfo hw_info;
- };
-
- int block_idx = 0;
- Params params;
-
- CUTLASS_DEVICE
- Sm100MlaPersistentTileScheduler(Params const& params) : block_idx(blockIdx.x), params(params) {}
-
- template
- static Params to_underlying_arguments(
- ProblemShape const& problem_shape, KernelHardwareInfo hw_info,
- ClusterShape const& cluster_shape, int const& split_kv) {
- using namespace cute;
- // Get SM count if needed, otherwise use user supplied SM count
- int sm_count = hw_info.sm_count;
- if (sm_count <= 1 || sm_count % size<0>(cluster_shape) != 0) {
- CUTLASS_TRACE_HOST(" WARNING: Arguments do not include a valid SM count.\n"
- " For optimal performance, populate the arguments KernelHardwareInfo struct with the SM count.");
- sm_count = KernelHardwareInfo::query_device_multiprocessor_count(hw_info.device_id);
- }
-
- CUTLASS_TRACE_HOST("to_underlying_arguments(): Setting persistent grid SM count to " << sm_count);
- hw_info.sm_count = sm_count;
-
- int num_m_blocks = size<0>(cluster_shape);
- int num_blocks = num_m_blocks * get<3>(problem_shape) /* Batch */;
- num_blocks *= split_kv; /* Maximum Split KV*/
-
- return Params {
- num_blocks,
- { num_m_blocks}, { get<3>(problem_shape) }, {split_kv},
- hw_info
- };
- }
-
- static dim3 get_grid_shape(Params const& params) {
- dim3 grid(std::min(params.num_blocks, params.hw_info.sm_count), 1, 1);
- return grid;
- }
-
- CUTLASS_DEVICE
- bool is_valid() {
- return block_idx < params.num_blocks;
- }
-
- CUTLASS_DEVICE
- auto get_block_coord() {
- using namespace cute;
- int block_decode = block_idx;
- int m_block, bidb, n_split_kv;
- params.divmod_m_block(block_decode, m_block, block_decode);
- params.divmod_b(block_decode, bidb, block_decode);
- params.divmod_split_kv(block_decode, n_split_kv, block_decode);
- return make_coord(m_block, _0{}, bidb, n_split_kv);
- }
-
- CUTLASS_DEVICE
- Sm100MlaPersistentTileScheduler& operator++() {
- block_idx += gridDim.x;
- return *this;
- }
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-} // namespace cutlass::fmha::kernel
diff --git a/python/sglang/kernels/aot/csrc/attention/vertical_slash_index.cu b/python/sglang/kernels/aot/csrc/attention/vertical_slash_index.cu
deleted file mode 100644
index 118f780dd..000000000
--- a/python/sglang/kernels/aot/csrc/attention/vertical_slash_index.cu
+++ /dev/null
@@ -1,462 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT license.
-// This file is for blocksparse attention utils cuda kernel.
-
-#include
-#include
-#include
-#include
-
-// Save the start index of each block in the given range into block_offset.
-// Returns the updated block count.
-__device__ int64_t save_blocks(
- int* block_offset,
- int64_t range_start,
- int64_t range_end,
- int64_t block_size,
- int64_t input_block_count,
- int64_t kv_seqlen) {
- if (range_start >= kv_seqlen) {
- return input_block_count;
- }
- if (range_end > kv_seqlen) {
- range_end = kv_seqlen;
- }
- int64_t current_block_count = input_block_count;
- for (int idx = range_start; idx < range_end; idx += block_size) {
- block_offset[current_block_count++] = idx;
- }
- return current_block_count;
-}
-
-// CUDA kernel: convert sparse vertical/slash indices to block/column offsets.
-__global__ void convert_vertical_slash_indexes_kernel(
- const int* q_seqlens, // [BATCH, ]
- const int* kv_seqlens, // [BATCH, ]
- const int* vertical_indexes, // [BATCH, N_HEADS, NNZ_V]
- const int* slash_indexes, // [BATCH, N_HEADS, NNZ_S]
- int* block_count, // [BATCH, N_HEADS, cdiv(N_CTX, BLOCK_SIZE_M)]
- int* block_offset, // [BATCH, N_HEADS, cdiv(N_CTX, BLOCK_SIZE_M), NNZ_S]
- int* column_count, // [BATCH, N_HEADS, cdiv(N_CTX, BLOCK_SIZE_M)]
- int* column_index, // [BATCH, N_HEADS, cdiv(N_CTX, BLOCK_SIZE_M), NNZ_V]
- int64_t N_HEADS,
- int64_t N_ROWS,
- int64_t BLOCK_SIZE_M,
- int64_t BLOCK_SIZE_N,
- int64_t NNZ_V,
- int64_t NNZ_S,
- bool causal // True for intra, False for succ
-) {
- const int batch_idx = blockIdx.y;
- const int head_idx = blockIdx.x;
- const int group_idx = blockIdx.z;
-
- int64_t q_seqlen = q_seqlens[batch_idx];
- int64_t kv_seqlen = kv_seqlens[batch_idx];
- int64_t block_idx_m = group_idx * blockDim.x + threadIdx.x;
- int64_t start_m = block_idx_m * BLOCK_SIZE_M;
- if (start_m >= q_seqlen) {
- return;
- }
- int64_t end_m = start_m + BLOCK_SIZE_M;
- vertical_indexes += (batch_idx * N_HEADS + head_idx) * NNZ_V;
- slash_indexes += (batch_idx * N_HEADS + head_idx) * NNZ_S;
- int64_t row_offset = (batch_idx * N_HEADS + head_idx) * N_ROWS + block_idx_m;
- block_count += row_offset;
- block_offset += row_offset * NNZ_S;
- column_count += row_offset;
- column_index += row_offset * NNZ_V;
-
- bool has_slash = true;
- int64_t tmp_col_cnt = 0, tmp_blk_cnt = 0;
- int64_t s = 0, v = 0;
- int64_t v_idx = vertical_indexes[v++];
- int64_t s_idx = slash_indexes[s++];
- if (causal) {
- while (s_idx >= end_m + (kv_seqlen - q_seqlen) && s < NNZ_S) {
- s_idx = slash_indexes[s++];
- }
- if (s_idx > end_m + (kv_seqlen - q_seqlen)) has_slash = false;
- s_idx = max((kv_seqlen - q_seqlen) + end_m - s_idx, BLOCK_SIZE_M);
- } else {
- while (s_idx >= end_m + kv_seqlen && s < NNZ_S) {
- s_idx = slash_indexes[s++];
- }
- if (s_idx > end_m + kv_seqlen) has_slash = false;
- s_idx = max(kv_seqlen + end_m - s_idx, BLOCK_SIZE_M);
- }
-
- int64_t range_start = s_idx - BLOCK_SIZE_M, range_end = s_idx;
- if (!has_slash) {
- if (causal) {
- range_start = (kv_seqlen - q_seqlen) + end_m;
- range_end = (kv_seqlen - q_seqlen) + end_m + BLOCK_SIZE_N;
- } else {
- range_start = kv_seqlen;
- range_end = kv_seqlen + BLOCK_SIZE_N;
- }
- }
-
- bool slash_finished = false;
- while (1) {
- if (v_idx < range_end) {
- if (v_idx < range_start) {
- column_index[tmp_col_cnt++] = v_idx;
- }
- if (v < NNZ_V) {
- v_idx = vertical_indexes[v++];
- } else {
- if (causal)
- v_idx = end_m + BLOCK_SIZE_N + (kv_seqlen - q_seqlen);
- else
- v_idx = end_m + BLOCK_SIZE_N + kv_seqlen;
- }
- } else {
- if ((s < NNZ_S && causal) || (s < NNZ_S && !causal && slash_indexes[s] >= start_m)) {
- if (causal)
- s_idx = max((kv_seqlen - q_seqlen) + end_m - slash_indexes[s++], BLOCK_SIZE_M);
- else
- s_idx = max(kv_seqlen + end_m - slash_indexes[s++], BLOCK_SIZE_M);
- } else {
- if (v == NNZ_V || (v_idx > range_start && causal)) {
- // add the last vertical if no more slash
- if (v == NNZ_V && !causal && v_idx < kv_seqlen) {
- column_index[tmp_col_cnt++] = v_idx;
- }
- tmp_blk_cnt = save_blocks(block_offset, range_start, range_end, BLOCK_SIZE_N, tmp_blk_cnt, kv_seqlen);
- break;
- } else {
- if (causal) {
- range_start = (kv_seqlen - q_seqlen) + end_m;
- range_end = (kv_seqlen - q_seqlen) + end_m + BLOCK_SIZE_N;
- } else {
- // if slash_finished but there are vertical left, save current
- // blocks
- tmp_blk_cnt = save_blocks(block_offset, range_start, range_end, BLOCK_SIZE_N, tmp_blk_cnt, kv_seqlen);
- range_start = kv_seqlen;
- range_end = kv_seqlen + BLOCK_SIZE_N;
- }
- slash_finished = true;
- }
- }
- if (!slash_finished) {
- if (s_idx > range_end + BLOCK_SIZE_M) {
- tmp_blk_cnt = save_blocks(block_offset, range_start, range_end, BLOCK_SIZE_N, tmp_blk_cnt, kv_seqlen);
- range_start = s_idx - BLOCK_SIZE_M;
- range_end = s_idx;
- } else if (s_idx > range_end) {
- range_end += BLOCK_SIZE_M;
- }
- }
- }
- }
-
- block_count[0] = tmp_blk_cnt;
- column_count[0] = tmp_col_cnt;
-}
-
-// Host function: launches the kernel with 64 threads per block.
-void convert_vertical_slash_indexes_64x64(
- const int* q_seqlens, // [BATCH, ]
- const int* kv_seqlens, // [BATCH, ]
- const int* vertical_indexes, // [BATCH, N_HEADS, NNZ_V]
- const int* slash_indexes, // [BATCH, N_HEADS, NNZ_S]
- int* block_count, // [BATCH, N_HEADS, cdiv(N_CTX, BLOCK_SIZE_M)]
- int* block_offset, // [BATCH, N_HEADS, cdiv(N_CTX, BLOCK_SIZE_M), NNZ_S]
- int* column_count, // [BATCH, N_HEADS, cdiv(N_CTX, BLOCK_SIZE_M)]
- int* column_index, // [BATCH, N_HEADS, cdiv(N_CTX, BLOCK_SIZE_M), NNZ_V]
- int64_t BATCH_SIZE,
- int64_t N_HEADS,
- int64_t N_ROWS,
- int64_t BLOCK_SIZE_M,
- int64_t BLOCK_SIZE_N,
- int64_t NNZ_V,
- int64_t NNZ_S,
- bool causal) {
- const int N_THREADS = 64;
- const dim3 dimBlock((int32_t)N_THREADS);
- const dim3 dimGrid(
- (int32_t)N_HEADS, (int32_t)BATCH_SIZE, ((int32_t)N_ROWS + (int32_t)N_THREADS - 1) / (int32_t)N_THREADS);
- cudaStream_t stream = at::cuda::getCurrentCUDAStream();
- convert_vertical_slash_indexes_kernel<<>>(
- q_seqlens,
- kv_seqlens,
- vertical_indexes,
- slash_indexes,
- block_count,
- block_offset,
- column_count,
- column_index,
- N_HEADS,
- N_ROWS,
- BLOCK_SIZE_M,
- BLOCK_SIZE_N,
- NNZ_V,
- NNZ_S,
- causal);
-}
-
-// Host function: prepares tensor pointers and launches the CUDA kernel.
-void convert_vertical_slash_indexes(
- torch::Tensor& block_count, // [BATCH, N_HEADS, NUM_ROWS]
- torch::Tensor& block_offset, // [BATCH, N_HEADS, NUM_ROWS, NNZ_S]
- torch::Tensor& column_count, // [BATCH, N_HEADS, NUM_ROWS]
- torch::Tensor& column_index, // [BATCH, N_HEADS, NUM_ROWS, NNZ_V]
- torch::Tensor q_seqlens, // [BATCH, ]
- torch::Tensor kv_seqlens, // [BATCH, ]
- torch::Tensor vertical_indexes, // [BATCH, N_HEADS, NNZ_V]
- torch::Tensor slash_indexes, // [BATCH, N_HEADS, NNZ_S]
- int64_t context_size,
- int64_t block_size_M,
- int64_t block_size_N,
- bool causal) {
- cudaSetDevice(q_seqlens.get_device());
-
- int64_t batch_size = slash_indexes.size(0);
- int64_t num_heads = slash_indexes.size(1);
- int64_t nnz_slash = slash_indexes.size(2);
- int64_t nnz_vertical = vertical_indexes.size(2);
- int64_t num_rows = (context_size + block_size_M - 1) / block_size_M;
-
- convert_vertical_slash_indexes_64x64(
- q_seqlens.data_ptr(),
- kv_seqlens.data_ptr(),
- vertical_indexes.data_ptr(),
- slash_indexes.data_ptr(),
- block_count.data_ptr(),
- block_offset.data_ptr(),
- column_count.data_ptr(),
- column_index.data_ptr(),
- batch_size,
- num_heads,
- num_rows,
- block_size_M,
- block_size_N,
- nnz_vertical,
- nnz_slash,
- causal);
-}
-
-// --- mergehead kernels --- //
-
-// Kernel: like above, but supports per-head variable NNZ_V/NNZ_S.
-__global__ void convert_vertical_slash_indexes_kernel_mergehead(
- const int* q_seqlens, // [BATCH, ]
- const int* kv_seqlens, // [BATCH, ]
- const int* vertical_indexes, // [BATCH, N_HEADS, NNZ_V]
- const int* slash_indexes, // [BATCH, N_HEADS, NNZ_S]
- const int* per_head_vertical_topkv,
- const int* per_head_slash_topkv,
- int* block_count, // [BATCH, N_HEADS, cdiv(N_CTX, BLOCK_SIZE_M)]
- int* block_offset, // [BATCH, N_HEADS, cdiv(N_CTX, BLOCK_SIZE_M), NNZ_S]
- int* column_count, // [BATCH, N_HEADS, cdiv(N_CTX, BLOCK_SIZE_M)]
- int* column_index, // [BATCH, N_HEADS, cdiv(N_CTX, BLOCK_SIZE_M), NNZ_V]
- int64_t N_HEADS,
- int64_t N_ROWS,
- int64_t BLOCK_SIZE_M,
- int64_t BLOCK_SIZE_N,
- int64_t NNZ_V,
- int64_t NNZ_S,
- bool causal // True for intra, False for succ
-) {
- const int batch_idx = blockIdx.y;
- const int head_idx = blockIdx.x;
- const int group_idx = blockIdx.z;
-
- int64_t q_seqlen = q_seqlens[batch_idx];
- int64_t kv_seqlen = kv_seqlens[batch_idx];
- int64_t block_idx_m = group_idx * blockDim.x + threadIdx.x;
- int64_t start_m = block_idx_m * BLOCK_SIZE_M;
- if (start_m >= q_seqlen) {
- return;
- }
- int64_t end_m = start_m + BLOCK_SIZE_M;
- vertical_indexes += (batch_idx * N_HEADS + head_idx) * NNZ_V;
- slash_indexes += (batch_idx * N_HEADS + head_idx) * NNZ_S;
- int64_t row_offset = (batch_idx * N_HEADS + head_idx) * N_ROWS + block_idx_m;
- block_count += row_offset;
- block_offset += row_offset * NNZ_S;
- column_count += row_offset;
- column_index += row_offset * NNZ_V;
-
- // MergeHead: each head has it's unique max topk NNZ_V,NNZ_S. (NNZ_V,NNZ_S
- // above is buffer size, use to compute offset)
- NNZ_S = per_head_slash_topkv[head_idx];
- NNZ_V = per_head_vertical_topkv[head_idx];
-
- bool has_slash = true;
- int64_t tmp_col_cnt = 0, tmp_blk_cnt = 0;
- int64_t s = 0, v = 0;
- int64_t v_idx = vertical_indexes[v++];
- int64_t s_idx = slash_indexes[s++];
- if (causal) {
- while (s_idx >= end_m + (kv_seqlen - q_seqlen) && s < NNZ_S) {
- s_idx = slash_indexes[s++];
- }
- if (s_idx > end_m + (kv_seqlen - q_seqlen)) has_slash = false;
- s_idx = max((kv_seqlen - q_seqlen) + end_m - s_idx, BLOCK_SIZE_M);
- } else {
- while (s_idx >= end_m + kv_seqlen && s < NNZ_S) {
- s_idx = slash_indexes[s++];
- }
- if (s_idx > end_m + kv_seqlen) has_slash = false;
- s_idx = max(kv_seqlen + end_m - s_idx, BLOCK_SIZE_M);
- }
-
- int64_t range_start = s_idx - BLOCK_SIZE_M, range_end = s_idx;
- if (!has_slash) {
- if (causal) {
- range_start = (kv_seqlen - q_seqlen) + end_m;
- range_end = (kv_seqlen - q_seqlen) + end_m + BLOCK_SIZE_N;
- } else {
- range_start = kv_seqlen;
- range_end = kv_seqlen + BLOCK_SIZE_N;
- }
- }
-
- bool slash_finished = false;
- while (1) {
- if (v_idx < range_end) {
- if (v_idx < range_start) {
- column_index[tmp_col_cnt++] = v_idx;
- }
- if (v < NNZ_V) {
- v_idx = vertical_indexes[v++];
- } else {
- if (causal)
- v_idx = end_m + BLOCK_SIZE_N + (kv_seqlen - q_seqlen);
- else
- v_idx = end_m + BLOCK_SIZE_N + kv_seqlen;
- }
- } else {
- if ((s < NNZ_S && causal) || (s < NNZ_S && !causal && slash_indexes[s] >= start_m)) {
- if (causal)
- s_idx = max((kv_seqlen - q_seqlen) + end_m - slash_indexes[s++], BLOCK_SIZE_M);
- else
- s_idx = max(kv_seqlen + end_m - slash_indexes[s++], BLOCK_SIZE_M);
- } else {
- if (v == NNZ_V || (v_idx > range_start && causal)) {
- // add the last vertical if no more slash
- if (v == NNZ_V && !causal && v_idx < kv_seqlen) {
- column_index[tmp_col_cnt++] = v_idx;
- }
- tmp_blk_cnt = save_blocks(block_offset, range_start, range_end, BLOCK_SIZE_N, tmp_blk_cnt, kv_seqlen);
- break;
- } else {
- if (causal) {
- range_start = (kv_seqlen - q_seqlen) + end_m;
- range_end = (kv_seqlen - q_seqlen) + end_m + BLOCK_SIZE_N;
- } else {
- // if slash_finished but there are vertical left, save current
- // blocks
- tmp_blk_cnt = save_blocks(block_offset, range_start, range_end, BLOCK_SIZE_N, tmp_blk_cnt, kv_seqlen);
- range_start = kv_seqlen;
- range_end = kv_seqlen + BLOCK_SIZE_N;
- }
- slash_finished = true;
- }
- }
- if (!slash_finished) {
- if (s_idx > range_end + BLOCK_SIZE_M) {
- tmp_blk_cnt = save_blocks(block_offset, range_start, range_end, BLOCK_SIZE_N, tmp_blk_cnt, kv_seqlen);
- range_start = s_idx - BLOCK_SIZE_M;
- range_end = s_idx;
- } else if (s_idx > range_end) {
- range_end += BLOCK_SIZE_M;
- }
- }
- }
- }
-
- block_count[0] = tmp_blk_cnt;
- column_count[0] = tmp_col_cnt;
-}
-
-// Launch the mergehead kernel with 64 threads per block.
-void convert_vertical_slash_indexes_64x64_mergehead(
- const int* q_seqlens, // [BATCH, ]
- const int* kv_seqlens, // [BATCH, ]
- const int* vertical_indexes, // [BATCH, N_HEADS, NNZ_V]
- const int* slash_indexes, // [BATCH, N_HEADS, NNZ_S]
- int* per_head_vertical_topkv,
- int* per_head_slash_topkv,
- int* block_count, // [BATCH, N_HEADS, cdiv(N_CTX, BLOCK_SIZE_M)]
- int* block_offset, // [BATCH, N_HEADS, cdiv(N_CTX, BLOCK_SIZE_M), NNZ_S]
- int* column_count, // [BATCH, N_HEADS, cdiv(N_CTX, BLOCK_SIZE_M)]
- int* column_index, // [BATCH, N_HEADS, cdiv(N_CTX, BLOCK_SIZE_M), NNZ_V]
- int64_t BATCH_SIZE,
- int64_t N_HEADS,
- int64_t N_ROWS,
- int64_t BLOCK_SIZE_M,
- int64_t BLOCK_SIZE_N,
- int64_t NNZ_V,
- int64_t NNZ_S,
- bool causal) {
- const int N_THREADS = 64;
- const dim3 dimBlock(N_THREADS);
- const dim3 dimGrid(N_HEADS, BATCH_SIZE, (N_ROWS + N_THREADS - 1) / N_THREADS);
- cudaStream_t stream = at::cuda::getCurrentCUDAStream();
- convert_vertical_slash_indexes_kernel_mergehead<<>>(
- q_seqlens,
- kv_seqlens,
- vertical_indexes,
- slash_indexes,
- per_head_vertical_topkv,
- per_head_slash_topkv,
- block_count,
- block_offset,
- column_count,
- column_index,
- N_HEADS,
- N_ROWS,
- BLOCK_SIZE_M,
- BLOCK_SIZE_N,
- NNZ_V,
- NNZ_S,
- causal);
-}
-
-// Host wrapper for mergehead kernel.
-void convert_vertical_slash_indexes_mergehead(
- torch::Tensor& block_count, // [BATCH, N_HEADS, NUM_ROWS]
- torch::Tensor& block_offset, // [BATCH, N_HEADS, NUM_ROWS, NNZ_S]
- torch::Tensor& column_count, // [BATCH, N_HEADS, NUM_ROWS]
- torch::Tensor& column_index, // [BATCH, N_HEADS, NUM_ROWS, NNZ_V]
- torch::Tensor q_seqlens, // [BATCH, ]
- torch::Tensor kv_seqlens, // [BATCH, ]
- torch::Tensor vertical_indexes, // [BATCH, N_HEADS, NNZ_V]
- torch::Tensor slash_indexes, // [BATCH, N_HEADS, NNZ_S]
- torch::Tensor vertical_indices_count, // [N_HEADS, ]
- torch::Tensor slash_indices_count,
- int64_t context_size,
- int64_t block_size_M,
- int64_t block_size_N,
- bool causal) {
- cudaSetDevice(q_seqlens.get_device());
-
- int batch_size = slash_indexes.size(0);
- int num_heads = slash_indexes.size(1);
- int nnz_slash = slash_indexes.size(2);
- int nnz_vertical = vertical_indexes.size(2);
- int num_rows = (context_size + block_size_M - 1) / block_size_M;
-
- convert_vertical_slash_indexes_64x64_mergehead(
- q_seqlens.data_ptr(),
- kv_seqlens.data_ptr(),
- vertical_indexes.data_ptr(),
- slash_indexes.data_ptr(),
- vertical_indices_count.data_ptr(),
- slash_indices_count.data_ptr(),
- block_count.data_ptr(),
- block_offset.data_ptr(),
- column_count.data_ptr(),
- column_index.data_ptr(),
- batch_size,
- num_heads,
- num_rows,
- block_size_M,
- block_size_N,
- nnz_vertical,
- nnz_slash,
- causal);
-}
diff --git a/python/sglang/kernels/aot/csrc/common_extension.cc b/python/sglang/kernels/aot/csrc/common_extension.cc
index 211bbdc05..4d0320202 100644
--- a/python/sglang/kernels/aot/csrc/common_extension.cc
+++ b/python/sglang/kernels/aot/csrc/common_extension.cc
@@ -43,11 +43,6 @@ TORCH_LIBRARY_FRAGMENT(sgl_kernel, m) {
*/
m.def("merge_state_v2(Tensor v_a, Tensor s_a, Tensor v_b, Tensor s_b, Tensor! v_merged, Tensor! s_merged) -> ()");
m.impl("merge_state_v2", torch::kCUDA, &merge_state_v2);
- m.def(
- "cutlass_mla_decode(Tensor! out, Tensor q_nope, Tensor q_pe, Tensor kv_c_and_k_pe_cache, Tensor seq_lens, Tensor "
- "page_table, Tensor! workspace, float sm_scale, int num_kv_splits) -> ()");
- m.impl("cutlass_mla_decode", torch::kCUDA, &cutlass_mla_decode);
- m.def("cutlass_mla_get_workspace_size", &cutlass_mla_get_workspace_size);
/*
* From csrc/infllm_v2
@@ -110,9 +105,6 @@ TORCH_LIBRARY_FRAGMENT(sgl_kernel, m) {
/*
* From csrc/gemm
*/
- m.def("awq_dequantize(Tensor qweight, Tensor scales, Tensor qzeros) -> Tensor");
- m.impl("awq_dequantize", torch::kCUDA, &awq_dequantize);
-
m.def(
"int8_scaled_mm(Tensor mat_a, Tensor mat_b, Tensor scales_a, Tensor scales_b, ScalarType out_dtype, Tensor? "
"bias) -> Tensor");
@@ -138,17 +130,6 @@ TORCH_LIBRARY_FRAGMENT(sgl_kernel, m) {
m.def("sgl_per_token_quant_fp8(Tensor input, Tensor! output_q, Tensor! output_s) -> ()");
m.impl("sgl_per_token_quant_fp8", torch::kCUDA, &sgl_per_token_quant_fp8);
- /*
- * From csrc/gemm/gptq
- */
- m.def(
- "gptq_gemm(Tensor a, Tensor b_q_weight, Tensor b_gptq_qzeros, Tensor b_gptq_scales, Tensor b_g_idx, bool "
- "use_shuffle, int bit) -> Tensor");
- m.impl("gptq_gemm", torch::kCUDA, &gptq_gemm);
-
- m.def("gptq_shuffle(Tensor! q_weight, Tensor q_perm, int bit) -> ()");
- m.impl("gptq_shuffle", torch::kCUDA, &gptq_shuffle);
-
/*
* From csrc/moe
*/
@@ -353,50 +334,6 @@ TORCH_LIBRARY_FRAGMENT(sgl_kernel, m) {
m.def("top_p_renorm_probs(Tensor probs, Tensor! renorm_probs, Tensor? maybe_top_p_arr, float top_p_val) -> ()");
m.impl("top_p_renorm_probs", torch::kCUDA, &top_p_renorm_probs);
- /*
- * From Sparse Flash Attention
- */
- m.def(
- "fwd_sparse(Tensor! q, Tensor k, Tensor v, "
- "Tensor block_count, Tensor block_offset, Tensor column_count, Tensor column_index, "
- "Tensor!? out, Tensor? alibi_slopes, "
- "float p_dropout, float softmax_scale, bool is_causal, "
- "float softcap, bool return_softmax, Generator? gen)"
- "-> Tensor[]");
- m.impl("fwd_sparse", torch::kCUDA, &flash::mha_fwd_sparse);
-
- m.def(
- "varlen_fwd_sparse(Tensor! q, Tensor k, Tensor v, "
- "Tensor block_count, Tensor block_offset, Tensor column_count, Tensor column_index, "
- "Tensor!? out, Tensor cu_seqlens_q, "
- "Tensor cu_seqlens_k, Tensor? seqused_k, Tensor? alibi_slopes, "
- "int max_seqlen_q, int max_seqlen_k, float p_dropout, float softmax_scale, bool zero_tensors, "
- "bool is_causal, float softcap, bool return_softmax, "
- "Generator? gen) -> Tensor[]");
- m.impl("varlen_fwd_sparse", torch::kCUDA, &flash::mha_varlen_fwd_sparse);
-
- // Sparse Attention utils
- m.def(
- "convert_vertical_slash_indexes("
- " Tensor! block_count, Tensor! block_offset, "
- " Tensor! column_count, Tensor! column_index, "
- " Tensor q_seqlens, Tensor q_seqlens, "
- " Tensor vertical_indexes, Tensor slash_indexes, "
- " int context_size, int block_size_M, int block_size_N, "
- " bool causal) -> ()");
- m.impl("convert_vertical_slash_indexes", torch::kCUDA, &convert_vertical_slash_indexes);
-
- m.def(
- "convert_vertical_slash_indexes_mergehead("
- " Tensor! block_count, Tensor! block_offset, "
- " Tensor! column_count, Tensor! column_index, "
- " Tensor q_seqlens, Tensor q_seqlens, "
- " Tensor vertical_indexes, Tensor slash_indexes, "
- " Tensor vertical_indices_count, Tensor slash_indices_count, "
- " int context_size, int block_size_M, int block_size_N, "
- " bool causal) -> ()");
- m.impl("convert_vertical_slash_indexes_mergehead", torch::kCUDA, &convert_vertical_slash_indexes_mergehead);
-
/*
* From csrc/grammar
*/
diff --git a/python/sglang/kernels/aot/csrc/common_extension_musa.cc b/python/sglang/kernels/aot/csrc/common_extension_musa.cc
index 1c8d71497..d734974a7 100644
--- a/python/sglang/kernels/aot/csrc/common_extension_musa.cc
+++ b/python/sglang/kernels/aot/csrc/common_extension_musa.cc
@@ -81,9 +81,6 @@ TORCH_LIBRARY_EXPAND(sgl_kernel, m) {
/*
* From csrc/gemm
*/
- m.def("awq_dequantize(Tensor qweight, Tensor scales, Tensor qzeros) -> Tensor");
- m.impl("awq_dequantize", torch::kMUSA, &awq_dequantize);
-
m.def(
"sgl_per_token_group_quant_8bit(Tensor input, Tensor output_q, Tensor output_s, int group_size,"
" float eps, float fp8_min, float fp8_max, bool scale_ue8m0) -> ()");
diff --git a/python/sglang/kernels/aot/csrc/gemm/awq_kernel.cu b/python/sglang/kernels/aot/csrc/gemm/awq_kernel.cu
deleted file mode 100644
index eec933689..000000000
--- a/python/sglang/kernels/aot/csrc/gemm/awq_kernel.cu
+++ /dev/null
@@ -1,221 +0,0 @@
-// Adapted from
-// https://github.com/vllm-project/vllm/blob/eb59b5a6cba6727d3727c0372258db9002f687c1/csrc/quantization/awq/gemm_kernels.cu#L350
-#include
-#include
-#include
-#include
-#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800
-#include
-#endif
-
-template
-__device__ inline int lop3(int a, int b, int c) {
- int res;
- asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n" : "=r"(res) : "r"(a), "r"(b), "r"(c), "n"(lut));
- return res;
-}
-
-__device__ uint4 dequantize_s4_to_fp16x2(uint32_t const& source) {
-#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 750
- uint4 result;
-
- uint32_t* h = reinterpret_cast(&result);
- uint32_t const i4s = reinterpret_cast(source);
-
- // First, we extract the i4s and construct an intermediate fp16 number.
- static constexpr uint32_t immLut = (0xf0 & 0xcc) | 0xaa;
- static constexpr uint32_t BOTTOM_MASK = 0x000f000f;
- static constexpr uint32_t TOP_MASK = 0x00f000f0;
- static constexpr uint32_t I4s_TO_F16s_MAGIC_NUM = 0x64006400;
-
- // Note that the entire sequence only requires 1 shift instruction. This is
- // thanks to the register packing format and the fact that we force our
- // integers to be unsigned, and account for this in the fp16 subtractions. In
- // addition, I exploit the fact that sub and fma have the same throughput in
- // order to convert elt_23 and elt_67 to fp16 without having to shift them to
- // the bottom bits before hand.
-
- // Shift right by 8 to now consider elt_45 and elt_67. Issue first to hide RAW
- // dependency if we issue immediately before required.
- const uint32_t top_i4s = i4s >> 8;
- // Extract elt_01 - (i4s & 0x000f000f) | 0x64006400
- asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
- : "=r"(h[0])
- : "r"(i4s), "n"(BOTTOM_MASK), "n"(I4s_TO_F16s_MAGIC_NUM), "n"(immLut));
- // Extract elt_23 (i4s & 0x00f000f0) | 0x64006400
- asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
- : "=r"(h[1])
- : "r"(i4s), "n"(TOP_MASK), "n"(I4s_TO_F16s_MAGIC_NUM), "n"(immLut));
- // Extract elt_45 (top_i4s & 0x000f000f) | 0x64006400
- asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
- : "=r"(h[2])
- : "r"(top_i4s), "n"(BOTTOM_MASK), "n"(I4s_TO_F16s_MAGIC_NUM), "n"(immLut));
- // Extract elt_67 (top_i4s & 0x00f000f0) | 0x64006400
- asm volatile("lop3.b32 %0, %1, %2, %3, %4;\n"
- : "=r"(h[3])
- : "r"(top_i4s), "n"(TOP_MASK), "n"(I4s_TO_F16s_MAGIC_NUM), "n"(immLut));
-
- // This is the half2 {1024, 1024} represented as an integer.
- static constexpr uint32_t FP16_TOP_MAGIC_NUM = 0x64006400;
- // This is the half2 {1 / 16, 1 / 16} represented as an integer.
- static constexpr uint32_t ONE_SIXTEENTH = 0x2c002c00;
- // This is the half2 {-64, -64} represented as an integer.
- static constexpr uint32_t NEG_64 = 0xd400d400;
-
- // Finally, we construct the output numbers.
- // Convert elt_01
- asm volatile("sub.f16x2 %0, %1, %2;\n" : "=r"(h[0]) : "r"(h[0]), "r"(FP16_TOP_MAGIC_NUM));
- // Convert elt_23
- asm volatile("fma.rn.f16x2 %0, %1, %2, %3;\n" : "=r"(h[1]) : "r"(h[1]), "r"(ONE_SIXTEENTH), "r"(NEG_64));
- // Convert elt_45
- asm volatile("sub.f16x2 %0, %1, %2;\n" : "=r"(h[2]) : "r"(h[2]), "r"(FP16_TOP_MAGIC_NUM));
- // Convert elt_67
- asm volatile("fma.rn.f16x2 %0, %1, %2, %3;\n" : "=r"(h[3]) : "r"(h[3]), "r"(ONE_SIXTEENTH), "r"(NEG_64));
-
- return result;
-#else
- assert(false);
- return {};
-#endif
-}
-
-__device__ uint4 dequantize_s4_to_bf16x2(uint32_t const& source) {
-#if CUDA_VERSION >= 12000
-#if defined(__CUDA_ARCH__) && __CUDA_ARCH__ >= 800
- uint4 result;
- uint32_t* h = reinterpret_cast(&result);
- uint32_t const i4s = source;
-
- // Define masks and constants
- static constexpr uint32_t MASK = 0x000f000f;
- static constexpr uint32_t EX = 0x43004300;
- static constexpr uint32_t MUL = 0x3F803F80;
- static constexpr uint32_t ADD = 0xC300C300;
-
- int lo0 = lop3<(0xf0 & 0xcc) | 0xaa>(i4s, MASK, EX);
- int hi0 = lop3<(0xf0 & 0xcc) | 0xaa>(i4s >> 4, MASK, EX);
- int lo1 = lop3<(0xf0 & 0xcc) | 0xaa>(i4s >> 8, MASK, EX);
- int hi1 = lop3<(0xf0 & 0xcc) | 0xaa>(i4s >> 12, MASK, EX);
-
- nv_bfloat162* res = reinterpret_cast(h);
- res[0] = __hfma2(
- *reinterpret_cast(&lo0),
- *reinterpret_cast(&MUL),
- *reinterpret_cast(&ADD));
- res[1] = __hfma2(
- *reinterpret_cast(&hi0),
- *reinterpret_cast(&MUL),
- *reinterpret_cast(&ADD));
- res[2] = __hfma2(
- *reinterpret_cast(&lo1),
- *reinterpret_cast(&MUL),
- *reinterpret_cast(&ADD));
- res[3] = __hfma2(
- *reinterpret_cast(&hi1),
- *reinterpret_cast(&MUL),
- *reinterpret_cast(&ADD));
-
- return result;
-#else
- assert(false);
- return {};
-#endif
-#endif
-}
-
-template
-__global__ void __launch_bounds__(256) dequantize_weights(
- int* __restrict__ qweight,
- OutputT* __restrict__ scales,
- int* __restrict__ qzeros,
- OutputT* __restrict__ output,
- int group_size,
- int qweight_cols,
- int qweight_rows) {
-#if CUDA_VERSION >= 12000
- int col = blockIdx.x * blockDim.x + threadIdx.x;
- int row = blockIdx.y * blockDim.y + threadIdx.y;
- if (col >= qweight_cols || row >= qweight_rows) return;
-
- int group_idx = row / group_size;
- int scale_offset = 8 * col + group_idx * qweight_cols * 8;
- uint4 loaded_scale = *(uint4*)(scales + scale_offset);
-
- // Handle different data types
- if constexpr (std::is_same::value) {
- // FP16 path
- uint4 zeros = dequantize_s4_to_fp16x2(qzeros[col + group_idx * qweight_cols]);
- uint4 weight_fp16 = dequantize_s4_to_fp16x2(qweight[col + row * qweight_cols]);
-
- // Use PTX assembly for FP16 operations
- asm volatile("sub.f16x2 %0, %1, %2;\n" : "=r"(weight_fp16.x) : "r"(weight_fp16.x), "r"(zeros.x));
- asm volatile("mul.rn.f16x2 %0, %1, %2;\n" : "=r"(weight_fp16.x) : "r"(weight_fp16.x), "r"(loaded_scale.x));
- asm volatile("sub.f16x2 %0, %1, %2;\n" : "=r"(weight_fp16.y) : "r"(weight_fp16.y), "r"(zeros.y));
- asm volatile("mul.rn.f16x2 %0, %1, %2;\n" : "=r"(weight_fp16.y) : "r"(weight_fp16.y), "r"(loaded_scale.y));
- asm volatile("sub.f16x2 %0, %1, %2;\n" : "=r"(weight_fp16.z) : "r"(weight_fp16.z), "r"(zeros.z));
- asm volatile("mul.rn.f16x2 %0, %1, %2;\n" : "=r"(weight_fp16.z) : "r"(weight_fp16.z), "r"(loaded_scale.z));
- asm volatile("sub.f16x2 %0, %1, %2;\n" : "=r"(weight_fp16.w) : "r"(weight_fp16.w), "r"(zeros.w));
- asm volatile("mul.rn.f16x2 %0, %1, %2;\n" : "=r"(weight_fp16.w) : "r"(weight_fp16.w), "r"(loaded_scale.w));
-
- OutputT* output_ptr = output + 8 * col + 8 * row * qweight_cols;
- *(uint4*)output_ptr = weight_fp16;
- } else if constexpr (std::is_same::value) {
- uint4 weight_raw = dequantize_s4_to_bf16x2(qweight[col + row * qweight_cols]);
- uint4 zero_raw = dequantize_s4_to_bf16x2(qzeros[col + group_idx * qweight_cols]);
- uint4 scale_raw = *reinterpret_cast(scales + scale_offset);
-
- // Vectorized processing (each uint4 contains 4 nv_bfloat162)
- nv_bfloat162* weight_vec = reinterpret_cast(&weight_raw);
- nv_bfloat162* zero_vec = reinterpret_cast(&zero_raw);
- nv_bfloat162* scale_vec = reinterpret_cast(&scale_raw);
-
-// Single instruction dual-channel operation
-#pragma unroll
- for (int i = 0; i < 4; ++i) { // uint4 = 4 * nv_bfloat162
- weight_vec[i] = __hmul2(__hsub2(weight_vec[i], zero_vec[i]), scale_vec[i]);
- }
-
- // Directly store to OutputT array (guaranteed contiguous memory)
- OutputT* output_ptr = output + 8 * col + row * qweight_cols * 8;
- static_assert(sizeof(uint4) == 8 * sizeof(OutputT), "Memory layout mismatch");
- *reinterpret_cast(output_ptr) = weight_raw;
- }
-#endif
-}
-
-torch::Tensor awq_dequantize(torch::Tensor qweight, torch::Tensor scales, torch::Tensor qzeros) {
- int qweight_rows = qweight.size(0);
- int qweight_cols = qweight.size(1);
- int group_size = qweight_rows / scales.size(0);
-
- int x_num_threads = 16;
- int y_num_threads = 16;
- int x_blocks = (qweight_cols + x_num_threads - 1) / x_num_threads;
- int y_blocks = (qweight_rows + y_num_threads - 1) / y_num_threads;
-
- const at::cuda::OptionalCUDAGuard device_guard(device_of(qweight));
-
- auto output_tensor_options = torch::TensorOptions().dtype(scales.dtype()).device(scales.device());
- at::Tensor output = torch::empty({qweight_rows, qweight_cols * 8}, output_tensor_options);
-
- auto _qweight = reinterpret_cast(qweight.data_ptr());
- auto _zeros = reinterpret_cast(qzeros.data_ptr());
-
- dim3 num_blocks(x_blocks, y_blocks);
- dim3 threads_per_block(x_num_threads, y_num_threads);
- const cudaStream_t stream = at::cuda::getCurrentCUDAStream();
-
- if (scales.scalar_type() == at::ScalarType::Half) {
- auto _scales = reinterpret_cast(scales.data_ptr());
- auto _output = reinterpret_cast(output.data_ptr());
- dequantize_weights<<>>(
- _qweight, _scales, _zeros, _output, group_size, qweight_cols, qweight_rows);
- } else {
- auto _scales = reinterpret_cast<__nv_bfloat16*>(scales.data_ptr());
- auto _output = reinterpret_cast<__nv_bfloat16*>(output.data_ptr());
- dequantize_weights<__nv_bfloat16><<>>(
- _qweight, _scales, _zeros, _output, group_size, qweight_cols, qweight_rows);
- }
-
- return output;
-}
diff --git a/python/sglang/kernels/aot/csrc/gemm/gptq/compat.cuh b/python/sglang/kernels/aot/csrc/gemm/gptq/compat.cuh
deleted file mode 100644
index 506eeb769..000000000
--- a/python/sglang/kernels/aot/csrc/gemm/gptq/compat.cuh
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-Copied from https://github.com/turboderp/exllamav2
-*/
-
-#ifndef _compat_cuh
-#define _compat_cuh
-
-namespace sglang {
-namespace gptq {
-// atomicAdd for half types, to support CC < 7.x
-
-__device__ __forceinline__ void atomicAdd_half(half* address, half val) {
- unsigned int* address_as_ui = (unsigned int*)((char*)address - ((size_t)address & 2));
- unsigned int old = *address_as_ui;
- unsigned int assumed;
-
- do {
- assumed = old;
- __half_raw hsum;
- hsum.x = (size_t)address & 2 ? (old >> 16) : (old & 0xffff);
- half tmpres = __hadd(hsum, val);
- hsum = __half_raw(tmpres);
- old = (size_t)address & 2 ? (old & 0xffff) | (hsum.x << 16) : (old & 0xffff0000) | hsum.x;
- old = atomicCAS(address_as_ui, assumed, old);
- } while (assumed != old);
-}
-
-// atomicAdd for half2 types
-
-__device__ __forceinline__ void atomicAdd_half2(half2* address, half2 val) {
- unsigned int* address_as_ui = (unsigned int*)address;
- unsigned int old = *address_as_ui;
- unsigned int assumed;
- do {
- assumed = old;
- half2 old_val = *((half2*)&old);
- half2 new_val = __hadd2(old_val, val);
- old = atomicCAS(address_as_ui, assumed, *((unsigned int*)&new_val));
- } while (assumed != old);
-}
-
-//
-
-#if defined(__CUDA_ARCH__) || defined(USE_ROCM)
-#if __CUDA_ARCH__ < 700 || defined(USE_ROCM)
-
-__device__ __forceinline__ void atomicAdd(half* address, half val) {
- atomicAdd_half(address, val);
-}
-
-#if __CUDA_ARCH__ < 600 || defined(USE_ROCM)
-__device__ __forceinline__ void atomicAdd(half2* address, half2 val) {
- atomicAdd_half2(address, val);
-}
-#endif
-
-#endif
-#endif
-
-} // namespace gptq
-} // namespace sglang
-#endif
diff --git a/python/sglang/kernels/aot/csrc/gemm/gptq/gptq_kernel.cu b/python/sglang/kernels/aot/csrc/gemm/gptq/gptq_kernel.cu
deleted file mode 100644
index 4dd5d8a24..000000000
--- a/python/sglang/kernels/aot/csrc/gemm/gptq/gptq_kernel.cu
+++ /dev/null
@@ -1,1950 +0,0 @@
-/*
-Adapted from https://github.com/turboderp/exllamav2 and
-https://github.com/qwopqwop200/GPTQ-for-LLaMa
-*/
-
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-
-#include "compat.cuh"
-#include "matrix_view.cuh"
-#include "qdq_2.cuh"
-#include "qdq_3.cuh"
-#include "qdq_4.cuh"
-#include "qdq_8.cuh"
-
-namespace sglang {
-namespace gptq {
-
-#define BLOCK_KN_SIZE 128
-#define BLOCK_M_SIZE_MAX 8
-#define MAX_GROUPS_IN_BLOCK (BLOCK_KN_SIZE / 32)
-#define MAX_Q_GEMM_ROWS 50
-#define MAX_Q_GEMM_ROWS_8BIT 24
-#define MAX_ALT_GEMM_ROWS 8
-#define THREADS_X 32
-#define THREADS_Y 32
-#define DIVIDE(x, size) (((x) + (size) - 1) / (size))
-
-#if defined(USE_ROCM)
-#include
-__host__ __forceinline__ hipblasStatus_t __compat_hipblasHgemm(
- hipblasHandle_t handle,
- hipblasOperation_t transA,
- hipblasOperation_t transB,
- int m,
- int n,
- int k,
- const half* alpha,
- const half* AP,
- int lda,
- const half* BP,
- int ldb,
- const half* beta,
- half* CP,
- int ldc) {
- return hipblasHgemm(
- handle,
- transA,
- transB,
- m,
- n,
- k,
- reinterpret_cast(alpha),
- reinterpret_cast(AP),
- lda,
- reinterpret_cast(BP),
- ldb,
- reinterpret_cast(beta),
- reinterpret_cast(CP),
- ldc);
-}
-#define hipblasHgemm __compat_hipblasHgemm
-
-// Previous version of PyTorch were converting to rocBLAS instead of hipBLAS.
-#define rocblas_operation_none HIPBLAS_OP_N
-#define rocblas_hgemm __compat_hipblasHgemm
-#endif
-
-__forceinline__ __device__ half2 dot22_8(half2 (&dq)[4], const half* a_ptr, const half2 g_result) {
- half2 result = {};
- const half2* a2_ptr = (const half2*)a_ptr;
-#pragma unroll
- for (int i = 0; i < 4; i++)
- result = __hfma2(dq[i], *a2_ptr++, result);
- return __hadd2(result, g_result);
-}
-
-__forceinline__ __device__ float dot22_8_f(half2 (&dq)[4], const half* a_ptr) {
- half2 result = {};
- const half2* a2_ptr = (const half2*)a_ptr;
-#pragma unroll
- for (int i = 0; i < 4; i++)
- result = __hfma2(dq[i], *a2_ptr++, result);
- return __half2float(__low2half(result)) + __half2float(__high2half(result));
-}
-
-__forceinline__ __device__ half2 dot22_8(half2 (&dq)[4], const half* a_ptr, const half2 g_result, const half qs_h) {
- half2 result = {};
- const half2* a2_ptr = (const half2*)a_ptr;
-#pragma unroll
- for (int i = 0; i < 4; i++)
- result = __hfma2(dq[i], *a2_ptr++, result);
- return __hfma2(result, __halves2half2(qs_h, qs_h), g_result);
-}
-
-__forceinline__ __device__ half2 dot22_16(half2 (&dq)[8], const half* a_ptr, const half2 g_result, const half qs_h) {
- half2 result = {};
- const half2* a2_ptr = (const half2*)a_ptr;
-#pragma unroll
- for (int i = 0; i < 8; i++)
- result = __hfma2(dq[i], *a2_ptr++, result);
- return __hfma2(result, __halves2half2(qs_h, qs_h), g_result);
-}
-
-__forceinline__ __device__ half2 dot22_32(half2 (&dq)[16], const half* a_ptr, const half2 g_result, const half qs_h) {
- half2 result = {};
- const half2* a2_ptr = (const half2*)a_ptr;
-#pragma unroll
- for (int i = 0; i < 16; i += 1)
- result = __hfma2(dq[i], *a2_ptr++, result);
- return __hfma2(result, __halves2half2(qs_h, qs_h), g_result);
-}
-
-__forceinline__ __device__ float dot22_8_f(half2 (&dq)[4], const half* a_ptr, const float g_result, const float qs_f) {
- half2 result = {};
- const half2* a2_ptr = (const half2*)a_ptr;
-#pragma unroll
- for (int i = 0; i < 4; i++)
- result = __hfma2(dq[i], *a2_ptr++, result);
- float result_f = __half2float(__low2half(result)) + __half2float(__high2half(result));
- return fma(result_f, qs_f, g_result);
-}
-
-__forceinline__ __device__ float dot22_16_f(half2 (&dq)[8], const half* a_ptr, const float g_result, const float qs_f) {
- half2 result = {};
- const half2* a2_ptr = (const half2*)a_ptr;
-#pragma unroll
- for (int i = 0; i < 8; i++)
- result = __hfma2(dq[i], *a2_ptr++, result);
- float result_f = __half2float(__low2half(result)) + __half2float(__high2half(result));
- return fma(result_f, qs_f, g_result);
-}
-
-__forceinline__ __device__ float
-dot22_32_f(half2 (&dq)[16], const half* a_ptr, const float g_result, const float qs_f) {
- half2 result = {};
- const half2* a2_ptr = (const half2*)a_ptr;
-#pragma unroll
- for (int i = 0; i < 16; i += 1)
- result = __hfma2(dq[i], *a2_ptr++, result);
- float result_f = __half2float(__low2half(result)) + __half2float(__high2half(result));
- return fma(result_f, qs_f, g_result);
-}
-
-__forceinline__ __device__ half dot22_8_h(half2 (&dq)[4], const half* a_ptr, const half g_result, const half qs_h) {
- // Use FP32 accumulator to avoid potential overflow since unscaled weights are
- // in the range -128..127
-
- float result = {};
-#pragma unroll
- for (int i = 0; i < 4; i++) {
- half2 w01 = dq[i];
- float w0 = __low2float(w01);
- float w1 = __high2float(w01);
- float x0 = __half2float(*a_ptr++);
- float x1 = __half2float(*a_ptr++);
- result = fma(w0, x0, result);
- result = fma(w1, x1, result);
- }
- float qs = __half2float(qs_h);
- result *= qs;
- half result_h = __float2half_rn(result);
- return __hadd(result_h, g_result);
-}
-
-__forceinline__ __device__ half dot22_16_h(half2 (&dq)[8], const half* a_ptr, const half g_result, const half qs_h) {
- half2 result = {};
- const half2* a2_ptr = (const half2*)a_ptr;
-#pragma unroll
- for (int i = 0; i < 8; i++)
- result = __hfma2(dq[i], *a2_ptr++, result);
- half result_h = __hadd(__low2half(result), __high2half(result));
- return __hfma(result_h, qs_h, g_result);
-}
-
-__forceinline__ __device__ half dot22_32_h(half2 (&dq)[16], const half* a_ptr, const half g_result, const half qs_h) {
- half2 result = {};
- const half2* a2_ptr = (const half2*)a_ptr;
-#pragma unroll
- for (int i = 0; i < 16; i += 1)
- result = __hfma2(dq[i], *a2_ptr++, result);
- half result_h = __hadd(__low2half(result), __high2half(result));
- return __hfma(result_h, qs_h, g_result);
-}
-
-typedef void (*fp_gemm_half_q_half_gptq_kernel)(
- const half*,
- const uint32_t*,
- const uint32_t*,
- const half*,
- half*,
- const int,
- const int,
- const int,
- const int,
- const int*);
-
-template
-__global__ void gemm_half_q_half_gptq_4bit_kernel(
- const half* __restrict__ a,
- const uint32_t* __restrict__ b_q_weight,
- const uint32_t* __restrict__ b_gptq_qzeros,
- const half* __restrict__ b_gptq_scales,
- half* __restrict__ c,
- const int size_m,
- const int size_n,
- const int size_k,
- const int groups,
- const int* __restrict__ b_q_perm) {
- MatrixView_half a_(a, size_m, size_k);
- MatrixView_half_rw c_(c, size_m, size_n);
- MatrixView_q4_row b_gptq_qzeros_(b_gptq_qzeros, groups, size_n);
- MatrixView_half b_gptq_scales_(b_gptq_scales, groups, size_n);
-
- auto t = threadIdx.x;
-
- // Block
- auto offset_n = blockIdx.x * BLOCK_KN_SIZE * 4;
- auto offset_m = blockIdx.y * m_count;
- auto offset_k = blockIdx.z * BLOCK_KN_SIZE;
-
- int end_k = min(offset_k + BLOCK_KN_SIZE, size_k);
-
- int n = offset_n + t * 4;
-
- // Preload block_a
- __shared__ half block_a[m_count][BLOCK_KN_SIZE];
-
- if (offset_k + t < end_k) {
- for (int m = 0; m < m_count; ++m) {
- const half* a_ptr = a_.item_ptr(offset_m + m, 0);
- half* block_a_ptr = block_a[m];
-
- half a0;
- if (b_q_perm)
- a0 = a_ptr[b_q_perm[offset_k + t]];
- else
- a0 = a_ptr[offset_k + t];
- block_a_ptr[t] = a0;
- }
- }
-
- // Zero output
- if (n >= size_n) return;
-
- if (blockIdx.z == 0) {
- for (int m = 0; m < m_count; m++)
- *((uint64_t*)c_.item_ptr(offset_m + m, n)) = 0;
- }
-
- __syncthreads();
-
- // Find initial group
- int groupsize = size_k / groups;
- int group = offset_k / groupsize;
- int nextgroup = offset_k + groupsize;
-
- // a, b offset
- int qk = offset_k / (32 / 4);
-
- const uint32_t* b_ptr = b_q_weight + qk * size_n + n;
- const half* a_ptr = &block_a[0][0];
- int a_stride = BLOCK_KN_SIZE;
-
- // Initial group
- int zeros[4];
- float scales[4];
- half2 z1z16[4][2];
- half2 y1y16[4][2];
- b_gptq_qzeros_.item4(zeros, group, n);
- b_gptq_scales_.item4_f(scales, group, n);
- dequant_4bit_8_prep_zero(zeros[0] + 1, z1z16[0], y1y16[0]);
- dequant_4bit_8_prep_zero(zeros[1] + 1, z1z16[1], y1y16[1]);
- dequant_4bit_8_prep_zero(zeros[2] + 1, z1z16[2], y1y16[2]);
- dequant_4bit_8_prep_zero(zeros[3] + 1, z1z16[3], y1y16[3]);
-
- // Column result
- float block_c[m_count][4] = {};
-
- // Dequantize and multiply
- int k = offset_k;
- while (k < end_k) {
- if (k == nextgroup) {
- group++;
- nextgroup += groupsize;
- b_gptq_qzeros_.item4(zeros, group, n);
- b_gptq_scales_.item4_f(scales, group, n);
- dequant_4bit_8_prep_zero(zeros[0] + 1, z1z16[0], y1y16[0]);
- dequant_4bit_8_prep_zero(zeros[1] + 1, z1z16[1], y1y16[1]);
- dequant_4bit_8_prep_zero(zeros[2] + 1, z1z16[2], y1y16[2]);
- dequant_4bit_8_prep_zero(zeros[3] + 1, z1z16[3], y1y16[3]);
- }
-
-#pragma unroll
- for (int j = 0; j < 4; j++) {
- const int4* b_ptr4 = (int4*)b_ptr;
- int4 load_int4 = *b_ptr4;
-
- half2 dq[4][4];
- dequant_4bit_8_gptq(load_int4.x, dq[0], z1z16[0], y1y16[0], size_n, false);
- dequant_4bit_8_gptq(load_int4.y, dq[1], z1z16[1], y1y16[1], size_n, false);
- dequant_4bit_8_gptq(load_int4.z, dq[2], z1z16[2], y1y16[2], size_n, false);
- dequant_4bit_8_gptq(load_int4.w, dq[3], z1z16[3], y1y16[3], size_n, false);
-
-#pragma unroll
- for (int m = 0; m < m_count; m++) {
- block_c[m][0] = fma(dot22_8_f(dq[0], a_ptr + m * a_stride), scales[0], block_c[m][0]);
- block_c[m][1] = fma(dot22_8_f(dq[1], a_ptr + m * a_stride), scales[1], block_c[m][1]);
- block_c[m][2] = fma(dot22_8_f(dq[2], a_ptr + m * a_stride), scales[2], block_c[m][2]);
- block_c[m][3] = fma(dot22_8_f(dq[3], a_ptr + m * a_stride), scales[3], block_c[m][3]);
- }
-
- b_ptr += size_n;
- a_ptr += 8;
- }
-
- k += 32;
- }
-
- for (int m = 0; m < m_count; m++) {
- half2* out = (half2*)c_.item_ptr(offset_m + m, n);
- half2 result01 = __halves2half2(__float2half_rn(block_c[m][0]), __float2half_rn(block_c[m][1]));
- half2 result23 = __halves2half2(__float2half_rn(block_c[m][2]), __float2half_rn(block_c[m][3]));
- atomicAdd(out, result01);
- atomicAdd(out + 1, result23);
- }
-}
-
-template
-__global__ void gemm_half_q_half_gptq_2bit_kernel(
- const half* __restrict__ a,
- const uint32_t* __restrict__ b_q_weight,
- const uint32_t* __restrict__ b_gptq_qzeros,
- const half* __restrict__ b_gptq_scales,
- half* __restrict__ c,
- const int size_m,
- const int size_n,
- const int size_k,
- const int groups,
- const int* __restrict__ b_q_perm) {
- MatrixView_half a_(a, size_m, size_k);
- MatrixView_half_rw c_(c, size_m, size_n);
- MatrixView_q2_row b_gptq_qzeros_(b_gptq_qzeros, groups, size_n);
- MatrixView_half b_gptq_scales_(b_gptq_scales, groups, size_n);
-
- auto t = threadIdx.x;
-
- // Block
- auto offset_n = blockIdx.x * BLOCK_KN_SIZE * 4;
- auto offset_m = blockIdx.y * m_count;
- auto offset_k = blockIdx.z * BLOCK_KN_SIZE;
-
- int end_k = min(offset_k + BLOCK_KN_SIZE, size_k);
-
- int n = offset_n + t * 4;
-
- // Preload block_a
- __shared__ half block_a[m_count][BLOCK_KN_SIZE];
-
- if (offset_k + t < end_k) {
- for (int m = 0; m < m_count; ++m) {
- const half* a_ptr = a_.item_ptr(offset_m + m, 0);
- half* block_a_ptr = block_a[m];
-
- half a0;
- if (b_q_perm)
- a0 = a_ptr[b_q_perm[offset_k + t]];
- else
- a0 = a_ptr[offset_k + t];
- block_a_ptr[t] = a0;
- }
- }
-
- // Zero output
- if (n >= size_n) return;
-
- if (blockIdx.z == 0) {
- for (int m = 0; m < m_count; m++)
- *((uint64_t*)c_.item_ptr(offset_m + m, n)) = 0;
- }
-
- __syncthreads();
-
- // Find initial group
- int groupsize = size_k / groups;
- int group = offset_k / groupsize;
- int nextgroup = offset_k + groupsize;
-
- // a, b offset
- int qk = offset_k / (32 / 2);
-
- const uint32_t* b_ptr = b_q_weight + qk * size_n + n;
- const half* a_ptr = &block_a[0][0];
- int a_stride = BLOCK_KN_SIZE;
-
- // Initial group
- int zeros[4];
- half scales[4];
- b_gptq_qzeros_.item4(zeros, group, n);
- b_gptq_scales_.item4(scales, group, n);
- // Column result
- half block_c[m_count][4] = {};
-
- // Dequantize and multiply
- int k = offset_k;
- while (k < end_k) {
- if (k == nextgroup) {
- group++;
- nextgroup += groupsize;
- b_gptq_qzeros_.item4(zeros, group, n);
- b_gptq_scales_.item4(scales, group, n);
- }
-
-#pragma unroll
- for (int j = 0; j < 1; j++) {
- const int4* b_ptr4 = (int4*)b_ptr;
- int4 load_int4 = *b_ptr4;
-
- half2 dq[4][8];
- dequant_2bit_16(load_int4.x, dq[0], size_n, zeros[0] + 1);
- dequant_2bit_16(load_int4.y, dq[1], size_n, zeros[1] + 1);
- dequant_2bit_16(load_int4.z, dq[2], size_n, zeros[2] + 1);
- dequant_2bit_16(load_int4.w, dq[3], size_n, zeros[3] + 1);
-
-#pragma unroll
- for (int m = 0; m < m_count; m++) {
- block_c[m][0] = dot22_16_h(dq[0], a_ptr + m * a_stride, block_c[m][0], scales[0]);
- block_c[m][1] = dot22_16_h(dq[1], a_ptr + m * a_stride, block_c[m][1], scales[1]);
- block_c[m][2] = dot22_16_h(dq[2], a_ptr + m * a_stride, block_c[m][2], scales[2]);
- block_c[m][3] = dot22_16_h(dq[3], a_ptr + m * a_stride, block_c[m][3], scales[3]);
- }
-
- b_ptr += size_n;
- a_ptr += 16;
- }
-
- k += 16;
- }
-
- for (int m = 0; m < m_count; m++) {
- half2* out = (half2*)c_.item_ptr(offset_m + m, n);
- half2 result01 = __halves2half2(block_c[m][0], block_c[m][1]);
- half2 result23 = __halves2half2(block_c[m][2], block_c[m][3]);
- atomicAdd(out, result01);
- atomicAdd(out + 1, result23);
- }
-}
-
-template
-__global__ void gemm_half_q_half_gptq_3bit_kernel(
- const half* __restrict__ a,
- const uint32_t* __restrict__ b_q_weight,
- const uint32_t* __restrict__ b_gptq_qzeros,
- const half* __restrict__ b_gptq_scales,
- half* __restrict__ c,
- const int size_m,
- const int size_n,
- const int size_k,
- const int groups,
- const int* __restrict__ b_q_perm) {
- MatrixView_half a_(a, size_m, size_k);
- MatrixView_half_rw c_(c, size_m, size_n);
- MatrixView_q3_row b_gptq_qzeros_(b_gptq_qzeros, groups, size_n);
- MatrixView_half b_gptq_scales_(b_gptq_scales, groups, size_n);
-
- auto t = threadIdx.x;
-
- // Block
- auto offset_n = blockIdx.x * BLOCK_KN_SIZE * 4;
- auto offset_m = blockIdx.y * m_count;
- auto offset_k = blockIdx.z * BLOCK_KN_SIZE;
-
- int end_k = min(offset_k + BLOCK_KN_SIZE, size_k);
-
- int n = offset_n + t * 4;
-
- // Preload block_a
- __shared__ half block_a[m_count][BLOCK_KN_SIZE];
-
- if (offset_k + t < end_k) {
- for (int m = 0; m < m_count; ++m) {
- const half* a_ptr = a_.item_ptr(offset_m + m, 0);
- half* block_a_ptr = block_a[m];
-
- half a0;
- if (b_q_perm)
- a0 = a_ptr[b_q_perm[offset_k + t]];
- else
- a0 = a_ptr[offset_k + t];
- block_a_ptr[t] = a0;
- }
- }
-
- // Zero output
- if (n >= size_n) return;
-
- if (blockIdx.z == 0) {
- for (int m = 0; m < m_count; m++)
- *((uint64_t*)c_.item_ptr(offset_m + m, n)) = 0;
- }
-
- __syncthreads();
-
- // Find initial group
- int groupsize = size_k / groups;
- int group = offset_k / groupsize;
- int nextgroup = offset_k + groupsize;
-
- // a, b offset
- int qk = offset_k / 32 * 3;
-
- const uint32_t* b_ptr = b_q_weight + qk * size_n + n;
- const half* a_ptr = &block_a[0][0];
- int a_stride = BLOCK_KN_SIZE;
-
- // Initial group
- int zeros[4];
- half scales[4];
- b_gptq_qzeros_.item4(zeros, group, n);
- b_gptq_scales_.item4(scales, group, n);
- // Column result
- half block_c[m_count][4] = {};
-
- // Dequantize and multiply
- int k = offset_k;
- while (k < end_k) {
- if (k == nextgroup) {
- group++;
- nextgroup += groupsize;
- b_gptq_qzeros_.item4(zeros, group, n);
- b_gptq_scales_.item4(scales, group, n);
- }
-
-#pragma unroll
- for (int j = 0; j < 1; j++) {
- int4 load_int4[3];
- load_int4[0] = *((int4*)b_ptr);
- b_ptr += size_n;
- load_int4[1] = *((int4*)b_ptr);
- b_ptr += size_n;
- load_int4[2] = *((int4*)b_ptr);
- b_ptr += size_n;
-
- half2 dq[4][16];
- dequant_3bit_32(load_int4[0].x, load_int4[1].x, load_int4[2].x, dq[0], size_n, zeros[0] + 1);
- dequant_3bit_32(load_int4[0].y, load_int4[1].y, load_int4[2].y, dq[1], size_n, zeros[1] + 1);
- dequant_3bit_32(load_int4[0].z, load_int4[1].z, load_int4[2].z, dq[2], size_n, zeros[2] + 1);
- dequant_3bit_32(load_int4[0].w, load_int4[1].w, load_int4[2].w, dq[3], size_n, zeros[3] + 1);
-
-#pragma unroll
- for (int m = 0; m < m_count; m++) {
- block_c[m][0] = dot22_32_h(dq[0], a_ptr + m * a_stride, block_c[m][0], scales[0]);
- block_c[m][1] = dot22_32_h(dq[1], a_ptr + m * a_stride, block_c[m][1], scales[1]);
- block_c[m][2] = dot22_32_h(dq[2], a_ptr + m * a_stride, block_c[m][2], scales[2]);
- block_c[m][3] = dot22_32_h(dq[3], a_ptr + m * a_stride, block_c[m][3], scales[3]);
- }
- a_ptr += 32;
- }
-
- k += 32;
- }
-
- for (int m = 0; m < m_count; m++) {
- half2* out = (half2*)c_.item_ptr(offset_m + m, n);
- half2 result01 = __halves2half2(block_c[m][0], block_c[m][1]);
- half2 result23 = __halves2half2(block_c[m][2], block_c[m][3]);
- atomicAdd(out, result01);
- atomicAdd(out + 1, result23);
- }
-}
-
-template
-__global__ void gemm_half_q_half_gptq_8bit_kernel(
- const half* __restrict__ a,
- const uint32_t* __restrict__ b_q_weight,
- const uint32_t* __restrict__ b_gptq_qzeros,
- const half* __restrict__ b_gptq_scales,
- half* __restrict__ c,
- const int size_m,
- const int size_n,
- const int size_k,
- const int groups,
- const int* __restrict__ b_q_perm) {
- MatrixView_half a_(a, size_m, size_k);
- MatrixView_half_rw c_(c, size_m, size_n);
- MatrixView_q8_row b_gptq_qzeros_(b_gptq_qzeros, groups, size_n);
- MatrixView_half b_gptq_scales_(b_gptq_scales, groups, size_n);
-
- auto t = threadIdx.x;
-
- // Block
- auto offset_n = blockIdx.x * BLOCK_KN_SIZE * 4;
- auto offset_m = blockIdx.y * m_count;
- auto offset_k = blockIdx.z * BLOCK_KN_SIZE;
-
- int end_k = min(offset_k + BLOCK_KN_SIZE, size_k);
-
- int n = offset_n + t * 4;
-
- // Preload block_a
- __shared__ half block_a[m_count][BLOCK_KN_SIZE];
-
- if (offset_k + t < end_k) {
- for (int m = 0; m < m_count; ++m) {
- const half* a_ptr = a_.item_ptr(offset_m + m, 0);
- half* block_a_ptr = block_a[m];
-
- half a0;
- if (b_q_perm)
- a0 = a_ptr[b_q_perm[offset_k + t]];
- else
- a0 = a_ptr[offset_k + t];
- block_a_ptr[t] = a0;
- }
- }
-
- // Zero output
- if (n >= size_n) return;
-
- if (blockIdx.z == 0) {
- for (int m = 0; m < m_count; m++)
- *((uint64_t*)c_.item_ptr(offset_m + m, n)) = 0;
- }
-
- __syncthreads();
-
- // Find initial group
- int groupsize = size_k / groups;
- int group = offset_k / groupsize;
- int nextgroup = offset_k + groupsize;
-
- // a, b offset
- int qk = offset_k / (32 / 8);
-
- const uint32_t* b_ptr = b_q_weight + qk * size_n + n;
- const half* a_ptr = &block_a[0][0];
- int a_stride = BLOCK_KN_SIZE;
-
- // Initial group
- int zeros[4];
- half scales[4];
- b_gptq_qzeros_.item4(zeros, group, n);
- b_gptq_scales_.item4(scales, group, n);
- // Column result
- half block_c[m_count][4] = {};
-
- // Dequantize and multiply
- int k = offset_k;
- while (k < end_k) {
- if (k == nextgroup) {
- group++;
- nextgroup += groupsize;
- b_gptq_qzeros_.item4(zeros, group, n);
- b_gptq_scales_.item4(scales, group, n);
- }
-
-#pragma unroll
- for (int j = 0; j < 4; j++) {
- int4 load_int4[2];
- load_int4[0] = *((int4*)b_ptr);
- b_ptr += size_n;
- load_int4[1] = *((int4*)b_ptr);
- b_ptr += size_n;
-
- half2 dq[4][4];
- dequant_8bit_8(load_int4[0].x, load_int4[1].x, dq[0], size_n, zeros[0] + 1);
- dequant_8bit_8(load_int4[0].y, load_int4[1].y, dq[1], size_n, zeros[1] + 1);
- dequant_8bit_8(load_int4[0].z, load_int4[1].z, dq[2], size_n, zeros[2] + 1);
- dequant_8bit_8(load_int4[0].w, load_int4[1].w, dq[3], size_n, zeros[3] + 1);
-
- for (int m = 0; m < m_count; m++) {
- block_c[m][0] = dot22_8_h(dq[0], a_ptr + m * a_stride, block_c[m][0], scales[0]);
- block_c[m][1] = dot22_8_h(dq[1], a_ptr + m * a_stride, block_c[m][1], scales[1]);
- block_c[m][2] = dot22_8_h(dq[2], a_ptr + m * a_stride, block_c[m][2], scales[2]);
- block_c[m][3] = dot22_8_h(dq[3], a_ptr + m * a_stride, block_c[m][3], scales[3]);
- }
- a_ptr += 8;
- }
- k += 32;
- }
-
- for (int m = 0; m < m_count; m++) {
- half2* out = (half2*)c_.item_ptr(offset_m + m, n);
- half2 result01 = __halves2half2(block_c[m][0], block_c[m][1]);
- half2 result23 = __halves2half2(block_c[m][2], block_c[m][3]);
- atomicAdd(out, result01);
- atomicAdd(out + 1, result23);
- }
-}
-
-fp_gemm_half_q_half_gptq_kernel pick_gemm_half_q_half_gptq_kernel(bool first_block, const int m_count, const int bit) {
-#define SELECT_KERNEL(M_COUNT) \
- if (m_count == M_COUNT) { \
- if (bit == 2) return gemm_half_q_half_gptq_2bit_kernel; \
- if (bit == 3) return gemm_half_q_half_gptq_3bit_kernel; \
- if (bit == 4) return gemm_half_q_half_gptq_4bit_kernel; \
- if (bit == 8) return gemm_half_q_half_gptq_8bit_kernel; \
- }
-#if BLOCK_M_SIZE_MAX >= 1
- SELECT_KERNEL(1);
-#endif
-#if BLOCK_M_SIZE_MAX >= 2
- SELECT_KERNEL(2);
-#endif
-#if BLOCK_M_SIZE_MAX >= 3
- SELECT_KERNEL(3);
-#endif
-#if BLOCK_M_SIZE_MAX >= 4
- SELECT_KERNEL(4);
-#endif
-#if BLOCK_M_SIZE_MAX >= 5
- SELECT_KERNEL(5);
-#endif
-#if BLOCK_M_SIZE_MAX >= 6
- SELECT_KERNEL(6);
-#endif
-#if BLOCK_M_SIZE_MAX >= 7
- SELECT_KERNEL(7);
-#endif
-#if BLOCK_M_SIZE_MAX >= 8
- SELECT_KERNEL(8);
-#endif
- return NULL;
-}
-
-void gemm_half_q_half_cuda_part(
- const half* a,
- const uint32_t* b_q_weight,
- const uint32_t* b_gptq_qzeros,
- const half* b_gptq_scales,
- const int* b_q_perm,
- half* c,
- int size_m,
- int size_n,
- int size_k,
- int m_count,
- int groups,
- int bit) {
- dim3 blockDim, gridDim;
- blockDim.x = BLOCK_KN_SIZE;
- blockDim.y = 1;
- blockDim.z = 1;
- gridDim.x = DIVIDE(size_n, BLOCK_KN_SIZE * 4);
- gridDim.y = DIVIDE(size_m, m_count);
- gridDim.z = DIVIDE(size_k, BLOCK_KN_SIZE);
-
- fp_gemm_half_q_half_gptq_kernel kernel = pick_gemm_half_q_half_gptq_kernel(true, m_count, bit);
-
- const cudaStream_t stream = at::cuda::getCurrentCUDAStream();
- kernel<<>>(
- a, b_q_weight, b_gptq_qzeros, b_gptq_scales, c, size_m, size_n, size_k, groups, b_q_perm);
-}
-
-__global__ void reconstruct_exllama_8bit_kernel(
- const uint32_t* __restrict__ b_q_weight,
- const int* __restrict__ b_q_perm,
- const uint32_t* __restrict__ b_gptq_qzeros,
- const half* __restrict__ b_gptq_scales,
- const int size_k,
- const int size_n,
- const int groups,
- half* __restrict__ b) {
- MatrixView_half_rw b_(b, size_k, size_n);
- MatrixView_q8_row b_gptq_qzeros_(b_gptq_qzeros, groups, size_n);
- MatrixView_half b_gptq_scales_(b_gptq_scales, groups, size_n);
-
- auto offset_k = BLOCK_KN_SIZE * blockIdx.y;
- auto offset_n = BLOCK_KN_SIZE * blockIdx.x * 4;
-
- int end_k = min(offset_k + BLOCK_KN_SIZE, size_k);
-
- // Preload remapping table
- __shared__ int perm[BLOCK_KN_SIZE];
- auto t = threadIdx.x;
-
- if (b_q_perm) {
- if (offset_k + t < size_k) perm[t] = b_q_perm[offset_k + t];
- }
-
- // Column
- int n = offset_n + t * 4;
- if (n >= size_n) return;
-
- // Find initial group
- int groupsize = size_k / groups;
- int group = offset_k / groupsize;
- int nextgroup = offset_k + groupsize;
-
- // b offset
- int qk = offset_k / (32 / 8);
-
- const uint32_t* b_ptr = b_q_weight + qk * size_n + n;
-
- // Initial zeros/scale
- int zeros[4];
- half2 scales[4];
- b_gptq_qzeros_.item4(zeros, group, n);
- b_gptq_scales_.item4_h2(scales, group, n);
-
- __syncthreads();
-
- int k = offset_k;
- int lk = 0;
-
- while (k < end_k) {
- if (k == nextgroup) {
- group++;
- nextgroup += groupsize;
- b_gptq_qzeros_.item4(zeros, group, n);
- b_gptq_scales_.item4_h2(scales, group, n);
- }
-
- for (int p = 0; p < 4; p++) {
- int4 load_int4[2];
- load_int4[0] = *((int4*)b_ptr);
- b_ptr += size_n;
- load_int4[1] = *((int4*)b_ptr);
- b_ptr += size_n;
-
- half2 dq[4][4];
- dequant_8bit_8(load_int4[0].x, load_int4[1].x, dq[0], size_n, zeros[0] + 1);
- dequant_8bit_8(load_int4[0].y, load_int4[1].y, dq[1], size_n, zeros[1] + 1);
- dequant_8bit_8(load_int4[0].z, load_int4[1].z, dq[2], size_n, zeros[2] + 1);
- dequant_8bit_8(load_int4[0].w, load_int4[1].w, dq[3], size_n, zeros[3] + 1);
-
- // half* dqh = (half*)dq;
- if (b_q_perm) {
- for (int j = 0; j < 4; j++) {
- for (int v = 0; v < 4; v++)
- dq[v][j] = __hmul2(scales[v], dq[v][j]);
- b_.set4(
- perm[lk++], n, __low2half(dq[0][j]), __low2half(dq[1][j]), __low2half(dq[2][j]), __low2half(dq[3][j]));
- b_.set4(
- perm[lk++],
- n,
- __high2half(dq[0][j]),
- __high2half(dq[1][j]),
- __high2half(dq[2][j]),
- __high2half(dq[3][j]));
- }
- } else {
- for (int j = 0; j < 4; j++) {
- for (int v = 0; v < 4; v++)
- dq[v][j] = __hmul2(scales[v], dq[v][j]);
- b_.set4(
- offset_k + lk++,
- n,
- __low2half(dq[0][j]),
- __low2half(dq[1][j]),
- __low2half(dq[2][j]),
- __low2half(dq[3][j]));
- b_.set4(
- offset_k + lk++,
- n,
- __high2half(dq[0][j]),
- __high2half(dq[1][j]),
- __high2half(dq[2][j]),
- __high2half(dq[3][j]));
- }
- }
- }
- k += 32;
- }
-}
-
-__global__ void reconstruct_exllama_4bit_kernel(
- const uint32_t* __restrict__ b_q_weight,
- const int* __restrict__ b_q_perm,
- const uint32_t* __restrict__ b_gptq_qzeros,
- const half* __restrict__ b_gptq_scales,
- const int size_k,
- const int size_n,
- const int groups,
- half* __restrict__ b) {
- MatrixView_half_rw b_(b, size_k, size_n);
- MatrixView_q4_row b_gptq_qzeros_(b_gptq_qzeros, groups, size_n);
- MatrixView_half b_gptq_scales_(b_gptq_scales, groups, size_n);
-
- auto offset_k = BLOCK_KN_SIZE * blockIdx.y;
- auto offset_n = BLOCK_KN_SIZE * blockIdx.x * 4;
-
- int end_k = min(offset_k + BLOCK_KN_SIZE, size_k);
-
- // Preload remapping table
- __shared__ int perm[BLOCK_KN_SIZE];
- auto t = threadIdx.x;
-
- if (b_q_perm) {
- if (offset_k + t < size_k) perm[t] = b_q_perm[offset_k + t];
- }
-
- // Column
- int n = offset_n + t * 4;
- if (n >= size_n) return;
-
- // Find initial group
- int groupsize = size_k / groups;
- int group = offset_k / groupsize;
- int nextgroup = offset_k + groupsize;
-
- // b offset
- int qk = offset_k / (32 / 4);
-
- const uint32_t* b_ptr = b_q_weight + qk * size_n + n;
-
- // Initial zeros/scale
- int zeros[4];
- half2 scales[4];
- half2 z1z16[4][2];
- half2 y1y16[4][2];
- b_gptq_qzeros_.item4(zeros, group, n);
- b_gptq_scales_.item4_h2(scales, group, n);
- dequant_4bit_8_prep_zero(zeros[0] + 1, z1z16[0], y1y16[0]);
- dequant_4bit_8_prep_zero(zeros[1] + 1, z1z16[1], y1y16[1]);
- dequant_4bit_8_prep_zero(zeros[2] + 1, z1z16[2], y1y16[2]);
- dequant_4bit_8_prep_zero(zeros[3] + 1, z1z16[3], y1y16[3]);
-
- __syncthreads();
-
- int k = offset_k;
- int lk = 0;
-
- while (k < end_k) {
- if (k == nextgroup) {
- group++;
- nextgroup += groupsize;
- b_gptq_qzeros_.item4(zeros, group, n);
- b_gptq_scales_.item4_h2(scales, group, n);
- dequant_4bit_8_prep_zero(zeros[0] + 1, z1z16[0], y1y16[0]);
- dequant_4bit_8_prep_zero(zeros[1] + 1, z1z16[1], y1y16[1]);
- dequant_4bit_8_prep_zero(zeros[2] + 1, z1z16[2], y1y16[2]);
- dequant_4bit_8_prep_zero(zeros[3] + 1, z1z16[3], y1y16[3]);
- }
-
- for (int p = 0; p < 4; p++) {
- half2 dq[4][4];
- const int4* b_ptr4 = (int4*)b_ptr;
- int4 load_int4 = *b_ptr4;
-
- dequant_4bit_8_gptq(load_int4.x, dq[0], z1z16[0], y1y16[0], size_n, false);
- dequant_4bit_8_gptq(load_int4.y, dq[1], z1z16[1], y1y16[1], size_n, false);
- dequant_4bit_8_gptq(load_int4.z, dq[2], z1z16[2], y1y16[2], size_n, false);
- dequant_4bit_8_gptq(load_int4.w, dq[3], z1z16[3], y1y16[3], size_n, false);
-
- b_ptr += size_n;
- // half* dqh = (half*)dq;
- if (b_q_perm) {
- for (int j = 0; j < 4; j++) {
- for (int v = 0; v < 4; v++)
- dq[v][j] = __hmul2(scales[v], dq[v][j]);
- b_.set4(
- perm[lk++], n, __low2half(dq[0][j]), __low2half(dq[1][j]), __low2half(dq[2][j]), __low2half(dq[3][j]));
- b_.set4(
- perm[lk++],
- n,
- __high2half(dq[0][j]),
- __high2half(dq[1][j]),
- __high2half(dq[2][j]),
- __high2half(dq[3][j]));
- }
- } else {
- for (int j = 0; j < 4; j++) {
- for (int v = 0; v < 4; v++)
- dq[v][j] = __hmul2(scales[v], dq[v][j]);
- b_.set4(
- offset_k + lk++,
- n,
- __low2half(dq[0][j]),
- __low2half(dq[1][j]),
- __low2half(dq[2][j]),
- __low2half(dq[3][j]));
- b_.set4(
- offset_k + lk++,
- n,
- __high2half(dq[0][j]),
- __high2half(dq[1][j]),
- __high2half(dq[2][j]),
- __high2half(dq[3][j]));
- }
- }
- }
- k += 32;
- }
-}
-
-__global__ void reconstruct_exllama_3bit_kernel(
- const uint32_t* __restrict__ b_q_weight,
- const int* __restrict__ b_q_perm,
- const uint32_t* __restrict__ b_gptq_qzeros,
- const half* __restrict__ b_gptq_scales,
- const int size_k,
- const int size_n,
- const int groups,
- half* __restrict__ b) {
- MatrixView_half_rw b_(b, size_k, size_n);
- MatrixView_q3_row b_gptq_qzeros_(b_gptq_qzeros, groups, size_n);
- MatrixView_half b_gptq_scales_(b_gptq_scales, groups, size_n);
-
- auto offset_k = BLOCK_KN_SIZE * blockIdx.y;
- auto offset_n = BLOCK_KN_SIZE * blockIdx.x * 4;
-
- int end_k = min(offset_k + BLOCK_KN_SIZE, size_k);
-
- // Preload remapping table
- __shared__ int perm[BLOCK_KN_SIZE];
- auto t = threadIdx.x;
-
- if (b_q_perm) {
- if (offset_k + t < size_k) perm[t] = b_q_perm[offset_k + t];
- }
-
- // Column
- int n = offset_n + t * 4;
- if (n >= size_n) return;
-
- // Find initial group
- int groupsize = size_k / groups;
- int group = offset_k / groupsize;
- int nextgroup = offset_k + groupsize;
-
- // b offset
- int qk = offset_k / 32 * 3;
-
- const uint32_t* b_ptr = b_q_weight + qk * size_n + n;
-
- // Initial zeros/scale
- int zeros[4];
- half2 scales[4];
- b_gptq_qzeros_.item4(zeros, group, n);
- b_gptq_scales_.item4_h2(scales, group, n);
-
- __syncthreads();
-
- int k = offset_k;
- int lk = 0;
-
- while (k < end_k) {
- if (k == nextgroup) {
- group++;
- nextgroup += groupsize;
- b_gptq_qzeros_.item4(zeros, group, n);
- b_gptq_scales_.item4_h2(scales, group, n);
- }
-
- for (int p = 0; p < 1; p++) {
- int4 load_int4[3];
- load_int4[0] = *((int4*)b_ptr);
- b_ptr += size_n;
- load_int4[1] = *((int4*)b_ptr);
- b_ptr += size_n;
- load_int4[2] = *((int4*)b_ptr);
- b_ptr += size_n;
-
- half2 dq[4][16];
- dequant_3bit_32(load_int4[0].x, load_int4[1].x, load_int4[2].x, dq[0], size_n, zeros[0] + 1);
- dequant_3bit_32(load_int4[0].y, load_int4[1].y, load_int4[2].y, dq[1], size_n, zeros[1] + 1);
- dequant_3bit_32(load_int4[0].z, load_int4[1].z, load_int4[2].z, dq[2], size_n, zeros[2] + 1);
- dequant_3bit_32(load_int4[0].w, load_int4[1].w, load_int4[2].w, dq[3], size_n, zeros[3] + 1);
-
- if (b_q_perm) {
- for (int j = 0; j < 16; j++) {
- for (int v = 0; v < 4; v++)
- dq[v][j] = __hmul2(scales[v], dq[v][j]);
- b_.set4(
- perm[lk++], n, __low2half(dq[0][j]), __low2half(dq[1][j]), __low2half(dq[2][j]), __low2half(dq[3][j]));
- b_.set4(
- perm[lk++],
- n,
- __high2half(dq[0][j]),
- __high2half(dq[1][j]),
- __high2half(dq[2][j]),
- __high2half(dq[3][j]));
- }
- } else {
- for (int j = 0; j < 16; j++) {
- for (int v = 0; v < 4; v++)
- dq[v][j] = __hmul2(scales[v], dq[v][j]);
- b_.set4(
- offset_k + lk++,
- n,
- __low2half(dq[0][j]),
- __low2half(dq[1][j]),
- __low2half(dq[2][j]),
- __low2half(dq[3][j]));
- b_.set4(
- offset_k + lk++,
- n,
- __high2half(dq[0][j]),
- __high2half(dq[1][j]),
- __high2half(dq[2][j]),
- __high2half(dq[3][j]));
- }
- }
- }
- k += 32;
- }
-}
-
-__global__ void reconstruct_exllama_2bit_kernel(
- const uint32_t* __restrict__ b_q_weight,
- const int* __restrict__ b_q_perm,
- const uint32_t* __restrict__ b_gptq_qzeros,
- const half* __restrict__ b_gptq_scales,
- const int size_k,
- const int size_n,
- const int groups,
- half* __restrict__ b) {
- MatrixView_half_rw b_(b, size_k, size_n);
- MatrixView_q2_row b_gptq_qzeros_(b_gptq_qzeros, groups, size_n);
- MatrixView_half b_gptq_scales_(b_gptq_scales, groups, size_n);
-
- auto offset_k = BLOCK_KN_SIZE * blockIdx.y;
- auto offset_n = BLOCK_KN_SIZE * blockIdx.x * 4;
-
- int end_k = min(offset_k + BLOCK_KN_SIZE, size_k);
-
- // Preload remapping table
- __shared__ int perm[BLOCK_KN_SIZE];
- auto t = threadIdx.x;
-
- if (b_q_perm) {
- if (offset_k + t < size_k) perm[t] = b_q_perm[offset_k + t];
- }
-
- // Column
- int n = offset_n + t * 4;
- if (n >= size_n) return;
-
- // Find initial group
- int groupsize = size_k / groups;
- int group = offset_k / groupsize;
- int nextgroup = offset_k + groupsize;
-
- // b offset
- int qk = offset_k / (32 / 2);
-
- const uint32_t* b_ptr = b_q_weight + qk * size_n + n;
-
- // Initial zeros/scale
- int zeros[4];
- half2 scales[4];
- b_gptq_qzeros_.item4(zeros, group, n);
- b_gptq_scales_.item4_h2(scales, group, n);
-
- __syncthreads();
-
- int k = offset_k;
- int lk = 0;
-
- while (k < end_k) {
- if (k == nextgroup) {
- group++;
- nextgroup += groupsize;
- b_gptq_qzeros_.item4(zeros, group, n);
- b_gptq_scales_.item4_h2(scales, group, n);
- }
-
- for (int p = 0; p < 2; p++) {
- const int4* b_ptr4 = (int4*)b_ptr;
- int4 load_int4 = *b_ptr4;
-
- half2 dq[4][8];
- dequant_2bit_16(load_int4.x, dq[0], size_n, zeros[0] + 1);
- dequant_2bit_16(load_int4.y, dq[1], size_n, zeros[1] + 1);
- dequant_2bit_16(load_int4.z, dq[2], size_n, zeros[2] + 1);
- dequant_2bit_16(load_int4.w, dq[3], size_n, zeros[3] + 1);
-
- b_ptr += size_n;
- // half* dqh = (half*)dq;
- if (b_q_perm) {
- for (int j = 0; j < 8; j++) {
- for (int v = 0; v < 4; v++)
- dq[v][j] = __hmul2(scales[v], dq[v][j]);
- b_.set4(
- perm[lk++], n, __low2half(dq[0][j]), __low2half(dq[1][j]), __low2half(dq[2][j]), __low2half(dq[3][j]));
- b_.set4(
- perm[lk++],
- n,
- __high2half(dq[0][j]),
- __high2half(dq[1][j]),
- __high2half(dq[2][j]),
- __high2half(dq[3][j]));
- }
- } else {
- for (int j = 0; j < 8; j++) {
- for (int v = 0; v < 4; v++)
- dq[v][j] = __hmul2(scales[v], dq[v][j]);
- b_.set4(
- offset_k + lk++,
- n,
- __low2half(dq[0][j]),
- __low2half(dq[1][j]),
- __low2half(dq[2][j]),
- __low2half(dq[3][j]));
- b_.set4(
- offset_k + lk++,
- n,
- __high2half(dq[0][j]),
- __high2half(dq[1][j]),
- __high2half(dq[2][j]),
- __high2half(dq[3][j]));
- }
- }
- }
- k += 32;
- }
-}
-
-void reconstruct_exllama(
- const uint32_t* b_q_weight,
- const uint32_t* b_gptq_qzeros,
- const half* b_gptq_scales,
- const int* b_q_perm,
- half* out,
- int height,
- int width,
- int groups,
- int bit) {
- dim3 blockDim, gridDim;
- blockDim.x = BLOCK_KN_SIZE;
- blockDim.y = 1;
- gridDim.y = DIVIDE(height, BLOCK_KN_SIZE);
- gridDim.x = DIVIDE(width, BLOCK_KN_SIZE);
-
- auto reconstruct_exllama_kernel = reconstruct_exllama_4bit_kernel;
- if (bit == 2) {
- reconstruct_exllama_kernel = reconstruct_exllama_2bit_kernel;
- } else if (bit == 3) {
- reconstruct_exllama_kernel = reconstruct_exllama_3bit_kernel;
- } else if (bit == 8) {
- reconstruct_exllama_kernel = reconstruct_exllama_8bit_kernel;
- }
-
- const cudaStream_t stream = at::cuda::getCurrentCUDAStream();
- reconstruct_exllama_kernel<<>>(
- b_q_weight, b_q_perm, b_gptq_qzeros, b_gptq_scales, height, width, groups, out);
-}
-
-__global__ void gemm_half_q_half_alt_4bit_kernel(
- const half2* __restrict__ vec,
- const uint32_t* __restrict__ mat,
- half* __restrict__ mul,
- const half* __restrict__ scales,
- const uint32_t* __restrict__ zeros,
- const int* __restrict__ g_idx,
- int batch,
- int height,
- int width) {
- int zero_width = width / 8;
- int vec_height = height * 4;
- const int blockwidth2 = BLOCK_KN_SIZE / 2;
- auto b = blockIdx.y * BLOCK_M_SIZE_MAX;
- int b_end = min(BLOCK_M_SIZE_MAX, batch - b);
- auto h = BLOCK_KN_SIZE * blockIdx.z / 8;
- int h_end = min(BLOCK_KN_SIZE / 8, height - h) * 4;
- auto w = BLOCK_KN_SIZE * blockIdx.x + threadIdx.x;
-
- __shared__ half2 blockvec[BLOCK_M_SIZE_MAX][blockwidth2];
- if (threadIdx.x < h_end) {
- for (int m = 0; m < b_end; ++m) {
- blockvec[m][threadIdx.x] = vec[(m + b) * vec_height + blockIdx.z * BLOCK_KN_SIZE / 2 + threadIdx.x];
- }
- }
-
- __shared__ half2 deq2[256][8];
- auto val = threadIdx.x / 8;
- auto off = threadIdx.x % 8;
- for (; val < 256; val += BLOCK_KN_SIZE / 8) {
- deq2[val][off] = __halves2half2(__int2half_rn(val & 0xF), __int2half_rn(val >> 4));
- }
-
- if (blockIdx.z == 0) {
- for (int m = 0; m < b_end; m++)
- mul[(b + m) * width + w] = __int2half_rn(0);
- }
- __syncthreads();
-
- int i = width * h + w;
- int g_h = h * 8;
- int k = 0;
- int z_w = w / 8;
- int z_mod = (w % 8) * 4;
- half2 res2;
- half res[BLOCK_M_SIZE_MAX] = {};
-
- unsigned int tmp;
- while (k < h_end) {
- tmp = mat[i];
- half2 scales_tmp[4];
- half2 zeros_tmp[4];
- for (int tmp_k = 0; tmp_k < 4; tmp_k++) {
- int g = g_idx[g_h + (k + tmp_k) * 2];
- int g2 = g_idx[g_h + (k + tmp_k) * 2 + 1];
- half scale_f = scales[g * width + w];
- half scale_f2 = scales[g2 * width + w];
- half2 scale = __halves2half2(scale_f, scale_f2);
- half2 zero = __halves2half2(
- __hmul(scale_f, __int2half_rn(-((zeros[g * zero_width + z_w] >> z_mod) & 0xF) - 1)),
- __hmul(scale_f2, __int2half_rn(-((zeros[g2 * zero_width + z_w] >> z_mod) & 0xF) - 1)));
- scales_tmp[tmp_k] = scale;
- zeros_tmp[tmp_k] = zero;
- }
- for (int m = 0; m < b_end; m++) {
-#ifndef USE_ROCM
- res2 = {};
-#else
- res2.x = __half_as_ushort(__float2half(0));
- res2.y = __half_as_ushort(__float2half(0));
-#endif
- res2 = __hfma2(__hfma2(deq2[(tmp >> 0) & 0xff][off], scales_tmp[0], zeros_tmp[0]), blockvec[m][k + 0], res2);
- res2 = __hfma2(__hfma2(deq2[(tmp >> 8) & 0xff][off], scales_tmp[1], zeros_tmp[1]), blockvec[m][k + 1], res2);
- res2 = __hfma2(__hfma2(deq2[(tmp >> 16) & 0xff][off], scales_tmp[2], zeros_tmp[2]), blockvec[m][k + 2], res2);
- res2 = __hfma2(__hfma2(deq2[(tmp >> 24) & 0xff][off], scales_tmp[3], zeros_tmp[3]), blockvec[m][k + 3], res2);
-#ifndef USE_ROCM
- res[m] = __hadd(res[m], __hadd(res2.x, res2.y));
-#else
- res[m] = __hadd(res[m], __hadd(__ushort_as_half(res2.x), __ushort_as_half(res2.y)));
-#endif
- }
- i += width;
- k += 4;
- }
- for (int m = 0; m < b_end; m++) {
- atomicAdd(&mul[(b + m) * width + w], res[m]);
- }
-}
-
-__global__ void gemm_half_q_half_alt_8bit_kernel(
- const half2* __restrict__ vec,
- const uint32_t* __restrict__ mat,
- half* __restrict__ mul,
- const half* __restrict__ scales,
- const uint32_t* __restrict__ zeros,
- const int* __restrict__ g_idx,
- int batch,
- int height,
- int width) {
- int zero_width = width / 4;
- int vec_height = height * 2;
- const int blockwidth2 = BLOCK_KN_SIZE / 2;
- auto b = blockIdx.y * BLOCK_M_SIZE_MAX;
- int b_end = min(BLOCK_M_SIZE_MAX, batch - b);
- auto h = BLOCK_KN_SIZE * blockIdx.z / 4;
- int h_end = min(BLOCK_KN_SIZE / 4, height - h) * 2;
- auto w = BLOCK_KN_SIZE * blockIdx.x + threadIdx.x;
-
- __shared__ half2 blockvec[BLOCK_M_SIZE_MAX][blockwidth2];
- if (threadIdx.x < h_end) {
- for (int m = 0; m < b_end; ++m) {
- blockvec[m][threadIdx.x] = vec[(m + b) * vec_height + blockIdx.z * BLOCK_KN_SIZE / 2 + threadIdx.x];
- }
- }
-
- if (blockIdx.z == 0) {
- for (int m = 0; m < b_end; m++)
- mul[(b + m) * width + w] = __int2half_rn(0);
- }
- __syncthreads();
-
- int i = width * h + w;
- int g_h = h * 4;
- int k = 0;
- int z_w = w / 4;
- int z_mod = (w % 4) * 8;
- half2 res2;
- half res[BLOCK_M_SIZE_MAX] = {};
-
- unsigned int tmp;
- while (k < h_end) {
- tmp = mat[i];
- half2 scales_tmp[2];
- half2 zeros_tmp[2];
- for (int tmp_k = 0; tmp_k < 2; tmp_k++) {
- int g = g_idx[g_h + (k + tmp_k) * 2];
- int g2 = g_idx[g_h + (k + tmp_k) * 2 + 1];
- half scale_f = scales[g * width + w];
- half scale_f2 = scales[g2 * width + w];
- half2 scale = __halves2half2(scale_f, scale_f2);
- half2 zero = __halves2half2(
- __hmul(scale_f, __int2half_rn(-((zeros[g * zero_width + z_w] >> z_mod) & 0xff) - 1)),
- __hmul(scale_f2, __int2half_rn(-((zeros[g2 * zero_width + z_w] >> z_mod) & 0xff) - 1)));
- scales_tmp[tmp_k] = scale;
- zeros_tmp[tmp_k] = zero;
- }
- for (int m = 0; m < b_end; m++) {
-#ifndef USE_ROCM
- res2 = {};
-#else
- res2.x = __half_as_ushort(__float2half(0));
- res2.y = __half_as_ushort(__float2half(0));
-#endif
- half2 v12 = __halves2half2(__int2half_rn(tmp & 0xFF), __int2half_rn((tmp >> 8) & 0xFF));
- res2 = __hfma2(__hfma2(v12, scales_tmp[0], zeros_tmp[0]), blockvec[m][k + 0], res2);
- half2 v34 = __halves2half2(__int2half_rn((tmp >> 16) & 0xFF), __int2half_rn((tmp >> 24) & 0xFF));
- res2 = __hfma2(__hfma2(v34, scales_tmp[1], zeros_tmp[1]), blockvec[m][k + 1], res2);
-#ifndef USE_ROCM
- res[m] = __hadd(res[m], __hadd(res2.x, res2.y));
-#else
- res[m] = __hadd(res[m], __hadd(__ushort_as_half(res2.x), __ushort_as_half(res2.y)));
-#endif
- }
- i += width;
- k += 2;
- }
- for (int m = 0; m < b_end; m++) {
- atomicAdd(&mul[(b + m) * width + w], res[m]);
- }
-}
-
-void gemm_half_q_half_alt(
- const half* a,
- const uint32_t* b_q_weight,
- const uint32_t* b_gptq_qzeros,
- const half* b_gptq_scales,
- const int* b_g_idx,
- half* c,
- int size_m,
- int size_n,
- int size_k,
- int bit) {
- dim3 blockDim, gridDim;
- blockDim.x = BLOCK_KN_SIZE;
- blockDim.y = 1;
- blockDim.z = 1;
- gridDim.x = DIVIDE(size_n, BLOCK_KN_SIZE);
- gridDim.y = DIVIDE(size_m, BLOCK_M_SIZE_MAX);
- gridDim.z = DIVIDE(size_k, BLOCK_KN_SIZE);
-
- auto kernel = gemm_half_q_half_alt_4bit_kernel;
- if (bit == 8) {
- kernel = gemm_half_q_half_alt_8bit_kernel;
- }
-
- const cudaStream_t stream = at::cuda::getCurrentCUDAStream();
- kernel<<>>(
- (const half2*)a, b_q_weight, c, b_gptq_scales, b_gptq_qzeros, b_g_idx, size_m, size_k / 32 * bit, size_n);
-}
-
-template
-__global__ void reconstruct_gptq_kernel(
- const uint32_t* __restrict__ w,
- const half* __restrict__ w_scales,
- const uint32_t* __restrict__ w_zeros,
- const int* __restrict__ g_idx,
- const int height,
- const int width,
- const int group,
- half* __restrict__ out) {
- // Start of block
-
- auto column = BLOCK_KN_SIZE * blockIdx.x + threadIdx.x;
- auto row = blockIdx.y * 32 / bit;
- if (column >= width) return;
-
- // Views
-
- MatrixView_half_rw out_(out, height, width);
- MatrixView_half w_scales_(w_scales, group, width);
- T w_zeros_(w_zeros, group, width);
-
- uint32_t w_read = w[blockIdx.y * width + column];
- half* out_ptr = out_.item_ptr(row, column);
-
-#pragma unroll
- for (int s = 0; s < 32; s += bit) {
- int group = g_idx[row + s / bit];
- half w_scale = w_scales_.item(group, column);
- uint32_t w_zero = w_zeros_.item(group, column) + 1;
- half w_item = __hmul(__int2half_rn((int)((w_read >> s) & ((1 << bit) - 1)) - w_zero), w_scale);
- *out_ptr = w_item;
- out_ptr += out_.width;
- }
-}
-
-__global__ void reconstruct_gptq_3bit_kernel(
- const uint32_t* __restrict__ w,
- const half* __restrict__ w_scales,
- const uint32_t* __restrict__ w_zeros,
- const int* __restrict__ g_idx,
- const int height,
- const int width,
- const int group,
- half* __restrict__ out) {
- // Start of block
- auto column = BLOCK_KN_SIZE * blockIdx.x + threadIdx.x;
- auto row = blockIdx.y * 32;
- if (column >= width) return;
-
- // Views
-
- MatrixView_half_rw out_(out, height, width);
- MatrixView_half w_scales_(w_scales, group, width);
- MatrixView_q3_row w_zeros_(w_zeros, group, width);
-
- uint32_t w1 = w[(blockIdx.y * 3) * width + column];
- uint32_t w2 = w[(blockIdx.y * 3 + 1) * width + column];
- uint32_t w3 = w[(blockIdx.y * 3 + 2) * width + column];
- half* out_ptr = out_.item_ptr(row, column);
-
-#pragma unroll
- for (int i = 0; i < 32; i += 1) {
- int group = g_idx[row + i];
- half w_scale = w_scales_.item(group, column);
- uint32_t w_zero = w_zeros_.item(group, column) + 1;
- int w_item;
- if (i == 10) {
- w_item = (w1 >> 30) | ((w2 << 2) & 0x4);
- } else if (i == 21) {
- w_item = (w2 >> 31) | ((w3 << 1) & 0x6);
- } else if (i < 10) {
- w_item = ((w1 >> (i * 3)) & 0x7);
- } else if (i < 21) {
- w_item = ((w2 >> (i * 3 - 32)) & 0x7);
- } else {
- w_item = ((w3 >> (i * 3 - 64)) & 0x7);
- }
- *out_ptr = __hmul(__int2half_rn(w_item - w_zero), w_scale);
- out_ptr += out_.width;
- }
-}
-
-void reconstruct_gptq(
- const uint32_t* b_q_weight,
- const uint32_t* b_gptq_qzeros,
- const half* b_gptq_scales,
- const int* b_g_idx,
- half* out,
- int height,
- int width,
- int groups,
- int bit) {
- dim3 blockDim, gridDim;
- blockDim.x = BLOCK_KN_SIZE;
- blockDim.y = 1;
- gridDim.y = DIVIDE(height, 32 / bit);
- gridDim.x = DIVIDE(width, BLOCK_KN_SIZE);
-
- auto kernel = reconstruct_gptq_kernel;
- if (bit == 2) {
- kernel = reconstruct_gptq_kernel;
- } else if (bit == 8) {
- kernel = reconstruct_gptq_kernel;
- } else if (bit == 3) {
- kernel = reconstruct_gptq_3bit_kernel;
- gridDim.y = DIVIDE(height, 32);
- }
-
- const cudaStream_t stream = at::cuda::getCurrentCUDAStream();
- kernel<<>>(
- b_q_weight, b_gptq_scales, b_gptq_qzeros, b_g_idx, height, width, groups, out);
-}
-
-void gemm_half_q_half_cuda(
- cublasHandle_t cublas_handle,
- const half* a,
- const uint32_t* b_q_weight,
- const uint32_t* b_gptq_qzeros,
- const half* b_gptq_scales,
- const int* b_g_idx,
- half* c,
- half* temp_dq,
- int size_m,
- int size_n,
- int size_k,
- int groups,
- bool use_shuffle,
- int bit) {
- bool use_reconstruct;
- if (use_shuffle) {
- use_reconstruct = ((bit == 8 && size_m > MAX_Q_GEMM_ROWS_8BIT) || (bit != 8 && size_m > MAX_Q_GEMM_ROWS));
- } else {
- // The 2/3-bit kernels are somehow slower than dequant + gemm baseline, so
- // we disabled them for now.
- use_reconstruct = (bit < 4 || size_m > MAX_ALT_GEMM_ROWS);
- }
- if (use_reconstruct) {
- // Reconstruct FP16 matrix, then cuBLAS
- if (use_shuffle) {
- reconstruct_exllama(b_q_weight, b_gptq_qzeros, b_gptq_scales, b_g_idx, temp_dq, size_k, size_n, groups, bit);
- } else {
- reconstruct_gptq(b_q_weight, b_gptq_qzeros, b_gptq_scales, b_g_idx, temp_dq, size_k, size_n, groups, bit);
- }
-
- const half alpha = __float2half(1.0f);
- const half beta = __float2half(0.0f);
- cublasHgemm(
- cublas_handle,
- CUBLAS_OP_N,
- CUBLAS_OP_N,
- size_n,
- size_m,
- size_k,
- &alpha,
- temp_dq,
- size_n,
- a,
- size_k,
- &beta,
- c,
- size_n);
- } else if (use_shuffle) {
- // Quantized matmul
- int max_chunks = size_m / BLOCK_M_SIZE_MAX;
- int last_chunk = max_chunks * BLOCK_M_SIZE_MAX;
- int last_chunk_size = size_m - last_chunk;
-
- if (max_chunks) {
- gemm_half_q_half_cuda_part(
- a,
- b_q_weight,
- b_gptq_qzeros,
- b_gptq_scales,
- b_g_idx,
- c,
- last_chunk,
- size_n,
- size_k,
- BLOCK_M_SIZE_MAX,
- groups,
- bit);
- }
-
- if (last_chunk_size) {
- gemm_half_q_half_cuda_part(
- a + last_chunk * size_k,
- b_q_weight,
- b_gptq_qzeros,
- b_gptq_scales,
- b_g_idx,
- c + last_chunk * size_n,
- last_chunk_size,
- size_n,
- size_k,
- last_chunk_size,
- groups,
- bit);
- }
- } else {
- gemm_half_q_half_alt(a, b_q_weight, b_gptq_qzeros, b_gptq_scales, b_g_idx, c, size_m, size_n, size_k, bit);
- }
-}
-
-__global__ void shuffle_4bit_kernel(uint32_t* __restrict__ b_q_weight, const int size_k, const int size_n) {
- auto n = blockIdx.x * THREADS_X + threadIdx.x;
- if (n >= size_n) return;
- int k = 0;
- uint32_t* b_ptr = b_q_weight + n;
- while (k < size_k) {
- shuffle_4bit_8(b_ptr, size_n);
- b_ptr += 1 * size_n;
- k += 8;
- }
-}
-
-__global__ void shuffle_8bit_kernel(uint32_t* __restrict__ b_q_weight, const int size_k, const int size_n) {
- auto n = blockIdx.x * THREADS_X + threadIdx.x;
- if (n >= size_n) return;
- int k = 0;
- uint32_t* b_ptr = b_q_weight + n;
- while (k < size_k) {
- shuffle_8bit_4(b_ptr, size_n);
- b_ptr += 1 * size_n;
- k += 4;
- }
-}
-
-__global__ void shuffle_2bit_kernel(uint32_t* __restrict__ b_q_weight, const int size_k, const int size_n) {
- auto n = blockIdx.x * THREADS_X + threadIdx.x;
- if (n >= size_n) return;
- int k = 0;
- uint32_t* b_ptr = b_q_weight + n;
- while (k < size_k) {
- shuffle_2bit_16(b_ptr, size_n);
- b_ptr += 1 * size_n;
- k += 16;
- }
-}
-
-__global__ void shuffle_3bit_kernel(uint32_t* __restrict__ b_q_weight, const int size_k, const int size_n) {
- auto n = blockIdx.x * THREADS_X + threadIdx.x;
- if (n >= size_n) return;
- int k = 0;
- uint32_t* b_ptr = b_q_weight + n;
- while (k < size_k) {
- shuffle_3bit_32(b_ptr, size_n);
- b_ptr += 3 * size_n;
- k += 32;
- }
-}
-
-__global__ void make_sequential_4bit_kernel(
- const uint32_t* __restrict__ w, uint32_t* __restrict__ w_new, const int* __restrict__ q_perm, const int w_width) {
- const uint64_t* w2 = (uint64_t*)w;
- uint64_t* w_new2 = (uint64_t*)w_new;
- int w2_stride = w_width >> 1;
- auto w2_column = THREADS_X * blockIdx.x + threadIdx.x;
- if (w2_column >= w2_stride) return;
- auto w_new2_row = blockIdx.y;
- int q_perm_idx = w_new2_row << 3;
- uint64_t dst = 0;
-
-#pragma unroll
- for (int i = 0; i < 8; i++) {
- int source_row = q_perm[q_perm_idx++];
-
- int w2_row = source_row >> 3;
- int w2_subrow = source_row & 0x07;
- int w2_row_shift = w2_subrow << 2;
- int wnew2_row_shift = i << 2;
-
- uint64_t src = w2[w2_row * w2_stride + w2_column];
- src >>= w2_row_shift;
- src &= 0x0000000f0000000f;
- src <<= wnew2_row_shift;
- dst |= src;
- }
- w_new2[w_new2_row * w2_stride + w2_column] = dst;
-}
-
-__global__ void make_sequential_2bit_kernel(
- const uint32_t* __restrict__ w, uint32_t* __restrict__ w_new, const int* __restrict__ q_perm, const int w_width) {
- const uint64_t* w2 = (uint64_t*)w;
- uint64_t* w_new2 = (uint64_t*)w_new;
- int w2_stride = w_width >> 1;
- auto w2_column = THREADS_X * blockIdx.x + threadIdx.x;
- if (w2_column >= w2_stride) return;
- auto w_new2_row = blockIdx.y;
- int q_perm_idx = w_new2_row << 4;
- uint64_t dst = 0;
-
-#pragma unroll
- for (int i = 0; i < 16; i++) {
- int source_row = q_perm[q_perm_idx++];
-
- int w2_row = source_row >> 4;
- int w2_subrow = source_row & 0x0f;
- int w2_row_shift = w2_subrow << 1;
- int wnew2_row_shift = i << 1;
-
- uint64_t src = w2[w2_row * w2_stride + w2_column];
- src >>= w2_row_shift;
- src &= 0x0000000300000003;
- src <<= wnew2_row_shift;
- dst |= src;
- }
- w_new2[w_new2_row * w2_stride + w2_column] = dst;
-}
-
-__global__ void make_sequential_3bit_kernel(
- const uint32_t* __restrict__ w, uint32_t* __restrict__ w_new, const int* __restrict__ q_perm, const int w_width) {
- auto w_column = THREADS_X * blockIdx.x + threadIdx.x;
- if (w_column >= w_width) return;
- auto w_new_row = blockIdx.y * 3;
- auto q_perm_idx = blockIdx.y << 5;
- uint32_t dst[3] = {0, 0, 0};
-
-#pragma unroll
- for (int i = 0; i < 32; i++) {
- int source_row = q_perm[q_perm_idx++];
- int z_w = (source_row / 32) * 3;
- int z_mod = source_row % 32;
- int z_bit;
-
- if (z_mod != 10) {
- if (z_mod != 21) {
- z_bit = z_mod;
- if (z_bit > 21) {
- z_bit *= 3;
- z_bit -= 64;
- z_w += 2;
- } else if (z_bit > 10) {
- z_bit *= 3;
- z_bit -= 32;
- z_w += 1;
- } else {
- z_bit *= 3;
- }
- } else {
- z_w += 1;
- }
- }
-
- uint64_t src;
- if (z_mod == 10) {
- src = (w[z_w * w_width + w_column] >> 30) | ((w[(z_w + 1) * w_width + w_column] << 2) & 0x4);
- } else if (z_mod == 21) {
- src = (w[z_w * w_width + w_column] >> 31) | ((w[(z_w + 1) * w_width + w_column] << 1) & 0x6);
- } else {
- src = w[z_w * w_width + w_column];
- src >>= z_bit;
- src &= 0x07;
- }
-
- z_w = 0;
- if (i != 10) {
- if (i != 21) {
- z_bit = i;
- if (z_bit > 21) {
- z_bit *= 3;
- z_bit -= 64;
- z_w += 2;
- } else if (z_bit > 10) {
- z_bit *= 3;
- z_bit -= 32;
- z_w += 1;
- } else {
- z_bit *= 3;
- }
- } else {
- z_w += 1;
- }
- }
- if (i == 10) {
- dst[z_w] |= (src & 0x03) << 30;
- dst[z_w + 1] |= ((src & 0x4) >> 2);
- } else if (i == 21) {
- dst[z_w] |= (src & 0x01) << 31;
- dst[z_w + 1] |= ((src & 0x6) >> 1);
- } else {
- dst[z_w] |= (src << z_bit);
- }
- }
- w_new[w_new_row * w_width + w_column] = dst[0];
- w_new[(w_new_row + 1) * w_width + w_column] = dst[1];
- w_new[(w_new_row + 2) * w_width + w_column] = dst[2];
-}
-
-__global__ void make_sequential_8bit_kernel(
- const uint32_t* __restrict__ w, uint32_t* __restrict__ w_new, const int* __restrict__ q_perm, const int w_width) {
- const uint64_t* w2 = (uint64_t*)w;
- uint64_t* w_new2 = (uint64_t*)w_new;
- int w2_stride = w_width >> 1;
- auto w2_column = THREADS_X * blockIdx.x + threadIdx.x;
- if (w2_column >= w2_stride) return;
- auto w_new2_row = blockIdx.y;
- int q_perm_idx = w_new2_row << 2;
- uint64_t dst = 0;
-
-#pragma unroll
- for (int i = 0; i < 4; i++) {
- int source_row = q_perm[q_perm_idx++];
-
- int w2_row = source_row >> 2;
- int w2_subrow = source_row & 0x03;
- int w2_row_shift = w2_subrow << 3;
- int wnew2_row_shift = i << 3;
-
- uint64_t src = w2[w2_row * w2_stride + w2_column];
- src >>= w2_row_shift;
- src &= 0x000000ff000000ff;
- src <<= wnew2_row_shift;
- dst |= src;
- }
- w_new2[w_new2_row * w2_stride + w2_column] = dst;
-}
-
-void shuffle_exllama_weight(uint32_t* q_weight, int* q_perm, int height, int width, int bit) {
- if (q_perm) {
- uint32_t* new_qweight = NULL;
- cudaMalloc(&new_qweight, height / 32 * bit * width * sizeof(uint32_t));
-
- dim3 blockDim, gridDim;
- blockDim.x = THREADS_X;
- blockDim.y = 1;
- gridDim.x = DIVIDE(width, THREADS_X);
- gridDim.y = height / 32 * bit;
-
- auto kernel = make_sequential_4bit_kernel;
- if (bit == 2) {
- kernel = make_sequential_2bit_kernel;
- } else if (bit == 3) {
- kernel = make_sequential_3bit_kernel;
- gridDim.y = height / 32;
- } else if (bit == 8) {
- kernel = make_sequential_8bit_kernel;
- }
- const cudaStream_t stream = at::cuda::getCurrentCUDAStream();
- kernel<<>>(q_weight, new_qweight, q_perm, width);
- // Replace qweights
- cudaMemcpyAsync(q_weight, new_qweight, height / 32 * bit * width * sizeof(uint32_t), cudaMemcpyDeviceToDevice);
- // Cleanup
- cudaDeviceSynchronize();
- cudaFree(new_qweight);
- }
- dim3 blockDim, gridDim;
- blockDim.x = THREADS_X;
- blockDim.y = 1;
- gridDim.x = DIVIDE(width, THREADS_X);
- gridDim.y = 1;
- auto shuffle_kernel = shuffle_4bit_kernel;
- if (bit == 2) {
- shuffle_kernel = shuffle_2bit_kernel;
- } else if (bit == 3) {
- shuffle_kernel = shuffle_3bit_kernel;
- } else if (bit == 8) {
- shuffle_kernel = shuffle_8bit_kernel;
- }
- const cudaStream_t stream = at::cuda::getCurrentCUDAStream();
- shuffle_kernel<<>>(q_weight, height, width);
-}
-
-} // namespace gptq
-} // namespace sglang
-
-torch::Tensor gptq_gemm(
- torch::Tensor a,
- torch::Tensor b_q_weight,
- torch::Tensor b_gptq_qzeros,
- torch::Tensor b_gptq_scales,
- torch::Tensor b_g_idx,
- bool use_shuffle,
- int64_t bit) {
- const at::cuda::OptionalCUDAGuard device_guard(device_of(a));
- auto options = torch::TensorOptions().dtype(a.dtype()).device(a.device());
- at::Tensor c = torch::empty({a.size(0), b_q_weight.size(1)}, options);
- at::Tensor temp_dq = torch::empty({b_q_weight.size(0) * 32 / bit, b_q_weight.size(1)}, options);
-
- sglang::gptq::gemm_half_q_half_cuda(
- at::cuda::getCurrentCUDABlasHandle(),
- (const half*)a.data_ptr(),
- (const uint32_t*)b_q_weight.data_ptr(),
- (const uint32_t*)b_gptq_qzeros.data_ptr(),
- (const half*)b_gptq_scales.data_ptr(),
- b_g_idx.device().is_meta() ? NULL : (const int*)b_g_idx.data_ptr(),
- (half*)c.data_ptr(),
- (half*)temp_dq.data_ptr(),
- c.size(0), // m
- c.size(1), // n
- a.size(1), // k
- b_gptq_qzeros.size(0), // group number
- use_shuffle,
- bit);
- return c;
-}
-
-void gptq_shuffle(torch::Tensor q_weight, torch::Tensor q_perm, int64_t bit) {
- const at::cuda::OptionalCUDAGuard device_guard(device_of(q_weight));
- sglang::gptq::shuffle_exllama_weight(
- (uint32_t*)q_weight.data_ptr(),
- q_perm.device().is_meta() || q_perm.numel() == 0 ? NULL : (int*)q_perm.data_ptr(),
- q_weight.size(0) * 32 / bit,
- q_weight.size(1),
- bit);
-}
diff --git a/python/sglang/kernels/aot/csrc/gemm/gptq/matrix_view.cuh b/python/sglang/kernels/aot/csrc/gemm/gptq/matrix_view.cuh
deleted file mode 100644
index 3dfc8794c..000000000
--- a/python/sglang/kernels/aot/csrc/gemm/gptq/matrix_view.cuh
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
-Adapted from https://github.com/turboderp/exllamav2 and
-https://github.com/turboderp/exllama
-*/
-
-#ifndef _matrix_view_cuh
-#define _matrix_view_cuh
-
-#include
-#include
-
-#include "qdq_util.cuh"
-
-namespace sglang {
-namespace gptq {
-
-class MatrixView_half {
- public:
- const half* data;
- const int height;
- const int width;
-
- __device__ __forceinline__ MatrixView_half(const half* data, const int height, const int width)
- : data(data), height(height), width(width) {}
-
- __device__ __forceinline__ half item(int row, int column) const {
- return data[row * width + column];
- }
- __device__ __forceinline__ half2 item_half2(int row, int column) const {
- return ((half2*)data)[(row * width + column) / 2];
- }
- __device__ __forceinline__ half2 item_half2half2(int row, int column) const {
- return __half2half2(data[row * width + column]);
- }
- __device__ __forceinline__ const half* item_ptr(int row, int column) const {
- return &data[row * width + column];
- }
-
- __device__ __forceinline__ void item4(half (&items)[4], int row, int column) const {
- half2* ptr = (half2*)item_ptr(row, column);
- half2 i01 = ptr[0];
- half2 i23 = ptr[1];
- items[0] = __low2half(i01);
- items[1] = __high2half(i01);
- items[2] = __low2half(i23);
- items[3] = __high2half(i23);
- }
- __device__ __forceinline__ void item4_f(float (&items)[4], int row, int column) const {
- half2* ptr = (half2*)item_ptr(row, column);
- half2 i01 = ptr[0];
- half2 i23 = ptr[1];
- items[0] = __half2float(__low2half(i01));
- items[1] = __half2float(__high2half(i01));
- items[2] = __half2float(__low2half(i23));
- items[3] = __half2float(__high2half(i23));
- }
-
- __device__ __forceinline__ void item4_h2(half2 (&items)[4], int row, int column) const {
- half2* ptr = (half2*)item_ptr(row, column);
- half2 i01 = ptr[0];
- half2 i23 = ptr[1];
- items[0] = __half2half2(__low2half(i01));
- items[1] = __half2half2(__high2half(i01));
- items[2] = __half2half2(__low2half(i23));
- items[3] = __half2half2(__high2half(i23));
- }
-};
-
-class MatrixView_half_rw {
- public:
- half* data;
- const int height;
- const int width;
-
- __device__ __forceinline__ MatrixView_half_rw(half* data, const int height, const int width)
- : data(data), height(height), width(width) {}
-
- __device__ __forceinline__ half item(int row, int column) const {
- return data[row * width + column];
- }
- __device__ __forceinline__ half2 item_half2(int row, int column) const {
- return ((half2*)data)[(row * width + column) / 2];
- }
- __device__ __forceinline__ half* item_ptr(int row, int column) {
- return &data[row * width + column];
- }
- __device__ __forceinline__ void set(int row, int column, half value) {
- data[row * width + column] = value;
- }
- __device__ __forceinline__ void set_half2(int row, int column, half2 value) {
- ((half2*)data)[(row * width + column) / 2] = value;
- }
-
- __device__ __forceinline__ void set4(int row, int column, half v0, half v1, half v2, half v3) {
- half2 v01 = __halves2half2(v0, v1);
- half2 v23 = __halves2half2(v2, v3);
- half2* ptr = (half2*)item_ptr(row, column);
- ptr[0] = v01;
- ptr[1] = v23;
- }
-};
-
-class MatrixView_q4_row {
- public:
- const uint32_t* data;
- const int height;
- const int width;
-
- __device__ __forceinline__ MatrixView_q4_row(const uint32_t* data, const int height, const int width)
- : data(data), height(height), width(width) {}
-
- __device__ __forceinline__ int item(int row, int column) const {
- int shift = (column & 0x07) * 4;
- return (data[row * width / 8 + column / 8] >> shift) & 0x0f;
- }
-
- __device__ __forceinline__ void item2(int (&items)[2], int row, int column) const {
- int shift = (column & 0x07) * 4;
- uint32_t d = data[row * width / 8 + column / 8] >> shift;
- items[0] = d & 0x0f;
- items[1] = (d >> 4) & 0x0f;
- }
-
- __device__ __forceinline__ void item4(int (&items)[4], int row, int column) const {
- int shift = (column & 0x07) * 4;
- uint32_t d = data[row * width / 8 + column / 8] >> shift;
- items[0] = d & 0x0f;
- items[1] = (d >> 4) & 0x0f;
- items[2] = (d >> 8) & 0x0f;
- items[3] = (d >> 12) & 0x0f;
- }
-};
-
-class MatrixView_q4_column {
- public:
- const uint32_t* data;
- const int height;
- const int width;
-
- __device__ __forceinline__ MatrixView_q4_column(const uint32_t* data, const int height, const int width)
- : data(data), height(height), width(width) {}
-
- __device__ __forceinline__ int item(int row, int column) const {
- int shift = (row & 0x07) * 4;
- return (data[row / 8 * width + column] >> shift) & 0x0f;
- }
-
- __device__ __forceinline__ uint32_t item_uint32_t(int row, int column) {
- return data[row / 8 * width + column];
- }
- __device__ __forceinline__ const uint32_t* item_uint32_ptr(int row, int column) {
- return &data[row / 8 * width + column];
- }
-};
-
-class MatrixView_q2_row {
- public:
- const uint32_t* data;
- const int height;
- const int width;
-
- __device__ __forceinline__ MatrixView_q2_row(const uint32_t* data, const int height, const int width)
- : data(data), height(height), width(width) {}
-
- __device__ __forceinline__ int item(int row, int column) const {
- int shift = (column & 0x0f) * 2;
- return (data[row * width / 16 + column / 16] >> shift) & 0x03;
- }
-
- __device__ __forceinline__ void item2(int (&items)[2], int row, int column) const {
- int shift = (column & 0x0f) * 2;
- uint32_t d = data[row * width / 16 + column / 16] >> shift;
- items[0] = d & 0x03;
- items[1] = (d >> 2) & 0x03;
- }
-
- __device__ __forceinline__ void item4(int (&items)[4], int row, int column) const {
- int shift = (column & 0x0f) * 2;
- uint32_t d = data[row * width / 16 + column / 16] >> shift;
- items[0] = d & 0x03;
- items[1] = (d >> 2) & 0x03;
- items[2] = (d >> 4) & 0x03;
- items[3] = (d >> 6) & 0x03;
- }
-};
-
-class MatrixView_q3_row {
- public:
- const uint32_t* data;
- const int height;
- const int width;
-
- __device__ __forceinline__ MatrixView_q3_row(const uint32_t* data, const int height, const int width)
- : data(data), height(height), width(width) {}
-
- __device__ __forceinline__ int item(int row, int column) const {
- int z_w = column * 3 / 32;
- int z_mod = column & 0x1f;
-
- if (z_mod == 10) {
- return (data[row * width * 3 / 32 + z_w] >> 30) | ((data[row * width * 3 / 32 + (z_w + 1)] << 2) & 0x4);
- } else if (z_mod == 21) {
- return (data[row * width * 3 / 32 + z_w] >> 31) | ((data[row * width * 3 / 32 + (z_w + 1)] << 1) & 0x6);
- } else if (z_mod < 10) {
- return (data[row * width * 3 / 32 + z_w] >> (z_mod * 3)) & 0x07;
- } else if (z_mod < 21) {
- return (data[row * width * 3 / 32 + z_w] >> (z_mod * 3 - 32)) & 0x07;
- } else {
- return (data[row * width * 3 / 32 + z_w] >> (z_mod * 3 - 64)) & 0x07;
- }
- }
-
- __device__ __forceinline__ void item4(int (&items)[4], int row, int column) const {
- int shift = (column & 0x1f);
- uint32_t d;
- if (shift <= 4) {
- d = data[row * width / 32 * 3 + column * 3 / 32] >> (shift * 3);
- } else if (shift == 8) {
- d = (data[row * width / 32 * 3 + column * 3 / 32] >> 24) |
- ((data[row * width / 32 * 3 + column * 3 / 32 + 1] & 0x0f) << 8);
- } else if (shift <= 16) {
- d = data[row * width / 32 * 3 + column * 3 / 32] >> (shift * 3 - 32);
- } else if (shift == 20) {
- d = (data[row * width / 32 * 3 + column * 3 / 32] >> 28) |
- ((data[row * width / 32 * 3 + column * 3 / 32 + 1] & 0xff) << 4);
- } else {
- d = data[row * width / 32 * 3 + column * 3 / 32] >> (shift * 3 - 64);
- }
- items[0] = d & 0x07;
- items[1] = (d >> 3) & 0x07;
- items[2] = (d >> 6) & 0x07;
- items[3] = (d >> 9) & 0x07;
- }
-};
-
-class MatrixView_q8_row {
- public:
- const uint32_t* data;
- const int height;
- const int width;
-
- __device__ __forceinline__ MatrixView_q8_row(const uint32_t* data, const int height, const int width)
- : data(data), height(height), width(width) {}
-
- __device__ __forceinline__ int item(int row, int column) const {
- int shift = (column & 0x03) * 8;
- return (data[row * width / 4 + column / 4] >> shift) & 0xff;
- }
-
- __device__ __forceinline__ void item2(int (&items)[2], int row, int column) const {
- int shift = (column & 0x03) * 8;
- uint32_t d = data[row * width / 4 + column / 4] >> shift;
- items[0] = d & 0xff;
- items[1] = (d >> 8) & 0xff;
- }
-
- __device__ __forceinline__ void item4(int (&items)[4], int row, int column) const {
- int shift = (column & 0x03) * 2;
- uint32_t d = data[row * width / 4 + column / 4] >> shift;
- items[0] = d & 0xff;
- items[1] = (d >> 8) & 0xff;
- items[2] = (d >> 16) & 0xff;
- items[3] = (d >> 24) & 0xff;
- }
-};
-
-} // namespace gptq
-} // namespace sglang
-#endif
diff --git a/python/sglang/kernels/aot/csrc/gemm/gptq/qdq_2.cuh b/python/sglang/kernels/aot/csrc/gemm/gptq/qdq_2.cuh
deleted file mode 100644
index 4a75d7b56..000000000
--- a/python/sglang/kernels/aot/csrc/gemm/gptq/qdq_2.cuh
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
-Copied from https://github.com/turboderp/exllamav2
-*/
-
-#ifndef _qdq_2_cuh
-#define _qdq_2_cuh
-
-#include "qdq_util.cuh"
-
-namespace sglang {
-namespace gptq {
-
-// Permutation:
-//
-// ffddbb99 77553311 eeccaa88 66442200
-
-__forceinline__ __device__ void shuffle_2bit_16(uint32_t* q, int stride) {
- uint32_t qa = q[0];
- uint32_t qb = 0;
-
-#pragma unroll
- for (int i = 0; i < 8; i++) {
- uint32_t qa0 = qa & 0x03;
- uint32_t qa1 = (qa & 0x0c) >> 2;
- qa >>= 4;
- qb |= (qa1 << (i * 2 + 16));
- qb |= (qa0 << (i * 2));
- }
- q[0] = qb;
-}
-
-__forceinline__ __device__ void dequant_2bit_16(const uint32_t q_0, half2 (&dq)[8], int stride, const uint32_t zero) {
- const uint32_t c0 = 0x64006400;
- const half y4_ = __float2half_rn(1.0f / 4.0f);
- const half y16_ = __float2half_rn(1.0f / 16.0f);
- const half y64_ = __float2half_rn(1.0f / 64.0f);
- const half2 y4 = __halves2half2(y4_, y4_);
- const half2 y16 = __halves2half2(y16_, y16_);
- const half2 y64 = __halves2half2(y64_, y64_);
-
- const half_uint16 z1_(0xe400 | zero); // half(-1024.0f - zero);
- const half z4_ = __hsub(__int2half_rn(-256), __int2half_rn(zero));
- const half z16_ = __hsub(__int2half_rn(-64), __int2half_rn(zero));
- const half z64_ = __hsub(__int2half_rn(-16), __int2half_rn(zero));
- const half2 z1 = __half2half2(z1_.as_half);
- const half2 z4 = __half2half2(z4_);
- const half2 z16 = __half2half2(z16_);
- const half2 z64 = __half2half2(z64_);
-
- uint32_t qa = q_0;
- half2_uint32 q0((qa & 0x00030003) | c0); // half2(q[ 0], q[ 1]) + 1024
- half2_uint32 q1((qa & 0x000c000c) | c0); // half2(q[ 2], q[ 3]) * 4 + 1024
- half2_uint32 q2((qa & 0x00300030) | c0); // half2(q[ 4], q[ 5]) * 16 + 1024
- half2_uint32 q3((qa & 0x00c000c0) | c0); // half2(q[ 6], q[ 7]) * 64 + 1024
- qa >>= 8;
- half2_uint32 q4((qa & 0x00030003) | c0); // half2(q[ 8], q[ 8]) + 1024
- half2_uint32 q5((qa & 0x000c000c) | c0); // half2(q[10], q[11]) * 4 + 1024
- half2_uint32 q6((qa & 0x00300030) | c0); // half2(q[12], q[13]) * 16 + 1024
- half2_uint32 q7((qa & 0x00c000c0) | c0); // half2(q[14], q[15]) * 64 + 1024
-
- dq[0] = __hadd2(q0.as_half2, z1);
- dq[1] = __hfma2(q1.as_half2, y4, z4);
- dq[2] = __hfma2(q2.as_half2, y16, z16);
- dq[3] = __hfma2(q3.as_half2, y64, z64);
- dq[4] = __hadd2(q4.as_half2, z1);
- dq[5] = __hfma2(q5.as_half2, y4, z4);
- dq[6] = __hfma2(q6.as_half2, y16, z16);
- dq[7] = __hfma2(q7.as_half2, y64, z64);
-}
-
-} // namespace gptq
-} // namespace sglang
-
-#endif
diff --git a/python/sglang/kernels/aot/csrc/gemm/gptq/qdq_3.cuh b/python/sglang/kernels/aot/csrc/gemm/gptq/qdq_3.cuh
deleted file mode 100644
index 5996f342d..000000000
--- a/python/sglang/kernels/aot/csrc/gemm/gptq/qdq_3.cuh
+++ /dev/null
@@ -1,146 +0,0 @@
-#ifndef _qdq_3_cuh
-#define _qdq_3_cuh
-
-#include "qdq_util.cuh"
-
-namespace sglang {
-namespace gptq {
-// Permutation:
-//
-// v9997775 55333111 u8886664 44222000 (u, v lsb)
-// vjjjhhhf ffdddbbb uiiiggge eecccaaa
-// vtttrrrp ppnnnlll usssqqqo oommmkkk
-
-__forceinline__ __device__ void shuffle_3bit_32(uint32_t* q, int stride) {
- uint32_t qa = q[0 * stride];
- uint32_t qb = q[1 * stride];
- uint32_t qc = q[2 * stride];
-
- // qa: aa999888 77766655 54443332 22111000
- // qb: lkkkjjji iihhhggg fffeeedd dcccbbba
- // qc: vvvuuutt tsssrrrq qqpppooo nnnmmmll
-
- uint32_t qd = qc >> 26;
- qc <<= 4;
- qc |= qb >> 28;
- qb <<= 2;
- qb |= qa >> 30;
-
- // qa: ..999888 77766655 54443332 22111000
- // qb: ..jjjiii hhhgggff feeedddc ccbbbaaa
- // qc: ..tttsss rrrqqqpp pooonnnm mmlllkkk
- // qd: vvvuuu
-
- uint32_t za = 0;
- uint32_t zb = 0;
- uint32_t zc = 0;
-
- for (int i = 0; i < 5; i++) {
- uint32_t t0 = qa & 0x07;
- uint32_t t1 = (qa & 0x38) >> 3;
- qa >>= 6;
- za |= (t0 << (i * 3));
- za |= (t1 << (i * 3 + 16));
- }
- for (int i = 0; i < 5; i++) {
- uint32_t t0 = qb & 0x07;
- uint32_t t1 = (qb & 0x38) >> 3;
- qb >>= 6;
- zb |= (t0 << (i * 3));
- zb |= (t1 << (i * 3 + 16));
- }
- for (int i = 0; i < 5; i++) {
- uint32_t t0 = qc & 0x07;
- uint32_t t1 = (qc & 0x38) >> 3;
- qc >>= 6;
- zc |= (t0 << (i * 3));
- zc |= (t1 << (i * 3 + 16));
- }
-
- // za: 9997775 55333111 8886664 44222000
- // zb: jjjhhhf ffdddbbb iiiggge eecccaaa
- // zc: tttrrrp ppnnnlll sssqqqo oommmkkk
- // qd: vvvuuu
-
- za |= ((qd & 0x01) >> 0) << 15;
- zb |= ((qd & 0x02) >> 1) << 15;
- zc |= ((qd & 0x04) >> 2) << 15;
- za |= ((qd & 0x08) >> 3) << 31;
- zb |= ((qd & 0x10) >> 4) << 31;
- zc |= ((qd & 0x20) >> 5) << 31;
-
- // za: v9997775 55333111 u8886664 44222000 (u, v lsb)
- // zb: vjjjhhhf ffdddbbb uiiiggge eecccaaa
- // zc: vtttrrrp ppnnnlll usssqqqo oommmkkk
-
- q[0 * stride] = za;
- q[1 * stride] = zb;
- q[2 * stride] = zc;
-}
-
-__forceinline__ __device__ void dequant_3bit_32(
- const uint32_t q_0, const uint32_t q_1, const uint32_t q_2, half2 (&dq)[16], int stride, const uint32_t zero) {
- const uint32_t c0 = 0x64006400;
- const half y8_ = __float2half_rn(1.0f / 8.0f);
- const half y64_ = __float2half_rn(1.0f / 64.0f);
- const half2 y8 = __halves2half2(y8_, y8_);
- const half2 y64 = __halves2half2(y64_, y64_);
- const half_uint16 z1_(0xe400 | zero); // half(-1024.0f - zero);
- const half z8_ = __hsub(__int2half_rn(-128), __int2half_rn(zero));
- const half z64_ = __hsub(__int2half_rn(-16), __int2half_rn(zero));
- const half2 z1 = __halves2half2(z1_.as_half, z1_.as_half);
- const half2 z8 = __halves2half2(z8_, z8_);
- const half2 z64 = __halves2half2(z64_, z64_);
-
- uint32_t qa = q_0;
- uint32_t qb = q_1;
- uint32_t qc = q_2;
-
- half2_uint32 q0((qa & 0x00070007) | c0); // half2(q[ 0], q[ 1]) + 1024
- half2_uint32 q1((qa & 0x00380038) | c0); // half2(q[ 2], q[ 3]) * 8 + 1024
- qa >>= 6;
- half2_uint32 q2((qa & 0x00070007) | c0); // half2(q[ 4], q[ 5]) + 1024
- half2_uint32 q3((qa & 0x00380038) | c0); // half2(q[ 6], q[ 7]) * 8 + 1024
- half2_uint32 q4((qa & 0x01c001c0) | c0); // half2(q[ 8], q[ 9]) * 64 + 1024
- qa >>= 9;
- qa &= 0x00010001;
- half2_uint32 q5((qb & 0x00070007) | c0); // half2(q[10], q[11]) + 1024
- half2_uint32 q6((qb & 0x00380038) | c0); // half2(q[12], q[13]) * 8 + 1024
- qb >>= 6;
- half2_uint32 q7((qb & 0x00070007) | c0); // half2(q[14], q[15]) + 1024
- half2_uint32 q8((qb & 0x00380038) | c0); // half2(q[16], q[17]) * 8 + 1024
- half2_uint32 q9((qb & 0x01c001c0) | c0); // half2(q[18], q[19]) * 64 + 1024
- qb >>= 8;
- qb &= 0x00020002;
- half2_uint32 q10((qc & 0x00070007) | c0); // half2(q[20], q[21]) + 1024
- half2_uint32 q11((qc & 0x00380038) | c0); // half2(q[22], q[23]) * 8 + 1024
- qc >>= 6;
- half2_uint32 q12((qc & 0x00070007) | c0); // half2(q[24], q[25]) + 1024
- half2_uint32 q13((qc & 0x00380038) | c0); // half2(q[26], q[27]) * 8 + 1024
- half2_uint32 q14((qc & 0x01c001c0) | c0); // half2(q[28], q[29]) * 64 + 1024
- qc >>= 7;
- qc &= 0x00040004;
- half2_uint32 q15((qa | qb | qc) | c0);
-
- dq[0] = __hadd2(q0.as_half2, z1);
- dq[1] = __hfma2(q1.as_half2, y8, z8);
- dq[2] = __hadd2(q2.as_half2, z1);
- dq[3] = __hfma2(q3.as_half2, y8, z8);
- dq[4] = __hfma2(q4.as_half2, y64, z64);
- dq[5] = __hadd2(q5.as_half2, z1);
- dq[6] = __hfma2(q6.as_half2, y8, z8);
- dq[7] = __hadd2(q7.as_half2, z1);
- dq[8] = __hfma2(q8.as_half2, y8, z8);
- dq[9] = __hfma2(q9.as_half2, y64, z64);
- dq[10] = __hadd2(q10.as_half2, z1);
- dq[11] = __hfma2(q11.as_half2, y8, z8);
- dq[12] = __hadd2(q12.as_half2, z1);
- dq[13] = __hfma2(q13.as_half2, y8, z8);
- dq[14] = __hfma2(q14.as_half2, y64, z64);
- dq[15] = __hadd2(q15.as_half2, z1);
-}
-
-} // namespace gptq
-} // namespace sglang
-
-#endif
diff --git a/python/sglang/kernels/aot/csrc/gemm/gptq/qdq_4.cuh b/python/sglang/kernels/aot/csrc/gemm/gptq/qdq_4.cuh
deleted file mode 100644
index c96af4718..000000000
--- a/python/sglang/kernels/aot/csrc/gemm/gptq/qdq_4.cuh
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
-Copied from https://github.com/turboderp/exllamav2
-*/
-
-#ifndef _qdq_4_cuh
-#define _qdq_4_cuh
-
-#include "qdq_util.cuh"
-
-namespace sglang {
-namespace gptq {
-// Permutation:
-//
-// 77775555 33331111 66664444 22220000
-
-__forceinline__ __device__ void shuffle_4bit_8(uint32_t* q, int stride) {
- uint32_t qa = q[0];
- uint32_t qb = 0;
-
-#pragma unroll
- for (int i = 0; i < 4; i++) {
- uint32_t qa0 = qa & 0x0f;
- uint32_t qa1 = (qa & 0xf0) >> 4;
- qa >>= 8;
- qb |= (qa1 << (i * 4 + 16));
- qb |= (qa0 << (i * 4));
- }
- q[0] = qb;
-}
-
-__forceinline__ __device__ void dequant_4bit_8(const uint32_t q_0, half2 (&dq)[4], int stride, const uint32_t zero) {
- const uint32_t c0 = 0x64006400;
- const half y16_ = __float2half_rn(1.0f / 16.0f);
- const half2 y16 = __halves2half2(y16_, y16_);
- const half_uint16 z1_(0xe400 | zero); // half(-1024.0f - zero);
- const half z16_ = __hsub(__int2half_rn(-64), __int2half_rn(zero));
- const half2 z1 = __half2half2(z1_.as_half);
- const half2 z16 = __half2half2(z16_);
-
- uint32_t qa = q_0;
- half2_uint32 q0((qa & 0x000f000f) | c0); // half2(q[ 0], q[ 1]) + 1024
- half2_uint32 q1((qa & 0x00f000f0) | c0); // half2(q[ 2], q[ 3]) * 16 + 1024
- qa >>= 8;
- half2_uint32 q2((qa & 0x000f000f) | c0); // half2(q[ 4], q[ 5]) + 1024
- half2_uint32 q3((qa & 0x00f000f0) | c0); // half2(q[ 6], q[ 7]) * 16 + 1024
-
- dq[0] = __hadd2(q0.as_half2, z1);
- dq[1] = __hfma2(q1.as_half2, y16, z16);
- dq[2] = __hadd2(q2.as_half2, z1);
- dq[3] = __hfma2(q3.as_half2, y16, z16);
-}
-
-__forceinline__ __device__ void
-dequant_4bit_8_prep_zero_scale(const uint32_t zero, const half scale, half2 (&z1z16)[2], half2 (&y1y16)[2]) {
- half_uint16 z1(0xe400 | zero); // half(-1024.0f - zero);
- half z16 = __hsub(__int2half_rn(-64), __int2half_rn(zero));
-
- half2 scale2 = __half2half2(scale);
-
- z1z16[0] = __hmul2(scale2, __half2half2(z1.as_half));
- z1z16[1] = __hmul2(scale2, __half2half2(z16));
-
- const half y1 = __float2half_rn(1.0f);
- const half y16 = __float2half_rn(1.0f / 16.0f);
-
- y1y16[0] = __hmul2(scale2, __half2half2(y1));
- y1y16[1] = __hmul2(scale2, __half2half2(y16));
-}
-
-__forceinline__ __device__ void dequant_4bit_8_prep_zero(const uint32_t zero, half2 (&z1z16)[2], half2 (&y1y16)[2]) {
- half_uint16 z1(0xe400 | zero); // half(-1024.0f - zero);
- half z16 = __hsub(__int2half_rn(-64), __int2half_rn(zero));
-
- z1z16[0] = __half2half2(z1.as_half);
- z1z16[1] = __half2half2(z16);
-
- const half y1 = __float2half_rn(1.0f);
- const half y16 = __float2half_rn(1.0f / 16.0f);
-
- y1y16[0] = __half2half2(y1);
- y1y16[1] = __half2half2(y16);
-}
-
-__forceinline__ __device__ void
-dequant_4bit_8_gptq(const uint32_t q_0, half2 (&dq)[4], half2 (&z1z16)[2], half2 (&y1y16)[2], int stride, bool scaled) {
- const uint32_t c0 = 0x64006400;
-
- uint32_t qa = q_0;
- half2_uint32 q0((qa & 0x000f000f) | c0); // half2( q[0] + 1024, q[1] + 1024 )
- half2_uint32 q1((qa & 0x00f000f0) | c0); // half2( q[2] * 16 + 1024, q[3] * 16 + 1024 )
- qa >>= 8;
- half2_uint32 q2((qa & 0x000f000f) | c0); // half2( q[4] + 1024, q[5] + 1024 )
- half2_uint32 q3((qa & 0x00f000f0) | c0); // half2( q[6] * 16 + 1024, q[7] * 16 + 1024 )
-
- if (scaled) {
- dq[0] = __hfma2(q0.as_half2, y1y16[0],
- z1z16[0]); // half2( q[0] * s - z * s, q[1] * s - z * s)
- dq[1] = __hfma2(q1.as_half2, y1y16[1],
- z1z16[1]); // half2( q[2] * s - z * s, q[3] * s - z * s)
- dq[2] = __hfma2(q2.as_half2, y1y16[0], z1z16[0]);
- dq[3] = __hfma2(q3.as_half2, y1y16[1], z1z16[1]);
- } else {
- dq[0] = __hadd2(q0.as_half2, z1z16[0]); // half2( q[0] - z, q[1] - z )
- dq[1] = __hfma2(q1.as_half2, y1y16[1],
- z1z16[1]); // half2( q[2] - z, q[3] - z )
- dq[2] = __hadd2(q2.as_half2, z1z16[0]); // half2( q[4] - z, q[5] - z )
- dq[3] = __hfma2(q3.as_half2, y1y16[1],
- z1z16[1]); // half2( q[6] - z, q[7] - z )
- }
-}
-} // namespace gptq
-} // namespace sglang
-
-#endif
diff --git a/python/sglang/kernels/aot/csrc/gemm/gptq/qdq_8.cuh b/python/sglang/kernels/aot/csrc/gemm/gptq/qdq_8.cuh
deleted file mode 100644
index c6a49d6dc..000000000
--- a/python/sglang/kernels/aot/csrc/gemm/gptq/qdq_8.cuh
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-Copied from https://github.com/turboderp/exllamav2
-*/
-
-#ifndef _qdq_8_cuh
-#define _qdq_8_cuh
-
-#include "qdq_util.cuh"
-
-namespace sglang {
-namespace gptq {
-
-__forceinline__ __device__ void shuffle_8bit_4(uint32_t* q, int stride) {}
-
-__forceinline__ __device__ void
-dequant_8bit_8(const uint32_t q_0, const uint32_t q_1, half2 (&dq)[4], int stride, const uint32_t zero) {
- half dqh[8];
- for (int i = 0; i < 4; i++)
- dqh[i] = dq_ns(exb(q_0, i * 8, 0xff), zero);
- for (int i = 0; i < 4; i++)
- dqh[i + 4] = dq_ns(exb(q_1, i * 8, 0xff), zero);
-
- for (int i = 0; i < 4; i++)
- dq[i] = __halves2half2(dqh[i * 2], dqh[i * 2 + 1]);
-}
-
-} // namespace gptq
-} // namespace sglang
-
-#endif
diff --git a/python/sglang/kernels/aot/csrc/gemm/gptq/qdq_util.cuh b/python/sglang/kernels/aot/csrc/gemm/gptq/qdq_util.cuh
deleted file mode 100644
index 0977269c3..000000000
--- a/python/sglang/kernels/aot/csrc/gemm/gptq/qdq_util.cuh
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-Copied from https://github.com/turboderp/exllamav2
-*/
-
-#ifndef _qdq_util_cuh
-#define _qdq_util_cuh
-
-namespace sglang {
-namespace gptq {
-
-union half2_uint32 {
- uint32_t as_uint32;
- half2 as_half2;
- __device__ half2_uint32(uint32_t val) : as_uint32(val) {}
- __device__ half2_uint32(half2 val) : as_half2(val) {}
-};
-
-union half_uint16 {
- uint16_t as_uint16;
- half as_half;
- __device__ half_uint16(uint16_t val) : as_uint16(val) {}
- __device__ half_uint16(half val) : as_half(val) {}
-};
-
-// Max_scale premultiplied by 1/256
-
-__forceinline__ __device__ half dq_scale(const int qs, const half max_scale) {
- int qs_i = qs + 1;
- half qs_h = __int2half_rn(qs_i * qs_i);
- qs_h = __hmul(qs_h, max_scale);
- return qs_h;
-}
-
-__forceinline__ __device__ half dq(const int q, const int qzero, const half scale) {
- return __hmul(__int2half_rn(q - qzero), scale);
-}
-
-__forceinline__ __device__ half dq_ns(const int q, const int qzero) {
- // return __hsub(__int2half_rn(q), __int2half_rn(qzero));
- return __int2half_rn(q - qzero);
-}
-
-__forceinline__ __device__ int exb(const uint32_t q, const int shift, const int mask) {
- return (int)((q >> shift) & mask);
-}
-
-__forceinline__ __device__ int exb(const uint32_t q1, const uint32_t q0, const int shift, const int mask) {
- return (int)(__funnelshift_rc(q0, q1, shift) & mask);
-}
-
-} // namespace gptq
-} // namespace sglang
-#endif
diff --git a/python/sglang/kernels/aot/include/sgl_kernel_ops.h b/python/sglang/kernels/aot/include/sgl_kernel_ops.h
index 4ee916228..846e67efd 100644
--- a/python/sglang/kernels/aot/include/sgl_kernel_ops.h
+++ b/python/sglang/kernels/aot/include/sgl_kernel_ops.h
@@ -96,21 +96,6 @@ void register_graph_buffers(
*/
void merge_state_v2(
at::Tensor v_a, at::Tensor s_a, at::Tensor v_b, at::Tensor s_b, at::Tensor v_merged, at::Tensor s_merged);
-void cutlass_mla_decode(
- torch::Tensor const& out,
- torch::Tensor const& q_nope,
- torch::Tensor const& q_pe,
- torch::Tensor const& kv_c_and_k_pe_cache,
- torch::Tensor const& seq_lens,
- torch::Tensor const& page_table,
- torch::Tensor const& workspace,
- double sm_scale,
- int64_t num_kv_splits = 1 /* Set to 1 to avoid cuda_graph issue by default. */);
-int64_t cutlass_mla_get_workspace_size(
- int64_t max_seq_len,
- int64_t num_batches,
- int64_t sm_count = 0,
- int64_t num_kv_splits = 1 /* Set to 1 to avoid cuda_graph issue by default. */);
/*
* From csrc/infllm_v2
@@ -220,7 +205,6 @@ void dsv4_fused_q_indexer_rope_hadamard_quant(
/*
* From csrc/gemm
*/
-torch::Tensor awq_dequantize(torch::Tensor qweight, torch::Tensor scales, torch::Tensor qzeros);
torch::Tensor int8_scaled_mm(
const torch::Tensor& mat_a,
const torch::Tensor& mat_b,
@@ -257,17 +241,6 @@ void sgl_per_token_group_quant_8bit_v2(
const std::optional& masked_m);
void sgl_per_token_quant_fp8(at::Tensor input, at::Tensor output_q, at::Tensor output_s);
-torch::Tensor gptq_gemm(
- torch::Tensor a,
- torch::Tensor b_q_weight,
- torch::Tensor b_gptq_qzeros,
- torch::Tensor b_gptq_scales,
- torch::Tensor b_g_idx,
- bool use_shuffle,
- int64_t bit);
-
-void gptq_shuffle(torch::Tensor q_weight, torch::Tensor q_perm, int64_t bit);
-
/*
* From csrc/moe
*/
@@ -643,82 +616,6 @@ void top_k_renorm_probs(
void top_p_renorm_probs(
at::Tensor probs, at::Tensor renorm_probs, std::optional maybe_top_p_arr, double top_p_val);
-namespace flash {
-/*
- * From fa2 sparse
- */
-std::vector mha_fwd_sparse(
- at::Tensor& q, // batch_size x seqlen_q x num_heads x head_size
- const at::Tensor& k, // batch_size x seqlen_k x num_heads_k x head_size
- const at::Tensor& v, // batch_size x seqlen_k x num_heads_k x head_size
- const at::Tensor& block_count,
- const at::Tensor& block_offset,
- const at::Tensor& column_count,
- const at::Tensor& column_index,
- const std::optional& out_, // batch_size x seqlen_q x num_heads x head_size
- const std::optional& alibi_slopes_, // num_heads or batch_size x num_heads
- const double p_dropout,
- const double softmax_scale,
- bool is_causal,
- const double softcap,
- const bool return_softmax,
- std::optional