[CP V1 Deprecation 3/5] Remove generic prefill CP v1 runtime (#36228)
This commit is contained in:
@@ -168,7 +168,7 @@ def validate_deepseek_v4_cp(server_args: ServerArgs) -> None:
|
|||||||
f"DeepSeekV4 only supports interleave CP strategy, got {cfg.cp_strategy}"
|
f"DeepSeekV4 only supports interleave CP strategy, got {cfg.cp_strategy}"
|
||||||
)
|
)
|
||||||
|
|
||||||
if get_platform().is_hip or get_platform().is_npu:
|
if get_platform().is_hip or get_platform().is_npu or get_platform().is_musa:
|
||||||
# Protected platform implementations still consume the legacy runtime
|
# Protected platform implementations still consume the legacy runtime
|
||||||
# fields. Generic backends use enable_prefill_cp/cp_strategy directly.
|
# fields. Generic backends use enable_prefill_cp/cp_strategy directly.
|
||||||
declare_resolution(
|
declare_resolution(
|
||||||
|
|||||||
@@ -487,9 +487,9 @@ def validate_prefill_only_disable_kv_cache_args(server_args: Any):
|
|||||||
"radix cache indexes KV pool slots that no longer hold real data."
|
"radix cache indexes KV pool slots that no longer hold real data."
|
||||||
)
|
)
|
||||||
|
|
||||||
# Context-parallel prefill stages K/V through cp_allgather_and_save_kv_cache,
|
# Context-parallel prefill writes K/V to the pool via set_kv_buffer.
|
||||||
# which writes to the pool via set_kv_buffer. NoOpMHATokenToKVPool intentionally
|
# NoOpMHATokenToKVPool intentionally raises on writes, so the engine would
|
||||||
# raises on writes, so the engine would boot fine but fail on the first request.
|
# boot fine but fail on the first request.
|
||||||
if resolved_view(server_args).attn_cp_size > 1:
|
if resolved_view(server_args).attn_cp_size > 1:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"--prefill-only-disable-kv-cache is incompatible with --attn-cp-size > 1: "
|
"--prefill-only-disable-kv-cache is incompatible with --attn-cp-size > 1: "
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ def handle_context_parallelism(server_args: Any):
|
|||||||
cfg.enable_prefill_cp
|
cfg.enable_prefill_cp
|
||||||
and model_arch == "DeepseekV32ForCausalLM"
|
and model_arch == "DeepseekV32ForCausalLM"
|
||||||
and cfg.cp_strategy == "zigzag"
|
and cfg.cp_strategy == "zigzag"
|
||||||
and not (platform.is_hip or platform.is_npu)
|
and not (platform.is_hip or platform.is_npu or platform.is_musa)
|
||||||
):
|
):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"DeepSeek V3.2 prefill CP does not support --cp-strategy "
|
"DeepSeek V3.2 prefill CP does not support --cp-strategy "
|
||||||
@@ -563,7 +563,7 @@ def handle_eplb_and_dispatch(server_args: Any):
|
|||||||
def handle_platform_cp_compatibility(server_args: Any):
|
def handle_platform_cp_compatibility(server_args: Any):
|
||||||
cfg = resolving_view(server_args)
|
cfg = resolving_view(server_args)
|
||||||
platform = get_platform()
|
platform = get_platform()
|
||||||
is_protected_platform = platform.is_hip or platform.is_npu
|
is_protected_platform = platform.is_hip or platform.is_npu or platform.is_musa
|
||||||
if not is_protected_platform:
|
if not is_protected_platform:
|
||||||
if (
|
if (
|
||||||
cfg.enable_prefill_context_parallel
|
cfg.enable_prefill_context_parallel
|
||||||
@@ -571,7 +571,7 @@ def handle_platform_cp_compatibility(server_args: Any):
|
|||||||
):
|
):
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Legacy prefill context-parallel options are supported only "
|
"Legacy prefill context-parallel options are supported only "
|
||||||
"by protected HIP or Ascend NPU paths. Use "
|
"by protected HIP, Ascend NPU, or MUSA paths. Use "
|
||||||
"--enable-prefill-cp with --cp-strategy."
|
"--enable-prefill-cp with --cp-strategy."
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
@@ -603,7 +603,10 @@ def handle_platform_cp_compatibility(server_args: Any):
|
|||||||
|
|
||||||
|
|
||||||
def handle_legacy_cp_runtime_compatibility(server_args: Any):
|
def handle_legacy_cp_runtime_compatibility(server_args: Any):
|
||||||
"""Project canonical CP settings for runtime consumers removed by PR3."""
|
"""Project canonical CP settings only for protected platform runtimes."""
|
||||||
|
platform = get_platform()
|
||||||
|
if not (platform.is_hip or platform.is_npu or platform.is_musa):
|
||||||
|
return
|
||||||
cfg = resolving_view(server_args)
|
cfg = resolving_view(server_args)
|
||||||
|
|
||||||
if cfg.enable_prefill_context_parallel and cfg.enable_dsa_prefill_context_parallel:
|
if cfg.enable_prefill_context_parallel and cfg.enable_dsa_prefill_context_parallel:
|
||||||
|
|||||||
@@ -287,8 +287,7 @@ def run_resolution_pipeline(server_args: Any) -> None:
|
|||||||
# Normalize load balancing defaults.
|
# Normalize load balancing defaults.
|
||||||
handle_load_balance_method(server_args)
|
handle_load_balance_method(server_args)
|
||||||
|
|
||||||
# The old runtime distinguishes DSA from other CP paths through legacy
|
# Protected runtimes still consume platform CP fields after backend selection.
|
||||||
# fields, so project only after attention_backend has been resolved.
|
|
||||||
handle_legacy_cp_runtime_compatibility(server_args)
|
handle_legacy_cp_runtime_compatibility(server_args)
|
||||||
|
|
||||||
# Handle context parallelism.
|
# Handle context parallelism.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import contextlib
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
|
from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, Union
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
from einops import rearrange
|
from einops import rearrange
|
||||||
@@ -29,7 +29,6 @@ from sglang.srt.layers.attention.dsa.paged_mqa_logits_backend import (
|
|||||||
from sglang.srt.layers.attention.dsa.utils import (
|
from sglang.srt.layers.attention.dsa.utils import (
|
||||||
aiter_can_use_preshuffle_paged_mqa,
|
aiter_can_use_preshuffle_paged_mqa,
|
||||||
is_dsa_enable_prefill_cp,
|
is_dsa_enable_prefill_cp,
|
||||||
is_dsa_prefill_cp_in_seq_split,
|
|
||||||
is_graph_dsa_split_op_surface,
|
is_graph_dsa_split_op_surface,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.layernorm import LayerNorm, RMSNorm
|
from sglang.srt.layers.layernorm import LayerNorm, RMSNorm
|
||||||
@@ -1418,167 +1417,6 @@ class Indexer(DSANPUIndexerMixin, BaseFusedOp):
|
|||||||
return None
|
return None
|
||||||
return raw_topk_result
|
return raw_topk_result
|
||||||
|
|
||||||
def _get_topk_ragged_with_cp(
|
|
||||||
self,
|
|
||||||
forward_batch: ForwardBatch,
|
|
||||||
layer_id: int,
|
|
||||||
q_fp8: torch.Tensor,
|
|
||||||
weights: torch.Tensor,
|
|
||||||
metadata: BaseIndexerMetadata,
|
|
||||||
kv_len: int,
|
|
||||||
actual_seq_q: int,
|
|
||||||
cp_index: List[Tuple[int, int, int]] = None,
|
|
||||||
) -> torch.Tensor:
|
|
||||||
assert not _is_in_piecewise_or_breakable_cuda_graph(), (
|
|
||||||
"DSA context parallel (_get_topk_ragged_with_cp) not supported under "
|
|
||||||
"piecewise/breakable CUDA graph"
|
|
||||||
)
|
|
||||||
if TYPE_CHECKING:
|
|
||||||
assert isinstance(get_token_to_kv_pool(), DSATokenToKVPool)
|
|
||||||
|
|
||||||
page_size = get_token_to_kv_pool().page_size
|
|
||||||
if _is_xpu:
|
|
||||||
assert page_size in (
|
|
||||||
64,
|
|
||||||
128,
|
|
||||||
), f"XPU DSA requires page_size 64 or 128, got {page_size}"
|
|
||||||
else:
|
|
||||||
assert page_size == 64, "only support page size 64"
|
|
||||||
assert len(weights.shape) == 3
|
|
||||||
weights = weights.squeeze(-1)
|
|
||||||
k_fp8_list = []
|
|
||||||
k_scale_list = []
|
|
||||||
ks_list = []
|
|
||||||
ke_offset_list = []
|
|
||||||
offset = 0
|
|
||||||
actual_seq_q_list = []
|
|
||||||
batch_idx_list = []
|
|
||||||
|
|
||||||
block_tables = metadata.get_page_table_64()
|
|
||||||
|
|
||||||
assert (
|
|
||||||
forward_batch.seq_lens_cpu is not None
|
|
||||||
and forward_batch.extend_seq_lens_cpu is not None
|
|
||||||
)
|
|
||||||
if cp_index is not None:
|
|
||||||
# TODO Multi-batch support has accuracy issues
|
|
||||||
for batch_idx, start_seq_position, end_seq_position in cp_index:
|
|
||||||
pre_chunk_offset = (
|
|
||||||
forward_batch.seq_lens_cpu[batch_idx].item()
|
|
||||||
- forward_batch.extend_seq_lens_cpu[batch_idx]
|
|
||||||
)
|
|
||||||
start_seq_position += pre_chunk_offset
|
|
||||||
end_seq_position += pre_chunk_offset
|
|
||||||
if offset == 0 and batch_idx != 0:
|
|
||||||
offset += forward_batch.extend_seq_lens_cpu[batch_idx - 1]
|
|
||||||
k_fp8 = get_token_to_kv_pool().get_index_k_continuous(
|
|
||||||
layer_id,
|
|
||||||
end_seq_position,
|
|
||||||
block_tables[batch_idx],
|
|
||||||
)
|
|
||||||
k_scale = get_token_to_kv_pool().get_index_k_scale_continuous(
|
|
||||||
layer_id,
|
|
||||||
end_seq_position,
|
|
||||||
block_tables[batch_idx],
|
|
||||||
)
|
|
||||||
|
|
||||||
extend_seq_len = end_seq_position - start_seq_position
|
|
||||||
ks = torch.full(
|
|
||||||
(extend_seq_len,), offset, dtype=torch.int32, device="cuda"
|
|
||||||
)
|
|
||||||
k_fp8_list.append(k_fp8)
|
|
||||||
k_scale_list.append(k_scale)
|
|
||||||
ks_list.append(ks)
|
|
||||||
ke_offset = torch.arange(
|
|
||||||
start_seq_position + 1,
|
|
||||||
end_seq_position + 1,
|
|
||||||
dtype=torch.int32,
|
|
||||||
device="cuda",
|
|
||||||
)
|
|
||||||
ke_offset_list.append(ke_offset)
|
|
||||||
actual_seq_q = torch.tensor(
|
|
||||||
[extend_seq_len], dtype=torch.int32, device="cuda"
|
|
||||||
)
|
|
||||||
actual_seq_q_list.append(actual_seq_q)
|
|
||||||
batch_idx_list.append(batch_idx)
|
|
||||||
|
|
||||||
k_fp8 = torch.cat(k_fp8_list, dim=0).view(torch.float8_e4m3fn)
|
|
||||||
k_scale = torch.cat(k_scale_list, dim=0).view(torch.float32).squeeze(-1)
|
|
||||||
kv_fp8 = (k_fp8, k_scale)
|
|
||||||
ks = torch.cat(ks_list, dim=0)
|
|
||||||
ke_offset = torch.cat(ke_offset_list, dim=0)
|
|
||||||
ke = ks + ke_offset
|
|
||||||
actual_seq_q = torch.cat(actual_seq_q_list, dim=0)
|
|
||||||
with self._with_real_sm_count():
|
|
||||||
q_padded, w_padded, _ = self._pad_heads_for_deep_gemm(q_fp8, weights)
|
|
||||||
logits = deep_gemm.fp8_mqa_logits(
|
|
||||||
q_padded,
|
|
||||||
kv_fp8,
|
|
||||||
w_padded,
|
|
||||||
ks,
|
|
||||||
ke,
|
|
||||||
clean_logits=False,
|
|
||||||
)
|
|
||||||
topk_result = metadata.topk_transform(
|
|
||||||
logits,
|
|
||||||
self.index_topk,
|
|
||||||
ks=ks,
|
|
||||||
cu_seqlens_q=actual_seq_q,
|
|
||||||
ke_offset=ke_offset,
|
|
||||||
batch_idx_list=batch_idx_list,
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
kv_len = (
|
|
||||||
forward_batch.seq_lens_cpu[0].item()
|
|
||||||
- forward_batch.extend_seq_lens_cpu[0]
|
|
||||||
+ kv_len
|
|
||||||
)
|
|
||||||
k_fp8 = get_token_to_kv_pool().get_index_k_continuous(
|
|
||||||
layer_id,
|
|
||||||
kv_len,
|
|
||||||
block_tables[0],
|
|
||||||
)
|
|
||||||
k_scale = get_token_to_kv_pool().get_index_k_scale_continuous(
|
|
||||||
layer_id,
|
|
||||||
kv_len,
|
|
||||||
block_tables[0],
|
|
||||||
)
|
|
||||||
|
|
||||||
k_fp8 = k_fp8.view(torch.float8_e4m3fn)
|
|
||||||
k_scale = k_scale.view(torch.float32).squeeze(-1)
|
|
||||||
kv_fp8 = (k_fp8, k_scale)
|
|
||||||
ks = torch.full((actual_seq_q,), offset, dtype=torch.int32, device="cuda")
|
|
||||||
ke_offset = torch.arange(
|
|
||||||
(kv_len - actual_seq_q) + 1,
|
|
||||||
kv_len + 1,
|
|
||||||
dtype=torch.int32,
|
|
||||||
device="cuda",
|
|
||||||
)
|
|
||||||
ke = ks + ke_offset
|
|
||||||
|
|
||||||
with self._with_real_sm_count():
|
|
||||||
q_padded, w_padded, _ = self._pad_heads_for_deep_gemm(q_fp8, weights)
|
|
||||||
logits = deep_gemm.fp8_mqa_logits(
|
|
||||||
q_padded,
|
|
||||||
kv_fp8,
|
|
||||||
w_padded,
|
|
||||||
ks,
|
|
||||||
ke,
|
|
||||||
clean_logits=False,
|
|
||||||
)
|
|
||||||
actual_seq_q = torch.tensor([actual_seq_q], dtype=torch.int32).to(
|
|
||||||
device="cuda", non_blocking=True
|
|
||||||
)
|
|
||||||
topk_result = metadata.topk_transform(
|
|
||||||
logits,
|
|
||||||
self.index_topk,
|
|
||||||
ks=ks,
|
|
||||||
cu_seqlens_q=actual_seq_q,
|
|
||||||
ke_offset=ke_offset,
|
|
||||||
)
|
|
||||||
|
|
||||||
return topk_result
|
|
||||||
|
|
||||||
def _store_index_k_cache(
|
def _store_index_k_cache(
|
||||||
self,
|
self,
|
||||||
forward_batch: ForwardBatch,
|
forward_batch: ForwardBatch,
|
||||||
@@ -1955,67 +1793,21 @@ class Indexer(DSANPUIndexerMixin, BaseFusedOp):
|
|||||||
forward_batch, layer_id, q_fp8, weights, metadata
|
forward_batch, layer_id, q_fp8, weights, metadata
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if (
|
# In-graph (PCG/BCG) non-CP prefill is handled earlier by the
|
||||||
forward_batch.attn_cp_metadata is not None
|
# graph DSA split-op dispatch, so only the eager path reaches
|
||||||
and is_dsa_prefill_cp_in_seq_split()
|
# here.
|
||||||
):
|
assert not in_piecewise_or_breakable_cuda_graph, (
|
||||||
kv_len_prev = forward_batch.attn_cp_metadata.kv_len_prev_list[0]
|
"Internal error: in-graph DSA prefill must go through the "
|
||||||
kv_len_next = forward_batch.attn_cp_metadata.kv_len_next_list[0]
|
"graph DSA split-op dispatch"
|
||||||
actual_seq_q_prev = (
|
)
|
||||||
forward_batch.attn_cp_metadata.actual_seq_q_prev_list[0]
|
topk_result = self._get_topk_ragged(
|
||||||
)
|
enable_dual_stream,
|
||||||
actual_seq_q_next = (
|
forward_batch,
|
||||||
forward_batch.attn_cp_metadata.actual_seq_q_next_list[0]
|
layer_id,
|
||||||
)
|
q_fp8,
|
||||||
|
weights,
|
||||||
# TODO support mutil-batch
|
metadata,
|
||||||
# cp_batch_seq_index_prev = forward_batch.attn_cp_metadata["cp_batch_seq_index_prev"]
|
)
|
||||||
# cp_batch_seq_index_next = forward_batch.attn_cp_metadata["cp_batch_seq_index_next"]
|
|
||||||
# TODO prev, next, combined into a single call
|
|
||||||
q_fp8_prev, q_fp8_next = torch.split(
|
|
||||||
q_fp8, (q_fp8.shape[0] + 1) // 2, dim=0
|
|
||||||
)
|
|
||||||
weights_prev, weights_next = torch.split(
|
|
||||||
weights, (weights.shape[0] + 1) // 2, dim=0
|
|
||||||
)
|
|
||||||
topk_result_prev = self._get_topk_ragged_with_cp(
|
|
||||||
forward_batch,
|
|
||||||
layer_id,
|
|
||||||
q_fp8_prev,
|
|
||||||
weights_prev,
|
|
||||||
metadata,
|
|
||||||
kv_len_prev,
|
|
||||||
actual_seq_q_prev,
|
|
||||||
)
|
|
||||||
|
|
||||||
topk_result_next = self._get_topk_ragged_with_cp(
|
|
||||||
forward_batch,
|
|
||||||
layer_id,
|
|
||||||
q_fp8_next,
|
|
||||||
weights_next,
|
|
||||||
metadata,
|
|
||||||
kv_len_next,
|
|
||||||
actual_seq_q_next,
|
|
||||||
)
|
|
||||||
topk_result = torch.cat([topk_result_prev, topk_result_next], dim=0)
|
|
||||||
topk_result = _broadcast_indexer_topk_from_rank0(topk_result)
|
|
||||||
return maybe_capture_indexer_topk(layer_id, topk_result)
|
|
||||||
else:
|
|
||||||
# In-graph (PCG/BCG) non-CP prefill is handled earlier by the
|
|
||||||
# graph DSA split-op dispatch, so only the eager path reaches
|
|
||||||
# here.
|
|
||||||
assert not in_piecewise_or_breakable_cuda_graph, (
|
|
||||||
"Internal error: in-graph DSA prefill must go through the "
|
|
||||||
"graph DSA split-op dispatch"
|
|
||||||
)
|
|
||||||
topk_result = self._get_topk_ragged(
|
|
||||||
enable_dual_stream,
|
|
||||||
forward_batch,
|
|
||||||
layer_id,
|
|
||||||
q_fp8,
|
|
||||||
weights,
|
|
||||||
metadata,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError("DSA indexer only supports CUDA, HIP, and NPU")
|
raise NotImplementedError("DSA indexer only supports CUDA, HIP, and NPU")
|
||||||
topk_result = _broadcast_indexer_topk_from_rank0(topk_result)
|
topk_result = _broadcast_indexer_topk_from_rank0(topk_result)
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ from sglang.srt.runtime_context import (
|
|||||||
get_parallel,
|
get_parallel,
|
||||||
process_model_config,
|
process_model_config,
|
||||||
)
|
)
|
||||||
from sglang.srt.utils import get_bool_env_var, is_cuda, is_hip, is_npu
|
from sglang.srt.utils import get_bool_env_var, is_cuda, is_hip, is_musa, is_npu
|
||||||
from sglang.srt.utils.common import ceil_align, ceil_div
|
from sglang.srt.utils.common import ceil_align, ceil_div
|
||||||
|
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ def should_use_dsa_fused_topk(seed_dsa_topk_from_draft_extend: bool) -> bool:
|
|||||||
|
|
||||||
|
|
||||||
def is_dsa_enable_prefill_cp():
|
def is_dsa_enable_prefill_cp():
|
||||||
if is_hip() or is_npu():
|
if is_hip() or is_npu() or is_musa():
|
||||||
return get_parallel().enable_dsa_prefill_context_parallel
|
return get_parallel().enable_dsa_prefill_context_parallel
|
||||||
|
|
||||||
# Generic prefill CP derives activation from the runtime topology and model
|
# Generic prefill CP derives activation from the runtime topology and model
|
||||||
@@ -128,13 +128,6 @@ def is_dsa_enable_prefill_cp():
|
|||||||
return is_deepseek_dsa(hf_config) or is_deepseek_v4(hf_config)
|
return is_deepseek_dsa(hf_config) or is_deepseek_v4(hf_config)
|
||||||
|
|
||||||
|
|
||||||
def is_dsa_prefill_cp_in_seq_split():
|
|
||||||
return (
|
|
||||||
is_dsa_enable_prefill_cp()
|
|
||||||
and get_parallel().dsa_prefill_cp_mode == "in-seq-split"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def is_dsa_prefill_cp_round_robin_split():
|
def is_dsa_prefill_cp_round_robin_split():
|
||||||
return (
|
return (
|
||||||
is_dsa_enable_prefill_cp()
|
is_dsa_enable_prefill_cp()
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ from sglang.srt.layers.attention.dsa.utils import (
|
|||||||
dsa_cp_round_robin_split_q_seqs,
|
dsa_cp_round_robin_split_q_seqs,
|
||||||
dsa_use_prefill_cp,
|
dsa_use_prefill_cp,
|
||||||
is_dsa_enable_prefill_cp,
|
is_dsa_enable_prefill_cp,
|
||||||
is_dsa_prefill_cp_in_seq_split,
|
|
||||||
pad_dsa_cache_seqlens,
|
pad_dsa_cache_seqlens,
|
||||||
should_use_dsa_fused_topk,
|
should_use_dsa_fused_topk,
|
||||||
)
|
)
|
||||||
@@ -141,6 +140,31 @@ def _all_gather_dsa_trtllm_fp8_kv(
|
|||||||
return kv.split((kv_lora_rank, qk_rope_head_dim), dim=-1)
|
return kv.split((kv_lora_rank, qk_rope_head_dim), dim=-1)
|
||||||
|
|
||||||
|
|
||||||
|
def prepare_kv_for_attention(
|
||||||
|
attn_mla,
|
||||||
|
forward_batch: ForwardBatch,
|
||||||
|
k_nope: torch.Tensor,
|
||||||
|
k_pe: torch.Tensor,
|
||||||
|
*,
|
||||||
|
defer_materialization: bool,
|
||||||
|
) -> tuple[torch.Tensor, torch.Tensor]:
|
||||||
|
"""Materialize KV needed before attention for the active layout."""
|
||||||
|
if (
|
||||||
|
defer_materialization
|
||||||
|
or not dsa_use_prefill_cp(forward_batch)
|
||||||
|
or not is_cp_v2_active(forward_batch)
|
||||||
|
):
|
||||||
|
return k_nope, k_pe
|
||||||
|
strategy = get_cp_strategy()
|
||||||
|
assert strategy is not None
|
||||||
|
return strategy.materialize_full_mla_kv(
|
||||||
|
forward_batch,
|
||||||
|
attn_mla.attn_mqa,
|
||||||
|
k_nope,
|
||||||
|
k_pe,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def materialize_full_kv_cp(
|
def materialize_full_kv_cp(
|
||||||
attn_mla,
|
attn_mla,
|
||||||
forward_batch: ForwardBatch,
|
forward_batch: ForwardBatch,
|
||||||
@@ -148,13 +172,18 @@ def materialize_full_kv_cp(
|
|||||||
k_nope: torch.Tensor,
|
k_nope: torch.Tensor,
|
||||||
k_pe: torch.Tensor,
|
k_pe: torch.Tensor,
|
||||||
) -> tuple[torch.Tensor, torch.Tensor]:
|
) -> tuple[torch.Tensor, torch.Tensor]:
|
||||||
|
"""Materialize generic CP KV, retaining the ROCm DSA fallback."""
|
||||||
if is_cp_v2_active(forward_batch):
|
if is_cp_v2_active(forward_batch):
|
||||||
return get_cp_strategy().materialize_full_mla_kv(
|
strategy = get_cp_strategy()
|
||||||
|
assert strategy is not None
|
||||||
|
return strategy.materialize_full_mla_kv(
|
||||||
forward_batch,
|
forward_batch,
|
||||||
attn_mla.attn_mqa,
|
attn_mla.attn_mqa,
|
||||||
k_nope,
|
k_nope,
|
||||||
k_pe,
|
k_pe,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
assert is_hip(), "Legacy DSA KV materialization is HIP-only"
|
||||||
return attn_mla.rebuild_cp_kv_cache(latent_cache, forward_batch, k_nope, k_pe)
|
return attn_mla.rebuild_cp_kv_cache(latent_cache, forward_batch, k_nope, k_pe)
|
||||||
|
|
||||||
|
|
||||||
@@ -3583,15 +3612,6 @@ class DeepseekSparseAttnBackend(
|
|||||||
block_tables = page_table_1.unsqueeze(1)
|
block_tables = page_table_1.unsqueeze(1)
|
||||||
seq_lens = metadata.cache_seqlens_int32 if seq_lens is None else seq_lens
|
seq_lens = metadata.cache_seqlens_int32 if seq_lens is None else seq_lens
|
||||||
|
|
||||||
if (
|
|
||||||
dsa_use_prefill_cp(forward_batch)
|
|
||||||
and is_dsa_prefill_cp_in_seq_split()
|
|
||||||
and forward_batch.attn_cp_metadata is not None
|
|
||||||
):
|
|
||||||
cp_meta = forward_batch.attn_cp_metadata
|
|
||||||
seq_chunks = list(torch.split(seq_lens, cp_meta.split_list, dim=0))
|
|
||||||
seq_lens = torch.cat([seq_chunks[i] for i in cp_meta.zigzag_index], dim=0)
|
|
||||||
|
|
||||||
out = flashinfer.decode.trtllm_batch_decode_with_kv_cache_mla(
|
out = flashinfer.decode.trtllm_batch_decode_with_kv_cache_mla(
|
||||||
query=q,
|
query=q,
|
||||||
kv_cache=kv,
|
kv_cache=kv,
|
||||||
|
|||||||
@@ -24,12 +24,8 @@ from sglang.srt.configs.model_config import AttentionArch
|
|||||||
from sglang.srt.layers.attention.base_attn_backend import AttentionBackend
|
from sglang.srt.layers.attention.base_attn_backend import AttentionBackend
|
||||||
from sglang.srt.layers.attention.verify_mask import VerifyMask, maybe_create_verify_mask
|
from sglang.srt.layers.attention.verify_mask import VerifyMask, maybe_create_verify_mask
|
||||||
from sglang.srt.layers.cp.base import CPAttentionBackendKind, get_cp_strategy
|
from sglang.srt.layers.cp.base import CPAttentionBackendKind, get_cp_strategy
|
||||||
from sglang.srt.layers.cp.utils import is_cp_v2_active
|
from sglang.srt.layers.cp.utils import enable_cp_v2, is_cp_v2_active
|
||||||
from sglang.srt.layers.radix_attention import AttentionType
|
from sglang.srt.layers.radix_attention import AttentionType
|
||||||
from sglang.srt.layers.utils.cp_utils import (
|
|
||||||
cp_allgather_and_save_kv_cache,
|
|
||||||
cp_attn_forward_extend,
|
|
||||||
)
|
|
||||||
from sglang.srt.mem_cache.memory_pool import KVWriteLoc
|
from sglang.srt.mem_cache.memory_pool import KVWriteLoc
|
||||||
from sglang.srt.mem_cache.swa_memory_pool import SWAKVPool
|
from sglang.srt.mem_cache.swa_memory_pool import SWAKVPool
|
||||||
from sglang.srt.model_executor.forward_batch_info import ForwardBatch, ForwardMode
|
from sglang.srt.model_executor.forward_batch_info import ForwardBatch, ForwardMode
|
||||||
@@ -1012,7 +1008,7 @@ class FlashAttentionBackend(AttentionBackend):
|
|||||||
# (req_to_token is zero-init) and outputs for padding queries are
|
# (req_to_token is zero-init) and outputs for padding queries are
|
||||||
# discarded downstream.
|
# discarded downstream.
|
||||||
if (
|
if (
|
||||||
not is_cp_v2_active(forward_batch)
|
not enable_cp_v2()
|
||||||
and self.attn_cp_size > 1
|
and self.attn_cp_size > 1
|
||||||
and forward_batch.global_num_tokens_cpu is not None
|
and forward_batch.global_num_tokens_cpu is not None
|
||||||
and forward_batch.extend_num_tokens is not None
|
and forward_batch.extend_num_tokens is not None
|
||||||
@@ -1266,11 +1262,7 @@ class FlashAttentionBackend(AttentionBackend):
|
|||||||
):
|
):
|
||||||
if score_mod is not None and self.fa_impl_ver != 4:
|
if score_mod is not None and self.fa_impl_ver != 4:
|
||||||
raise RuntimeError("score_mod is only supported by the FA4 backend.")
|
raise RuntimeError("score_mod is only supported by the FA4 backend.")
|
||||||
is_cp_mode = (
|
cp_active = is_cp_v2_active(forward_batch)
|
||||||
forward_batch.forward_mode.is_context_parallel_extend()
|
|
||||||
and forward_batch.attn_cp_metadata is not None
|
|
||||||
and self.attn_cp_size > 1
|
|
||||||
)
|
|
||||||
|
|
||||||
if k is not None:
|
if k is not None:
|
||||||
assert v is not None
|
assert v is not None
|
||||||
@@ -1282,25 +1274,20 @@ class FlashAttentionBackend(AttentionBackend):
|
|||||||
else forward_batch.encoder_out_cache_loc
|
else forward_batch.encoder_out_cache_loc
|
||||||
)
|
)
|
||||||
if self.use_mla:
|
if self.use_mla:
|
||||||
if is_cp_v2_active(forward_batch):
|
if cp_active:
|
||||||
# CP-v2: k/k_rope are rank-local; the strategy gathers
|
|
||||||
# the latent to full sequence and writes it.
|
|
||||||
cp_strategy = get_cp_strategy()
|
cp_strategy = get_cp_strategy()
|
||||||
assert cp_strategy is not None
|
assert cp_strategy is not None
|
||||||
cp_strategy.materialize_full_mla_kv(
|
cp_strategy.materialize_full_mla_kv(
|
||||||
forward_batch, layer, k, k_rope
|
forward_batch, layer, k, k_rope
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# CP-v1: k/k_rope arrive full-sequence (rebuild_cp_kv_cache
|
|
||||||
# ran upstream); rank-local when CP is off. out_cache_loc is
|
|
||||||
# never zigzag-split, so the write lands in the right slots.
|
|
||||||
self.token_to_kv_pool.set_mla_kv_buffer(
|
self.token_to_kv_pool.set_mla_kv_buffer(
|
||||||
layer,
|
layer,
|
||||||
cache_loc,
|
cache_loc,
|
||||||
k,
|
k,
|
||||||
k_rope,
|
k_rope,
|
||||||
)
|
)
|
||||||
elif is_cp_mode:
|
elif cp_active:
|
||||||
# Dense-MHA CP: k, v are still rank-local; backend
|
# Dense-MHA CP: k, v are still rank-local; backend
|
||||||
# all-gathers and writes to the per-rank pool.
|
# all-gathers and writes to the per-rank pool.
|
||||||
swa_loc = (
|
swa_loc = (
|
||||||
@@ -1308,21 +1295,11 @@ class FlashAttentionBackend(AttentionBackend):
|
|||||||
if self.use_sliding_window_kv_pool
|
if self.use_sliding_window_kv_pool
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
if is_cp_v2_active(forward_batch):
|
cp_strategy = get_cp_strategy()
|
||||||
cp_strategy = get_cp_strategy()
|
assert cp_strategy is not None
|
||||||
assert cp_strategy is not None
|
cp_strategy.materialize_full_kv(
|
||||||
cp_strategy.materialize_full_kv(
|
forward_batch, layer, k, v, swa_loc=swa_loc
|
||||||
forward_batch, layer, k, v, swa_loc=swa_loc
|
)
|
||||||
)
|
|
||||||
else:
|
|
||||||
cp_allgather_and_save_kv_cache(
|
|
||||||
forward_batch,
|
|
||||||
layer,
|
|
||||||
k,
|
|
||||||
v,
|
|
||||||
self.attn_cp_size,
|
|
||||||
swa_loc=swa_loc,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
k_scale = k_descale if self.kv_cache_is_mxfp8 else layer.k_scale
|
k_scale = k_descale if self.kv_cache_is_mxfp8 else layer.k_scale
|
||||||
v_scale = v_descale if self.kv_cache_is_mxfp8 else layer.v_scale
|
v_scale = v_descale if self.kv_cache_is_mxfp8 else layer.v_scale
|
||||||
@@ -1459,11 +1436,7 @@ class FlashAttentionBackend(AttentionBackend):
|
|||||||
cu_seqlens_k = metadata.encoder_cu_seqlens_k
|
cu_seqlens_k = metadata.encoder_cu_seqlens_k
|
||||||
window_size = (-1, -1)
|
window_size = (-1, -1)
|
||||||
|
|
||||||
if (
|
if cp_active:
|
||||||
forward_batch.forward_mode.is_context_parallel_extend()
|
|
||||||
and forward_batch.attn_cp_metadata is not None
|
|
||||||
and self.attn_cp_size > 1
|
|
||||||
):
|
|
||||||
|
|
||||||
def _fa_cp_attn(
|
def _fa_cp_attn(
|
||||||
q_chunk, cu_seqlens_q_cp, cache_seqlens_cp, max_seqlen_q_cp
|
q_chunk, cu_seqlens_q_cp, cache_seqlens_cp, max_seqlen_q_cp
|
||||||
@@ -1488,23 +1461,15 @@ class FlashAttentionBackend(AttentionBackend):
|
|||||||
)
|
)
|
||||||
|
|
||||||
q_cp = q.contiguous().view(-1, layer.tp_q_head_num, layer.head_dim)
|
q_cp = q.contiguous().view(-1, layer.tp_q_head_num, layer.head_dim)
|
||||||
if is_cp_v2_active(forward_batch):
|
cp_strategy = get_cp_strategy()
|
||||||
cp_strategy = get_cp_strategy()
|
assert cp_strategy is not None
|
||||||
assert cp_strategy is not None
|
result = cp_strategy.run_attention(
|
||||||
result = cp_strategy.run_attention(
|
q_cp,
|
||||||
q_cp,
|
forward_batch,
|
||||||
forward_batch,
|
self.device,
|
||||||
self.device,
|
_fa_cp_attn,
|
||||||
_fa_cp_attn,
|
attention_backend=CPAttentionBackendKind.FLASH_ATTENTION,
|
||||||
attention_backend=CPAttentionBackendKind.FLASH_ATTENTION,
|
)
|
||||||
)
|
|
||||||
else:
|
|
||||||
result = cp_attn_forward_extend(
|
|
||||||
forward_batch,
|
|
||||||
q_cp,
|
|
||||||
self.device,
|
|
||||||
_fa_cp_attn,
|
|
||||||
)
|
|
||||||
elif self.fa_skip_kv_cache:
|
elif self.fa_skip_kv_cache:
|
||||||
# Embedding mode: skip KV cache read and use raw K/V tensors
|
# Embedding mode: skip KV cache read and use raw K/V tensors
|
||||||
# directly via flash_attn_varlen_func. The KV cache write is
|
# directly via flash_attn_varlen_func. The KV cache write is
|
||||||
@@ -1731,16 +1696,15 @@ class FlashAttentionBackend(AttentionBackend):
|
|||||||
q_nope = q_all[:, :, : layer.v_head_dim]
|
q_nope = q_all[:, :, : layer.v_head_dim]
|
||||||
q_rope = q_all[:, :, layer.v_head_dim :]
|
q_rope = q_all[:, :, layer.v_head_dim :]
|
||||||
|
|
||||||
if is_cp_mode:
|
if cp_active:
|
||||||
# MLA CP: q is rank-local zigzag-split; run the
|
# MLA CP: q is rank-local zigzag-split; run the
|
||||||
# absorbed-MLA kernel twice (prev/next halves) against
|
# absorbed-MLA kernel twice (prev/next halves) against
|
||||||
# the full latent KV pool (which rebuild_cp_kv_cache
|
# the full latent KV pool through the selected strategy.
|
||||||
# populated upstream) via cp_attn_forward_extend.
|
|
||||||
# Concat q_nope + q_rope along dim=-1 so the wrapper's
|
# Concat q_nope + q_rope along dim=-1 so the wrapper's
|
||||||
# chunk(2, dim=0) keeps their alignment; split back
|
# chunk(2, dim=0) keeps their alignment; split back
|
||||||
# inside the closure.
|
# inside the closure.
|
||||||
assert not use_cascade_attn, (
|
assert not use_cascade_attn, (
|
||||||
"Cascade attention under MLA CP is not supported in v1."
|
"Cascade attention under MLA CP is not supported."
|
||||||
)
|
)
|
||||||
q_fused = torch.cat([q_nope, q_rope], dim=-1)
|
q_fused = torch.cat([q_nope, q_rope], dim=-1)
|
||||||
|
|
||||||
@@ -1773,20 +1737,15 @@ class FlashAttentionBackend(AttentionBackend):
|
|||||||
ver=self.fa_impl_ver,
|
ver=self.fa_impl_ver,
|
||||||
)
|
)
|
||||||
|
|
||||||
if is_cp_v2_active(forward_batch):
|
cp_strategy = get_cp_strategy()
|
||||||
cp_strategy = get_cp_strategy()
|
assert cp_strategy is not None
|
||||||
assert cp_strategy is not None
|
o = cp_strategy.run_attention(
|
||||||
o = cp_strategy.run_attention(
|
q_fused,
|
||||||
q_fused,
|
forward_batch,
|
||||||
forward_batch,
|
self.device,
|
||||||
self.device,
|
_mla_cp_attn,
|
||||||
_mla_cp_attn,
|
attention_backend=CPAttentionBackendKind.FLASH_ATTENTION,
|
||||||
attention_backend=CPAttentionBackendKind.FLASH_ATTENTION,
|
)
|
||||||
)
|
|
||||||
else:
|
|
||||||
o = cp_attn_forward_extend(
|
|
||||||
forward_batch, q_fused, self.device, _mla_cp_attn
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
result = flash_attn_with_kvcache(
|
result = flash_attn_with_kvcache(
|
||||||
q=q_rope,
|
q=q_rope,
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ from __future__ import annotations
|
|||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from typing import TYPE_CHECKING, Iterator, Optional
|
from typing import TYPE_CHECKING, Iterator, Optional
|
||||||
|
|
||||||
|
from sglang.srt.layers.cp.utils import cp_gather_after_forward, is_cp_v2_active
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
@@ -33,8 +35,11 @@ class IndexTopKShareState:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def _seed_buf(self) -> Optional[torch.Tensor]:
|
def _seed_buf(self) -> Optional[torch.Tensor]:
|
||||||
if self._forward_batch.forward_mode.is_extend(include_draft_extend_v2=True):
|
spec_info = self._forward_batch.spec_info
|
||||||
return self._forward_batch.spec_info.dsa_seed_topk_capture
|
if spec_info is not None and self._forward_batch.forward_mode.is_extend(
|
||||||
|
include_draft_extend_v2=True
|
||||||
|
):
|
||||||
|
return spec_info.dsa_seed_topk_capture
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -46,6 +51,12 @@ class IndexTopKShareState:
|
|||||||
return self._topk_indices
|
return self._topk_indices
|
||||||
|
|
||||||
def update(self, topk_indices: Optional[torch.Tensor]) -> None:
|
def update(self, topk_indices: Optional[torch.Tensor]) -> None:
|
||||||
|
if (
|
||||||
|
topk_indices is not None
|
||||||
|
and self.should_publish
|
||||||
|
and is_cp_v2_active(self._forward_batch)
|
||||||
|
):
|
||||||
|
topk_indices = cp_gather_after_forward(topk_indices, self._forward_batch)
|
||||||
self._topk_indices = topk_indices
|
self._topk_indices = topk_indices
|
||||||
|
|
||||||
def publish(self) -> None:
|
def publish(self) -> None:
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ from sglang.srt.layers.attention.dsa.utils import (
|
|||||||
is_dsa_enable_prefill_cp,
|
is_dsa_enable_prefill_cp,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.aux_hidden_states import AuxHiddenStateAccumulator
|
from sglang.srt.layers.aux_hidden_states import AuxHiddenStateAccumulator
|
||||||
|
from sglang.srt.layers.cp.utils import (
|
||||||
|
is_mla_prefill_cp_enabled,
|
||||||
|
mla_use_prefill_cp,
|
||||||
|
)
|
||||||
from sglang.srt.layers.dp_attention import (
|
from sglang.srt.layers.dp_attention import (
|
||||||
attn_tp_all_gather_into_tensor,
|
attn_tp_all_gather_into_tensor,
|
||||||
attn_tp_reduce_scatter_tensor,
|
attn_tp_reduce_scatter_tensor,
|
||||||
@@ -64,10 +68,6 @@ from sglang.srt.layers.quantization.fp8_utils import (
|
|||||||
_use_aiter_bpreshuffle_gfx95,
|
_use_aiter_bpreshuffle_gfx95,
|
||||||
materialize_bpreshuffle_fp8_scale_tuple,
|
materialize_bpreshuffle_fp8_scale_tuple,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.utils.cp_utils import (
|
|
||||||
is_mla_prefill_cp_enabled,
|
|
||||||
mla_use_prefill_cp,
|
|
||||||
)
|
|
||||||
from sglang.srt.model_executor.cuda_graph_config import (
|
from sglang.srt.model_executor.cuda_graph_config import (
|
||||||
Backend,
|
Backend,
|
||||||
Phase,
|
Phase,
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import torch
|
|||||||
|
|
||||||
from sglang.srt.layers.attention.dsa.utils import (
|
from sglang.srt.layers.attention.dsa.utils import (
|
||||||
dsa_use_prefill_cp,
|
dsa_use_prefill_cp,
|
||||||
is_dsa_enable_prefill_cp,
|
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.communicator import (
|
from sglang.srt.layers.communicator import (
|
||||||
CommunicateContext,
|
CommunicateContext,
|
||||||
@@ -31,24 +30,17 @@ from sglang.srt.layers.communicator import (
|
|||||||
LayerScatterModes,
|
LayerScatterModes,
|
||||||
ScatterMode,
|
ScatterMode,
|
||||||
)
|
)
|
||||||
|
from sglang.srt.layers.cp.utils import mla_use_prefill_cp
|
||||||
from sglang.srt.layers.dp_attention import (
|
from sglang.srt.layers.dp_attention import (
|
||||||
attn_cp_all_gather_into_tensor,
|
attn_cp_all_gather_into_tensor,
|
||||||
attn_cp_reduce_scatter_tensor,
|
attn_cp_reduce_scatter_tensor,
|
||||||
get_local_dp_buffer,
|
get_local_dp_buffer,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.utils.cp_utils import mla_use_prefill_cp
|
|
||||||
from sglang.srt.model_executor.forward_batch_info import ForwardBatch
|
from sglang.srt.model_executor.forward_batch_info import ForwardBatch
|
||||||
from sglang.srt.model_executor.forward_context import get_token_to_kv_pool
|
from sglang.srt.model_executor.forward_context import get_token_to_kv_pool
|
||||||
from sglang.srt.runtime_context import get_parallel
|
from sglang.srt.runtime_context import get_parallel
|
||||||
|
|
||||||
|
|
||||||
def dsa_enable_prefill_cp():
|
|
||||||
# After using cp, the communication mode of this part changes.
|
|
||||||
# The three parts of prepare_attn, prepare_mlp, and postprocess_layer
|
|
||||||
# no longer require additional communication for reduce, scatter, etc.
|
|
||||||
return is_dsa_enable_prefill_cp()
|
|
||||||
|
|
||||||
|
|
||||||
def maybe_prefetch_next_full_attention_kv(
|
def maybe_prefetch_next_full_attention_kv(
|
||||||
forward_batch: ForwardBatch,
|
forward_batch: ForwardBatch,
|
||||||
next_full_attention_layer_id: Optional[int],
|
next_full_attention_layer_id: Optional[int],
|
||||||
|
|||||||
@@ -23,11 +23,10 @@ from sglang.srt.runtime_context import get_parallel
|
|||||||
|
|
||||||
def get_cp_padding_align_size() -> int:
|
def get_cp_padding_align_size() -> int:
|
||||||
"""Return the token-count alignment required by the active CP strategy."""
|
"""Return the token-count alignment required by the active CP strategy."""
|
||||||
from sglang.srt.layers.attention.dsa.utils import is_dsa_prefill_cp_in_seq_split
|
from sglang.srt.layers.cp.base import is_zigzag
|
||||||
from sglang.srt.layers.utils.cp_utils import is_prefill_cp_in_seq_split
|
|
||||||
|
|
||||||
attn_cp_size = get_parallel().attn_cp_size
|
attn_cp_size = get_parallel().attn_cp_size
|
||||||
if is_prefill_cp_in_seq_split() or is_dsa_prefill_cp_in_seq_split():
|
if is_zigzag():
|
||||||
return attn_cp_size * 2
|
return attn_cp_size * 2
|
||||||
return attn_cp_size
|
return attn_cp_size
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ from sglang.srt.layers.cp.base import (
|
|||||||
ContextParallelStrategyKind,
|
ContextParallelStrategyKind,
|
||||||
CPAttentionBackendKind,
|
CPAttentionBackendKind,
|
||||||
get_cp_strategy,
|
get_cp_strategy,
|
||||||
|
is_cp_enabled,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.cp.interleave import (
|
from sglang.srt.layers.cp.interleave import (
|
||||||
InterleaveContextParallelMetadata,
|
InterleaveContextParallelMetadata,
|
||||||
@@ -35,7 +36,7 @@ from sglang.srt.layers.cp.zigzag import (
|
|||||||
ZigzagCPStrategy,
|
ZigzagCPStrategy,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.moe.utils import get_moe_a2a_backend
|
from sglang.srt.layers.moe.utils import get_moe_a2a_backend
|
||||||
from sglang.srt.runtime_context import get_parallel
|
from sglang.srt.runtime_context import get_parallel, uses_mla_backend
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from sglang.srt.model_executor.model_runner import ModelRunner
|
from sglang.srt.model_executor.model_runner import ModelRunner
|
||||||
@@ -119,9 +120,9 @@ def get_layer_owner(local_layer_idx: int, shard_size: int, total_layers: int) ->
|
|||||||
|
|
||||||
def enable_cp_v2() -> bool:
|
def enable_cp_v2() -> bool:
|
||||||
"""Return whether the strategy-based generic prefill CP path is available."""
|
"""Return whether the strategy-based generic prefill CP path is available."""
|
||||||
from sglang.srt.utils import is_hip, is_npu
|
from sglang.srt.utils import is_hip, is_musa, is_npu
|
||||||
|
|
||||||
return not (is_hip() or is_npu())
|
return not (is_hip() or is_npu() or is_musa())
|
||||||
|
|
||||||
|
|
||||||
def is_cp_v2_active(forward_batch) -> bool:
|
def is_cp_v2_active(forward_batch) -> bool:
|
||||||
@@ -143,6 +144,24 @@ def is_cp_v2_active(forward_batch) -> bool:
|
|||||||
return strategy.can_apply(len(input_ids), forward_batch)
|
return strategy.can_apply(len(input_ids), forward_batch)
|
||||||
|
|
||||||
|
|
||||||
|
def is_mla_prefill_cp_enabled() -> bool:
|
||||||
|
"""Return whether prefill CP is configured for an MLA attention backend."""
|
||||||
|
if enable_cp_v2():
|
||||||
|
return is_cp_enabled() and uses_mla_backend()
|
||||||
|
return get_parallel().enable_prefill_context_parallel and uses_mla_backend()
|
||||||
|
|
||||||
|
|
||||||
|
def mla_use_prefill_cp(forward_batch) -> bool:
|
||||||
|
"""Return whether this MLA forward batch is using prefill CP."""
|
||||||
|
if enable_cp_v2():
|
||||||
|
return is_mla_prefill_cp_enabled() and is_cp_v2_active(forward_batch)
|
||||||
|
return (
|
||||||
|
getattr(forward_batch, "attn_cp_metadata", None) is not None
|
||||||
|
and is_mla_prefill_cp_enabled()
|
||||||
|
and forward_batch.forward_mode.is_context_parallel_extend()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def prepare_cp_forward(forward_batch) -> None:
|
def prepare_cp_forward(forward_batch) -> None:
|
||||||
"""Build CP-v2 metadata for an active context-parallel prefill batch."""
|
"""Build CP-v2 metadata for an active context-parallel prefill batch."""
|
||||||
assert is_cp_v2_active(forward_batch)
|
assert is_cp_v2_active(forward_batch)
|
||||||
@@ -251,8 +270,8 @@ def cp_materialize_global_token_order(
|
|||||||
assert strategy is not None
|
assert strategy is not None
|
||||||
return strategy.gather_kv_cache(x, forward_batch, stream)
|
return strategy.gather_kv_cache(x, forward_batch, stream)
|
||||||
|
|
||||||
# TODO(hzh0425): Keep the legacy gather temporarily for CP-v1 compatibility. Remove it
|
# HIP/NPU still materialize their protected platform layout through the
|
||||||
# with the follow-up CP-v1 cleanup.
|
# legacy collective until those backends migrate independently.
|
||||||
from sglang.srt.layers.utils.cp_utils import cp_all_gather_rerange_output
|
from sglang.srt.layers.utils.cp_utils import cp_all_gather_rerange_output
|
||||||
|
|
||||||
return cp_all_gather_rerange_output(
|
return cp_all_gather_rerange_output(
|
||||||
@@ -265,6 +284,7 @@ def cp_shard_model_inputs(
|
|||||||
complete_hidden_states: Any,
|
complete_hidden_states: Any,
|
||||||
complete_position_ids: Any,
|
complete_position_ids: Any,
|
||||||
forward_batch,
|
forward_batch,
|
||||||
|
complete_input_ids: Optional[Any] = None,
|
||||||
):
|
):
|
||||||
"""Restore the shared batch so logits processing keeps full-batch metadata."""
|
"""Restore the shared batch so logits processing keeps full-batch metadata."""
|
||||||
assert is_cp_v2_active(forward_batch)
|
assert is_cp_v2_active(forward_batch)
|
||||||
@@ -272,6 +292,18 @@ def cp_shard_model_inputs(
|
|||||||
complete_hidden_states, forward_batch
|
complete_hidden_states, forward_batch
|
||||||
)
|
)
|
||||||
sharded_positions = cp_shard_position_ids(complete_position_ids, forward_batch)
|
sharded_positions = cp_shard_position_ids(complete_position_ids, forward_batch)
|
||||||
|
model_input_ids = (
|
||||||
|
cp_shard_hidden_states(complete_input_ids, forward_batch)
|
||||||
|
if complete_input_ids is not None
|
||||||
|
else None
|
||||||
|
)
|
||||||
|
|
||||||
|
had_input_ids_global = hasattr(forward_batch, "input_ids_global")
|
||||||
|
input_ids_global_backup = getattr(forward_batch, "input_ids_global", None)
|
||||||
|
if complete_input_ids is not None:
|
||||||
|
forward_batch.input_ids_global = cp_round_robin_input_ids_v2(
|
||||||
|
complete_input_ids, forward_batch
|
||||||
|
)
|
||||||
|
|
||||||
spec_info = getattr(forward_batch, "spec_info", None)
|
spec_info = getattr(forward_batch, "spec_info", None)
|
||||||
spec_hidden_states = getattr(spec_info, "hidden_states", None)
|
spec_hidden_states = getattr(spec_info, "hidden_states", None)
|
||||||
@@ -286,10 +318,14 @@ def cp_shard_model_inputs(
|
|||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
yield sharded_hidden_states, sharded_positions
|
yield sharded_hidden_states, sharded_positions, model_input_ids
|
||||||
finally:
|
finally:
|
||||||
if spec_hidden_states_backup is not None:
|
if spec_hidden_states_backup is not None:
|
||||||
spec_info.hidden_states = spec_hidden_states_backup
|
spec_info.hidden_states = spec_hidden_states_backup
|
||||||
|
if had_input_ids_global:
|
||||||
|
forward_batch.input_ids_global = input_ids_global_backup
|
||||||
|
elif hasattr(forward_batch, "input_ids_global"):
|
||||||
|
delattr(forward_batch, "input_ids_global")
|
||||||
|
|
||||||
|
|
||||||
def _to_int_list(values) -> Optional[list[int]]:
|
def _to_int_list(values) -> Optional[list[int]]:
|
||||||
@@ -313,6 +349,8 @@ __all__ = [
|
|||||||
"enable_cp_v2",
|
"enable_cp_v2",
|
||||||
"get_cp_strategy",
|
"get_cp_strategy",
|
||||||
"is_cp_v2_active",
|
"is_cp_v2_active",
|
||||||
|
"is_mla_prefill_cp_enabled",
|
||||||
|
"mla_use_prefill_cp",
|
||||||
"cp_gather_after_forward",
|
"cp_gather_after_forward",
|
||||||
"cp_materialize_global_token_order",
|
"cp_materialize_global_token_order",
|
||||||
"cp_round_robin_input_ids_v2",
|
"cp_round_robin_input_ids_v2",
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
"""Legacy prefill CP helpers retained for HIP, NPU, and MUSA callers."""
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from itertools import accumulate
|
from itertools import accumulate
|
||||||
from typing import Callable, List
|
from typing import List
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
import torch.nn.functional as F
|
import torch.nn.functional as F
|
||||||
@@ -66,13 +68,6 @@ def is_prefill_context_parallel_enabled():
|
|||||||
return get_parallel().enable_prefill_context_parallel
|
return get_parallel().enable_prefill_context_parallel
|
||||||
|
|
||||||
|
|
||||||
def is_prefill_cp_in_seq_split():
|
|
||||||
return (
|
|
||||||
is_prefill_context_parallel_enabled()
|
|
||||||
and get_parallel().prefill_cp_mode == "in-seq-split"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def is_mla_prefill_cp_enabled() -> bool:
|
def is_mla_prefill_cp_enabled() -> bool:
|
||||||
return get_parallel().enable_prefill_context_parallel and uses_mla_backend()
|
return get_parallel().enable_prefill_context_parallel and uses_mla_backend()
|
||||||
|
|
||||||
@@ -477,48 +472,6 @@ def cp_allgather_and_save_kv_cache(forward_batch, layer, k, v, cp_size, swa_loc=
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def cp_attn_forward_extend(
|
|
||||||
forward_batch,
|
|
||||||
q: torch.Tensor,
|
|
||||||
device: torch.device,
|
|
||||||
attn_fn: Callable[[torch.Tensor, torch.Tensor, torch.Tensor, int], torch.Tensor],
|
|
||||||
) -> torch.Tensor:
|
|
||||||
"""
|
|
||||||
Split q into prev/next zigzag halves based on CP metadata, call the
|
|
||||||
backend-specific attention function twice with appropriate per-half
|
|
||||||
metadata, and concatenate the results.
|
|
||||||
|
|
||||||
For bs > 1, q is laid out as [all_prev_tokens_across_seqs,
|
|
||||||
all_next_tokens_across_seqs]; the split point is total_q_prev_tokens.
|
|
||||||
cu_seqlens_q_prev/next tensors have shape [bs+1] and carry the
|
|
||||||
per-sequence boundaries through FlashAttention's variable-length API.
|
|
||||||
|
|
||||||
attn_fn signature:
|
|
||||||
attn_fn(q, cu_seqlens_q, cache_seqlens, max_seqlen_q) -> result
|
|
||||||
where only these four CP-varying parameters differ between halves.
|
|
||||||
All other backend-specific args should be captured in the closure.
|
|
||||||
"""
|
|
||||||
cp_meta = forward_batch.attn_cp_metadata
|
|
||||||
|
|
||||||
q_prev = q[: cp_meta.total_q_prev_tokens]
|
|
||||||
q_next = q[cp_meta.total_q_prev_tokens :]
|
|
||||||
|
|
||||||
result_prev = attn_fn(
|
|
||||||
q_prev,
|
|
||||||
cp_meta.cu_seqlens_q_prev_tensor,
|
|
||||||
cp_meta.kv_len_prev_tensor,
|
|
||||||
cp_meta.max_seqlen_q_prev,
|
|
||||||
)
|
|
||||||
result_next = attn_fn(
|
|
||||||
q_next,
|
|
||||||
cp_meta.cu_seqlens_q_next_tensor,
|
|
||||||
cp_meta.kv_len_next_tensor,
|
|
||||||
cp_meta.max_seqlen_q_next,
|
|
||||||
)
|
|
||||||
|
|
||||||
return torch.concat([result_prev, result_next], dim=0)
|
|
||||||
|
|
||||||
|
|
||||||
def prepare_context_parallel_metadata(
|
def prepare_context_parallel_metadata(
|
||||||
kv_len,
|
kv_len,
|
||||||
cp_rank,
|
cp_rank,
|
||||||
|
|||||||
@@ -39,8 +39,6 @@ from typing import TYPE_CHECKING, Dict, List, Optional, Set, Union
|
|||||||
import torch
|
import torch
|
||||||
|
|
||||||
from sglang.srt.dllm.config import DllmConfig
|
from sglang.srt.dllm.config import DllmConfig
|
||||||
from sglang.srt.layers.attention.dsa.utils import is_dsa_prefill_cp_in_seq_split
|
|
||||||
from sglang.srt.layers.utils.cp_utils import is_prefill_context_parallel_enabled
|
|
||||||
from sglang.srt.managers.schedule_batch import (
|
from sglang.srt.managers.schedule_batch import (
|
||||||
Req,
|
Req,
|
||||||
ScheduleBatch,
|
ScheduleBatch,
|
||||||
@@ -582,9 +580,7 @@ class PrefillAdder:
|
|||||||
self.priority_scheduling_preemption_threshold = (
|
self.priority_scheduling_preemption_threshold = (
|
||||||
priority_scheduling_preemption_threshold
|
priority_scheduling_preemption_threshold
|
||||||
)
|
)
|
||||||
self.dsa_prefill_cp_in_seq_split = is_dsa_prefill_cp_in_seq_split()
|
|
||||||
self.max_running_requests = max_running_requests
|
self.max_running_requests = max_running_requests
|
||||||
self.prefill_context_parallel_enabled = is_prefill_context_parallel_enabled()
|
|
||||||
self.prefill_max_requests = prefill_max_requests
|
self.prefill_max_requests = prefill_max_requests
|
||||||
self.prefill_delayer_single_pass = prefill_delayer_single_pass
|
self.prefill_delayer_single_pass = prefill_delayer_single_pass
|
||||||
self.max_prefill_bs = max_prefill_bs
|
self.max_prefill_bs = max_prefill_bs
|
||||||
@@ -1200,12 +1196,6 @@ class PrefillAdder:
|
|||||||
def add_one_req(
|
def add_one_req(
|
||||||
self, req: Req, has_chunked_req: bool, truncation_align_size: Optional[int]
|
self, req: Req, has_chunked_req: bool, truncation_align_size: Optional[int]
|
||||||
):
|
):
|
||||||
# TODO support cp with multiple requests
|
|
||||||
# Enabling context parallelism currently presents precision issues;
|
|
||||||
# therefore, the prefill-batch setting is temporarily set to 1.
|
|
||||||
if (self.dsa_prefill_cp_in_seq_split) and len(self.can_run_list) >= 1:
|
|
||||||
return AddReqResult.OTHER
|
|
||||||
|
|
||||||
if (x := self.prefill_max_requests) is not None and len(self.can_run_list) >= x:
|
if (x := self.prefill_max_requests) is not None and len(self.can_run_list) >= x:
|
||||||
return AddReqResult.OTHER
|
return AddReqResult.OTHER
|
||||||
|
|
||||||
|
|||||||
@@ -67,9 +67,9 @@ from sglang.srt.utils import (
|
|||||||
from sglang.srt.utils.common import ceil_align, is_pin_memory_available
|
from sglang.srt.utils.common import ceil_align, is_pin_memory_available
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
from sglang.srt.layers.cp.base import BaseContextParallelMetadata
|
||||||
from sglang.srt.layers.dcp.metadata import DecodeContextParallelMetadata
|
from sglang.srt.layers.dcp.metadata import DecodeContextParallelMetadata
|
||||||
from sglang.srt.layers.logits_processor import LogitsProcessorOutput
|
from sglang.srt.layers.logits_processor import LogitsProcessorOutput
|
||||||
from sglang.srt.layers.utils.cp_utils import ContextParallelMetadata
|
|
||||||
from sglang.srt.managers.schedule_batch import MultimodalInputs, ScheduleBatch
|
from sglang.srt.managers.schedule_batch import MultimodalInputs, ScheduleBatch
|
||||||
from sglang.srt.model_executor.model_runner import ModelRunner
|
from sglang.srt.model_executor.model_runner import ModelRunner
|
||||||
from sglang.srt.sampling.sampling_batch_info import SamplingBatchInfo
|
from sglang.srt.sampling.sampling_batch_info import SamplingBatchInfo
|
||||||
@@ -304,8 +304,8 @@ def compute_local_num_token_non_padded_cpu(
|
|||||||
def prefill_graph_tolerates_sum_len() -> bool:
|
def prefill_graph_tolerates_sum_len() -> bool:
|
||||||
"""Whether MegaMoE may replay prefill graphs with local shapes."""
|
"""Whether MegaMoE may replay prefill graphs with local shapes."""
|
||||||
from sglang.srt.layers.attention.dsa.utils import is_dsa_enable_prefill_cp
|
from sglang.srt.layers.attention.dsa.utils import is_dsa_enable_prefill_cp
|
||||||
|
from sglang.srt.layers.cp.utils import is_mla_prefill_cp_enabled
|
||||||
from sglang.srt.layers.moe.utils import get_moe_a2a_backend
|
from sglang.srt.layers.moe.utils import get_moe_a2a_backend
|
||||||
from sglang.srt.layers.utils.cp_utils import is_mla_prefill_cp_enabled
|
|
||||||
|
|
||||||
if not get_moe_a2a_backend().is_megamoe():
|
if not get_moe_a2a_backend().is_megamoe():
|
||||||
return False
|
return False
|
||||||
@@ -598,7 +598,7 @@ class ForwardBatch(ForwardBatchDeepSeekMHAMixin):
|
|||||||
tbo_padded_len: Optional[int] = None
|
tbo_padded_len: Optional[int] = None
|
||||||
tbo_children: Optional[List[ForwardBatch]] = None
|
tbo_children: Optional[List[ForwardBatch]] = None
|
||||||
|
|
||||||
attn_cp_metadata: Optional[ContextParallelMetadata] = None
|
attn_cp_metadata: Optional[BaseContextParallelMetadata] = None
|
||||||
|
|
||||||
# For decode context parallel.
|
# For decode context parallel.
|
||||||
# NOTE: DecodeContextParallelMetadata is imported under TYPE_CHECKING only (see the
|
# NOTE: DecodeContextParallelMetadata is imported under TYPE_CHECKING only (see the
|
||||||
|
|||||||
@@ -77,10 +77,10 @@ from sglang.srt.layers.attention.dsa.utils import is_dsa_enable_prefill_cp
|
|||||||
from sglang.srt.layers.cp.utils import (
|
from sglang.srt.layers.cp.utils import (
|
||||||
get_cp_strategy,
|
get_cp_strategy,
|
||||||
is_cp_v2_active,
|
is_cp_v2_active,
|
||||||
|
is_mla_prefill_cp_enabled,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.logits_processor import LogitsProcessorOutput
|
from sglang.srt.layers.logits_processor import LogitsProcessorOutput
|
||||||
from sglang.srt.layers.sampler import create_sampler
|
from sglang.srt.layers.sampler import create_sampler
|
||||||
from sglang.srt.layers.utils.cp_utils import is_mla_prefill_cp_enabled
|
|
||||||
from sglang.srt.lora.lora_manager import LoRAManager, init_lora_cuda_graph_moe_buffers
|
from sglang.srt.lora.lora_manager import LoRAManager, init_lora_cuda_graph_moe_buffers
|
||||||
from sglang.srt.lora.lora_registry import LoRARef
|
from sglang.srt.lora.lora_registry import LoRARef
|
||||||
from sglang.srt.managers.schedule_batch import sanity_check_mm_pad_shift_value
|
from sglang.srt.managers.schedule_batch import sanity_check_mm_pad_shift_value
|
||||||
@@ -264,7 +264,7 @@ class SamplingPrewarmResult:
|
|||||||
def _prefill_cuda_graph_allows_context_parallel(
|
def _prefill_cuda_graph_allows_context_parallel(
|
||||||
prefill_runner, forward_batch: ForwardBatch
|
prefill_runner, forward_batch: ForwardBatch
|
||||||
) -> bool:
|
) -> bool:
|
||||||
"""Allow CP only through a runner that captured the validated CP-v2 body."""
|
"""Allow CP only through a runner that captured the validated CP body."""
|
||||||
return get_cp_strategy() is None or (
|
return get_cp_strategy() is None or (
|
||||||
bool(getattr(prefill_runner, "enable_cp_v2_bcg_capture", False))
|
bool(getattr(prefill_runner, "enable_cp_v2_bcg_capture", False))
|
||||||
and is_cp_v2_active(forward_batch)
|
and is_cp_v2_active(forward_batch)
|
||||||
|
|||||||
@@ -49,13 +49,13 @@ from sglang.srt.layers.attention.base_attn_backend import (
|
|||||||
SharedReadEnds,
|
SharedReadEnds,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.attention.dsa.utils import is_dsa_enable_prefill_cp
|
from sglang.srt.layers.attention.dsa.utils import is_dsa_enable_prefill_cp
|
||||||
|
from sglang.srt.layers.cp.utils import is_mla_prefill_cp_enabled
|
||||||
from sglang.srt.layers.dp_attention import (
|
from sglang.srt.layers.dp_attention import (
|
||||||
DpPaddingMode,
|
DpPaddingMode,
|
||||||
set_dp_buffer_len,
|
set_dp_buffer_len,
|
||||||
set_is_extend_in_batch,
|
set_is_extend_in_batch,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.logits_processor import LogitsProcessorOutput
|
from sglang.srt.layers.logits_processor import LogitsProcessorOutput
|
||||||
from sglang.srt.layers.utils.cp_utils import is_mla_prefill_cp_enabled
|
|
||||||
from sglang.srt.model_executor.cuda_graph_buffer_registry import (
|
from sglang.srt.model_executor.cuda_graph_buffer_registry import (
|
||||||
CudaGraphBufferRegistry,
|
CudaGraphBufferRegistry,
|
||||||
build_decode_registry,
|
build_decode_registry,
|
||||||
|
|||||||
@@ -380,7 +380,7 @@ class EagerRunner(BaseRunner):
|
|||||||
def _execute_extend_cp_v2(
|
def _execute_extend_cp_v2(
|
||||||
self, forward_batch: ForwardBatch, kwargs: dict
|
self, forward_batch: ForwardBatch, kwargs: dict
|
||||||
) -> Union[LogitsProcessorOutput, PPProxyTensors]:
|
) -> Union[LogitsProcessorOutput, PPProxyTensors]:
|
||||||
"""CP-v2 extend: shard inputs at the model boundary, run the body on the
|
"""CP extend: shard inputs at the model boundary, run the body on the
|
||||||
rank-local slice, then gather hidden states before the logits step.
|
rank-local slice, then gather hidden states before the logits step.
|
||||||
"""
|
"""
|
||||||
model = self.model_runner.model
|
model = self.model_runner.model
|
||||||
@@ -389,13 +389,16 @@ class EagerRunner(BaseRunner):
|
|||||||
if input_embeds is None:
|
if input_embeds is None:
|
||||||
input_embeds = model.get_input_embeddings()(forward_batch.input_ids)
|
input_embeds = model.get_input_embeddings()(forward_batch.input_ids)
|
||||||
with cp_shard_model_inputs(
|
with cp_shard_model_inputs(
|
||||||
input_embeds, forward_batch.positions, forward_batch
|
input_embeds,
|
||||||
) as (sharded_input_embeds, sharded_positions):
|
forward_batch.positions,
|
||||||
|
forward_batch,
|
||||||
|
forward_batch.input_ids,
|
||||||
|
) as (sharded_input_embeds, sharded_positions, model_input_ids):
|
||||||
model_kwargs = {"input_embeds": sharded_input_embeds}
|
model_kwargs = {"input_embeds": sharded_input_embeds}
|
||||||
if (pp_proxy_tensors := kwargs.get("pp_proxy_tensors")) is not None:
|
if (pp_proxy_tensors := kwargs.get("pp_proxy_tensors")) is not None:
|
||||||
model_kwargs["pp_proxy_tensors"] = pp_proxy_tensors
|
model_kwargs["pp_proxy_tensors"] = pp_proxy_tensors
|
||||||
hidden_states = model.model(
|
hidden_states = model.model(
|
||||||
forward_batch.input_ids,
|
model_input_ids,
|
||||||
sharded_positions,
|
sharded_positions,
|
||||||
forward_batch,
|
forward_batch,
|
||||||
**model_kwargs,
|
**model_kwargs,
|
||||||
|
|||||||
@@ -64,7 +64,10 @@ from sglang.srt.layers.cp.bcg import (
|
|||||||
execute_prefill_cp_bcg,
|
execute_prefill_cp_bcg,
|
||||||
filter_prefill_cp_bcg_capture_num_tokens,
|
filter_prefill_cp_bcg_capture_num_tokens,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.cp.utils import is_cp_v2_active
|
from sglang.srt.layers.cp.utils import (
|
||||||
|
is_cp_v2_active,
|
||||||
|
is_mla_prefill_cp_enabled,
|
||||||
|
)
|
||||||
from sglang.srt.layers.dp_attention import (
|
from sglang.srt.layers.dp_attention import (
|
||||||
DpPaddingMode,
|
DpPaddingMode,
|
||||||
set_dp_buffer_len,
|
set_dp_buffer_len,
|
||||||
@@ -72,7 +75,6 @@ from sglang.srt.layers.dp_attention import (
|
|||||||
)
|
)
|
||||||
from sglang.srt.layers.logits_processor import LogitsProcessorOutput
|
from sglang.srt.layers.logits_processor import LogitsProcessorOutput
|
||||||
from sglang.srt.layers.pooler import EmbeddingPoolerOutput
|
from sglang.srt.layers.pooler import EmbeddingPoolerOutput
|
||||||
from sglang.srt.layers.utils.cp_utils import is_mla_prefill_cp_enabled
|
|
||||||
from sglang.srt.model_executor.cuda_graph_buffer_registry import (
|
from sglang.srt.model_executor.cuda_graph_buffer_registry import (
|
||||||
CudaGraphBufferRegistry,
|
CudaGraphBufferRegistry,
|
||||||
build_prefill_registry,
|
build_prefill_registry,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
from sglang.srt.environ import envs
|
from sglang.srt.environ import envs
|
||||||
from sglang.srt.layers.attention.tbo_backend import TboAttnBackend
|
from sglang.srt.layers.attention.tbo_backend import TboAttnBackend
|
||||||
|
from sglang.srt.layers.cp.utils import enable_cp_v2, is_cp_v2_active
|
||||||
from sglang.srt.layers.utils.cp_utils import mla_use_prefill_cp
|
from sglang.srt.layers.utils.cp_utils import mla_use_prefill_cp
|
||||||
from sglang.srt.model_executor.forward_context import get_attn_backend
|
from sglang.srt.model_executor.forward_context import get_attn_backend
|
||||||
from sglang.srt.model_executor.runner_backend_utils.breakable_cuda_graph import (
|
from sglang.srt.model_executor.runner_backend_utils.breakable_cuda_graph import (
|
||||||
@@ -111,10 +112,12 @@ def _handle_attention_backend(attn, forward_batch, backend_name):
|
|||||||
if is_in_tc_piecewise_cuda_graph() or is_in_breakable_cuda_graph():
|
if is_in_tc_piecewise_cuda_graph() or is_in_breakable_cuda_graph():
|
||||||
return AttnForwardMethod.MLA
|
return AttnForwardMethod.MLA
|
||||||
|
|
||||||
# MLA prefill CP forces absorbed MLA regardless of prefix length: the
|
# Strategy CP gathers latent KV in the backend's absorbed MLA path;
|
||||||
# CP path gathers latent KV via rebuild_cp_kv_cache and feeds the
|
# normal MHA would write rank-local KV against full cache locations.
|
||||||
# backend's absorbed-MLA kernel.
|
# Protected platform CP retains its model-side materialization path.
|
||||||
if mla_use_prefill_cp(forward_batch):
|
if is_cp_v2_active(forward_batch) or (
|
||||||
|
not enable_cp_v2() and mla_use_prefill_cp(forward_batch)
|
||||||
|
):
|
||||||
return _dispatch_mla_subtype(attn, forward_batch)
|
return _dispatch_mla_subtype(attn, forward_batch)
|
||||||
|
|
||||||
sum_extend_prefix_lens = _get_sum_extend_prefix_lens(forward_batch)
|
sum_extend_prefix_lens = _get_sum_extend_prefix_lens(forward_batch)
|
||||||
|
|||||||
@@ -14,12 +14,10 @@ from sglang.kernels.ops.quantization.fp8_kernel import (
|
|||||||
from sglang.srt.compilation.compilation_config import register_split_op
|
from sglang.srt.compilation.compilation_config import register_split_op
|
||||||
from sglang.srt.environ import envs
|
from sglang.srt.environ import envs
|
||||||
from sglang.srt.layers import deep_gemm_wrapper
|
from sglang.srt.layers import deep_gemm_wrapper
|
||||||
from sglang.srt.layers.attention.dsa.utils import (
|
from sglang.srt.layers.attention.dsa.utils import is_graph_dsa_split_op_surface
|
||||||
dsa_use_prefill_cp,
|
from sglang.srt.layers.attention.dsa_backend import prepare_kv_for_attention
|
||||||
is_graph_dsa_split_op_surface,
|
|
||||||
)
|
|
||||||
from sglang.srt.layers.communicator import get_attn_tp_context
|
from sglang.srt.layers.communicator import get_attn_tp_context
|
||||||
from sglang.srt.layers.cp.utils import is_cp_v2_active
|
from sglang.srt.layers.cp.utils import enable_cp_v2
|
||||||
from sglang.srt.layers.dcp import (
|
from sglang.srt.layers.dcp import (
|
||||||
all_gather_kv_cache_for_mla_extend,
|
all_gather_kv_cache_for_mla_extend,
|
||||||
all_gather_q_for_mla_decode,
|
all_gather_q_for_mla_decode,
|
||||||
@@ -115,6 +113,7 @@ def should_defer_dsa_cp_kv_gather(
|
|||||||
dsa_prefill_cp: bool,
|
dsa_prefill_cp: bool,
|
||||||
fuse_rope_for_trtllm_mla: bool,
|
fuse_rope_for_trtllm_mla: bool,
|
||||||
) -> bool:
|
) -> bool:
|
||||||
|
"""Compatibility predicate imported by the unchanged ROCm MLA path."""
|
||||||
return dsa_prefill_cp and fuse_rope_for_trtllm_mla
|
return dsa_prefill_cp and fuse_rope_for_trtllm_mla
|
||||||
|
|
||||||
|
|
||||||
@@ -266,10 +265,6 @@ class DeepseekMLAForwardMixin:
|
|||||||
return None
|
return None
|
||||||
if get_parallel().dcp_enabled:
|
if get_parallel().dcp_enabled:
|
||||||
return None
|
return None
|
||||||
# Context-parallel prefill reshuffles the KV side; keep the handshake
|
|
||||||
# out of those paths.
|
|
||||||
if dsa_use_prefill_cp(forward_batch) or mla_use_prefill_cp(forward_batch):
|
|
||||||
return None
|
|
||||||
# Kernel shape constraints (tl.arange / tl.dot / block tiling). K
|
# Kernel shape constraints (tl.arange / tl.dot / block tiling). K
|
||||||
# (qk_nope_head_dim) needs only K % 16 == 0 and K <= 256: power-of-2
|
# (qk_nope_head_dim) needs only K % 16 == 0 and K <= 256: power-of-2
|
||||||
# K (DeepSeek 128) takes the kernel's preload-once path, other K
|
# K (DeepSeek 128) takes the kernel's preload-once path, other K
|
||||||
@@ -623,30 +618,17 @@ class DeepseekMLAForwardMixin:
|
|||||||
num_tokens, self.num_local_heads, self.kv_lora_rank, q_nope.device
|
num_tokens, self.num_local_heads, self.kv_lora_rank, q_nope.device
|
||||||
)
|
)
|
||||||
|
|
||||||
dsa_prefill_cp = dsa_use_prefill_cp(forward_batch)
|
k_nope, k_pe = prepare_kv_for_attention(
|
||||||
mla_prefill_cp = mla_use_prefill_cp(forward_batch)
|
self,
|
||||||
defer_kv_gather_until_after_rope = should_defer_dsa_cp_kv_gather(
|
forward_batch,
|
||||||
dsa_prefill_cp=dsa_prefill_cp,
|
k_nope,
|
||||||
fuse_rope_for_trtllm_mla=fuse_rope_for_trtllm_mla,
|
k_pe,
|
||||||
|
defer_materialization=fuse_rope_for_trtllm_mla,
|
||||||
)
|
)
|
||||||
if dsa_prefill_cp and not defer_kv_gather_until_after_rope:
|
|
||||||
from sglang.srt.layers.attention.dsa_backend import materialize_full_kv_cp
|
|
||||||
|
|
||||||
k_nope, k_pe = materialize_full_kv_cp(
|
if not enable_cp_v2() and mla_use_prefill_cp(forward_batch):
|
||||||
self,
|
|
||||||
forward_batch,
|
|
||||||
latent_cache,
|
|
||||||
k_nope,
|
|
||||||
k_pe,
|
|
||||||
)
|
|
||||||
elif mla_prefill_cp and not is_cp_v2_active(forward_batch):
|
|
||||||
# CP-v1 gathers the latent here; CP-v2 gathers it in the attention
|
|
||||||
# backend via the strategy (materialize_full_mla_kv).
|
|
||||||
k_nope, k_pe = self.rebuild_cp_kv_cache(
|
k_nope, k_pe = self.rebuild_cp_kv_cache(
|
||||||
latent_cache,
|
latent_cache, forward_batch, k_nope, k_pe
|
||||||
forward_batch,
|
|
||||||
k_nope,
|
|
||||||
k_pe,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# all_gather q_pe, q_nope_out,take tp8 as an example, q_pe [B, H, ROPE_DIM], q_nope_out [B, H, NOPE_DIM] gathered to [B, H * dcp_world_size, ROPE_DIM] [B, H * dcp_world_size, NOPE_DIM] for decode batch, and all gather k_pe, k_nope for extend batch.
|
# all_gather q_pe, q_nope_out,take tp8 as an example, q_pe [B, H, ROPE_DIM], q_nope_out [B, H, NOPE_DIM] gathered to [B, H * dcp_world_size, ROPE_DIM] [B, H * dcp_world_size, NOPE_DIM] for decode batch, and all gather k_pe, k_nope for extend batch.
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ from torch import nn
|
|||||||
from transformers import PretrainedConfig
|
from transformers import PretrainedConfig
|
||||||
|
|
||||||
from sglang.kernels.ops.layernorm.fused_eh_norm import fused_eh_norm
|
from sglang.kernels.ops.layernorm.fused_eh_norm import fused_eh_norm
|
||||||
from sglang.srt.configs.model_config import is_deepseek_dsa
|
|
||||||
from sglang.srt.distributed import get_pp_group
|
from sglang.srt.distributed import get_pp_group
|
||||||
from sglang.srt.environ import envs
|
from sglang.srt.environ import envs
|
||||||
from sglang.srt.eplb.expert_distribution import get_global_expert_distribution_recorder
|
from sglang.srt.eplb.expert_distribution import get_global_expert_distribution_recorder
|
||||||
@@ -36,7 +35,7 @@ from sglang.srt.layers.attention.dsa.utils import (
|
|||||||
is_dsa_prefill_cp_round_robin_split,
|
is_dsa_prefill_cp_round_robin_split,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.attention.index_topk_share import IndexTopKShareState
|
from sglang.srt.layers.attention.index_topk_share import IndexTopKShareState
|
||||||
from sglang.srt.layers.cp.utils import cp_gather_after_forward, is_cp_v2_active
|
from sglang.srt.layers.cp.utils import enable_cp_v2
|
||||||
from sglang.srt.layers.layernorm import RMSNorm
|
from sglang.srt.layers.layernorm import RMSNorm
|
||||||
from sglang.srt.layers.linear import ReplicatedLinear
|
from sglang.srt.layers.linear import ReplicatedLinear
|
||||||
from sglang.srt.layers.logits_processor import LogitsProcessor
|
from sglang.srt.layers.logits_processor import LogitsProcessor
|
||||||
@@ -166,14 +165,6 @@ class DeepseekModelNextN(nn.Module):
|
|||||||
layer_name = "layers." + str(config.num_hidden_layers)
|
layer_name = "layers." + str(config.num_hidden_layers)
|
||||||
|
|
||||||
self.quant_config = quant_config
|
self.quant_config = quant_config
|
||||||
self.dsa_enable_prefill_cp = is_dsa_enable_prefill_cp()
|
|
||||||
self.mla_enable_prefill_cp = (
|
|
||||||
is_mla_prefill_cp_enabled() and not is_deepseek_dsa(config)
|
|
||||||
)
|
|
||||||
if self.dsa_enable_prefill_cp or self.mla_enable_prefill_cp:
|
|
||||||
self.cp_size = get_parallel().attn_cp_size
|
|
||||||
else:
|
|
||||||
self.cp_size = None
|
|
||||||
self.decoder = DeepseekV2DecoderLayer(
|
self.decoder = DeepseekV2DecoderLayer(
|
||||||
config,
|
config,
|
||||||
0,
|
0,
|
||||||
@@ -183,8 +174,6 @@ class DeepseekModelNextN(nn.Module):
|
|||||||
prefix=add_prefix(layer_name, prefix),
|
prefix=add_prefix(layer_name, prefix),
|
||||||
alt_stream=self.alt_stream,
|
alt_stream=self.alt_stream,
|
||||||
skip_rope=config.qk_rope_head_dim == 0,
|
skip_rope=config.qk_rope_head_dim == 0,
|
||||||
dsa_enable_prefill_cp=self.dsa_enable_prefill_cp,
|
|
||||||
mla_enable_prefill_cp=self.mla_enable_prefill_cp,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.shared_head = nn.Module()
|
self.shared_head = nn.Module()
|
||||||
@@ -271,13 +260,11 @@ class DeepseekModelNextN(nn.Module):
|
|||||||
else:
|
else:
|
||||||
hidden_states = self.eh_proj(eh_input)
|
hidden_states = self.eh_proj(eh_input)
|
||||||
|
|
||||||
# CP-v2 shards/gathers hidden states at the eager-runner boundary.
|
# Protected platforms retain their model-side token split.
|
||||||
cp_v2_active = is_cp_v2_active(forward_batch)
|
use_platform_cp = not enable_cp_v2() and (
|
||||||
use_cp_v1 = (
|
dsa_use_prefill_cp(forward_batch) or mla_use_prefill_cp(forward_batch)
|
||||||
dsa_use_prefill_cp(forward_batch, self.dsa_enable_prefill_cp)
|
)
|
||||||
or mla_use_prefill_cp(forward_batch, self.mla_enable_prefill_cp)
|
if use_platform_cp:
|
||||||
) and not cp_v2_active
|
|
||||||
if use_cp_v1:
|
|
||||||
hidden_states = cp_split_and_rebuild_data(forward_batch, hidden_states)
|
hidden_states = cp_split_and_rebuild_data(forward_batch, hidden_states)
|
||||||
positions = cp_split_and_rebuild_position(forward_batch, positions)
|
positions = cp_split_and_rebuild_position(forward_batch, positions)
|
||||||
residual = None
|
residual = None
|
||||||
@@ -297,11 +284,11 @@ class DeepseekModelNextN(nn.Module):
|
|||||||
else:
|
else:
|
||||||
hidden_states = self.shared_head.norm(hidden_states)
|
hidden_states = self.shared_head.norm(hidden_states)
|
||||||
|
|
||||||
if use_cp_v1:
|
if use_platform_cp:
|
||||||
local_num_tokens = hidden_states.shape[0]
|
local_num_tokens = hidden_states.shape[0]
|
||||||
hidden_states = cp_all_gather_rerange_output(
|
hidden_states = cp_all_gather_rerange_output(
|
||||||
hidden_states,
|
hidden_states,
|
||||||
self.cp_size,
|
get_parallel().attn_cp_size,
|
||||||
forward_batch,
|
forward_batch,
|
||||||
torch.cuda.current_stream(),
|
torch.cuda.current_stream(),
|
||||||
)
|
)
|
||||||
@@ -309,16 +296,10 @@ class DeepseekModelNextN(nn.Module):
|
|||||||
topk_indices = _gather_dsa_topk_indices_for_cp(
|
topk_indices = _gather_dsa_topk_indices_for_cp(
|
||||||
topk_indices,
|
topk_indices,
|
||||||
local_num_tokens,
|
local_num_tokens,
|
||||||
self.cp_size,
|
get_parallel().attn_cp_size,
|
||||||
forward_batch,
|
forward_batch,
|
||||||
torch.cuda.current_stream(),
|
torch.cuda.current_stream(),
|
||||||
)
|
)
|
||||||
elif (
|
|
||||||
cp_v2_active
|
|
||||||
and index_topk_share.should_publish
|
|
||||||
and topk_indices is not None
|
|
||||||
):
|
|
||||||
topk_indices = cp_gather_after_forward(topk_indices, forward_batch)
|
|
||||||
index_topk_share.update(topk_indices)
|
index_topk_share.update(topk_indices)
|
||||||
index_topk_share.publish()
|
index_topk_share.publish()
|
||||||
finally:
|
finally:
|
||||||
@@ -369,16 +350,6 @@ class DeepseekV3ForCausalLMNextN(DeepseekV3ForCausalLM):
|
|||||||
# if not set, model load will be broken in DeepseekV3ForCausalLM load_weights()
|
# if not set, model load will be broken in DeepseekV3ForCausalLM load_weights()
|
||||||
self.pp_group = get_pp_group()
|
self.pp_group = get_pp_group()
|
||||||
self.determine_num_fused_shared_experts()
|
self.determine_num_fused_shared_experts()
|
||||||
self.use_dsa = is_deepseek_dsa(config)
|
|
||||||
self.dsa_enable_prefill_cp = is_dsa_enable_prefill_cp()
|
|
||||||
self.mla_enable_prefill_cp = is_mla_prefill_cp_enabled() and not self.use_dsa
|
|
||||||
if self.dsa_enable_prefill_cp or self.mla_enable_prefill_cp:
|
|
||||||
self.cp_rank = get_parallel().attn_cp_rank
|
|
||||||
self.cp_size = get_parallel().attn_cp_size
|
|
||||||
else:
|
|
||||||
self.cp_rank = None
|
|
||||||
self.cp_size = None
|
|
||||||
|
|
||||||
nextn_quant_config = self._resolve_nextn_quant_config(config, quant_config)
|
nextn_quant_config = self._resolve_nextn_quant_config(config, quant_config)
|
||||||
|
|
||||||
self.model = DeepseekModelNextN(
|
self.model = DeepseekModelNextN(
|
||||||
@@ -400,25 +371,31 @@ class DeepseekV3ForCausalLMNextN(DeepseekV3ForCausalLM):
|
|||||||
positions: torch.Tensor,
|
positions: torch.Tensor,
|
||||||
forward_batch: ForwardBatch,
|
forward_batch: ForwardBatch,
|
||||||
) -> torch.Tensor:
|
) -> torch.Tensor:
|
||||||
# TODO current just support prefill batch=1 and len(input_ids) > self.cp_size * 2
|
if not enable_cp_v2():
|
||||||
if not is_cp_v2_active(forward_batch):
|
if is_dsa_enable_prefill_cp():
|
||||||
if self.dsa_enable_prefill_cp:
|
|
||||||
if can_dsa_cp_split(
|
if can_dsa_cp_split(
|
||||||
len(input_ids), self.cp_size, self.use_dsa, forward_batch
|
len(input_ids),
|
||||||
|
get_parallel().attn_cp_size,
|
||||||
|
self.model.decoder.self_attn.use_dsa,
|
||||||
|
forward_batch,
|
||||||
):
|
):
|
||||||
forward_batch.attn_cp_metadata = prepare_context_parallel_metadata(
|
forward_batch.attn_cp_metadata = prepare_context_parallel_metadata(
|
||||||
len(input_ids),
|
len(input_ids),
|
||||||
self.cp_rank,
|
get_parallel().attn_cp_rank,
|
||||||
self.cp_size,
|
get_parallel().attn_cp_size,
|
||||||
forward_batch.seq_lens_cpu.tolist(),
|
forward_batch.seq_lens_cpu.tolist(),
|
||||||
extend_seqs_len=forward_batch.extend_seq_lens_cpu,
|
extend_seqs_len=forward_batch.extend_seq_lens_cpu,
|
||||||
)
|
)
|
||||||
elif self.mla_enable_prefill_cp:
|
elif (
|
||||||
if can_cp_split(len(input_ids), self.cp_size, forward_batch):
|
is_mla_prefill_cp_enabled() and not self.model.decoder.self_attn.use_dsa
|
||||||
|
):
|
||||||
|
if can_cp_split(
|
||||||
|
len(input_ids), get_parallel().attn_cp_size, forward_batch
|
||||||
|
):
|
||||||
forward_batch.attn_cp_metadata = prepare_context_parallel_metadata(
|
forward_batch.attn_cp_metadata = prepare_context_parallel_metadata(
|
||||||
len(input_ids),
|
len(input_ids),
|
||||||
self.cp_rank,
|
get_parallel().attn_cp_rank,
|
||||||
self.cp_size,
|
get_parallel().attn_cp_size,
|
||||||
forward_batch.seq_lens_cpu.tolist(),
|
forward_batch.seq_lens_cpu.tolist(),
|
||||||
extend_seqs_len=forward_batch.extend_seq_lens_cpu,
|
extend_seqs_len=forward_batch.extend_seq_lens_cpu,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ from sglang.srt.layers.communicator_dsa_cp import (
|
|||||||
maybe_prefetch_next_full_attention_kv,
|
maybe_prefetch_next_full_attention_kv,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.cp.cp_decode_attn_tp import get_cp_decode_attn_tp_ctx
|
from sglang.srt.layers.cp.cp_decode_attn_tp import get_cp_decode_attn_tp_ctx
|
||||||
from sglang.srt.layers.cp.utils import is_cp_v2_active
|
from sglang.srt.layers.cp.utils import enable_cp_v2
|
||||||
from sglang.srt.layers.dcp.planner import (
|
from sglang.srt.layers.dcp.planner import (
|
||||||
prepare_decode_context_parallel_metadata,
|
prepare_decode_context_parallel_metadata,
|
||||||
)
|
)
|
||||||
@@ -470,14 +470,10 @@ class MoEGate(nn.Module):
|
|||||||
config,
|
config,
|
||||||
quant_config,
|
quant_config,
|
||||||
prefix: str = "",
|
prefix: str = "",
|
||||||
is_nextn: bool = False,
|
|
||||||
is_hash_moe: bool = False,
|
is_hash_moe: bool = False,
|
||||||
is_deepseek_v4: bool = False,
|
is_deepseek_v4: bool = False,
|
||||||
dsa_enable_prefill_cp: bool = False,
|
|
||||||
mla_enable_prefill_cp: bool = False,
|
|
||||||
):
|
):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.is_nextn = is_nextn
|
|
||||||
self.is_deepseek_v4 = is_deepseek_v4
|
self.is_deepseek_v4 = is_deepseek_v4
|
||||||
self.weight = nn.Parameter(
|
self.weight = nn.Parameter(
|
||||||
torch.empty(
|
torch.empty(
|
||||||
@@ -509,9 +505,6 @@ class MoEGate(nn.Module):
|
|||||||
self.e_score_correction_bias = None
|
self.e_score_correction_bias = None
|
||||||
if _is_cpu and _is_cpu_amx_available:
|
if _is_cpu and _is_cpu_amx_available:
|
||||||
self.quant_method = PackWeightMethod(weight_names=["weight"])
|
self.quant_method = PackWeightMethod(weight_names=["weight"])
|
||||||
self.use_dsa = is_deepseek_dsa(config)
|
|
||||||
self.dsa_enable_prefill_cp = dsa_enable_prefill_cp
|
|
||||||
self.mla_enable_prefill_cp = mla_enable_prefill_cp
|
|
||||||
self.tiny_router_gemm_max_tokens = tiny_router_gemm_max_tokens(
|
self.tiny_router_gemm_max_tokens = tiny_router_gemm_max_tokens(
|
||||||
num_experts=config.n_routed_experts,
|
num_experts=config.n_routed_experts,
|
||||||
hidden_size=config.hidden_size,
|
hidden_size=config.hidden_size,
|
||||||
@@ -539,36 +532,29 @@ class MoEGate(nn.Module):
|
|||||||
return F.linear(hidden_states, self.weight, None)
|
return F.linear(hidden_states, self.weight, None)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
not self.is_deepseek_v4
|
not enable_cp_v2()
|
||||||
|
and not self.is_deepseek_v4
|
||||||
and forward_batch is not None
|
and forward_batch is not None
|
||||||
and (
|
and (dsa_use_prefill_cp(forward_batch) or mla_use_prefill_cp(forward_batch))
|
||||||
dsa_use_prefill_cp(forward_batch, self.dsa_enable_prefill_cp)
|
|
||||||
or mla_use_prefill_cp(forward_batch, self.mla_enable_prefill_cp)
|
|
||||||
)
|
|
||||||
):
|
):
|
||||||
if _is_cuda:
|
|
||||||
from sglang.kernels.ops.attention.dsv4 import linear_bf16_fp32
|
|
||||||
|
|
||||||
return linear_bf16_fp32(hidden_states, self.weight)
|
|
||||||
return F.linear(hidden_states, self.weight, None)
|
return F.linear(hidden_states, self.weight, None)
|
||||||
|
|
||||||
|
if hidden_states.shape[0] <= self.tiny_router_gemm_max_tokens:
|
||||||
|
logits = tiny_gemm_bf16(
|
||||||
|
hidden_states,
|
||||||
|
self.weight,
|
||||||
|
out_dtype=torch.float32,
|
||||||
|
max_m=self.tiny_router_gemm_max_tokens,
|
||||||
|
)
|
||||||
|
elif _use_aiter:
|
||||||
|
logits = aiter_dsv3_router_gemm(hidden_states, self.weight)
|
||||||
|
elif not _is_cuda:
|
||||||
|
logits = F.linear(hidden_states, self.weight, None)
|
||||||
else:
|
else:
|
||||||
if hidden_states.shape[0] <= self.tiny_router_gemm_max_tokens:
|
# cuBLAS bf16 x bf16 -> fp32 GEMM (torch.mm's out_dtype kwarg is CUDA-only)
|
||||||
logits = tiny_gemm_bf16(
|
from sglang.kernels.ops.attention.dsv4 import linear_bf16_fp32
|
||||||
hidden_states,
|
|
||||||
self.weight,
|
|
||||||
out_dtype=torch.float32,
|
|
||||||
max_m=self.tiny_router_gemm_max_tokens,
|
|
||||||
)
|
|
||||||
|
|
||||||
elif _use_aiter:
|
logits = linear_bf16_fp32(hidden_states, self.weight)
|
||||||
logits = aiter_dsv3_router_gemm(hidden_states, self.weight)
|
|
||||||
elif not _is_cuda:
|
|
||||||
logits = F.linear(hidden_states, self.weight, None)
|
|
||||||
else:
|
|
||||||
# cuBLAS bf16 x bf16 -> fp32 GEMM (torch.mm's out_dtype kwarg is CUDA-only)
|
|
||||||
from sglang.kernels.ops.attention.dsv4 import linear_bf16_fp32
|
|
||||||
|
|
||||||
logits = linear_bf16_fp32(hidden_states, self.weight)
|
|
||||||
|
|
||||||
return logits
|
return logits
|
||||||
|
|
||||||
@@ -583,8 +569,6 @@ class DeepseekV2MoE(nn.Module):
|
|||||||
alt_stream: Optional[torch.cuda.Stream] = None,
|
alt_stream: Optional[torch.cuda.Stream] = None,
|
||||||
is_nextn: bool = False,
|
is_nextn: bool = False,
|
||||||
is_deepseek_v4: bool = False,
|
is_deepseek_v4: bool = False,
|
||||||
dsa_enable_prefill_cp: bool = False,
|
|
||||||
mla_enable_prefill_cp: bool = False,
|
|
||||||
):
|
):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.tp_size = get_parallel().tp_size
|
self.tp_size = get_parallel().tp_size
|
||||||
@@ -643,11 +627,8 @@ class DeepseekV2MoE(nn.Module):
|
|||||||
config=config,
|
config=config,
|
||||||
quant_config=quant_config,
|
quant_config=quant_config,
|
||||||
prefix=add_prefix("gate", prefix),
|
prefix=add_prefix("gate", prefix),
|
||||||
is_nextn=is_nextn,
|
|
||||||
is_hash_moe=self.is_hash,
|
is_hash_moe=self.is_hash,
|
||||||
is_deepseek_v4=is_deepseek_v4,
|
is_deepseek_v4=is_deepseek_v4,
|
||||||
dsa_enable_prefill_cp=dsa_enable_prefill_cp,
|
|
||||||
mla_enable_prefill_cp=mla_enable_prefill_cp,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# scaling factor for fused shared experts on AMD-platform.
|
# scaling factor for fused shared experts on AMD-platform.
|
||||||
@@ -1771,8 +1752,6 @@ class DeepseekV2AttentionMLA(
|
|||||||
alt_stream: Optional[torch.cuda.Stream] = None,
|
alt_stream: Optional[torch.cuda.Stream] = None,
|
||||||
skip_rope: bool = False,
|
skip_rope: bool = False,
|
||||||
is_nextn: bool = False,
|
is_nextn: bool = False,
|
||||||
dsa_enable_prefill_cp: bool = False,
|
|
||||||
mla_enable_prefill_cp: bool = False,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.layer_id = layer_id
|
self.layer_id = layer_id
|
||||||
@@ -1788,15 +1767,6 @@ class DeepseekV2AttentionMLA(
|
|||||||
attn_tp_rank = get_parallel().attn_tp_rank
|
attn_tp_rank = get_parallel().attn_tp_rank
|
||||||
attn_tp_size = get_parallel().attn_tp_size
|
attn_tp_size = get_parallel().attn_tp_size
|
||||||
self.use_dsa = is_deepseek_dsa(config)
|
self.use_dsa = is_deepseek_dsa(config)
|
||||||
self.dsa_enable_prefill_cp = dsa_enable_prefill_cp
|
|
||||||
self.mla_enable_prefill_cp = mla_enable_prefill_cp
|
|
||||||
if self.dsa_enable_prefill_cp:
|
|
||||||
assert self.use_dsa, "CP currently only supports deepseek v3.2 model"
|
|
||||||
# cp reuses the attn_tp comm group but needs to duplicate the weights;
|
|
||||||
# store cp_size whenever either CP flavor is active so rebuild_cp_kv_cache
|
|
||||||
# and the FA3 MLA wrapper can reach it on the dense MLA path too.
|
|
||||||
if self.dsa_enable_prefill_cp or self.mla_enable_prefill_cp:
|
|
||||||
self.cp_size = get_parallel().attn_cp_size
|
|
||||||
self.num_heads = num_heads
|
self.num_heads = num_heads
|
||||||
assert num_heads % attn_tp_size == 0
|
assert num_heads % attn_tp_size == 0
|
||||||
self.num_local_heads = num_heads // attn_tp_size
|
self.num_local_heads = num_heads // attn_tp_size
|
||||||
@@ -2291,12 +2261,12 @@ class DeepseekV2AttentionMLA(
|
|||||||
return q.view(-1, self.num_local_heads, self.qk_head_dim)
|
return q.view(-1, self.num_local_heads, self.qk_head_dim)
|
||||||
|
|
||||||
def rebuild_cp_kv_cache(self, latent_cache, forward_batch, k_nope, k_pe):
|
def rebuild_cp_kv_cache(self, latent_cache, forward_batch, k_nope, k_pe):
|
||||||
# support allgather+rerrange
|
# Retained for the platform MLA paths.
|
||||||
latent_cache[..., : self.kv_lora_rank] = k_nope.squeeze(1)
|
latent_cache[..., : self.kv_lora_rank] = k_nope.squeeze(1)
|
||||||
latent_cache[..., self.kv_lora_rank :] = k_pe.squeeze(1)
|
latent_cache[..., self.kv_lora_rank :] = k_pe.squeeze(1)
|
||||||
latent_cache_output = cp_all_gather_rerange_output(
|
latent_cache_output = cp_all_gather_rerange_output(
|
||||||
latent_cache.contiguous(),
|
latent_cache.contiguous(),
|
||||||
self.cp_size,
|
get_parallel().attn_cp_size,
|
||||||
forward_batch,
|
forward_batch,
|
||||||
torch.cuda.current_stream(),
|
torch.cuda.current_stream(),
|
||||||
)
|
)
|
||||||
@@ -2327,8 +2297,6 @@ class DeepseekV2DecoderLayer(nn.Module):
|
|||||||
prefix: str = "",
|
prefix: str = "",
|
||||||
alt_stream: Optional[torch.cuda.Stream] = None,
|
alt_stream: Optional[torch.cuda.Stream] = None,
|
||||||
skip_rope: bool = False,
|
skip_rope: bool = False,
|
||||||
dsa_enable_prefill_cp: bool = False,
|
|
||||||
mla_enable_prefill_cp: bool = False,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.hidden_size = config.hidden_size
|
self.hidden_size = config.hidden_size
|
||||||
@@ -2345,8 +2313,6 @@ class DeepseekV2DecoderLayer(nn.Module):
|
|||||||
self.speculative_algorithm = SpeculativeAlgorithm.from_string(
|
self.speculative_algorithm = SpeculativeAlgorithm.from_string(
|
||||||
get_spec().speculative_algorithm
|
get_spec().speculative_algorithm
|
||||||
)
|
)
|
||||||
self.dsa_enable_prefill_cp = dsa_enable_prefill_cp
|
|
||||||
self.mla_enable_prefill_cp = mla_enable_prefill_cp
|
|
||||||
self.layer_id = layer_id
|
self.layer_id = layer_id
|
||||||
self.is_nextn = is_nextn
|
self.is_nextn = is_nextn
|
||||||
if is_nextn and getattr(config, "mla_nope", False):
|
if is_nextn and getattr(config, "mla_nope", False):
|
||||||
@@ -2374,8 +2340,6 @@ class DeepseekV2DecoderLayer(nn.Module):
|
|||||||
alt_stream=alt_stream,
|
alt_stream=alt_stream,
|
||||||
skip_rope=skip_rope,
|
skip_rope=skip_rope,
|
||||||
is_nextn=is_nextn,
|
is_nextn=is_nextn,
|
||||||
dsa_enable_prefill_cp=dsa_enable_prefill_cp,
|
|
||||||
mla_enable_prefill_cp=mla_enable_prefill_cp,
|
|
||||||
)
|
)
|
||||||
if not hasattr(config, "q_lora_rank") and envs.SGLANG_USE_AG_AFTER_QLORA.get():
|
if not hasattr(config, "q_lora_rank") and envs.SGLANG_USE_AG_AFTER_QLORA.get():
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
@@ -2402,8 +2366,6 @@ class DeepseekV2DecoderLayer(nn.Module):
|
|||||||
layer_id=self.layer_id,
|
layer_id=self.layer_id,
|
||||||
alt_stream=alt_stream,
|
alt_stream=alt_stream,
|
||||||
is_nextn=is_nextn,
|
is_nextn=is_nextn,
|
||||||
dsa_enable_prefill_cp=dsa_enable_prefill_cp,
|
|
||||||
mla_enable_prefill_cp=mla_enable_prefill_cp,
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
if enable_moe_dense_fully_dp():
|
if enable_moe_dense_fully_dp():
|
||||||
@@ -2428,31 +2390,21 @@ class DeepseekV2DecoderLayer(nn.Module):
|
|||||||
|
|
||||||
self._gfx95_quant_format = self._detect_gfx95_quant_format()
|
self._gfx95_quant_format = self._detect_gfx95_quant_format()
|
||||||
|
|
||||||
if self.dsa_enable_prefill_cp or self.mla_enable_prefill_cp:
|
communicator_cls = (
|
||||||
# DSACPLayerCommunicator is flavor-agnostic; its internal gates
|
DSACPLayerCommunicator
|
||||||
# read both dsa_use_prefill_cp and mla_use_prefill_cp. The rename
|
if get_parallel().enable_prefill_cp
|
||||||
# to CPLayerCommunicator is deferred to a cleanup PR.
|
else LayerCommunicator
|
||||||
self.layer_communicator = DSACPLayerCommunicator(
|
)
|
||||||
layer_scatter_modes=self.layer_scatter_modes,
|
self.layer_communicator = communicator_cls(
|
||||||
input_layernorm=self.input_layernorm,
|
layer_scatter_modes=self.layer_scatter_modes,
|
||||||
post_attention_layernorm=self.post_attention_layernorm,
|
input_layernorm=self.input_layernorm,
|
||||||
allow_reduce_scatter=True,
|
post_attention_layernorm=self.post_attention_layernorm,
|
||||||
is_last_layer=(
|
allow_reduce_scatter=True,
|
||||||
is_nextn or (self.layer_id == self.config.num_hidden_layers - 1)
|
is_last_layer=(
|
||||||
),
|
is_nextn or (self.layer_id == self.config.num_hidden_layers - 1)
|
||||||
qkv_latent_func=self.self_attn.prepare_qkv_latent,
|
),
|
||||||
)
|
qkv_latent_func=self.self_attn.prepare_qkv_latent,
|
||||||
else:
|
)
|
||||||
self.layer_communicator = LayerCommunicator(
|
|
||||||
layer_scatter_modes=self.layer_scatter_modes,
|
|
||||||
input_layernorm=self.input_layernorm,
|
|
||||||
post_attention_layernorm=self.post_attention_layernorm,
|
|
||||||
allow_reduce_scatter=True,
|
|
||||||
is_last_layer=(
|
|
||||||
is_nextn or (self.layer_id == self.config.num_hidden_layers - 1)
|
|
||||||
),
|
|
||||||
qkv_latent_func=self.self_attn.prepare_qkv_latent,
|
|
||||||
)
|
|
||||||
|
|
||||||
def _detect_gfx95_quant_format(self) -> str:
|
def _detect_gfx95_quant_format(self) -> str:
|
||||||
if not _is_gfx95_supported:
|
if not _is_gfx95_supported:
|
||||||
@@ -2577,10 +2529,7 @@ class DeepseekV2DecoderLayer(nn.Module):
|
|||||||
gemm_output_zero_allocator,
|
gemm_output_zero_allocator,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (
|
if fuse_mlp_allreduce:
|
||||||
not (self.dsa_enable_prefill_cp or self.mla_enable_prefill_cp)
|
|
||||||
and fuse_mlp_allreduce
|
|
||||||
):
|
|
||||||
hidden_states._sglang_needs_allreduce_fusion = True
|
hidden_states._sglang_needs_allreduce_fusion = True
|
||||||
|
|
||||||
if not fuse_mlp_allreduce:
|
if not fuse_mlp_allreduce:
|
||||||
@@ -2666,14 +2615,6 @@ class DeepseekV2Model(nn.Module):
|
|||||||
self.vocab_size = config.vocab_size
|
self.vocab_size = config.vocab_size
|
||||||
self.first_k_dense_replace = config.first_k_dense_replace
|
self.first_k_dense_replace = config.first_k_dense_replace
|
||||||
self.pp_group = get_pp_group()
|
self.pp_group = get_pp_group()
|
||||||
self.dsa_enable_prefill_cp = is_dsa_enable_prefill_cp()
|
|
||||||
self.mla_enable_prefill_cp = (
|
|
||||||
is_prefill_context_parallel_enabled() and not self.use_dsa
|
|
||||||
)
|
|
||||||
if self.dsa_enable_prefill_cp or self.mla_enable_prefill_cp:
|
|
||||||
self.cp_size = get_parallel().attn_cp_size
|
|
||||||
else:
|
|
||||||
self.cp_size = None
|
|
||||||
|
|
||||||
if self.pp_group.is_first_rank:
|
if self.pp_group.is_first_rank:
|
||||||
self.embed_tokens = VocabParallelEmbedding(
|
self.embed_tokens = VocabParallelEmbedding(
|
||||||
@@ -2704,8 +2645,6 @@ class DeepseekV2Model(nn.Module):
|
|||||||
prefix=prefix,
|
prefix=prefix,
|
||||||
alt_stream=self.alt_stream,
|
alt_stream=self.alt_stream,
|
||||||
skip_rope=config.qk_rope_head_dim == 0,
|
skip_rope=config.qk_rope_head_dim == 0,
|
||||||
dsa_enable_prefill_cp=self.dsa_enable_prefill_cp,
|
|
||||||
mla_enable_prefill_cp=self.mla_enable_prefill_cp,
|
|
||||||
),
|
),
|
||||||
pp_rank=self.pp_group.rank_in_group,
|
pp_rank=self.pp_group.rank_in_group,
|
||||||
pp_size=self.pp_group.world_size,
|
pp_size=self.pp_group.world_size,
|
||||||
@@ -2864,13 +2803,11 @@ class DeepseekV2Model(nn.Module):
|
|||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
|
|
||||||
# CP-v2 shards/gathers at the eager-runner boundary instead.
|
# HIP/NPU/MUSA retain their model-side CP boundary.
|
||||||
use_cp_v1 = (
|
use_platform_cp = not enable_cp_v2() and (
|
||||||
dsa_use_prefill_cp(forward_batch, self.dsa_enable_prefill_cp)
|
dsa_use_prefill_cp(forward_batch) or mla_use_prefill_cp(forward_batch)
|
||||||
or mla_use_prefill_cp(forward_batch, self.mla_enable_prefill_cp)
|
)
|
||||||
) and not is_cp_v2_active(forward_batch)
|
if use_platform_cp:
|
||||||
|
|
||||||
if use_cp_v1:
|
|
||||||
if self.pp_group.is_first_rank:
|
if self.pp_group.is_first_rank:
|
||||||
hidden_states = cp_split_and_rebuild_data(forward_batch, hidden_states)
|
hidden_states = cp_split_and_rebuild_data(forward_batch, hidden_states)
|
||||||
positions = cp_split_and_rebuild_position(forward_batch, positions)
|
positions = cp_split_and_rebuild_position(forward_batch, positions)
|
||||||
@@ -2974,11 +2911,11 @@ class DeepseekV2Model(nn.Module):
|
|||||||
else:
|
else:
|
||||||
hidden_states, _ = self.norm(hidden_states, residual)
|
hidden_states, _ = self.norm(hidden_states, residual)
|
||||||
|
|
||||||
if self.pp_group.is_last_rank and use_cp_v1:
|
if self.pp_group.is_last_rank and use_platform_cp:
|
||||||
# allgather + rerrange
|
# allgather + rerrange
|
||||||
hidden_states = cp_all_gather_rerange_output(
|
hidden_states = cp_all_gather_rerange_output(
|
||||||
hidden_states,
|
hidden_states,
|
||||||
self.cp_size,
|
get_parallel().attn_cp_size,
|
||||||
forward_batch,
|
forward_batch,
|
||||||
torch.cuda.current_stream(),
|
torch.cuda.current_stream(),
|
||||||
)
|
)
|
||||||
@@ -3051,16 +2988,6 @@ class DeepseekV2ForCausalLM(nn.Module, DeepseekV2WeightLoaderMixin):
|
|||||||
)
|
)
|
||||||
self.capture_aux_hidden_states = False
|
self.capture_aux_hidden_states = False
|
||||||
|
|
||||||
self.dsa_enable_prefill_cp = is_dsa_enable_prefill_cp()
|
|
||||||
self.mla_enable_prefill_cp = (
|
|
||||||
is_prefill_context_parallel_enabled() and not is_deepseek_dsa(config)
|
|
||||||
)
|
|
||||||
if self.dsa_enable_prefill_cp or self.mla_enable_prefill_cp:
|
|
||||||
self.cp_rank = get_parallel().attn_cp_rank
|
|
||||||
self.cp_size = get_parallel().attn_cp_size
|
|
||||||
else:
|
|
||||||
self.cp_rank = self.cp_size = None
|
|
||||||
|
|
||||||
q_lora_rank = config.q_lora_rank if hasattr(config, "q_lora_rank") else None
|
q_lora_rank = config.q_lora_rank if hasattr(config, "q_lora_rank") else None
|
||||||
get_attn_tp_context().init_context(q_lora_rank, is_deepseek_dsa(config))
|
get_attn_tp_context().init_context(q_lora_rank, is_deepseek_dsa(config))
|
||||||
|
|
||||||
@@ -3161,24 +3088,29 @@ class DeepseekV2ForCausalLM(nn.Module, DeepseekV2WeightLoaderMixin):
|
|||||||
len_input_ids = input_embeds.shape[0]
|
len_input_ids = input_embeds.shape[0]
|
||||||
else:
|
else:
|
||||||
len_input_ids = pp_proxy_tensors["hidden_states"].shape[0]
|
len_input_ids = pp_proxy_tensors["hidden_states"].shape[0]
|
||||||
if not is_cp_v2_active(forward_batch):
|
if not enable_cp_v2():
|
||||||
if self.dsa_enable_prefill_cp:
|
if is_dsa_enable_prefill_cp():
|
||||||
if can_dsa_cp_split(
|
if can_dsa_cp_split(
|
||||||
len_input_ids, self.cp_size, self.use_dsa, forward_batch
|
len_input_ids,
|
||||||
|
get_parallel().attn_cp_size,
|
||||||
|
self.use_dsa,
|
||||||
|
forward_batch,
|
||||||
):
|
):
|
||||||
forward_batch.attn_cp_metadata = prepare_context_parallel_metadata(
|
forward_batch.attn_cp_metadata = prepare_context_parallel_metadata(
|
||||||
len_input_ids,
|
len_input_ids,
|
||||||
self.cp_rank,
|
get_parallel().attn_cp_rank,
|
||||||
self.cp_size,
|
get_parallel().attn_cp_size,
|
||||||
forward_batch.seq_lens_cpu.tolist(),
|
forward_batch.seq_lens_cpu.tolist(),
|
||||||
extend_seqs_len=forward_batch.extend_seq_lens_cpu,
|
extend_seqs_len=forward_batch.extend_seq_lens_cpu,
|
||||||
)
|
)
|
||||||
elif self.mla_enable_prefill_cp:
|
elif is_prefill_context_parallel_enabled() and not self.use_dsa:
|
||||||
if can_cp_split(len_input_ids, self.cp_size, forward_batch):
|
if can_cp_split(
|
||||||
|
len_input_ids, get_parallel().attn_cp_size, forward_batch
|
||||||
|
):
|
||||||
forward_batch.attn_cp_metadata = prepare_context_parallel_metadata(
|
forward_batch.attn_cp_metadata = prepare_context_parallel_metadata(
|
||||||
len_input_ids,
|
len_input_ids,
|
||||||
self.cp_rank,
|
get_parallel().attn_cp_rank,
|
||||||
self.cp_size,
|
get_parallel().attn_cp_size,
|
||||||
forward_batch.seq_lens_cpu.tolist(),
|
forward_batch.seq_lens_cpu.tolist(),
|
||||||
extend_seqs_len=forward_batch.extend_seq_lens_cpu,
|
extend_seqs_len=forward_batch.extend_seq_lens_cpu,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ from sglang.srt.layers.communicator_dsa_cp import (
|
|||||||
from sglang.srt.layers.cp.cp_decode_attn_tp import get_cp_decode_attn_tp_ctx
|
from sglang.srt.layers.cp.cp_decode_attn_tp import get_cp_decode_attn_tp_ctx
|
||||||
from sglang.srt.layers.cp.utils import (
|
from sglang.srt.layers.cp.utils import (
|
||||||
cp_materialize_global_token_order,
|
cp_materialize_global_token_order,
|
||||||
cp_round_robin_input_ids_v2,
|
enable_cp_v2,
|
||||||
is_cp_v2_active,
|
is_cp_v2_active,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.dp_attention import (
|
from sglang.srt.layers.dp_attention import (
|
||||||
@@ -3223,8 +3223,6 @@ class DeepseekV4Model(nn.Module):
|
|||||||
input_embeds: Optional[torch.Tensor],
|
input_embeds: Optional[torch.Tensor],
|
||||||
pp_proxy_tensors: Optional[PPProxyTensors] = None,
|
pp_proxy_tensors: Optional[PPProxyTensors] = None,
|
||||||
) -> Union[torch.Tensor, PPProxyTensors]:
|
) -> Union[torch.Tensor, PPProxyTensors]:
|
||||||
cp_v2_active = is_cp_v2_active(forward_batch)
|
|
||||||
use_prefill_cp = dsa_use_prefill_cp(forward_batch)
|
|
||||||
if self.pp_group.is_first_rank:
|
if self.pp_group.is_first_rank:
|
||||||
if input_embeds is None:
|
if input_embeds is None:
|
||||||
hidden_states = self.embed_tokens(input_ids)
|
hidden_states = self.embed_tokens(input_ids)
|
||||||
@@ -3254,7 +3252,7 @@ class DeepseekV4Model(nn.Module):
|
|||||||
)
|
)
|
||||||
input_ids_global = input_ids_global.squeeze(-1)
|
input_ids_global = input_ids_global.squeeze(-1)
|
||||||
else:
|
else:
|
||||||
input_ids_global = input_ids
|
input_ids_global = getattr(forward_batch, "input_ids_global", input_ids)
|
||||||
|
|
||||||
capture_dspark = self.dspark_layers_to_capture is not None
|
capture_dspark = self.dspark_layers_to_capture is not None
|
||||||
dspark_aux_hidden_states: List[torch.Tensor] = []
|
dspark_aux_hidden_states: List[torch.Tensor] = []
|
||||||
@@ -3262,16 +3260,12 @@ class DeepseekV4Model(nn.Module):
|
|||||||
# execution cannot expose per-layer completed hidden states), so skip
|
# execution cannot expose per-layer completed hidden states), so skip
|
||||||
# TBO when capturing -- a perf-only downgrade, not a correctness one.
|
# TBO when capturing -- a perf-only downgrade, not a correctness one.
|
||||||
run_tbo = self._can_run_tbo(forward_batch) and not capture_dspark
|
run_tbo = self._can_run_tbo(forward_batch) and not capture_dspark
|
||||||
if use_prefill_cp and not run_tbo:
|
use_platform_cp = not enable_cp_v2() and dsa_use_prefill_cp(forward_batch)
|
||||||
if cp_v2_active:
|
if use_platform_cp and not run_tbo:
|
||||||
input_ids = cp_round_robin_input_ids_v2(input_ids, forward_batch)
|
if self.pp_group.is_first_rank:
|
||||||
else:
|
hidden_states = cp_split_and_rebuild_data(forward_batch, hidden_states)
|
||||||
if self.pp_group.is_first_rank:
|
positions = cp_split_and_rebuild_position(forward_batch, positions)
|
||||||
hidden_states = cp_split_and_rebuild_data(
|
input_ids = cp_round_robin_input_ids(input_ids)
|
||||||
forward_batch, hidden_states
|
|
||||||
)
|
|
||||||
positions = cp_split_and_rebuild_position(forward_batch, positions)
|
|
||||||
input_ids = cp_round_robin_input_ids(input_ids)
|
|
||||||
input_ids_global = input_ids
|
input_ids_global = input_ids
|
||||||
|
|
||||||
# Reset Compressor's per-step freqs_cis cache from any previous step.
|
# Reset Compressor's per-step freqs_cis cache from any previous step.
|
||||||
@@ -3323,12 +3317,7 @@ class DeepseekV4Model(nn.Module):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# CP all-gather only on the last PP rank; PP IPC carries CP-split tensors.
|
# CP all-gather only on the last PP rank; PP IPC carries CP-split tensors.
|
||||||
if (
|
if self.pp_group.is_last_rank and use_platform_cp and not run_tbo:
|
||||||
self.pp_group.is_last_rank
|
|
||||||
and use_prefill_cp
|
|
||||||
and not cp_v2_active
|
|
||||||
and not run_tbo
|
|
||||||
):
|
|
||||||
stream = torch.cuda.current_stream()
|
stream = torch.cuda.current_stream()
|
||||||
hidden_states = cp_all_gather_rerange_output(
|
hidden_states = cp_all_gather_rerange_output(
|
||||||
hidden_states,
|
hidden_states,
|
||||||
@@ -3489,7 +3478,7 @@ class DeepseekV4ForCausalLM(nn.Module):
|
|||||||
input_embeds: Optional[torch.Tensor] = None,
|
input_embeds: Optional[torch.Tensor] = None,
|
||||||
pp_proxy_tensors: Optional[PPProxyTensors] = None,
|
pp_proxy_tensors: Optional[PPProxyTensors] = None,
|
||||||
) -> torch.Tensor:
|
) -> torch.Tensor:
|
||||||
if self.dsa_enable_prefill_cp:
|
if not enable_cp_v2() and self.dsa_enable_prefill_cp:
|
||||||
if can_dsa_cp_split(len(input_ids), self.cp_size, True, forward_batch):
|
if can_dsa_cp_split(len(input_ids), self.cp_size, True, forward_batch):
|
||||||
forward_batch.attn_cp_metadata = prepare_context_parallel_metadata(
|
forward_batch.attn_cp_metadata = prepare_context_parallel_metadata(
|
||||||
len(input_ids),
|
len(input_ids),
|
||||||
|
|||||||
@@ -14,8 +14,7 @@ from sglang.srt.layers.attention.dsa.utils import (
|
|||||||
is_dsa_prefill_cp_round_robin_split,
|
is_dsa_prefill_cp_round_robin_split,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.cp.utils import (
|
from sglang.srt.layers.cp.utils import (
|
||||||
cp_round_robin_input_ids_v2,
|
enable_cp_v2,
|
||||||
is_cp_v2_active,
|
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.dp_attention import (
|
from sglang.srt.layers.dp_attention import (
|
||||||
dp_gather_replicate,
|
dp_gather_replicate,
|
||||||
@@ -144,8 +143,7 @@ class DeepseekV4ModelNextN(nn.Module):
|
|||||||
forward_batch: ForwardBatch,
|
forward_batch: ForwardBatch,
|
||||||
input_embeds: torch.Tensor = None,
|
input_embeds: torch.Tensor = None,
|
||||||
) -> torch.Tensor:
|
) -> torch.Tensor:
|
||||||
cp_v2_active = is_cp_v2_active(forward_batch)
|
use_platform_cp = not enable_cp_v2() and dsa_use_prefill_cp(forward_batch)
|
||||||
use_prefill_cp = dsa_use_prefill_cp(forward_batch)
|
|
||||||
if input_embeds is None:
|
if input_embeds is None:
|
||||||
hidden_states = self.embed_tokens(input_ids)
|
hidden_states = self.embed_tokens(input_ids)
|
||||||
else:
|
else:
|
||||||
@@ -179,15 +177,12 @@ class DeepseekV4ModelNextN(nn.Module):
|
|||||||
)
|
)
|
||||||
input_ids_global = input_ids_global.squeeze(-1)
|
input_ids_global = input_ids_global.squeeze(-1)
|
||||||
else:
|
else:
|
||||||
input_ids_global = input_ids
|
input_ids_global = getattr(forward_batch, "input_ids_global", input_ids)
|
||||||
|
|
||||||
if use_prefill_cp:
|
if use_platform_cp:
|
||||||
if cp_v2_active:
|
hidden_states = cp_split_and_rebuild_data(forward_batch, hidden_states)
|
||||||
input_ids = cp_round_robin_input_ids_v2(input_ids, forward_batch)
|
positions = cp_split_and_rebuild_position(forward_batch, positions)
|
||||||
else:
|
input_ids = cp_round_robin_input_ids(input_ids)
|
||||||
hidden_states = cp_split_and_rebuild_data(forward_batch, hidden_states)
|
|
||||||
positions = cp_split_and_rebuild_position(forward_batch, positions)
|
|
||||||
input_ids = cp_round_robin_input_ids(input_ids)
|
|
||||||
input_ids_global = input_ids
|
input_ids_global = input_ids
|
||||||
|
|
||||||
hidden_states, residual, post, comb = self.decoder(
|
hidden_states, residual, post, comb = self.decoder(
|
||||||
@@ -202,7 +197,7 @@ class DeepseekV4ModelNextN(nn.Module):
|
|||||||
# deferred fused hc_post state.
|
# deferred fused hc_post state.
|
||||||
hidden_states = self.decoder.hc_post(hidden_states, residual, post, comb)
|
hidden_states = self.decoder.hc_post(hidden_states, residual, post, comb)
|
||||||
|
|
||||||
if use_prefill_cp and not cp_v2_active:
|
if use_platform_cp:
|
||||||
hidden_states = cp_all_gather_rerange_output(
|
hidden_states = cp_all_gather_rerange_output(
|
||||||
hidden_states,
|
hidden_states,
|
||||||
self.cp_size,
|
self.cp_size,
|
||||||
@@ -260,7 +255,7 @@ class DeepseekV4ForCausalLMNextN(DeepseekV4ForCausalLM):
|
|||||||
positions: torch.Tensor,
|
positions: torch.Tensor,
|
||||||
forward_batch: ForwardBatch,
|
forward_batch: ForwardBatch,
|
||||||
) -> torch.Tensor:
|
) -> torch.Tensor:
|
||||||
if self.dsa_enable_prefill_cp and not is_cp_v2_active(forward_batch):
|
if self.dsa_enable_prefill_cp and not enable_cp_v2():
|
||||||
if can_dsa_cp_split(len(input_ids), self.cp_size, True, forward_batch):
|
if can_dsa_cp_split(len(input_ids), self.cp_size, True, forward_batch):
|
||||||
forward_batch.attn_cp_metadata = prepare_context_parallel_metadata(
|
forward_batch.attn_cp_metadata = prepare_context_parallel_metadata(
|
||||||
len(input_ids),
|
len(input_ids),
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ from sglang.srt.layers.communicator import (
|
|||||||
LayerScatterModes,
|
LayerScatterModes,
|
||||||
ScatterMode,
|
ScatterMode,
|
||||||
)
|
)
|
||||||
from sglang.srt.layers.cp.utils import is_cp_v2_active
|
from sglang.srt.layers.cp.utils import enable_cp_v2
|
||||||
from sglang.srt.layers.dp_attention import (
|
from sglang.srt.layers.dp_attention import (
|
||||||
is_dp_attention_enabled,
|
is_dp_attention_enabled,
|
||||||
)
|
)
|
||||||
@@ -1132,7 +1132,7 @@ class Qwen2MoeModel(nn.Module):
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
is_prefill_context_parallel_enabled()
|
is_prefill_context_parallel_enabled()
|
||||||
and not is_cp_v2_active(forward_batch)
|
and not enable_cp_v2()
|
||||||
and forward_batch.forward_mode.is_context_parallel_extend()
|
and forward_batch.forward_mode.is_context_parallel_extend()
|
||||||
and forward_batch.attn_cp_metadata is not None
|
and forward_batch.attn_cp_metadata is not None
|
||||||
):
|
):
|
||||||
@@ -1198,7 +1198,7 @@ class Qwen2MoeModel(nn.Module):
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
self.pp_group.is_last_rank
|
self.pp_group.is_last_rank
|
||||||
and not is_cp_v2_active(forward_batch)
|
and not enable_cp_v2()
|
||||||
and is_prefill_context_parallel_enabled()
|
and is_prefill_context_parallel_enabled()
|
||||||
and forward_batch.forward_mode.is_context_parallel_extend()
|
and forward_batch.forward_mode.is_context_parallel_extend()
|
||||||
and forward_batch.attn_cp_metadata is not None
|
and forward_batch.attn_cp_metadata is not None
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ from sglang.srt.eplb.expert_distribution import get_global_expert_distribution_r
|
|||||||
from sglang.srt.eplb.expert_location import ModelConfigForExpertLocation
|
from sglang.srt.eplb.expert_location import ModelConfigForExpertLocation
|
||||||
from sglang.srt.eplb.expert_location_dispatch import ExpertLocationDispatchInfo
|
from sglang.srt.eplb.expert_location_dispatch import ExpertLocationDispatchInfo
|
||||||
from sglang.srt.layers.communicator import LayerCommunicator, LayerScatterModes
|
from sglang.srt.layers.communicator import LayerCommunicator, LayerScatterModes
|
||||||
from sglang.srt.layers.cp.utils import is_cp_v2_active
|
from sglang.srt.layers.cp.utils import enable_cp_v2
|
||||||
from sglang.srt.layers.layernorm import RMSNorm
|
from sglang.srt.layers.layernorm import RMSNorm
|
||||||
from sglang.srt.layers.linear import (
|
from sglang.srt.layers.linear import (
|
||||||
QKVParallelLinear,
|
QKVParallelLinear,
|
||||||
@@ -995,7 +995,7 @@ class Qwen3MoeForCausalLM(nn.Module):
|
|||||||
input_embeds: torch.Tensor = None,
|
input_embeds: torch.Tensor = None,
|
||||||
pp_proxy_tensors: Optional[PPProxyTensors] = None,
|
pp_proxy_tensors: Optional[PPProxyTensors] = None,
|
||||||
) -> torch.Tensor:
|
) -> torch.Tensor:
|
||||||
if is_prefill_context_parallel_enabled() and not is_cp_v2_active(forward_batch):
|
if is_prefill_context_parallel_enabled() and not enable_cp_v2():
|
||||||
if can_cp_split(len(input_ids), self.attn_cp_size, forward_batch):
|
if can_cp_split(len(input_ids), self.attn_cp_size, forward_batch):
|
||||||
forward_batch.attn_cp_metadata = prepare_context_parallel_metadata(
|
forward_batch.attn_cp_metadata = prepare_context_parallel_metadata(
|
||||||
len(input_ids),
|
len(input_ids),
|
||||||
|
|||||||
@@ -30,14 +30,14 @@ from sglang.kernels.ops.layernorm.norm import (
|
|||||||
fused_inplace_qknorm,
|
fused_inplace_qknorm,
|
||||||
)
|
)
|
||||||
from sglang.srt.environ import envs
|
from sglang.srt.environ import envs
|
||||||
|
from sglang.srt.layers.cp.utils import is_cp_v2_active
|
||||||
from sglang.srt.layers.radix_attention import RadixAttention
|
from sglang.srt.layers.radix_attention import RadixAttention
|
||||||
from sglang.srt.layers.utils.cp_utils import is_prefill_context_parallel_enabled
|
|
||||||
from sglang.srt.mem_cache.swa_memory_pool import SWAKVPool
|
from sglang.srt.mem_cache.swa_memory_pool import SWAKVPool
|
||||||
from sglang.srt.model_executor.forward_batch_info import ForwardBatch
|
from sglang.srt.model_executor.forward_batch_info import ForwardBatch
|
||||||
from sglang.srt.model_executor.forward_context import get_token_to_kv_pool
|
from sglang.srt.model_executor.forward_context import get_token_to_kv_pool
|
||||||
from sglang.srt.model_executor.runner import get_is_capture_mode
|
from sglang.srt.model_executor.runner import get_is_capture_mode
|
||||||
from sglang.srt.model_loader.weight_utils import default_weight_loader
|
from sglang.srt.model_loader.weight_utils import default_weight_loader
|
||||||
from sglang.srt.runtime_context import get_exec
|
from sglang.srt.runtime_context import get_exec, get_parallel
|
||||||
from sglang.srt.utils import get_current_device_stream_fast, is_cuda, is_hip
|
from sglang.srt.utils import get_current_device_stream_fast, is_cuda, is_hip
|
||||||
from sglang.srt.utils.custom_op import register_custom_op
|
from sglang.srt.utils.custom_op import register_custom_op
|
||||||
|
|
||||||
@@ -296,11 +296,11 @@ def enable_fused_set_kv_buffer(forward_batch: ForwardBatch):
|
|||||||
_is_cuda
|
_is_cuda
|
||||||
and pool.dtype == torch.bfloat16
|
and pool.dtype == torch.bfloat16
|
||||||
and not isinstance(pool, SWAKVPool)
|
and not isinstance(pool, SWAKVPool)
|
||||||
and not is_prefill_context_parallel_enabled()
|
and not is_cp_v2_active(forward_batch)
|
||||||
and getattr(forward_batch, "dcp_kv_mask", None) is None
|
and getattr(forward_batch, "dcp_kv_mask", None) is None
|
||||||
) or (
|
) or (
|
||||||
_is_hip
|
_is_hip
|
||||||
and not is_prefill_context_parallel_enabled()
|
and not get_parallel().enable_prefill_context_parallel
|
||||||
and getattr(forward_batch, "dcp_kv_mask", None) is None
|
and getattr(forward_batch, "dcp_kv_mask", None) is None
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -342,12 +342,11 @@ class DSAMockModelRunner(ModelRunner):
|
|||||||
dllm_algorithm_config=None,
|
dllm_algorithm_config=None,
|
||||||
dp_size=1,
|
dp_size=1,
|
||||||
dsa_decode_backend=dsa_decode_backend,
|
dsa_decode_backend=dsa_decode_backend,
|
||||||
dsa_prefill_cp_mode="round-robin-split",
|
|
||||||
dsa_prefill_backend=dsa_prefill_backend,
|
dsa_prefill_backend=dsa_prefill_backend,
|
||||||
device=device,
|
device=device,
|
||||||
enable_deterministic_inference=False,
|
enable_deterministic_inference=False,
|
||||||
enable_dp_attention=False,
|
enable_dp_attention=False,
|
||||||
enable_dsa_prefill_context_parallel=False,
|
enable_prefill_cp=False,
|
||||||
enable_mis=False,
|
enable_mis=False,
|
||||||
is_embedding=False,
|
is_embedding=False,
|
||||||
kv_cache_dtype="auto",
|
kv_cache_dtype="auto",
|
||||||
|
|||||||
@@ -597,17 +597,7 @@ class TestCPZigzagStrategy(CustomTestCase):
|
|||||||
max_rank_len=[7, 7],
|
max_rank_len=[7, 7],
|
||||||
)
|
)
|
||||||
|
|
||||||
with (
|
with get_parallel().override(attn_cp_size=cp_size):
|
||||||
get_parallel().override(attn_cp_size=cp_size),
|
|
||||||
patch(
|
|
||||||
"sglang.srt.layers.utils.cp_utils.is_prefill_cp_in_seq_split",
|
|
||||||
return_value=True,
|
|
||||||
),
|
|
||||||
patch(
|
|
||||||
"sglang.srt.layers.attention.dsa.utils.is_dsa_prefill_cp_in_seq_split",
|
|
||||||
return_value=False,
|
|
||||||
),
|
|
||||||
):
|
|
||||||
align_size = get_cp_padding_align_size()
|
align_size = get_cp_padding_align_size()
|
||||||
pad_logical_token_to_physical(metadata)
|
pad_logical_token_to_physical(metadata)
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import pytest
|
|||||||
import torch
|
import torch
|
||||||
|
|
||||||
from sglang.srt.layers.attention.index_topk_share import IndexTopKShareState
|
from sglang.srt.layers.attention.index_topk_share import IndexTopKShareState
|
||||||
|
from sglang.srt.model_executor.forward_batch_info import ForwardMode
|
||||||
from sglang.test.ci.ci_register import register_cpu_ci
|
from sglang.test.ci.ci_register import register_cpu_ci
|
||||||
|
|
||||||
register_cpu_ci(est_time=6, suite="base-a-test-cpu")
|
register_cpu_ci(est_time=6, suite="base-a-test-cpu")
|
||||||
@@ -15,9 +16,7 @@ def _batch(
|
|||||||
) -> SimpleNamespace:
|
) -> SimpleNamespace:
|
||||||
return SimpleNamespace(
|
return SimpleNamespace(
|
||||||
reuse_dsa_topk_indices=reuse,
|
reuse_dsa_topk_indices=reuse,
|
||||||
forward_mode=SimpleNamespace(
|
forward_mode=ForwardMode.DRAFT_EXTEND_V2 if is_extend else ForwardMode.DECODE,
|
||||||
is_extend=lambda include_draft_extend_v2: is_extend
|
|
||||||
),
|
|
||||||
spec_info=SimpleNamespace(
|
spec_info=SimpleNamespace(
|
||||||
dsa_topk_indices=carried,
|
dsa_topk_indices=carried,
|
||||||
dsa_seed_topk_capture=seed_buf,
|
dsa_seed_topk_capture=seed_buf,
|
||||||
|
|||||||
@@ -14,6 +14,11 @@ import unittest
|
|||||||
from types import SimpleNamespace
|
from types import SimpleNamespace
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
from sglang.srt.layers.cp import base as cp_base
|
||||||
|
from sglang.srt.layers.cp import utils as cp_utils
|
||||||
|
from sglang.srt.layers.cp.zigzag import ZigzagCPStrategy
|
||||||
|
from sglang.srt.layers.utils import cp_utils as platform_cp_utils
|
||||||
|
from sglang.srt.model_executor.forward_batch_info import ForwardMode
|
||||||
from sglang.srt.models.deepseek_common import attention_backend_handler as abh
|
from sglang.srt.models.deepseek_common import attention_backend_handler as abh
|
||||||
from sglang.srt.models.deepseek_common.attention_forward_methods.forward_methods import (
|
from sglang.srt.models.deepseek_common.attention_forward_methods.forward_methods import (
|
||||||
AttnForwardMethod,
|
AttnForwardMethod,
|
||||||
@@ -95,5 +100,55 @@ class TestResolveRocmForwardMethod(CustomTestCase):
|
|||||||
self.assertEqual(abh.resolve_rocm_forward_method(method), method)
|
self.assertEqual(abh.resolve_rocm_forward_method(method), method)
|
||||||
|
|
||||||
|
|
||||||
|
class TestCPMLADispatch(CustomTestCase):
|
||||||
|
def test_strategy_cp_uses_absorbed_mla_without_legacy_flags(self):
|
||||||
|
# Normal MHA writes rank-local KV against full out_cache_loc before
|
||||||
|
# the CP backend can gather it. Both one-shot and chunked MHA must
|
||||||
|
# therefore be bypassed for an active strategy-based CP batch.
|
||||||
|
attn = SimpleNamespace(
|
||||||
|
chunked_prefix_cache_threshold=0,
|
||||||
|
disable_chunked_prefix_cache=False,
|
||||||
|
flashinfer_mla_disable_ragged=False,
|
||||||
|
)
|
||||||
|
with (
|
||||||
|
mock.patch.object(abh, "_is_hip", False),
|
||||||
|
mock.patch.object(cp_utils, "enable_cp_v2", return_value=True),
|
||||||
|
mock.patch.object(cp_base, "_STRATEGY", ZigzagCPStrategy(cp_size=4)),
|
||||||
|
mock.patch.object(
|
||||||
|
platform_cp_utils,
|
||||||
|
"get_parallel",
|
||||||
|
return_value=SimpleNamespace(enable_prefill_context_parallel=False),
|
||||||
|
),
|
||||||
|
):
|
||||||
|
for prefix in (0, 32):
|
||||||
|
for capacity in (0, 8192):
|
||||||
|
for num_tokens in (1, 3952):
|
||||||
|
with self.subTest(
|
||||||
|
prefix=prefix, capacity=capacity, num_tokens=num_tokens
|
||||||
|
):
|
||||||
|
batch = SimpleNamespace(
|
||||||
|
forward_mode=ForwardMode.EXTEND,
|
||||||
|
input_ids=range(num_tokens),
|
||||||
|
attn_cp_metadata=None,
|
||||||
|
extend_prefix_lens_cpu=[prefix],
|
||||||
|
extend_seq_lens_cpu=[num_tokens],
|
||||||
|
seq_lens_cpu=[prefix + num_tokens],
|
||||||
|
get_max_chunk_capacity=lambda: capacity,
|
||||||
|
)
|
||||||
|
expected = (
|
||||||
|
AttnForwardMethod.MLA
|
||||||
|
if num_tokens == 3952
|
||||||
|
else (
|
||||||
|
AttnForwardMethod.MHA_ONE_SHOT
|
||||||
|
if capacity == 8192
|
||||||
|
else AttnForwardMethod.MHA_CHUNKED_KV
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
abh._handle_attention_backend(attn, batch, "fa3"),
|
||||||
|
expected,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
@@ -1075,28 +1075,22 @@ class TestContextParallelServerArgs(CustomTestCase):
|
|||||||
with self.assertRaisesRegex(ValueError, "DeepSeek V3.2.*interleave"):
|
with self.assertRaisesRegex(ValueError, "DeepSeek V3.2.*interleave"):
|
||||||
handle_context_parallelism(server_args)
|
handle_context_parallelism(server_args)
|
||||||
|
|
||||||
@override_platform(is_hip=False, is_npu=False)
|
@override_platform(is_hip=False, is_npu=False, is_musa=False)
|
||||||
def test_generic_canonical_cp_mirrors_to_transitional_runtime_fields(self):
|
def test_generic_canonical_cp_does_not_enable_platform_runtime_fields(self):
|
||||||
cases = (
|
cases = (
|
||||||
(
|
(
|
||||||
"zigzag_mla_or_gqa",
|
"zigzag_mla_or_gqa",
|
||||||
"zigzag",
|
"zigzag",
|
||||||
"fa3",
|
"fa3",
|
||||||
True,
|
|
||||||
False,
|
|
||||||
"in-seq-split",
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"interleave_dsa",
|
"interleave_dsa",
|
||||||
"interleave",
|
"interleave",
|
||||||
"dsa",
|
"dsa",
|
||||||
False,
|
|
||||||
True,
|
|
||||||
"round-robin-split",
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
for name, strategy, backend, expect_generic, expect_dsa, mode in cases:
|
for name, strategy, backend in cases:
|
||||||
with self.subTest(name=name):
|
with self.subTest(name=name):
|
||||||
server_args = self._new_cp_args(
|
server_args = self._new_cp_args(
|
||||||
enable_prefill_cp=True,
|
enable_prefill_cp=True,
|
||||||
@@ -1105,6 +1099,7 @@ class TestContextParallelServerArgs(CustomTestCase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
handle_platform_cp_compatibility(server_args)
|
handle_platform_cp_compatibility(server_args)
|
||||||
|
handle_legacy_cp_runtime_compatibility(server_args)
|
||||||
|
|
||||||
self.assertFalse(
|
self.assertFalse(
|
||||||
resolution_result(server_args, "enable_prefill_context_parallel")
|
resolution_result(server_args, "enable_prefill_context_parallel")
|
||||||
@@ -1115,32 +1110,13 @@ class TestContextParallelServerArgs(CustomTestCase):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
handle_legacy_cp_runtime_compatibility(server_args)
|
@override_platform(is_hip=False, is_npu=False, is_musa=False)
|
||||||
|
|
||||||
self.assertEqual(
|
|
||||||
resolution_result(server_args, "enable_prefill_context_parallel"),
|
|
||||||
expect_generic,
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
resolution_result(
|
|
||||||
server_args, "enable_dsa_prefill_context_parallel"
|
|
||||||
),
|
|
||||||
expect_dsa,
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
resolution_result(server_args, "dsa_prefill_cp_mode"), mode
|
|
||||||
)
|
|
||||||
self.assertEqual(
|
|
||||||
resolution_result(server_args, "prefill_cp_mode"), mode
|
|
||||||
)
|
|
||||||
|
|
||||||
@override_platform(is_hip=False, is_npu=False)
|
|
||||||
def test_non_platform_legacy_prefill_cp_is_rejected(self):
|
def test_non_platform_legacy_prefill_cp_is_rejected(self):
|
||||||
server_args = ServerArgs(
|
server_args = ServerArgs(
|
||||||
model_path="instance://127.0.0.1:8000/dummy",
|
model_path="instance://127.0.0.1:8000/dummy",
|
||||||
enable_prefill_context_parallel=True,
|
enable_prefill_context_parallel=True,
|
||||||
)
|
)
|
||||||
with self.assertRaisesRegex(ValueError, "HIP or Ascend NPU"):
|
with self.assertRaisesRegex(ValueError, "protected HIP, Ascend NPU, or MUSA"):
|
||||||
handle_platform_cp_compatibility(server_args)
|
handle_platform_cp_compatibility(server_args)
|
||||||
|
|
||||||
def test_generic_v1_cp_options_are_not_public_cli(self):
|
def test_generic_v1_cp_options_are_not_public_cli(self):
|
||||||
@@ -1172,28 +1148,36 @@ class TestContextParallelServerArgs(CustomTestCase):
|
|||||||
resolution_result(args, "dsa_prefill_cp_mode"), "round-robin-split"
|
resolution_result(args, "dsa_prefill_cp_mode"), "round-robin-split"
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_canonical_interleave_cp_mirrors_to_dsa_runtime_aliases(self):
|
def test_platform_interleave_cp_mirrors_to_dsa_runtime_aliases(self):
|
||||||
server_args = self._new_cp_args(
|
for platform in ("is_hip", "is_npu", "is_musa"):
|
||||||
enable_prefill_cp=True,
|
facts = dict(is_hip=False, is_npu=False, is_musa=False)
|
||||||
cp_strategy="interleave",
|
facts[platform] = True
|
||||||
attention_backend="dsa",
|
with self.subTest(platform=platform), override_platform(**facts):
|
||||||
)
|
server_args = self._new_cp_args(
|
||||||
|
enable_prefill_cp=True,
|
||||||
|
cp_strategy="interleave",
|
||||||
|
attention_backend="dsa",
|
||||||
|
)
|
||||||
|
|
||||||
handle_legacy_cp_runtime_compatibility(server_args)
|
handle_legacy_cp_runtime_compatibility(server_args)
|
||||||
handle_context_parallelism(server_args)
|
handle_context_parallelism(server_args)
|
||||||
|
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
resolution_result(server_args, "enable_dsa_prefill_context_parallel")
|
resolution_result(
|
||||||
)
|
server_args, "enable_dsa_prefill_context_parallel"
|
||||||
self.assertFalse(
|
)
|
||||||
resolution_result(server_args, "enable_prefill_context_parallel")
|
)
|
||||||
)
|
self.assertFalse(
|
||||||
self.assertEqual(
|
resolution_result(server_args, "enable_prefill_context_parallel")
|
||||||
resolution_result(server_args, "dsa_prefill_cp_mode"), "round-robin-split"
|
)
|
||||||
)
|
self.assertEqual(
|
||||||
self.assertEqual(
|
resolution_result(server_args, "dsa_prefill_cp_mode"),
|
||||||
resolution_result(server_args, "prefill_cp_mode"), "round-robin-split"
|
"round-robin-split",
|
||||||
)
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
resolution_result(server_args, "prefill_cp_mode"),
|
||||||
|
"round-robin-split",
|
||||||
|
)
|
||||||
|
|
||||||
def test_context_parallel_handler_initializes_cp_strategy(self):
|
def test_context_parallel_handler_initializes_cp_strategy(self):
|
||||||
server_args = self._new_cp_args(
|
server_args = self._new_cp_args(
|
||||||
|
|||||||
Reference in New Issue
Block a user