Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
bada6df
support k3 on a5
zhaozx-cn Aug 28, 2026
59b2075
refractor
zhaozx-cn Aug 28, 2026
0eacad5
Run the shared-expert MLP on the alternate stream while keeping atten…
hanwlax Aug 13, 2026
98ba765
run fused_qkvg_proj with Kimi-K3-W4A8 quanted with modelslim
hanwlax Aug 28, 2026
2324c84
fix(npu): skip KDA autotune during first request (#2)
McZyWu Aug 31, 2026
75c0cb4
skip qkv_proj (#4)
hanwlax Aug 31, 2026
ac83e8b
fix spec acc
zhaozx-cn Sep 1, 2026
955bf4b
k3 use fias v2 (#6)
hanwlax Sep 2, 2026
e83efb3
feat: support Kimi-K3 DSPARK PD decode radix cache (#7)
qybnb Sep 3, 2026
10cdafa
fix(npu): use DeepEP MXFP8 dispatch for W4A8 MXFP MoE (#11)
hanwlax Sep 3, 2026
af7152c
A5 k3 fp8 fused (#13)
hanwlax Sep 4, 2026
eec5cb7
perf(npu): reuse graph update worker
McZyWu Aug 21, 2026
21009b2
fix(npu): use NPU chain rejection sampling for DSPARK
hanwlax Sep 5, 2026
f1179a6
feat(npu): add fine-grained Kimi-K3 shared expert overlap
Hexq0210 Sep 5, 2026
4782966
[NPU] Skip DSpark Mamba tracking when no boundary can be crossed
Hexq0210 Sep 5, 2026
21a4a01
feat(npu): switch Ascend KDA extend to fused chunk_kda_fwd (#30)
sherdavincl9 Sep 7, 2026
7ac8292
nz
zhaozx-cn Sep 5, 2026
4cd9ed4
fix(npu): restore logical MLA prefix pages from NZ cache
hanwlax Sep 8, 2026
58ae5ec
[Kimi-K3] Allow shared-expert TP subgroups below attention TP
Hexq0210 Sep 8, 2026
91cb6a0
revert kda triton kernel modification
zhaozx-cn Sep 15, 2026
23ba155
Revert "feat: support Kimi-K3 DSPARK PD decode radix cache (#7)"
zhaozx-cn Sep 15, 2026
83a12a4
fix
zhaozx-cn Sep 15, 2026
da481f4
fix lint
zhaozx-cn Sep 15, 2026
eb64d9c
fix shares expert tp
zhaozx-cn Sep 15, 2026
f9b16ad
fix lint
zhaozx-cn Sep 15, 2026
ce651b1
fix dispatch
zhaozx-cn Sep 15, 2026
db368a2
fix lint
zhaozx-cn Sep 15, 2026
929a91b
remove unused code
zhaozx-cn Sep 16, 2026
478f45f
fia v2 for mtp
zhaozx-cn Sep 16, 2026
361de6a
fia v2
zhaozx-cn Sep 16, 2026
957f4b7
Merge branch 'main' into a5-k3-0915
zhaozx-cn Sep 16, 2026
a122d31
fix kimi k3 pd acc on npu
zhaozx-cn Sep 16, 2026
c1b396b
fix pd kimi k3 acc on npu
zhaozx-cn Sep 16, 2026
bd0c6a5
fix ci
zhaozx-cn Sep 16, 2026
9742bb3
fix
zhaozx-cn Sep 16, 2026
09d6d8a
fix ci
zhaozx-cn Sep 17, 2026
acafebd
Merge branch 'main' into a5-k3-0915
zhaozx-cn Sep 17, 2026
775bcc4
fix
zhaozx-cn Sep 17, 2026
0a236c4
Merge branch 'main' into a5-k3-0915
sglang-npu-bot Sep 17, 2026
4ab4643
Merge branch 'main' into a5-k3-0915
zhaozx-cn Sep 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions python/sglang/kernels/ops/speculative/dspark/dspark_accept.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,22 @@
import triton.language as tl

from sglang.kernels.ops.speculative.dspark.dispatch import inputs_on_cuda
from sglang.kernels.ops.speculative.reject_sampling import (
chain_speculative_sampling_triton,
)
from sglang.srt.speculative.dflash_info_v2 import DFlashDraftInputV2
from sglang.srt.speculative.dflash_utils import (
_get_or_create_chain_verify_buffers,
build_dflash_verify_target_probs,
compute_dflash_correct_drafts_and_bonus,
)
from sglang.srt.utils import is_npu

_is_npu = is_npu()

if _is_npu:
from sgl_kernel_npu.sample import chain_speculative_sampling_triton
else:
from sglang.kernels.ops.speculative.reject_sampling import (
chain_speculative_sampling_triton,
)


class AcceptSampling:
Expand Down Expand Up @@ -117,7 +124,12 @@ def _accept_sampling_core(
draft_token_num=verify_num_draft_tokens,
device=device,
)
uniform_samples = torch.rand((bs, gamma), dtype=torch.float32, device=device)
# The NPU implementation uses the candidate width as its row stride. The
# last value is intentionally unused because candidate slot 0 is the root.
uniform_width = candidates.shape[1] if _is_npu else gamma
uniform_samples = torch.rand(
(bs, uniform_width), dtype=torch.float32, device=device
)
uniform_samples_final = torch.rand((bs,), dtype=torch.float32, device=device)
chain_speculative_sampling_triton(
predicts=predicts,
Expand Down
1 change: 1 addition & 0 deletions python/sglang/srt/arg_groups/field_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
"enable_tp_lm_head_all_to_all",
"enable_attn_tp_input_scattered",
"enable_shared_experts_attn_tp",
"shared_experts_tp_size",
"enable_dense_mlp_attn_tp",
"enable_layernorm_sp",
"disable_attn_tp_gather",
Expand Down
6 changes: 6 additions & 0 deletions python/sglang/srt/arg_groups/fields/parallel.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,12 @@ class Parallel(msgspec.Struct):
bool,
"Shard shared expert weights across the attention TP group when using an expert-parallel all-to-all backend.",
] = False
shared_experts_tp_size: A[
Optional[int],
"Shared-expert TP size for Kimi-K3 with an expert-parallel all-to-all "
"backend. Must divide attention TP size. Overrides "
"--enable-shared-experts-attn-tp when set; 1 replicates the weights.",
] = None
enable_dense_mlp_attn_tp: A[
bool,
"Shard dense MLP weights across the attention TP group under DP attention.",
Expand Down
40 changes: 40 additions & 0 deletions python/sglang/srt/arg_groups/parallel_hook.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,46 @@ def handle_context_parallelism(server_args: Any):
)


def handle_shared_experts_tp(server_args: Any):
cfg = resolving_view(server_args)
size = cfg.shared_experts_tp_size
if size is None:
return

from sglang.srt.runtime_context import derive_attention_widths

view = resolved_view(server_args)
_, attn_tp_size = derive_attention_widths(
tp_size=cfg.tp_size,
attn_cp_size=view.attn_cp_size,
dp_size=cfg.dp_size,
enable_dp_attention=view.enable_dp_attention,
)
if size < 1 or attn_tp_size % size != 0:
raise ValueError(
f"--shared-experts-tp-size ({size}) must be a positive divisor "
f"of attention TP size ({attn_tp_size})."
)
if parse_connector_type(cfg.model_path) == ConnectorType.INSTANCE:
raise ValueError(
"--shared-experts-tp-size requires a Kimi-K3 model configuration."
)
model_arch = model_config_of(server_args).hf_config.architectures[0]
if model_arch != "KimiK3ForConditionalGeneration":
raise ValueError("--shared-experts-tp-size is only supported for Kimi-K3.")
if cfg.moe_a2a_backend not in (
"deepep",
"megamoe",
"mooncake",
"ascend_fuseep",
"mori",
):
raise ValueError(
"--shared-experts-tp-size requires an expert-parallel all-to-all "
"backend (deepep, megamoe, mooncake, ascend_fuseep or mori)."
)


def handle_decode_context_parallelism(server_args: Any):
run_post_process_pass(server_args, _dcp_comm_backend_default)
cfg = resolving_view(server_args)
Expand Down
2 changes: 2 additions & 0 deletions python/sglang/srt/arg_groups/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ def run_resolution_pipeline(server_args: Any) -> None:
handle_elastic_ep,
handle_eplb_and_dispatch,
handle_expert_distribution_metrics,
handle_shared_experts_tp,
)

run_hook(validate_prefill_only_disable_kv_cache_args, server_args)
Expand Down Expand Up @@ -311,6 +312,7 @@ def run_resolution_pipeline(server_args: Any) -> None:

run_hook(handle_moe_kernel_config, server_args)
run_hook(handle_a2a_moe, server_args)
run_hook(handle_shared_experts_tp, server_args)
run_hook(handle_eplb_and_dispatch, server_args)
run_hook(handle_expert_distribution_metrics, server_args)
run_hook(handle_elastic_ep, server_args)
Expand Down
1 change: 1 addition & 0 deletions python/sglang/srt/arg_groups/resolution_hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
"handle_a2a_moe",
"handle_eplb_and_dispatch",
"handle_expert_distribution_metrics",
"handle_shared_experts_tp",
"handle_elastic_ep",
"validate_experimental_sgl_marlin",
"handle_speculative_decoding",
Expand Down
1 change: 1 addition & 0 deletions python/sglang/srt/distributed/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,7 @@ def _init_parallel_groups(
attention_context_model_parallel_size=attn_cp_size,
moe_data_model_parallel_size=moe_dp_size,
decode_context_parallel_size=dcp_size,
shared_experts_tensor_parallel_size=get_parallel().shared_experts_tp_size,
duplicate_tp_group=get_disagg().enable_pdmux,
enable_symm_mem=get_exec().comm.enable_symm_mem,
# Only WORLD is extended during scale-up. The joiner's model-parallel
Expand Down
52 changes: 50 additions & 2 deletions python/sglang/srt/distributed/parallel_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -2142,6 +2142,7 @@ def init_model_parallel_group(

_TP: Optional[GroupCoordinator] = None
_ATTN_TP: Optional[GroupCoordinator] = None
_SHARED_EXPERTS_TP: Optional[GroupCoordinator] = None
_ATTN_CP: Optional[GroupCoordinator] = None
_DCP: Optional[GroupCoordinator] = None

Expand Down Expand Up @@ -2173,6 +2174,13 @@ def get_attn_tp_group() -> GroupCoordinator:
return _ATTN_TP


def get_shared_experts_tp_group() -> GroupCoordinator:
assert _SHARED_EXPERTS_TP is not None, (
"shared-expert tensor model parallel group is not initialized"
)
return _SHARED_EXPERTS_TP


def get_attn_cp_group() -> GroupCoordinator:
assert _ATTN_CP is not None, (
"attention context model parallel group is not initialized"
Expand Down Expand Up @@ -2263,7 +2271,7 @@ def graph_capture(stream=None):
):
with contextlib.ExitStack() as stack:
seen = {id(_TP), id(_PP)}
for group in (_DCP, _ATTN_TP, _MOE_EP, _MOE_TP):
for group in (_DCP, _ATTN_TP, _SHARED_EXPERTS_TP, _MOE_EP, _MOE_TP):
if group is not None and id(group) not in seen:
seen.add(id(group))
stack.enter_context(group.graph_capture(context))
Expand Down Expand Up @@ -2518,6 +2526,7 @@ def initialize_model_parallel(
recovered_rank: bool = False,
rank_offset: int = 0,
max_world_size: Optional[int] = None,
shared_experts_tensor_parallel_size: Optional[int] = None,
) -> None:
"""
Initialize model parallel groups.
Expand All @@ -2540,6 +2549,8 @@ def initialize_model_parallel(
tensor-parallel group during decoding. Must be a divisor of
tensor_model_parallel_size and is currently only supported on the
AMD HIP platform.
shared_experts_tensor_parallel_size: optional shared-expert TP width.
Must divide attention TP; subgroups never cross attention replicas.

Let's say we have a total of 8 GPUs denoted by g0 ... g7 and we
use 2 GPUs to parallelize the model tensor, and 4 GPUs to parallelize
Expand Down Expand Up @@ -2762,6 +2773,34 @@ def initialize_model_parallel(
max_world_size=max_world_size,
)

global _SHARED_EXPERTS_TP
assert _SHARED_EXPERTS_TP is None, "shared-expert TP group already initialized"
if (
shared_experts_tensor_parallel_size is not None
and shared_experts_tensor_parallel_size > 1
):
if shared_experts_tensor_parallel_size == attn_tp_size:
_SHARED_EXPERTS_TP = _ATTN_TP
else:
# Attention TP groups are contiguous, and the requested width
# divides each one. These groups also stay inside their PP stage.
shared_size = shared_experts_tensor_parallel_size
shared_group_ranks = [
list(range(start, start + shared_size))
for start in range(0, world_size, shared_size)
]
_SHARED_EXPERTS_TP = init_model_parallel_group(
shared_group_ranks,
get_world_group().local_rank,
backend,
use_custom_allreduce=False,
use_torch_symm_mem_allreduce=False,
group_name="shared_experts_tp",
recovered_rank=recovered_rank,
rank_offset=rank_offset,
max_world_size=max_world_size,
)

moe_ep_size = expert_model_parallel_size
moe_dp_size = moe_data_model_parallel_size
moe_tp_size = derived_widths["moe_tp_size"]
Expand Down Expand Up @@ -3106,7 +3145,17 @@ def destroy_model_parallel():
dwdp_mgr.cleanup()
set_global_dwdp_manager(None)

global _SHARED_EXPERTS_TP
global _ATTN_TP
global _TP
if (
_SHARED_EXPERTS_TP is not None
and _SHARED_EXPERTS_TP is not _ATTN_TP
and _SHARED_EXPERTS_TP is not _TP
):
_SHARED_EXPERTS_TP.destroy()
_SHARED_EXPERTS_TP = None

if _TP:
_TP.destroy()
_TP = None
Expand Down Expand Up @@ -3142,7 +3191,6 @@ def destroy_model_parallel():
_ATTN_CP.destroy()
_ATTN_CP = None

global _ATTN_TP
if _ATTN_TP:
_ATTN_TP.destroy()
_ATTN_TP = None
Expand Down
9 changes: 9 additions & 0 deletions python/sglang/srt/environ.py
Original file line number Diff line number Diff line change
Expand Up @@ -948,8 +948,17 @@ class Envs:
# ===================================================================
SGLANG_NPU_DISABLE_ACL_FORMAT_WEIGHT = EnvBool(False)
SGLANG_NPU_USE_MULTI_STREAM = EnvBool(False)
# Kimi-K3 attention-TP shared experts: overlap AG / MLP / RS with the
# routed front / DeepEP dispatch / routed GEMMs, respectively.
SGLANG_NPU_FINE_GRAINED_MOE_DUAL_STREAM = EnvBool(False)
SGLANG_NPU_USE_MLAPO = EnvBool(False)
# Fuse grouped Kimi-K3 SiTU with valid-row MXFP8 quantization before GMM2.
# Set to 0 to restore the separate SiTU + npu_dynamic_mx_quant path.
SGLANG_NPU_MOE_SITU_MXFP8_FUSED = EnvBool(True)
SGLANG_NPU_ENABLE_SPARSE_KV_OFFLOAD = EnvBool(False)
# Use FIAS V2 for DSpark MLA target verify and MHA draft paths. Graph
# replay requires torch_npu's V2 handler to update actual_seq_kvlen.
SGLANG_NPU_USE_FIAS_V2_BSND = EnvBool(False)
Comment thread
zhaozx-cn marked this conversation as resolved.
Resolved
# BF16 wo_a: use F.linear for single-local-group decode (Flash TP8),
# retaining the original weight layout. Opt-in for A/B.
SGLANG_OPT_NPU_BF16_WO_A_GEMM = EnvBool(False)
Expand Down
Loading
Loading