[jit_kernel] Add fused_qknorm_rope JIT kernel (#19059)

Co-authored-by: Xiaoyu Zhang <35585791+BBuf@users.noreply.github.com>
This commit is contained in:
Johnsonms
2026-03-27 13:21:28 +08:00
committed by GitHub
co-authored by Xiaoyu Zhang
parent 0138129d3c
commit c531be455e
5 changed files with 1127 additions and 3 deletions
@@ -0,0 +1,183 @@
"""
Benchmark: fused_qknorm_rope JIT vs AOT (sgl_kernel)
Measures throughput (us) for fused_qk_norm_rope across typical
LLM configurations (head_dim x num_heads x num_tokens).
Run:
python python/sglang/jit_kernel/benchmark/bench_fused_qknorm_rope.py
"""
import itertools
import torch
import triton
import triton.testing
from sglang.jit_kernel.benchmark.utils import get_benchmark_range, run_benchmark
from sglang.jit_kernel.fused_qknorm_rope import (
fused_qk_norm_rope as fused_qk_norm_rope_jit,
)
try:
from sgl_kernel import fused_qk_norm_rope as fused_qk_norm_rope_aot
AOT_AVAILABLE = True
except ImportError:
fused_qk_norm_rope_aot = None
AOT_AVAILABLE = False
# ---------------------------------------------------------------------------
# Benchmark configuration
# ---------------------------------------------------------------------------
NUM_TOKENS_RANGE = get_benchmark_range(
full_range=[1, 64, 256, 1024, 4096],
ci_range=[64, 512],
)
# (head_dim, num_heads_q, num_heads_k, num_heads_v) - typical MoE/dense configs
MODEL_CONFIGS = get_benchmark_range(
full_range=[
(64, 32, 8, 8), # small
(128, 32, 8, 8), # typical (e.g. Qwen3-8B)
(256, 16, 4, 4), # large head_dim
],
ci_range=[(128, 32, 8, 8)],
)
LINE_VALS = ["jit", "aot"] if AOT_AVAILABLE else ["jit"]
LINE_NAMES = ["JIT (new)", "AOT sgl_kernel"] if AOT_AVAILABLE else ["JIT (new)"]
STYLES = [("blue", "--"), ("orange", "-")] if AOT_AVAILABLE else [("blue", "--")]
# ---------------------------------------------------------------------------
# Benchmark: fused_qk_norm_rope (interleave style, no YaRN)
# ---------------------------------------------------------------------------
@triton.testing.perf_report(
triton.testing.Benchmark(
x_names=["num_tokens", "head_dim", "num_heads_q", "num_heads_k", "num_heads_v"],
x_vals=[
(nt, hd, nq, nk, nv)
for nt, (hd, nq, nk, nv) in itertools.product(
NUM_TOKENS_RANGE, MODEL_CONFIGS
)
],
line_arg="provider",
line_vals=LINE_VALS,
line_names=LINE_NAMES,
styles=STYLES,
ylabel="us",
plot_name="fused-qknorm-rope-performance",
args={},
)
)
def bench_fused_qknorm_rope(
num_tokens: int,
head_dim: int,
num_heads_q: int,
num_heads_k: int,
num_heads_v: int,
provider: str,
):
device = "cuda"
total_heads = num_heads_q + num_heads_k + num_heads_v
qkv = torch.randn(
(num_tokens, total_heads * head_dim), dtype=torch.bfloat16, device=device
)
q_weight = torch.ones(head_dim, dtype=torch.bfloat16, device=device)
k_weight = torch.ones(head_dim, dtype=torch.bfloat16, device=device)
position_ids = torch.arange(num_tokens, dtype=torch.int32, device=device)
common_kwargs = dict(
num_heads_q=num_heads_q,
num_heads_k=num_heads_k,
num_heads_v=num_heads_v,
head_dim=head_dim,
eps=1e-5,
q_weight=q_weight,
k_weight=k_weight,
base=10000.0,
is_neox=False,
position_ids=position_ids,
factor=1.0,
low=1.0,
high=32.0,
attention_factor=1.0,
rotary_dim=head_dim,
)
if provider == "jit":
fn = lambda: fused_qk_norm_rope_jit(qkv.clone(), **common_kwargs)
elif provider == "aot":
fn = lambda: fused_qk_norm_rope_aot(qkv.clone(), **common_kwargs)
else:
raise ValueError(f"Unknown provider: {provider}")
return run_benchmark(fn)
# ---------------------------------------------------------------------------
# Quick correctness diff
# ---------------------------------------------------------------------------
def calculate_diff():
if not AOT_AVAILABLE:
print("sgl_kernel not available - skipping AOT diff check")
return
device = "cuda"
print("Correctness diff (JIT vs AOT):")
for head_dim, is_neox in [(64, False), (128, False), (128, True), (256, False)]:
num_tokens = 32
num_heads_q, num_heads_k, num_heads_v = 4, 2, 2
total_heads = num_heads_q + num_heads_k + num_heads_v
qkv = torch.randn(
(num_tokens, total_heads * head_dim), dtype=torch.bfloat16, device=device
)
q_weight = torch.ones(head_dim, dtype=torch.bfloat16, device=device)
k_weight = torch.ones(head_dim, dtype=torch.bfloat16, device=device)
position_ids = torch.arange(num_tokens, dtype=torch.int32, device=device)
common = dict(
num_heads_q=num_heads_q,
num_heads_k=num_heads_k,
num_heads_v=num_heads_v,
head_dim=head_dim,
eps=1e-5,
q_weight=q_weight,
k_weight=k_weight,
base=10000.0,
is_neox=is_neox,
position_ids=position_ids,
factor=1.0,
low=1.0,
high=32.0,
attention_factor=1.0,
rotary_dim=head_dim,
)
qkv_jit = qkv.clone()
fused_qk_norm_rope_jit(qkv_jit, **common)
qkv_aot = qkv.clone()
fused_qk_norm_rope_aot(qkv_aot, **common)
match = torch.allclose(qkv_jit.float(), qkv_aot.float(), atol=1e-2, rtol=1e-2)
status = "OK" if match else "MISMATCH"
max_err = (qkv_jit.float() - qkv_aot.float()).abs().max().item()
print(
f" head_dim={head_dim:3d} is_neox={str(is_neox):5s} "
f"max_err={max_err:.2e} [{status}]"
)
if __name__ == "__main__":
calculate_diff()
print()
bench_fused_qknorm_rope.run(print_data=True)