From ff1285cc28d6b3e0ad19c45e8b14a5966bc95c78 Mon Sep 17 00:00:00 2001 From: Baizhou Zhang Date: Thu, 3 Sep 2026 20:24:19 -0700 Subject: [PATCH] [CP V1 Deprecation 2/5] Make strategy prefill CP canonical (#36223) --- .../sglang/srt/arg_groups/deepseek_v4_hook.py | 33 +-- python/sglang/srt/arg_groups/parallel_hook.py | 78 +++--- python/sglang/srt/arg_groups/pipeline.py | 15 +- python/sglang/srt/environ.py | 4 +- .../sglang/srt/layers/attention/dsa/utils.py | 9 +- python/sglang/srt/layers/cp/utils.py | 19 +- python/sglang/srt/server_args.py | 34 --- test/registered/cp/test_cp_strategy_unit.py | 89 ++++--- .../unit/server_args/test_server_args.py | 238 ++++++++---------- 9 files changed, 240 insertions(+), 279 deletions(-) diff --git a/python/sglang/srt/arg_groups/deepseek_v4_hook.py b/python/sglang/srt/arg_groups/deepseek_v4_hook.py index 551625c6d..42f515ca4 100644 --- a/python/sglang/srt/arg_groups/deepseek_v4_hook.py +++ b/python/sglang/srt/arg_groups/deepseek_v4_hook.py @@ -168,21 +168,24 @@ def validate_deepseek_v4_cp(server_args: ServerArgs) -> None: f"DeepSeekV4 only supports interleave CP strategy, got {cfg.cp_strategy}" ) - declare_resolution( - server_args, - "validate_deepseek_v4_cp", - enable_dsa_prefill_context_parallel=True, - ) - declare_resolution( - server_args, - "validate_deepseek_v4_cp", - enable_prefill_context_parallel=False, - ) - declare_resolution( - server_args, - "validate_deepseek_v4_cp", - dsa_prefill_cp_mode="round-robin-split", - ) + if get_platform().is_hip or get_platform().is_npu: + # Protected platform implementations still consume the legacy runtime + # fields. Generic backends use enable_prefill_cp/cp_strategy directly. + declare_resolution( + server_args, + "validate_deepseek_v4_cp", + enable_dsa_prefill_context_parallel=True, + ) + declare_resolution( + server_args, + "validate_deepseek_v4_cp", + enable_prefill_context_parallel=False, + ) + declare_resolution( + server_args, + "validate_deepseek_v4_cp", + dsa_prefill_cp_mode="round-robin-split", + ) declare_resolution( server_args, "validate_deepseek_v4_cp", diff --git a/python/sglang/srt/arg_groups/parallel_hook.py b/python/sglang/srt/arg_groups/parallel_hook.py index 7573a92ed..a76111a59 100644 --- a/python/sglang/srt/arg_groups/parallel_hook.py +++ b/python/sglang/srt/arg_groups/parallel_hook.py @@ -31,35 +31,36 @@ def handle_context_parallelism(server_args: Any): cfg = resolving_view(server_args) if parse_connector_type(cfg.model_path) != ConnectorType.INSTANCE: - from sglang.srt.configs.model_config import is_deepseek_dsa - from sglang.srt.layers.cp.utils import CP_V2_DEFAULT_MODEL_CLASSES - model_config = model_config_of(server_args) hf_config = model_config.hf_config model_arch = hf_config.architectures[0] - if model_arch in CP_V2_DEFAULT_MODEL_CLASSES: - is_dsa_default_model = is_deepseek_dsa(hf_config) - # DSA CP-v2 currently supports only the interleave strategy. - enable_default_cp_v2 = not is_dsa_default_model or ( - cfg.enable_prefill_cp and cfg.cp_strategy == "interleave" - ) - if enable_default_cp_v2 and not envs.SGLANG_ENABLE_CP_V2.is_set(): - envs.SGLANG_ENABLE_CP_V2.set(True) - + platform = get_platform() if ( cfg.enable_prefill_cp - and model_arch in ("MiMoV2ForCausalLM", "MiMoV2FlashForCausalLM") - and envs.SGLANG_ENABLE_CP_V2.get() + and model_arch == "DeepseekV32ForCausalLM" + and cfg.cp_strategy == "zigzag" + and not (platform.is_hip or platform.is_npu) + ): + raise ValueError( + "DeepSeek V3.2 prefill CP does not support --cp-strategy " + "zigzag; use interleave." + ) + if cfg.enable_prefill_cp and model_arch in ( + "MiMoV2ForCausalLM", + "MiMoV2FlashForCausalLM", ): if cfg.cp_strategy != "zigzag": - raise ValueError("MiMo V2 CP-v2 only supports --cp-strategy zigzag.") + raise ValueError( + "MiMo V2 prefill CP only supports --cp-strategy zigzag." + ) if ( model_config.is_multimodal and not cfg.language_only and not cfg.language_model_only ): raise ValueError( - "MiMo V2 CP-v2 only supports text inference; add --language-only." + "MiMo V2 prefill CP only supports text inference; add " + "--language-only." ) if cfg.enable_prefill_cp and cfg.cp_strategy is None: @@ -559,43 +560,62 @@ def handle_eplb_and_dispatch(server_args: Any): assert resolved_view(server_args).ep_size > 1 -def handle_legacy_cp_arguments(server_args: Any): +def handle_platform_cp_compatibility(server_args: Any): cfg = resolving_view(server_args) + platform = get_platform() + is_protected_platform = platform.is_hip or platform.is_npu + if not is_protected_platform: + if ( + server_args.enable_prefill_context_parallel + or server_args.enable_dsa_prefill_context_parallel + ): + raise ValueError( + "Legacy prefill context-parallel options are supported only " + "by protected HIP or Ascend NPU paths. Use " + "--enable-prefill-cp with --cp-strategy." + ) + return + legacy_mode_to_strategy = { "in-seq-split": "zigzag", "round-robin-split": "interleave", } - strategy_to_legacy_mode = { - "zigzag": "in-seq-split", - "interleave": "round-robin-split", - } if cfg.enable_prefill_context_parallel or cfg.enable_dsa_prefill_context_parallel: declare_resolution( server_args, - "_handle_legacy_cp_arguments", + "_handle_platform_cp_compatibility", enable_prefill_cp=True, ) if cfg.enable_prefill_context_parallel and cfg.cp_strategy is None: declare_resolution( server_args, - "_handle_legacy_cp_arguments", + "_handle_platform_cp_compatibility", cp_strategy=legacy_mode_to_strategy[cfg.prefill_cp_mode], ) if cfg.enable_dsa_prefill_context_parallel and cfg.cp_strategy is None: declare_resolution( server_args, - "_handle_legacy_cp_arguments", + "_handle_platform_cp_compatibility", cp_strategy=legacy_mode_to_strategy[cfg.dsa_prefill_cp_mode], ) + +def handle_legacy_cp_runtime_compatibility(server_args: Any): + """Project canonical CP settings for runtime consumers removed by PR3.""" + cfg = resolving_view(server_args) + if cfg.enable_prefill_context_parallel and cfg.enable_dsa_prefill_context_parallel: return if not cfg.enable_prefill_cp or cfg.cp_strategy is None: return + strategy_to_legacy_mode = { + "zigzag": "in-seq-split", + "interleave": "round-robin-split", + } mode = strategy_to_legacy_mode[cfg.cp_strategy] use_dsa_legacy_aliases = cfg.enable_dsa_prefill_context_parallel or getattr( resolved_view(server_args), "attention_backend", None @@ -603,28 +623,28 @@ def handle_legacy_cp_arguments(server_args: Any): if use_dsa_legacy_aliases: declare_resolution( server_args, - "_handle_legacy_cp_arguments", + "_handle_legacy_cp_runtime_compatibility", enable_dsa_prefill_context_parallel=True, ) declare_resolution( server_args, - "_handle_legacy_cp_arguments", + "_handle_legacy_cp_runtime_compatibility", enable_prefill_context_parallel=False, ) else: declare_resolution( server_args, - "_handle_legacy_cp_arguments", + "_handle_legacy_cp_runtime_compatibility", enable_prefill_context_parallel=True, ) declare_resolution( server_args, - "_handle_legacy_cp_arguments", + "_handle_legacy_cp_runtime_compatibility", dsa_prefill_cp_mode=mode, ) declare_resolution( server_args, - "_handle_legacy_cp_arguments", + "_handle_legacy_cp_runtime_compatibility", prefill_cp_mode=mode, ) diff --git a/python/sglang/srt/arg_groups/pipeline.py b/python/sglang/srt/arg_groups/pipeline.py index 5b9fd2364..74ed99b05 100644 --- a/python/sglang/srt/arg_groups/pipeline.py +++ b/python/sglang/srt/arg_groups/pipeline.py @@ -146,8 +146,8 @@ def run_resolution_pipeline(server_args: Any) -> None: handle_pd_disaggregation(server_args) - # Normalize deprecated CP aliases before validations or model-specific - # defaults inspect enable_prefill_cp/cp_strategy. + # Normalize protected-platform CP aliases before validations or + # model-specific defaults inspect enable_prefill_cp/cp_strategy. from sglang.srt.arg_groups.parallel_hook import ( handle_context_parallelism, handle_data_parallelism, @@ -156,10 +156,11 @@ def run_resolution_pipeline(server_args: Any) -> None: handle_elastic_ep, handle_eplb_and_dispatch, handle_expert_distribution_metrics, - handle_legacy_cp_arguments, + handle_legacy_cp_runtime_compatibility, + handle_platform_cp_compatibility, ) - handle_legacy_cp_arguments(server_args) + handle_platform_cp_compatibility(server_args) from sglang.srt.arg_groups.kv_cache_hook import ( handle_cache_compatibility, handle_kv4_compatibility, @@ -286,9 +287,9 @@ def run_resolution_pipeline(server_args: Any) -> None: # Normalize load balancing defaults. handle_load_balance_method(server_args) - # Re-apply after model-specific defaults resolve attention_backend so - # canonical CP mirrors to the right legacy runtime aliases. - handle_legacy_cp_arguments(server_args) + # The old runtime distinguishes DSA from other CP paths through legacy + # fields, so project only after attention_backend has been resolved. + handle_legacy_cp_runtime_compatibility(server_args) # Handle context parallelism. handle_context_parallelism(server_args) diff --git a/python/sglang/srt/environ.py b/python/sglang/srt/environ.py index fb5b25e84..7698b1200 100644 --- a/python/sglang/srt/environ.py +++ b/python/sglang/srt/environ.py @@ -677,7 +677,6 @@ class Envs: # =================================================================== # Distributed and model-parallel runtime # =================================================================== - SGLANG_ENABLE_CP_V2 = EnvBool(False) SGLANG_ONE_VISIBLE_DEVICE_PER_PROCESS = EnvBool(False) # Comma-separated bundle indices for Ray Custom PG mode (e.g., "0,1,2,7"). SGLANG_RAY_BUNDLE_INDICES = EnvStr("") @@ -1753,6 +1752,9 @@ _DEPRECATED_ENVS: Dict[str, _DeprecatedEnv] = { note="Note the unit change: milliseconds -> seconds.", ), # Removed without replacement. + "SGLANG_ENABLE_CP_V2": _DeprecatedEnv( + note="Strategy-based prefill context parallelism is now the only generic implementation." + ), "SGLANG_PER_TOKEN_GROUP_QUANT_8BIT_V2": _DeprecatedEnv(), # Superseded by the unified JIT per_token_group_quant, the default CUDA path. "SGLANG_OPT_USE_JIT_PER_TOKEN_GROUP_QUANT": _DeprecatedEnv(), diff --git a/python/sglang/srt/layers/attention/dsa/utils.py b/python/sglang/srt/layers/attention/dsa/utils.py index d9995a94d..b1ce79611 100644 --- a/python/sglang/srt/layers/attention/dsa/utils.py +++ b/python/sglang/srt/layers/attention/dsa/utils.py @@ -18,7 +18,7 @@ from sglang.srt.runtime_context import ( get_parallel, process_model_config, ) -from sglang.srt.utils import get_bool_env_var, is_cuda, is_hip +from sglang.srt.utils import get_bool_env_var, is_cuda, is_hip, is_npu from sglang.srt.utils.common import ceil_align, ceil_div @@ -105,12 +105,11 @@ def should_use_dsa_fused_topk(seed_dsa_topk_from_draft_extend: bool) -> bool: def is_dsa_enable_prefill_cp(): - if not envs.SGLANG_ENABLE_CP_V2.get(): + if is_hip() or is_npu(): return get_parallel().enable_dsa_prefill_context_parallel - # Derive from the runtime CP topology + model arch rather than the legacy - # flag under CP-v2: DSA prefill CP is active when the CP group is on for a - # DeepSeek Sparse Attention model. + # Generic prefill CP derives activation from the runtime topology and model + # architecture. Protected HIP/NPU paths continue to use their legacy field. if get_parallel().attn_cp_size <= 1: return False from sglang.srt.configs.model_config import is_deepseek_dsa, is_deepseek_v4 diff --git a/python/sglang/srt/layers/cp/utils.py b/python/sglang/srt/layers/cp/utils.py index 54157743f..21f46a0e4 100644 --- a/python/sglang/srt/layers/cp/utils.py +++ b/python/sglang/srt/layers/cp/utils.py @@ -40,18 +40,6 @@ from sglang.srt.runtime_context import get_parallel if TYPE_CHECKING: from sglang.srt.model_executor.model_runner import ModelRunner -CP_V2_DEFAULT_MODEL_CLASSES = frozenset( - { - "DeepseekV32ForCausalLM", - "GlmMoeDsaForCausalLM", - "GptOssForCausalLM", - "MiMoV2FlashForCausalLM", - "MiMoV2ForCausalLM", - "Qwen3MoeForCausalLM", - "DeepseekV3ForCausalLM", - } -) - def is_glm_dsa_cache_layer_split_enabled(model_runner: "ModelRunner") -> bool: """Whether DSA GPU KV/indexer cache layers are sharded across CP ranks. @@ -130,10 +118,10 @@ def get_layer_owner(local_layer_idx: int, shard_size: int, total_layers: int) -> def enable_cp_v2() -> bool: - """Return whether the CP-v2 path is enabled for this process.""" - from sglang.srt.environ import envs + """Return whether the strategy-based generic prefill CP path is available.""" + from sglang.srt.utils import is_hip, is_npu - return bool(envs.SGLANG_ENABLE_CP_V2.get()) + return not (is_hip() or is_npu()) def is_cp_v2_active(forward_batch) -> bool: @@ -322,7 +310,6 @@ __all__ = [ "InterleaveContextParallelMetadata", "ZigzagCPStrategy", "ZigzagContextParallelMetadata", - "CP_V2_DEFAULT_MODEL_CLASSES", "enable_cp_v2", "get_cp_strategy", "is_cp_v2_active", diff --git a/python/sglang/srt/server_args.py b/python/sglang/srt/server_args.py index afb985c55..1b21c9cad 100644 --- a/python/sglang/srt/server_args.py +++ b/python/sglang/srt/server_args.py @@ -4019,13 +4019,6 @@ class ServerArgs: dest="cuda_graph_max_bs_prefill", help="Deprecated alias for --cuda-graph-max-bs-prefill.", ) - parser.add_argument( - "--enable-dsa-prefill-context-parallel", - dest="enable_dsa_prefill_context_parallel", - action=DeprecatedStoreTrueAction, - new_flag="--enable-prefill-cp", - help="[Deprecated] Use --enable-prefill-cp instead.", - ) parser.add_argument( "--enable-nsa-prefill-context-parallel", dest="enable_dsa_prefill_context_parallel", @@ -4047,20 +4040,6 @@ class ServerArgs: new_flag="--enable-prefill-cp", help="[Deprecated] Use --enable-prefill-cp instead.", ) - parser.add_argument( - "--dsa-prefill-cp-mode", - dest="dsa_prefill_cp_mode", - action=DeprecatedAliasStoreAction, - new_flag="--cp-strategy", - type=str, - default=ServerArgs.dsa_prefill_cp_mode, - choices=["in-seq-split", "round-robin-split"], - help=( - "[Deprecated] Use --cp-strategy {zigzag,interleave} instead. " - "'in-seq-split' maps to 'zigzag'; 'round-robin-split' maps to " - "'interleave'." - ), - ) parser.add_argument( "--nsa-prefill-cp-mode", dest="dsa_prefill_cp_mode", @@ -4071,19 +4050,6 @@ class ServerArgs: choices=["in-seq-split", "round-robin-split"], help="[Deprecated] Use --cp-strategy instead.", ) - parser.add_argument( - "--prefill-cp-mode", - dest="prefill_cp_mode", - action=DeprecatedAliasStoreAction, - new_flag="--cp-strategy", - type=str, - default=ServerArgs.prefill_cp_mode, - choices=["in-seq-split"], - help=( - "[Deprecated] Use --cp-strategy {zigzag,interleave} instead. " - "'in-seq-split' maps to 'zigzag'." - ), - ) parser.add_argument( "--enable-flashinfer-allreduce-fusion", action="store_true", diff --git a/test/registered/cp/test_cp_strategy_unit.py b/test/registered/cp/test_cp_strategy_unit.py index 53cc4fa2e..321f81f1f 100644 --- a/test/registered/cp/test_cp_strategy_unit.py +++ b/test/registered/cp/test_cp_strategy_unit.py @@ -5,6 +5,7 @@ from unittest.mock import patch import torch +from sglang.srt.layers.attention.dsa.utils import is_dsa_enable_prefill_cp from sglang.srt.layers.cp.base import ( ContextParallelStrategyKind, get_cp_strategy, @@ -94,12 +95,43 @@ class TestCPStrategyUnit(CustomTestCase): cp_strategy="interleave", ) - with patch( - "sglang.srt.environ.envs.SGLANG_ENABLE_CP_V2.get", return_value=True + self.assertIsNotNone(get_cp_strategy()) + self.assertTrue(is_cp_enabled()) + self.assertTrue(is_interleave()) + + def test_hip_dsa_cp_uses_protected_legacy_runtime_flag(self): + parallel = SimpleNamespace( + enable_dsa_prefill_context_parallel=False, + attn_cp_size=2, + ) + model_config = SimpleNamespace(hf_config=SimpleNamespace()) + + with ( + patch( + "sglang.srt.layers.attention.dsa.utils.get_parallel", + return_value=parallel, + ), + patch( + "sglang.srt.layers.attention.dsa.utils.process_model_config", + return_value=model_config, + ), + patch("sglang.srt.layers.attention.dsa.utils.is_hip", return_value=True), + patch( + "sglang.srt.configs.model_config.is_deepseek_dsa", + return_value=True, + ), ): - self.assertIsNotNone(get_cp_strategy()) - self.assertTrue(is_cp_enabled()) - self.assertTrue(is_interleave()) + self.assertFalse(is_dsa_enable_prefill_cp()) + + @patch("sglang.srt.utils.is_npu", return_value=False) + @patch("sglang.srt.utils.is_hip", return_value=True) + def test_hip_keeps_strategy_cp_disabled(self, _mock_is_hip, _mock_is_npu): + self.assertFalse(enable_cp_v2()) + + @patch("sglang.srt.utils.is_npu", return_value=True) + @patch("sglang.srt.utils.is_hip", return_value=False) + def test_npu_keeps_strategy_cp_disabled(self, _mock_is_hip, _mock_is_npu): + self.assertFalse(enable_cp_v2()) class TestPrefillCPBCGReplay(CustomTestCase): @@ -155,10 +187,6 @@ class TestPrefillCPBCGReplay(CustomTestCase): self._enable_zigzag() with ( - patch( - "sglang.srt.environ.envs.SGLANG_ENABLE_CP_V2.get", - return_value=True, - ), patch( "sglang.srt.layers.cp.bcg.get_cp_padding_align_size", return_value=8, @@ -209,10 +237,6 @@ class TestPrefillCPBCGReplay(CustomTestCase): with ( get_parallel().override(attn_cp_rank=0, attn_cp_size=4), - patch( - "sglang.srt.environ.envs.SGLANG_ENABLE_CP_V2.get", - return_value=True, - ), patch( "sglang.srt.layers.cp.bcg.get_cp_padding_align_size", return_value=8, @@ -243,10 +267,6 @@ class TestPrefillCPBCGReplay(CustomTestCase): with ( get_parallel().override(attn_cp_rank=0, attn_cp_size=4), - patch( - "sglang.srt.environ.envs.SGLANG_ENABLE_CP_V2.get", - return_value=True, - ), patch( "sglang.srt.layers.cp.bcg.get_cp_padding_align_size", return_value=8, @@ -298,9 +318,7 @@ class TestCPZigzagStrategy(CustomTestCase): extend_seq_lens_cpu=[7], ) - with patch( - "sglang.srt.environ.envs.SGLANG_ENABLE_CP_V2.get", return_value=True - ): + with patch.dict("os.environ", {"SGLANG_ENABLE_CP_V2": "0"}): self.assertTrue(enable_cp_v2()) self.assertTrue(is_cp_v2_active(active_batch)) self.assertFalse(is_cp_v2_active(inactive_batch)) @@ -494,14 +512,11 @@ class TestCPZigzagStrategy(CustomTestCase): local_x = strategy.shard_hidden_states(x, fb) local_positions = strategy.shard_position_ids(positions, fb) - with patch( - "sglang.srt.environ.envs.SGLANG_ENABLE_CP_V2.get", return_value=True - ): - helper_x, helper_positions = cp_split_before_forward( - x, - positions, - fb, - ) + helper_x, helper_positions = cp_split_before_forward( + x, + positions, + fb, + ) self.assertTrue(torch.equal(local_x, expected_x)) self.assertTrue(torch.equal(local_positions, expected_positions)) @@ -916,10 +931,6 @@ class TestCPInterleaveStrategy(CustomTestCase): with ( get_parallel().override(attn_cp_rank=2, attn_cp_size=4), - patch( - "sglang.srt.environ.envs.SGLANG_ENABLE_CP_V2.get", - return_value=True, - ), patch( "sglang.srt.layers.cp.padding.get_cp_padding_align_size", return_value=4, @@ -965,15 +976,11 @@ class TestCPInterleaveStrategy(CustomTestCase): local_x = strategy.shard_hidden_states(x, fb) local_positions = strategy.shard_position_ids(positions, fb) - with patch( - "sglang.srt.environ.envs.SGLANG_ENABLE_CP_V2.get", - return_value=True, - ): - helper_x, helper_positions = cp_split_before_forward( - x, - positions, - fb, - ) + helper_x, helper_positions = cp_split_before_forward( + x, + positions, + fb, + ) self.assertTrue(torch.equal(local_x, expected_x)) self.assertTrue(torch.equal(local_positions, expected_positions)) diff --git a/test/registered/unit/server_args/test_server_args.py b/test/registered/unit/server_args/test_server_args.py index 009e312a6..d5f26623e 100644 --- a/test/registered/unit/server_args/test_server_args.py +++ b/test/registered/unit/server_args/test_server_args.py @@ -47,7 +47,8 @@ from sglang.srt.arg_groups.overrides import ( from sglang.srt.arg_groups.parallel_hook import ( handle_context_parallelism, handle_data_parallelism, - handle_legacy_cp_arguments, + handle_legacy_cp_runtime_compatibility, + handle_platform_cp_compatibility, ) from sglang.srt.arg_groups.pd_disaggregation_hook import handle_pd_disaggregation from sglang.srt.arg_groups.serving_hook import ( @@ -1056,52 +1057,116 @@ class TestContextParallelServerArgs(CustomTestCase): with self.assertRaisesRegex(ValueError, "--cp-strategy"): handle_context_parallelism(server_args) - def test_deprecated_dsa_cp_mode_maps_to_unified_strategy(self): + @override_platform(is_hip=False, is_npu=False) + def test_deepseek_v32_prefill_cp_rejects_zigzag(self): + server_args = self._new_cp_args( + model_path="deepseek-ai/DeepSeek-V3.2", + enable_prefill_cp=True, + cp_strategy="zigzag", + ) + server_args._model_config = SimpleNamespace( + hf_config=SimpleNamespace(architectures=["DeepseekV32ForCausalLM"]), + is_multimodal=False, + ) + + with self.assertRaisesRegex(ValueError, "DeepSeek V3.2.*interleave"): + handle_context_parallelism(server_args) + + @override_platform(is_hip=False, is_npu=False) + def test_generic_canonical_cp_mirrors_to_transitional_runtime_fields(self): + cases = ( + ( + "zigzag_mla_or_gqa", + "zigzag", + "fa3", + True, + False, + "in-seq-split", + ), + ( + "interleave_dsa", + "interleave", + "dsa", + False, + True, + "round-robin-split", + ), + ) + + for name, strategy, backend, expect_generic, expect_dsa, mode in cases: + with self.subTest(name=name): + server_args = self._new_cp_args( + enable_prefill_cp=True, + cp_strategy=strategy, + attention_backend=backend, + ) + + handle_platform_cp_compatibility(server_args) + + self.assertFalse( + resolution_result(server_args, "enable_prefill_context_parallel") + ) + self.assertFalse( + resolution_result( + server_args, "enable_dsa_prefill_context_parallel" + ) + ) + + handle_legacy_cp_runtime_compatibility(server_args) + + 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): + server_args = ServerArgs( + model_path="instance://127.0.0.1:8000/dummy", + enable_prefill_context_parallel=True, + ) + with self.assertRaisesRegex(ValueError, "HIP or Ascend NPU"): + handle_platform_cp_compatibility(server_args) + + def test_generic_v1_cp_options_are_not_public_cli(self): + removed_options = ( + ("--enable-dsa-prefill-context-parallel", []), + ("--dsa-prefill-cp-mode", ["round-robin-split"]), + ("--prefill-cp-mode", ["in-seq-split"]), + ) + + for option, values in removed_options: + with self.subTest(option=option), self.assertRaises(SystemExit): + self.parser.parse_args(["--model", "dummy", option, *values]) + + def test_npu_cp_compatibility_options_remain_public_cli(self): args = self.parser.parse_args( [ "--model", "dummy", - "--enable-dsa-prefill-context-parallel", - "--dsa-prefill-cp-mode", + "--enable-prefill-context-parallel", + "--enable-nsa-prefill-context-parallel", + "--nsa-prefill-cp-mode", "round-robin-split", ] ) - server_args = self._new_cp_args( - enable_dsa_prefill_context_parallel=( - resolution_result(args, "enable_dsa_prefill_context_parallel") - ), - dsa_prefill_cp_mode=resolution_result(args, "dsa_prefill_cp_mode"), - ) - handle_legacy_cp_arguments(server_args) - - self.assertTrue(resolution_result(server_args, "enable_prefill_cp")) - self.assertEqual(resolution_result(server_args, "cp_strategy"), "interleave") + self.assertTrue(resolution_result(args, "enable_prefill_context_parallel")) + self.assertTrue(resolution_result(args, "enable_dsa_prefill_context_parallel")) self.assertEqual( - resolution_result(server_args, "dsa_prefill_cp_mode"), "round-robin-split" - ) - - def test_canonical_interleave_cp_mirrors_to_dsa_runtime_aliases(self): - server_args = self._new_cp_args( - enable_prefill_cp=True, - cp_strategy="interleave", - attention_backend="dsa", - ) - - handle_legacy_cp_arguments(server_args) - handle_context_parallelism(server_args) - - self.assertTrue( - resolution_result(server_args, "enable_dsa_prefill_context_parallel") - ) - self.assertFalse( - resolution_result(server_args, "enable_prefill_context_parallel") - ) - self.assertEqual( - resolution_result(server_args, "dsa_prefill_cp_mode"), "round-robin-split" - ) - self.assertEqual( - resolution_result(server_args, "prefill_cp_mode"), "round-robin-split" + resolution_result(args, "dsa_prefill_cp_mode"), "round-robin-split" ) def test_context_parallel_handler_initializes_cp_strategy(self): @@ -1117,97 +1182,6 @@ class TestContextParallelServerArgs(CustomTestCase): self.assertTrue(is_cp_enabled()) self.assertTrue(is_interleave()) - def test_registered_cp_legacy_args_map_to_unified_strategy(self): - cases = [ - ( - "deepseek_v3_mla_cp", - dict(enable_prefill_context_parallel=True), - "zigzag", - "in-seq-split", - False, - True, - ), - ( - "qwen3_gqa_cp", - dict( - enable_prefill_context_parallel=True, - tp_size=4, - attn_cp_size=2, - ), - "zigzag", - "in-seq-split", - False, - True, - ), - ( - "deepseek_v32_dsa_in_seq_split", - dict( - enable_dsa_prefill_context_parallel=True, - dsa_prefill_cp_mode="in-seq-split", - tp_size=8, - dp_size=2, - attn_cp_size=4, - ), - "zigzag", - "in-seq-split", - True, - False, - ), - ( - "deepseek_v32_dsa_round_robin_split", - dict( - enable_dsa_prefill_context_parallel=True, - tp_size=8, - attn_cp_size=8, - ), - "interleave", - "round-robin-split", - True, - False, - ), - ( - "deepseek_v4_flash_fp4_b200_dsa_round_robin_split", - dict( - enable_dsa_prefill_context_parallel=True, - dsa_prefill_cp_mode="round-robin-split", - tp_size=4, - attn_cp_size=4, - ), - "interleave", - "round-robin-split", - True, - False, - ), - ] - - for name, overrides, strategy, mode, expect_dsa, expect_generic in cases: - with self.subTest(name=name): - server_args = self._new_cp_args(**overrides) - - handle_legacy_cp_arguments(server_args) - handle_context_parallelism(server_args) - - self.assertTrue(resolution_result(server_args, "enable_prefill_cp")) - self.assertEqual( - resolution_result(server_args, "cp_strategy"), strategy - ) - self.assertEqual( - resolution_result(server_args, "dsa_prefill_cp_mode"), mode - ) - self.assertEqual( - resolution_result(server_args, "prefill_cp_mode"), mode - ) - self.assertEqual( - resolution_result( - server_args, "enable_dsa_prefill_context_parallel" - ), - expect_dsa, - ) - self.assertEqual( - resolution_result(server_args, "enable_prefill_context_parallel"), - expect_generic, - ) - class TestPortArgs(unittest.TestCase): @patch("sglang.srt.server_args.tempfile.NamedTemporaryFile") @@ -1804,7 +1778,6 @@ class TestPrefillOnlyDisableKvCache(unittest.TestCase): def _validate_prefill_only_args(self, **overrides): sa = ServerArgs(**self._base_kwargs(**overrides)) - handle_legacy_cp_arguments(sa) validate_prefill_only_disable_kv_cache_args(sa) return sa @@ -1830,7 +1803,10 @@ class TestPrefillOnlyDisableKvCache(unittest.TestCase): def test_rejects_prefill_context_parallel(self): with self.assertRaisesRegex(ValueError, "--enable-prefill-cp"): - self._validate_prefill_only_args(enable_prefill_context_parallel=True) + self._validate_prefill_only_args( + enable_prefill_cp=True, + cp_strategy="zigzag", + ) def test_rejects_hisparse(self): with self.assertRaisesRegex(ValueError, "--enable-hisparse"):