config: the resolution pipeline's dispatcher leaves the record (#36896)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
46ccd7ce3e
commit
48b88e1256
@@ -0,0 +1,361 @@
|
|||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
"""The resolution pipeline: the ordered dispatcher every publishing entry runs.
|
||||||
|
|
||||||
|
``ServerArgs.resolve_once`` is the only caller. It lives here rather than on the
|
||||||
|
record because a step decides *about* the record; none of them is a member of
|
||||||
|
it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import dataclasses
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from sglang.srt.arg_groups.overrides import (
|
||||||
|
_page_size_default,
|
||||||
|
_pipeline_parallel_overlap_disable,
|
||||||
|
_sampling_backend_default,
|
||||||
|
declare_direct_writes,
|
||||||
|
resolving_view,
|
||||||
|
run_post_process_pass,
|
||||||
|
)
|
||||||
|
from sglang.srt.platforms import current_platform
|
||||||
|
from sglang.srt.utils.common import get_device_memory_capacity
|
||||||
|
|
||||||
|
|
||||||
|
def run_resolution_pipeline(server_args: Any) -> None:
|
||||||
|
"""
|
||||||
|
Orchestrates the handling of various server arguments, ensuring proper configuration and validation.
|
||||||
|
|
||||||
|
Dispatcher style principles:
|
||||||
|
1. Keep this function as an ordered dispatcher. Each step should be a
|
||||||
|
named call into an ``arg_groups`` family; put imports, conditionals,
|
||||||
|
mutations, and raises inside the family instead of inline here.
|
||||||
|
2. Keep the dummy-model boundary as early as correctness allows. Only
|
||||||
|
model-independent bootstrap, API/network/protocol validation, and
|
||||||
|
errors that should fire for dummy models should run before it.
|
||||||
|
3. Order handlers by dependency domains, not by historical insertion:
|
||||||
|
internal/bootstrap, API/network/protocol, model source/path
|
||||||
|
resolution, hardware/platform, model-specific adjustment,
|
||||||
|
parallelism, kernel/attention backend, cuda graph, memory/cache,
|
||||||
|
and advanced/debug features.
|
||||||
|
4. Hide narrow integrations behind general handler names. The
|
||||||
|
dispatcher should say what phase is being handled, not expose a
|
||||||
|
vendor-, hook-, or feature-specific implementation detail.
|
||||||
|
5. Give each handler one clear contract: what state it expects, what it
|
||||||
|
may mutate, and whether it validates only. Long ordering comments
|
||||||
|
belong in the helper or signal that the helper should be split.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# What the caller asked for, before any handler runs; this plus the
|
||||||
|
# stash is the resolution result the projection reads.
|
||||||
|
server_args._raw_input = {
|
||||||
|
field.name: getattr(server_args, field.name)
|
||||||
|
for field in dataclasses.fields(server_args)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Declaration stash for the override/post-process passes. Set before any
|
||||||
|
# short-circuit (none/dummy model paths) so run_post_process_pass and
|
||||||
|
# direct handler invocations can rely on it even when
|
||||||
|
# _handle_model_specific_adjustments never runs.
|
||||||
|
server_args._resolved_overrides = []
|
||||||
|
|
||||||
|
cfg = resolving_view(server_args)
|
||||||
|
|
||||||
|
from sglang.srt.arg_groups.mega_moe_hook import handle_mega_moe
|
||||||
|
|
||||||
|
handle_mega_moe(server_args)
|
||||||
|
from sglang.srt.arg_groups.serving_hook import (
|
||||||
|
handle_asr_validation,
|
||||||
|
handle_crash_dump_env,
|
||||||
|
handle_debug_utils,
|
||||||
|
handle_deprecated_args,
|
||||||
|
handle_environment_variables,
|
||||||
|
handle_grammar_backend,
|
||||||
|
handle_load_balance_method,
|
||||||
|
handle_media_url_security,
|
||||||
|
handle_missing_default_values,
|
||||||
|
handle_multimodal,
|
||||||
|
handle_other_validations,
|
||||||
|
handle_prefill_delayer_env_compat,
|
||||||
|
handle_return_hidden_states_mode,
|
||||||
|
handle_ssl_validation,
|
||||||
|
handle_tokenizer_batching,
|
||||||
|
)
|
||||||
|
|
||||||
|
handle_return_hidden_states_mode(server_args)
|
||||||
|
handle_media_url_security(server_args)
|
||||||
|
from sglang.srt.arg_groups.hicache_hook import (
|
||||||
|
handle_hicache,
|
||||||
|
handle_hicache_ratio_default,
|
||||||
|
)
|
||||||
|
|
||||||
|
handle_hicache_ratio_default(server_args)
|
||||||
|
from sglang.srt.arg_groups.validation_hook import (
|
||||||
|
validate_experimental_sgl_marlin,
|
||||||
|
validate_prefill_decode_interval,
|
||||||
|
)
|
||||||
|
|
||||||
|
validate_prefill_decode_interval(server_args)
|
||||||
|
|
||||||
|
# Reject an explicitly enabled but incompatible hardware runtime before
|
||||||
|
# model path resolution, downloads, or the dummy-model short circuit.
|
||||||
|
from sglang.srt.arg_groups.platform_hook import (
|
||||||
|
handle_hardware_runtime_validation,
|
||||||
|
)
|
||||||
|
|
||||||
|
handle_hardware_runtime_validation(server_args)
|
||||||
|
if cfg.model_path.lower() in ["none", "dummy"]:
|
||||||
|
return
|
||||||
|
|
||||||
|
from sglang.srt.arg_groups.model_path_hook import (
|
||||||
|
handle_load_format,
|
||||||
|
handle_model_source_paths,
|
||||||
|
)
|
||||||
|
|
||||||
|
handle_model_source_paths(server_args)
|
||||||
|
|
||||||
|
# Validate mm_process_config.
|
||||||
|
handle_multimodal(server_args)
|
||||||
|
# Validate SSL arguments early.
|
||||||
|
handle_ssl_validation(server_args)
|
||||||
|
# Validate transcription/ASR-specific server args.
|
||||||
|
handle_asr_validation(server_args)
|
||||||
|
|
||||||
|
# Handle deprecated arguments.
|
||||||
|
handle_deprecated_args(server_args)
|
||||||
|
|
||||||
|
# Handle deprecated environment variables for prefill delayer.
|
||||||
|
handle_prefill_delayer_env_compat(server_args)
|
||||||
|
|
||||||
|
# Set missing default values.
|
||||||
|
handle_missing_default_values(server_args)
|
||||||
|
|
||||||
|
# expert_pack may replace a raw GGUF input with its generated local
|
||||||
|
# model metadata before any model-specific handler calls model_config_of.
|
||||||
|
# It also establishes eager-only invariants before CUDA graph parsing.
|
||||||
|
from sglang.srt.arg_groups.expert_pack_hook import handle_expert_pack
|
||||||
|
|
||||||
|
handle_expert_pack(server_args)
|
||||||
|
|
||||||
|
# Validate PD disaggregation flags before CUDA graph config.
|
||||||
|
from sglang.srt.arg_groups.pd_disaggregation_hook import (
|
||||||
|
handle_encoder_disaggregation,
|
||||||
|
handle_pd_disaggregation,
|
||||||
|
)
|
||||||
|
|
||||||
|
handle_pd_disaggregation(server_args)
|
||||||
|
|
||||||
|
# Normalize deprecated 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,
|
||||||
|
handle_dcp_validation,
|
||||||
|
handle_dwdp,
|
||||||
|
handle_elastic_ep,
|
||||||
|
handle_eplb_and_dispatch,
|
||||||
|
handle_expert_distribution_metrics,
|
||||||
|
handle_legacy_cp_arguments,
|
||||||
|
)
|
||||||
|
|
||||||
|
handle_legacy_cp_arguments(server_args)
|
||||||
|
from sglang.srt.arg_groups.kv_cache_hook import (
|
||||||
|
handle_cache_compatibility,
|
||||||
|
handle_kv4_compatibility,
|
||||||
|
handle_mxfp8_kv_cache_compatibility,
|
||||||
|
handle_page_major_kv_layout,
|
||||||
|
handle_prefill_only_disable_kv_cache,
|
||||||
|
handle_unified_memory_pool,
|
||||||
|
validate_prefill_only_disable_kv_cache_args,
|
||||||
|
)
|
||||||
|
|
||||||
|
validate_prefill_only_disable_kv_cache_args(server_args)
|
||||||
|
handle_dcp_validation(server_args)
|
||||||
|
|
||||||
|
# Model-arch prefill CUDA-graph default must land before cuda-graph
|
||||||
|
# resolution (the declarative registry materializes too late to affect
|
||||||
|
# it). Inkling opts into full-graph prefill capture here.
|
||||||
|
from sglang.srt.arg_groups.cuda_graph_hook import (
|
||||||
|
apply_inkling_prefill_cuda_graph_default,
|
||||||
|
apply_muse_glimmer_prefill_cuda_graph_max_bs_default,
|
||||||
|
disable_prefill_cuda_graph_for_deepseek_trtllm_mla,
|
||||||
|
handle_cuda_graph_config,
|
||||||
|
)
|
||||||
|
|
||||||
|
apply_inkling_prefill_cuda_graph_default(server_args)
|
||||||
|
apply_muse_glimmer_prefill_cuda_graph_max_bs_default(server_args)
|
||||||
|
|
||||||
|
# must run before _handle_cuda_graph_config and _handle_data_parallelism
|
||||||
|
handle_dwdp(server_args)
|
||||||
|
|
||||||
|
handle_cuda_graph_config(server_args)
|
||||||
|
|
||||||
|
# Handle device-specific backends.
|
||||||
|
from sglang.srt.arg_groups.platform_hook import (
|
||||||
|
handle_amd_specifics,
|
||||||
|
handle_cpu_backends,
|
||||||
|
handle_hpu_backends,
|
||||||
|
handle_mps_backends,
|
||||||
|
handle_nccl_pre_warm,
|
||||||
|
handle_npu_backends,
|
||||||
|
handle_xpu_backends,
|
||||||
|
)
|
||||||
|
|
||||||
|
handle_hpu_backends(server_args)
|
||||||
|
handle_cpu_backends(server_args)
|
||||||
|
handle_npu_backends(server_args)
|
||||||
|
handle_mps_backends(server_args)
|
||||||
|
handle_xpu_backends(server_args)
|
||||||
|
|
||||||
|
# OOT platform plugins set fields directly (an interface this tree
|
||||||
|
# does not own); the diff records what they applied.
|
||||||
|
declare_direct_writes(
|
||||||
|
server_args,
|
||||||
|
f"platform:{current_platform.device_name}",
|
||||||
|
current_platform.apply_server_args_defaults,
|
||||||
|
)
|
||||||
|
|
||||||
|
gpu_mem = get_device_memory_capacity(cfg.device)
|
||||||
|
|
||||||
|
# Handle memory-related, chunked prefill, and CUDA graph batch size configurations.
|
||||||
|
from sglang.srt.arg_groups.memory_hook import handle_gpu_memory_settings
|
||||||
|
|
||||||
|
handle_gpu_memory_settings(server_args, gpu_mem)
|
||||||
|
|
||||||
|
# Apply model-specific adjustments.
|
||||||
|
from sglang.srt.arg_groups.model_hook import (
|
||||||
|
handle_model_capability_adjustments,
|
||||||
|
handle_model_specific_adjustments,
|
||||||
|
)
|
||||||
|
|
||||||
|
handle_model_specific_adjustments(server_args)
|
||||||
|
|
||||||
|
# Set kernel backends.
|
||||||
|
run_post_process_pass(server_args, _sampling_backend_default)
|
||||||
|
# Must run before _handle_attention_backend_compatibility so the
|
||||||
|
# deterministic backend is set before auto-detection fills it in.
|
||||||
|
from sglang.srt.arg_groups.attention_hook import (
|
||||||
|
handle_attention_backend_compatibility,
|
||||||
|
handle_deterministic_inference,
|
||||||
|
handle_linear_attn_backend,
|
||||||
|
handle_multi_item_scoring,
|
||||||
|
)
|
||||||
|
|
||||||
|
handle_deterministic_inference(server_args)
|
||||||
|
handle_attention_backend_compatibility(server_args)
|
||||||
|
# Must run after the attention backend is resolved so the trtllm_mla
|
||||||
|
# default (auto-selected for DeepseekV3ForCausalLM on sm100) is visible.
|
||||||
|
disable_prefill_cuda_graph_for_deepseek_trtllm_mla(server_args)
|
||||||
|
from sglang.srt.arg_groups.mamba_hook import (
|
||||||
|
handle_int8_mamba_checkpoint,
|
||||||
|
handle_mamba_backend,
|
||||||
|
)
|
||||||
|
|
||||||
|
handle_mamba_backend(server_args)
|
||||||
|
handle_int8_mamba_checkpoint(server_args)
|
||||||
|
handle_linear_attn_backend(server_args)
|
||||||
|
handle_kv4_compatibility(server_args)
|
||||||
|
handle_mxfp8_kv_cache_compatibility(server_args)
|
||||||
|
run_post_process_pass(server_args, _page_size_default)
|
||||||
|
handle_amd_specifics(server_args)
|
||||||
|
handle_nccl_pre_warm(server_args)
|
||||||
|
handle_grammar_backend(server_args)
|
||||||
|
|
||||||
|
# Handle multi-item scoring constraints. Must run after the above so
|
||||||
|
# the final attention backend and chunked_prefill_size are in effect.
|
||||||
|
handle_multi_item_scoring(server_args)
|
||||||
|
|
||||||
|
# Backend-dependent half of --prefill-only-disable-kv-cache validation.
|
||||||
|
# Must stay after _handle_attention_backend_compatibility() (above) and
|
||||||
|
# _handle_multi_item_scoring() so the resolved prefill backend is final;
|
||||||
|
# the flag/precondition half runs earlier in
|
||||||
|
# _validate_prefill_only_disable_kv_cache_args().
|
||||||
|
handle_prefill_only_disable_kv_cache(server_args)
|
||||||
|
|
||||||
|
# Handle Hicache settings.
|
||||||
|
handle_hicache(server_args)
|
||||||
|
|
||||||
|
# Handle data parallelism.
|
||||||
|
handle_data_parallelism(server_args)
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
# Handle context parallelism.
|
||||||
|
handle_context_parallelism(server_args)
|
||||||
|
|
||||||
|
# Handle MoE configurations.
|
||||||
|
from sglang.srt.arg_groups.moe_hook import (
|
||||||
|
handle_a2a_moe,
|
||||||
|
handle_moe_kernel_config,
|
||||||
|
validate_cutedsl_a2a_token_budget,
|
||||||
|
validate_deepep_v2_dispatch_token_budget,
|
||||||
|
validate_deepep_v2_speculative_draft,
|
||||||
|
)
|
||||||
|
|
||||||
|
handle_moe_kernel_config(server_args)
|
||||||
|
handle_a2a_moe(server_args)
|
||||||
|
handle_eplb_and_dispatch(server_args)
|
||||||
|
handle_expert_distribution_metrics(server_args)
|
||||||
|
handle_elastic_ep(server_args)
|
||||||
|
validate_experimental_sgl_marlin(server_args)
|
||||||
|
|
||||||
|
# Handle pipeline parallelism.
|
||||||
|
run_post_process_pass(server_args, _pipeline_parallel_overlap_disable)
|
||||||
|
|
||||||
|
# Handle speculative decoding logic.
|
||||||
|
|
||||||
|
from sglang.srt.arg_groups.speculative_hook import handle_speculative_decoding
|
||||||
|
|
||||||
|
handle_speculative_decoding(server_args)
|
||||||
|
|
||||||
|
# Validate the CuteDSL A2A token budget now that num_tokens_per_req is final.
|
||||||
|
validate_cutedsl_a2a_token_budget(server_args)
|
||||||
|
|
||||||
|
# Handle model loading format.
|
||||||
|
handle_load_format(server_args)
|
||||||
|
|
||||||
|
# Handle Encoder disaggregation.
|
||||||
|
handle_encoder_disaggregation(server_args)
|
||||||
|
|
||||||
|
# Validate tokenizer settings.
|
||||||
|
handle_tokenizer_batching(server_args)
|
||||||
|
|
||||||
|
# Propagate environment variables.
|
||||||
|
handle_environment_variables(server_args)
|
||||||
|
|
||||||
|
# Validate cache settings.
|
||||||
|
handle_cache_compatibility(server_args)
|
||||||
|
|
||||||
|
handle_page_major_kv_layout(server_args)
|
||||||
|
|
||||||
|
handle_unified_memory_pool(server_args)
|
||||||
|
|
||||||
|
# Handle diffusion LLM inference.
|
||||||
|
from sglang.srt.arg_groups.dllm_hook import handle_dllm_inference
|
||||||
|
|
||||||
|
handle_dllm_inference(server_args)
|
||||||
|
|
||||||
|
# Handle crash dump environment variables (must run before CUDA init).
|
||||||
|
handle_crash_dump_env(server_args)
|
||||||
|
|
||||||
|
# Handle debug utilities.
|
||||||
|
handle_debug_utils(server_args)
|
||||||
|
|
||||||
|
# Handle any other necessary validations.
|
||||||
|
handle_other_validations(server_args)
|
||||||
|
|
||||||
|
# Model-capability adjustments that legacy code applied at model-load
|
||||||
|
# time; last declarations of the resolution, mirroring that order.
|
||||||
|
handle_model_capability_adjustments(server_args)
|
||||||
|
|
||||||
|
# Validate after all batch-size declarations are visible.
|
||||||
|
validate_deepep_v2_speculative_draft(server_args)
|
||||||
|
validate_deepep_v2_dispatch_token_budget(server_args)
|
||||||
|
|
||||||
|
server_args._resolution_finished = True
|
||||||
@@ -17,6 +17,14 @@ from sglang.srt.utils.common import is_cuda, is_hip, is_host_cpu_arm64, is_npu
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def handle_hardware_runtime_validation(server_args: Any):
|
||||||
|
# This is intentionally independent of `server_args.device`: setting
|
||||||
|
# SGLANG_USE_MLX opts into the MLX backend and must fail immediately if
|
||||||
|
# the environment cannot honor that request. With the flag unset,
|
||||||
|
# use_mlx() remains lazy and does not import MLX.
|
||||||
|
use_mlx()
|
||||||
|
|
||||||
|
|
||||||
def handle_npu_backends(server_args: Any):
|
def handle_npu_backends(server_args: Any):
|
||||||
cfg = resolving_view(server_args)
|
cfg = resolving_view(server_args)
|
||||||
if cfg.device == "npu":
|
if cfg.device == "npu":
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ Keep this file in the following top-level order:
|
|||||||
aliases. A choice list used by only one field belongs inline in that field.
|
aliases. A choice list used by only one field belongs inline in that field.
|
||||||
4. ``ServerArgs``: fields first, then resolution/validation helpers, then CLI
|
4. ``ServerArgs``: fields first, then resolution/validation helpers, then CLI
|
||||||
registration and small query helpers. New resolution steps are appended at
|
registration and small query helpers. New resolution steps are appended at
|
||||||
the end of ``_run_resolution_pipeline``, immediately before resolution is
|
the end of ``arg_groups.pipeline.run_resolution_pipeline``, immediately
|
||||||
marked complete, unless an earlier dependency is documented explicitly.
|
marked complete, unless an earlier dependency is documented explicitly.
|
||||||
5. Module-level ``ServerArgs`` construction/runtime shims.
|
5. Module-level ``ServerArgs`` construction/runtime shims.
|
||||||
6. Networking constants and ``PortArgs``.
|
6. Networking constants and ``PortArgs``.
|
||||||
@@ -57,7 +57,6 @@ from sglang.srt.arg_groups.argparse_actions import (
|
|||||||
)
|
)
|
||||||
from sglang.srt.arg_groups.overrides import (
|
from sglang.srt.arg_groups.overrides import (
|
||||||
attention_backends_of,
|
attention_backends_of,
|
||||||
declare_direct_writes,
|
|
||||||
mamba_extra_buffer_lazy_of,
|
mamba_extra_buffer_lazy_of,
|
||||||
mamba_extra_buffer_of,
|
mamba_extra_buffer_of,
|
||||||
remote_instance_transfer_engine_of,
|
remote_instance_transfer_engine_of,
|
||||||
@@ -66,7 +65,6 @@ from sglang.srt.arg_groups.overrides import (
|
|||||||
)
|
)
|
||||||
from sglang.srt.environ import envs
|
from sglang.srt.environ import envs
|
||||||
from sglang.srt.function_call.function_call_parser import FunctionCallParser
|
from sglang.srt.function_call.function_call_parser import FunctionCallParser
|
||||||
from sglang.srt.hardware_backend.mlx.runtime import use_mlx
|
|
||||||
from sglang.srt.lora.lora_registry import LoRARef
|
from sglang.srt.lora.lora_registry import LoRARef
|
||||||
from sglang.srt.model_executor.cuda_graph_config import (
|
from sglang.srt.model_executor.cuda_graph_config import (
|
||||||
Backend,
|
Backend,
|
||||||
@@ -81,7 +79,6 @@ from sglang.srt.speculative.decoupled_spec_io import DecoupledSpecIpcConfig
|
|||||||
from sglang.srt.utils.common import (
|
from sglang.srt.utils.common import (
|
||||||
LORA_TARGET_ALL_MODULES,
|
LORA_TARGET_ALL_MODULES,
|
||||||
SUPPORTED_LORA_TARGET_MODULES,
|
SUPPORTED_LORA_TARGET_MODULES,
|
||||||
get_device_memory_capacity,
|
|
||||||
human_readable_int,
|
human_readable_int,
|
||||||
is_flashinfer_available,
|
is_flashinfer_available,
|
||||||
is_hip,
|
is_hip,
|
||||||
@@ -3690,8 +3687,10 @@ class ServerArgs:
|
|||||||
"read that partial output as fresh input. Build a new record "
|
"read that partial output as fresh input. Build a new record "
|
||||||
"from the corrected arguments."
|
"from the corrected arguments."
|
||||||
)
|
)
|
||||||
|
from sglang.srt.arg_groups.pipeline import run_resolution_pipeline
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._run_resolution_pipeline()
|
run_resolution_pipeline(self)
|
||||||
except BaseException:
|
except BaseException:
|
||||||
# The handlers that ran already declared, and they are not
|
# The handlers that ran already declared, and they are not
|
||||||
# idempotent over their own output.
|
# idempotent over their own output.
|
||||||
@@ -3774,345 +3773,6 @@ class ServerArgs:
|
|||||||
|
|
||||||
declare_resolution(self, source, **fields)
|
declare_resolution(self, source, **fields)
|
||||||
|
|
||||||
def _run_resolution_pipeline(self):
|
|
||||||
"""
|
|
||||||
Orchestrates the handling of various server arguments, ensuring proper configuration and validation.
|
|
||||||
|
|
||||||
Dispatcher style principles:
|
|
||||||
1. Keep this method as an ordered dispatcher. Each step should be a
|
|
||||||
named self._handle_* call; put imports, conditionals, mutations, and
|
|
||||||
raises inside helpers instead of inline here.
|
|
||||||
2. Keep the dummy-model boundary as early as correctness allows. Only
|
|
||||||
model-independent bootstrap, API/network/protocol validation, and
|
|
||||||
errors that should fire for dummy models should run before it.
|
|
||||||
3. Order handlers by dependency domains, not by historical insertion:
|
|
||||||
internal/bootstrap, API/network/protocol, model source/path
|
|
||||||
resolution, hardware/platform, model-specific adjustment,
|
|
||||||
parallelism, kernel/attention backend, cuda graph, memory/cache,
|
|
||||||
and advanced/debug features.
|
|
||||||
4. Hide narrow integrations behind general handler names. The
|
|
||||||
dispatcher should say what phase is being handled, not expose a
|
|
||||||
vendor-, hook-, or feature-specific implementation detail.
|
|
||||||
5. Give each handler one clear contract: what state it expects, what it
|
|
||||||
may mutate, and whether it validates only. Long ordering comments
|
|
||||||
belong in the helper or signal that the helper should be split.
|
|
||||||
"""
|
|
||||||
|
|
||||||
# What the caller asked for, before any handler runs; this plus the
|
|
||||||
# stash is the resolution result the projection reads.
|
|
||||||
self._raw_input = {
|
|
||||||
field.name: getattr(self, field.name) for field in dataclasses.fields(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
# Declaration stash for the override/post-process passes. Set before any
|
|
||||||
# short-circuit (none/dummy model paths) so run_post_process_pass and
|
|
||||||
# direct handler invocations can rely on it even when
|
|
||||||
# _handle_model_specific_adjustments never runs.
|
|
||||||
self._resolved_overrides = []
|
|
||||||
|
|
||||||
cfg = resolving_view(self)
|
|
||||||
|
|
||||||
from sglang.srt.arg_groups.mega_moe_hook import handle_mega_moe
|
|
||||||
|
|
||||||
handle_mega_moe(self)
|
|
||||||
from sglang.srt.arg_groups.serving_hook import (
|
|
||||||
handle_asr_validation,
|
|
||||||
handle_crash_dump_env,
|
|
||||||
handle_debug_utils,
|
|
||||||
handle_deprecated_args,
|
|
||||||
handle_environment_variables,
|
|
||||||
handle_grammar_backend,
|
|
||||||
handle_load_balance_method,
|
|
||||||
handle_media_url_security,
|
|
||||||
handle_missing_default_values,
|
|
||||||
handle_multimodal,
|
|
||||||
handle_other_validations,
|
|
||||||
handle_prefill_delayer_env_compat,
|
|
||||||
handle_return_hidden_states_mode,
|
|
||||||
handle_ssl_validation,
|
|
||||||
handle_tokenizer_batching,
|
|
||||||
)
|
|
||||||
|
|
||||||
handle_return_hidden_states_mode(self)
|
|
||||||
handle_media_url_security(self)
|
|
||||||
from sglang.srt.arg_groups.hicache_hook import (
|
|
||||||
handle_hicache,
|
|
||||||
handle_hicache_ratio_default,
|
|
||||||
)
|
|
||||||
|
|
||||||
handle_hicache_ratio_default(self)
|
|
||||||
from sglang.srt.arg_groups.validation_hook import (
|
|
||||||
validate_experimental_sgl_marlin,
|
|
||||||
validate_prefill_decode_interval,
|
|
||||||
)
|
|
||||||
|
|
||||||
validate_prefill_decode_interval(self)
|
|
||||||
|
|
||||||
# Reject an explicitly enabled but incompatible hardware runtime before
|
|
||||||
# model path resolution, downloads, or the dummy-model short circuit.
|
|
||||||
self._handle_hardware_runtime_validation()
|
|
||||||
if cfg.model_path.lower() in ["none", "dummy"]:
|
|
||||||
return
|
|
||||||
|
|
||||||
from sglang.srt.arg_groups.model_path_hook import (
|
|
||||||
handle_load_format,
|
|
||||||
handle_model_source_paths,
|
|
||||||
)
|
|
||||||
|
|
||||||
handle_model_source_paths(self)
|
|
||||||
|
|
||||||
# Validate mm_process_config.
|
|
||||||
handle_multimodal(self)
|
|
||||||
# Validate SSL arguments early.
|
|
||||||
handle_ssl_validation(self)
|
|
||||||
# Validate transcription/ASR-specific server args.
|
|
||||||
handle_asr_validation(self)
|
|
||||||
|
|
||||||
# Handle deprecated arguments.
|
|
||||||
handle_deprecated_args(self)
|
|
||||||
|
|
||||||
# Handle deprecated environment variables for prefill delayer.
|
|
||||||
handle_prefill_delayer_env_compat(self)
|
|
||||||
|
|
||||||
# Set missing default values.
|
|
||||||
handle_missing_default_values(self)
|
|
||||||
|
|
||||||
# expert_pack may replace a raw GGUF input with its generated local
|
|
||||||
# model metadata before any model-specific handler calls get_model_config.
|
|
||||||
# It also establishes eager-only invariants before CUDA graph parsing.
|
|
||||||
from sglang.srt.arg_groups.expert_pack_hook import handle_expert_pack
|
|
||||||
|
|
||||||
handle_expert_pack(self)
|
|
||||||
|
|
||||||
# Validate PD disaggregation flags before CUDA graph config.
|
|
||||||
from sglang.srt.arg_groups.pd_disaggregation_hook import (
|
|
||||||
handle_encoder_disaggregation,
|
|
||||||
handle_pd_disaggregation,
|
|
||||||
)
|
|
||||||
|
|
||||||
handle_pd_disaggregation(self)
|
|
||||||
|
|
||||||
# Normalize deprecated 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,
|
|
||||||
handle_dcp_validation,
|
|
||||||
handle_dwdp,
|
|
||||||
handle_elastic_ep,
|
|
||||||
handle_eplb_and_dispatch,
|
|
||||||
handle_expert_distribution_metrics,
|
|
||||||
handle_legacy_cp_arguments,
|
|
||||||
)
|
|
||||||
|
|
||||||
handle_legacy_cp_arguments(self)
|
|
||||||
from sglang.srt.arg_groups.kv_cache_hook import (
|
|
||||||
handle_cache_compatibility,
|
|
||||||
handle_kv4_compatibility,
|
|
||||||
handle_mxfp8_kv_cache_compatibility,
|
|
||||||
handle_page_major_kv_layout,
|
|
||||||
handle_prefill_only_disable_kv_cache,
|
|
||||||
handle_unified_memory_pool,
|
|
||||||
validate_prefill_only_disable_kv_cache_args,
|
|
||||||
)
|
|
||||||
|
|
||||||
validate_prefill_only_disable_kv_cache_args(self)
|
|
||||||
handle_dcp_validation(self)
|
|
||||||
|
|
||||||
# Model-arch prefill CUDA-graph default must land before cuda-graph
|
|
||||||
# resolution (the declarative registry materializes too late to affect
|
|
||||||
# it). Inkling opts into full-graph prefill capture here.
|
|
||||||
from sglang.srt.arg_groups.cuda_graph_hook import (
|
|
||||||
apply_inkling_prefill_cuda_graph_default,
|
|
||||||
apply_muse_glimmer_prefill_cuda_graph_max_bs_default,
|
|
||||||
disable_prefill_cuda_graph_for_deepseek_trtllm_mla,
|
|
||||||
handle_cuda_graph_config,
|
|
||||||
)
|
|
||||||
|
|
||||||
apply_inkling_prefill_cuda_graph_default(self)
|
|
||||||
apply_muse_glimmer_prefill_cuda_graph_max_bs_default(self)
|
|
||||||
|
|
||||||
# must run before _handle_cuda_graph_config and _handle_data_parallelism
|
|
||||||
handle_dwdp(self)
|
|
||||||
|
|
||||||
handle_cuda_graph_config(self)
|
|
||||||
|
|
||||||
# Handle device-specific backends.
|
|
||||||
from sglang.srt.arg_groups.platform_hook import (
|
|
||||||
handle_amd_specifics,
|
|
||||||
handle_cpu_backends,
|
|
||||||
handle_hpu_backends,
|
|
||||||
handle_mps_backends,
|
|
||||||
handle_nccl_pre_warm,
|
|
||||||
handle_npu_backends,
|
|
||||||
handle_xpu_backends,
|
|
||||||
)
|
|
||||||
|
|
||||||
handle_hpu_backends(self)
|
|
||||||
handle_cpu_backends(self)
|
|
||||||
handle_npu_backends(self)
|
|
||||||
handle_mps_backends(self)
|
|
||||||
handle_xpu_backends(self)
|
|
||||||
|
|
||||||
# OOT platform plugins set fields directly (an interface this tree
|
|
||||||
# does not own); the diff records what they applied.
|
|
||||||
declare_direct_writes(
|
|
||||||
self,
|
|
||||||
f"platform:{current_platform.device_name}",
|
|
||||||
current_platform.apply_server_args_defaults,
|
|
||||||
)
|
|
||||||
|
|
||||||
gpu_mem = get_device_memory_capacity(cfg.device)
|
|
||||||
|
|
||||||
# Handle memory-related, chunked prefill, and CUDA graph batch size configurations.
|
|
||||||
from sglang.srt.arg_groups.memory_hook import handle_gpu_memory_settings
|
|
||||||
|
|
||||||
handle_gpu_memory_settings(self, gpu_mem)
|
|
||||||
|
|
||||||
# Apply model-specific adjustments.
|
|
||||||
from sglang.srt.arg_groups.model_hook import (
|
|
||||||
handle_model_capability_adjustments,
|
|
||||||
handle_model_specific_adjustments,
|
|
||||||
)
|
|
||||||
|
|
||||||
handle_model_specific_adjustments(self)
|
|
||||||
|
|
||||||
# Set kernel backends.
|
|
||||||
self._handle_sampling_backend()
|
|
||||||
# Must run before _handle_attention_backend_compatibility so the
|
|
||||||
# deterministic backend is set before auto-detection fills it in.
|
|
||||||
from sglang.srt.arg_groups.attention_hook import (
|
|
||||||
handle_attention_backend_compatibility,
|
|
||||||
handle_deterministic_inference,
|
|
||||||
handle_linear_attn_backend,
|
|
||||||
handle_multi_item_scoring,
|
|
||||||
)
|
|
||||||
|
|
||||||
handle_deterministic_inference(self)
|
|
||||||
handle_attention_backend_compatibility(self)
|
|
||||||
# Must run after the attention backend is resolved so the trtllm_mla
|
|
||||||
# default (auto-selected for DeepseekV3ForCausalLM on sm100) is visible.
|
|
||||||
disable_prefill_cuda_graph_for_deepseek_trtllm_mla(self)
|
|
||||||
from sglang.srt.arg_groups.mamba_hook import (
|
|
||||||
handle_int8_mamba_checkpoint,
|
|
||||||
handle_mamba_backend,
|
|
||||||
)
|
|
||||||
|
|
||||||
handle_mamba_backend(self)
|
|
||||||
handle_int8_mamba_checkpoint(self)
|
|
||||||
handle_linear_attn_backend(self)
|
|
||||||
handle_kv4_compatibility(self)
|
|
||||||
handle_mxfp8_kv_cache_compatibility(self)
|
|
||||||
self._handle_page_size()
|
|
||||||
handle_amd_specifics(self)
|
|
||||||
handle_nccl_pre_warm(self)
|
|
||||||
handle_grammar_backend(self)
|
|
||||||
|
|
||||||
# Handle multi-item scoring constraints. Must run after the above so
|
|
||||||
# the final attention backend and chunked_prefill_size are in effect.
|
|
||||||
handle_multi_item_scoring(self)
|
|
||||||
|
|
||||||
# Backend-dependent half of --prefill-only-disable-kv-cache validation.
|
|
||||||
# Must stay after _handle_attention_backend_compatibility() (above) and
|
|
||||||
# _handle_multi_item_scoring() so the resolved prefill backend is final;
|
|
||||||
# the flag/precondition half runs earlier in
|
|
||||||
# _validate_prefill_only_disable_kv_cache_args().
|
|
||||||
handle_prefill_only_disable_kv_cache(self)
|
|
||||||
|
|
||||||
# Handle Hicache settings.
|
|
||||||
handle_hicache(self)
|
|
||||||
|
|
||||||
# Handle data parallelism.
|
|
||||||
handle_data_parallelism(self)
|
|
||||||
|
|
||||||
# Normalize load balancing defaults.
|
|
||||||
handle_load_balance_method(self)
|
|
||||||
|
|
||||||
# Re-apply after model-specific defaults resolve attention_backend so
|
|
||||||
# canonical CP mirrors to the right legacy runtime aliases.
|
|
||||||
handle_legacy_cp_arguments(self)
|
|
||||||
|
|
||||||
# Handle context parallelism.
|
|
||||||
handle_context_parallelism(self)
|
|
||||||
|
|
||||||
# Handle MoE configurations.
|
|
||||||
from sglang.srt.arg_groups.moe_hook import (
|
|
||||||
handle_a2a_moe,
|
|
||||||
handle_moe_kernel_config,
|
|
||||||
validate_cutedsl_a2a_token_budget,
|
|
||||||
validate_deepep_v2_dispatch_token_budget,
|
|
||||||
validate_deepep_v2_speculative_draft,
|
|
||||||
)
|
|
||||||
|
|
||||||
handle_moe_kernel_config(self)
|
|
||||||
handle_a2a_moe(self)
|
|
||||||
handle_eplb_and_dispatch(self)
|
|
||||||
handle_expert_distribution_metrics(self)
|
|
||||||
handle_elastic_ep(self)
|
|
||||||
validate_experimental_sgl_marlin(self)
|
|
||||||
|
|
||||||
# Handle pipeline parallelism.
|
|
||||||
self._handle_pipeline_parallelism()
|
|
||||||
|
|
||||||
# Handle speculative decoding logic.
|
|
||||||
|
|
||||||
from sglang.srt.arg_groups.speculative_hook import handle_speculative_decoding
|
|
||||||
|
|
||||||
handle_speculative_decoding(self)
|
|
||||||
|
|
||||||
# Validate the CuteDSL A2A token budget now that num_tokens_per_req is final.
|
|
||||||
validate_cutedsl_a2a_token_budget(self)
|
|
||||||
|
|
||||||
# Handle model loading format.
|
|
||||||
handle_load_format(self)
|
|
||||||
|
|
||||||
# Handle Encoder disaggregation.
|
|
||||||
handle_encoder_disaggregation(self)
|
|
||||||
|
|
||||||
# Validate tokenizer settings.
|
|
||||||
handle_tokenizer_batching(self)
|
|
||||||
|
|
||||||
# Propagate environment variables.
|
|
||||||
handle_environment_variables(self)
|
|
||||||
|
|
||||||
# Validate cache settings.
|
|
||||||
handle_cache_compatibility(self)
|
|
||||||
|
|
||||||
handle_page_major_kv_layout(self)
|
|
||||||
|
|
||||||
handle_unified_memory_pool(self)
|
|
||||||
|
|
||||||
# Handle diffusion LLM inference.
|
|
||||||
from sglang.srt.arg_groups.dllm_hook import handle_dllm_inference
|
|
||||||
|
|
||||||
handle_dllm_inference(self)
|
|
||||||
|
|
||||||
# Handle crash dump environment variables (must run before CUDA init).
|
|
||||||
handle_crash_dump_env(self)
|
|
||||||
|
|
||||||
# Handle debug utilities.
|
|
||||||
handle_debug_utils(self)
|
|
||||||
|
|
||||||
# Handle any other necessary validations.
|
|
||||||
handle_other_validations(self)
|
|
||||||
|
|
||||||
# Model-capability adjustments that legacy code applied at model-load
|
|
||||||
# time; last declarations of the resolution, mirroring that order.
|
|
||||||
handle_model_capability_adjustments(self)
|
|
||||||
|
|
||||||
# Validate after all batch-size declarations are visible.
|
|
||||||
validate_deepep_v2_speculative_draft(self)
|
|
||||||
validate_deepep_v2_dispatch_token_budget(self)
|
|
||||||
|
|
||||||
self._resolution_finished = True
|
|
||||||
|
|
||||||
def _handle_hardware_runtime_validation(self):
|
|
||||||
# This is intentionally independent of self.device: setting
|
|
||||||
# SGLANG_USE_MLX opts into the MLX backend and must fail immediately if
|
|
||||||
# the environment cannot honor that request. With the flag unset,
|
|
||||||
# use_mlx() remains lazy and does not import MLX.
|
|
||||||
use_mlx()
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# CUDA graph configuration resolution
|
# CUDA graph configuration resolution
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
@@ -4366,16 +4026,6 @@ class ServerArgs:
|
|||||||
|
|
||||||
return supports_mamba_cache_extra_buffer(self, model_arch)
|
return supports_mamba_cache_extra_buffer(self, model_arch)
|
||||||
|
|
||||||
def _handle_sampling_backend(self):
|
|
||||||
# Moved to the resolution pipeline (arg_groups/overrides.py:
|
|
||||||
# _sampling_backend_default), invoked here at its legacy slot.
|
|
||||||
from sglang.srt.arg_groups.overrides import (
|
|
||||||
_sampling_backend_default,
|
|
||||||
run_post_process_pass,
|
|
||||||
)
|
|
||||||
|
|
||||||
run_post_process_pass(self, _sampling_backend_default)
|
|
||||||
|
|
||||||
def _get_default_attn_backend(self, use_mla_backend: bool, model_config):
|
def _get_default_attn_backend(self, use_mla_backend: bool, model_config):
|
||||||
"""
|
"""
|
||||||
Auto select the fastest attention backend.
|
Auto select the fastest attention backend.
|
||||||
@@ -4451,16 +4101,6 @@ class ServerArgs:
|
|||||||
else:
|
else:
|
||||||
return "triton"
|
return "triton"
|
||||||
|
|
||||||
def _handle_page_size(self):
|
|
||||||
# Moved to the resolution pipeline (arg_groups/overrides.py:
|
|
||||||
# _page_size_default), invoked here at its legacy slot.
|
|
||||||
from sglang.srt.arg_groups.overrides import (
|
|
||||||
_page_size_default,
|
|
||||||
run_post_process_pass,
|
|
||||||
)
|
|
||||||
|
|
||||||
run_post_process_pass(self, _page_size_default)
|
|
||||||
|
|
||||||
def cutedsl_moe_max_num_tokens(self) -> int:
|
def cutedsl_moe_max_num_tokens(self) -> int:
|
||||||
"""Largest number of tokens a single forward routes through a CuteDSL
|
"""Largest number of tokens a single forward routes through a CuteDSL
|
||||||
MoE layer on one (DP) rank. Single source of truth for both the
|
MoE layer on one (DP) rank. Single source of truth for both the
|
||||||
@@ -4511,16 +4151,6 @@ class ServerArgs:
|
|||||||
|
|
||||||
# ===== END TO BE REFACTORED ====
|
# ===== END TO BE REFACTORED ====
|
||||||
|
|
||||||
def _handle_pipeline_parallelism(self):
|
|
||||||
# Moved to the resolution pipeline (arg_groups/overrides.py:
|
|
||||||
# _pipeline_parallel_overlap_disable), invoked here at its legacy slot.
|
|
||||||
from sglang.srt.arg_groups.overrides import (
|
|
||||||
_pipeline_parallel_overlap_disable,
|
|
||||||
run_post_process_pass,
|
|
||||||
)
|
|
||||||
|
|
||||||
run_post_process_pass(self, _pipeline_parallel_overlap_disable)
|
|
||||||
|
|
||||||
def _is_mistral_native_format(self) -> bool:
|
def _is_mistral_native_format(self) -> bool:
|
||||||
"""True iff the checkpoint requires load_format=mistral.
|
"""True iff the checkpoint requires load_format=mistral.
|
||||||
|
|
||||||
|
|||||||
@@ -311,6 +311,11 @@ def _hook_declarations(dispatch, source_module):
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
# The dispatcher's own file: its imports are what map a bare-name call in it
|
||||||
|
# to the family that defines the callable.
|
||||||
|
_DISPATCH_MODULE = _SRT / "arg_groups" / "pipeline.py"
|
||||||
|
|
||||||
|
|
||||||
def _hook_functions():
|
def _hook_functions():
|
||||||
"""Module-level resolution functions under `arg_groups/`.
|
"""Module-level resolution functions under `arg_groups/`.
|
||||||
|
|
||||||
@@ -341,7 +346,7 @@ def _pipeline():
|
|||||||
# against `arg_groups/` alongside the record's own methods.
|
# against `arg_groups/` alongside the record's own methods.
|
||||||
hooks = _hook_functions()
|
hooks = _hook_functions()
|
||||||
methods.update({name: node for name, node in hooks.items() if name not in methods})
|
methods.update({name: node for name, node in hooks.items() if name not in methods})
|
||||||
dispatch = methods["_run_resolution_pipeline"]
|
dispatch = methods["run_resolution_pipeline"]
|
||||||
# A step is either a record method (`self._x()`) or a bare-name hook call.
|
# A step is either a record method (`self._x()`) or a bare-name hook call.
|
||||||
steps = [
|
steps = [
|
||||||
name
|
name
|
||||||
@@ -501,7 +506,7 @@ def _declaration_positions():
|
|||||||
build_index, build_step, build_method, build_line_in_body = site
|
build_index, build_step, build_method, build_line_in_body = site
|
||||||
first_build = (build_index, build_step)
|
first_build = (build_index, build_step)
|
||||||
|
|
||||||
source_module = _SRT / "server_args.py"
|
source_module = _DISPATCH_MODULE
|
||||||
imported = {}
|
imported = {}
|
||||||
for node in ast.walk(_parsed(source_module)):
|
for node in ast.walk(_parsed(source_module)):
|
||||||
if isinstance(node, ast.ImportFrom) and node.module:
|
if isinstance(node, ast.ImportFrom) and node.module:
|
||||||
@@ -551,9 +556,9 @@ def _declaration_positions():
|
|||||||
# the dispatcher*: a handler body sits further down the file than the
|
# the dispatcher*: a handler body sits further down the file than the
|
||||||
# dispatcher that calls it, so a line number taken from one scope says
|
# dispatcher that calls it, so a line number taken from one scope says
|
||||||
# nothing about ordering against the other.
|
# nothing about ordering against the other.
|
||||||
dispatch = methods["_run_resolution_pipeline"]
|
dispatch = methods["run_resolution_pipeline"]
|
||||||
build_line = step_lines[first_build[1]]
|
build_line = step_lines[first_build[1]]
|
||||||
for field, line in _hook_declarations(dispatch, _SRT / "server_args.py").items():
|
for field, line in _hook_declarations(dispatch, _DISPATCH_MODULE).items():
|
||||||
if field in wanted and line > build_line:
|
if field in wanted and line > build_line:
|
||||||
declared_at[field] = max(
|
declared_at[field] = max(
|
||||||
declared_at.get(field, (build_index, 1)), (10**6, 1)
|
declared_at.get(field, (build_index, 1)), (10**6, 1)
|
||||||
@@ -656,8 +661,8 @@ class TestModelConfigReadsResolvedInput(CustomTestCase):
|
|||||||
documents a hazard that no longer exists and hides the day one appears.
|
documents a hazard that no longer exists and hides the day one appears.
|
||||||
"""
|
"""
|
||||||
steps, methods, reached, step_lines = _pipeline()
|
steps, methods, reached, step_lines = _pipeline()
|
||||||
dispatch = methods["_run_resolution_pipeline"]
|
dispatch = methods["run_resolution_pipeline"]
|
||||||
hooks = _hook_declarations(dispatch, _SRT / "server_args.py")
|
hooks = _hook_declarations(dispatch, _DISPATCH_MODULE)
|
||||||
build_line = min(
|
build_line = min(
|
||||||
step_lines[step]
|
step_lines[step]
|
||||||
for step in steps
|
for step in steps
|
||||||
@@ -695,8 +700,8 @@ class TestModelConfigReadsResolvedInput(CustomTestCase):
|
|||||||
then, rather than keeping a note about a hazard that is gone.
|
then, rather than keeping a note about a hazard that is gone.
|
||||||
"""
|
"""
|
||||||
steps, methods, reached, step_lines = _pipeline()
|
steps, methods, reached, step_lines = _pipeline()
|
||||||
dispatch = methods["_run_resolution_pipeline"]
|
dispatch = methods["run_resolution_pipeline"]
|
||||||
positions = _opaque_callback_positions(dispatch, _SRT / "server_args.py")
|
positions = _opaque_callback_positions(dispatch, _DISPATCH_MODULE)
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
sorted(positions),
|
sorted(positions),
|
||||||
[
|
[
|
||||||
|
|||||||
@@ -526,14 +526,16 @@ class TestResolutionDeclarations(CustomTestCase):
|
|||||||
reset_context()
|
reset_context()
|
||||||
child = pickle.loads(blob)
|
child = pickle.loads(blob)
|
||||||
entered = []
|
entered = []
|
||||||
original = ServerArgs._run_resolution_pipeline
|
from sglang.srt.arg_groups import pipeline as pipeline_module
|
||||||
|
|
||||||
def counted(self, _original=original):
|
original = pipeline_module.run_resolution_pipeline
|
||||||
|
|
||||||
|
def counted(server_args, _original=original):
|
||||||
entered.append(1)
|
entered.append(1)
|
||||||
return _original(self)
|
return _original(server_args)
|
||||||
|
|
||||||
with unittest.mock.patch.object(
|
with unittest.mock.patch.object(
|
||||||
ServerArgs, "_run_resolution_pipeline", counted
|
pipeline_module, "run_resolution_pipeline", counted
|
||||||
):
|
):
|
||||||
publish(child, role="scheduler")
|
publish(child, role="scheduler")
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@@ -848,7 +850,7 @@ class TestResolutionDeclarations(CustomTestCase):
|
|||||||
"capturing like apply_server_args_defaults",
|
"capturing like apply_server_args_defaults",
|
||||||
)
|
)
|
||||||
|
|
||||||
pipeline = (_SRT / "server_args.py").read_text(encoding="utf-8-sig")
|
pipeline = (_SRT / "arg_groups" / "pipeline.py").read_text(encoding="utf-8-sig")
|
||||||
for hook in sorted(taking_the_record):
|
for hook in sorted(taking_the_record):
|
||||||
self.assertIn(
|
self.assertIn(
|
||||||
f"current_platform.{hook},",
|
f"current_platform.{hook},",
|
||||||
@@ -892,9 +894,11 @@ class TestResolutionDeclarations(CustomTestCase):
|
|||||||
server_args.attention_backend = "triton"
|
server_args.attention_backend = "triton"
|
||||||
server_args.schedule_conservativeness = 0.5
|
server_args.schedule_conservativeness = 0.5
|
||||||
|
|
||||||
with unittest.mock.patch.object(
|
from sglang.srt.arg_groups import pipeline as pipeline_module
|
||||||
server_args_module, "current_platform", _Plugin()
|
|
||||||
):
|
# The write capture runs in the dispatcher, so that is the namespace the
|
||||||
|
# plugin has to be installed in.
|
||||||
|
with unittest.mock.patch.object(pipeline_module, "current_platform", _Plugin()):
|
||||||
server_args = self._resolve({})
|
server_args = self._resolve({})
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -445,14 +445,16 @@ class TestResolutionIsReproducible(_RestoresProcessState, CustomTestCase):
|
|||||||
record.resolve_once()
|
record.resolve_once()
|
||||||
|
|
||||||
entries = []
|
entries = []
|
||||||
original = ServerArgs._run_resolution_pipeline
|
from sglang.srt.arg_groups import pipeline as pipeline_module
|
||||||
|
|
||||||
def counted(self):
|
original = pipeline_module.run_resolution_pipeline
|
||||||
|
|
||||||
|
def counted(server_args):
|
||||||
entries.append(1)
|
entries.append(1)
|
||||||
return original(self)
|
return original(server_args)
|
||||||
|
|
||||||
with unittest.mock.patch.object(
|
with unittest.mock.patch.object(
|
||||||
ServerArgs, "_run_resolution_pipeline", counted
|
pipeline_module, "run_resolution_pipeline", counted
|
||||||
):
|
):
|
||||||
record.resolve_once()
|
record.resolve_once()
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@@ -964,7 +966,7 @@ class TestTheResolutionSeamHasOneCaller(CustomTestCase):
|
|||||||
for path in sorted(package_root.rglob("*.py")):
|
for path in sorted(package_root.rglob("*.py")):
|
||||||
try:
|
try:
|
||||||
source = path.read_text()
|
source = path.read_text()
|
||||||
if "_run_resolution_pipeline" not in source:
|
if "run_resolution_pipeline" not in source:
|
||||||
continue
|
continue
|
||||||
tree = ast.parse(source)
|
tree = ast.parse(source)
|
||||||
except SyntaxError:
|
except SyntaxError:
|
||||||
@@ -984,8 +986,8 @@ class TestTheResolutionSeamHasOneCaller(CustomTestCase):
|
|||||||
for node in ast.walk(tree):
|
for node in ast.walk(tree):
|
||||||
if (
|
if (
|
||||||
isinstance(node, ast.Call)
|
isinstance(node, ast.Call)
|
||||||
and isinstance(node.func, ast.Attribute)
|
and isinstance(node.func, ast.Name)
|
||||||
and node.func.attr == "_run_resolution_pipeline"
|
and node.func.id == "run_resolution_pipeline"
|
||||||
):
|
):
|
||||||
rel = path.relative_to(package_root).as_posix()
|
rel = path.relative_to(package_root).as_posix()
|
||||||
callers.append((rel, ".".join(scopes.get(id(node), ()))))
|
callers.append((rel, ".".join(scopes.get(id(node), ()))))
|
||||||
@@ -1131,12 +1133,14 @@ class TestResolutionStaysLazy(CustomTestCase):
|
|||||||
import sglang
|
import sglang
|
||||||
|
|
||||||
srt = pathlib.Path(next(iter(sglang.__path__))).resolve() / "srt"
|
srt = pathlib.Path(next(iter(sglang.__path__))).resolve() / "srt"
|
||||||
tree = ast.parse((srt / "server_args.py").read_text(encoding="utf-8-sig"))
|
tree = ast.parse(
|
||||||
|
(srt / "arg_groups" / "pipeline.py").read_text(encoding="utf-8-sig")
|
||||||
|
)
|
||||||
dispatch = next(
|
dispatch = next(
|
||||||
node
|
node
|
||||||
for node in ast.walk(tree)
|
for node in ast.walk(tree)
|
||||||
if isinstance(node, ast.FunctionDef)
|
if isinstance(node, ast.FunctionDef)
|
||||||
and node.name == "_run_resolution_pipeline"
|
and node.name == "run_resolution_pipeline"
|
||||||
)
|
)
|
||||||
early_return = min(
|
early_return = min(
|
||||||
(
|
(
|
||||||
|
|||||||
@@ -81,37 +81,6 @@ def _field_reads(fn, holders):
|
|||||||
yield node.lineno, node.attr
|
yield node.lineno, node.attr
|
||||||
|
|
||||||
|
|
||||||
def _resolution_handlers():
|
|
||||||
"""The `ServerArgs` methods the dispatcher reaches, transitively."""
|
|
||||||
tree = ast.parse((_SRT / "server_args.py").read_text(encoding="utf-8-sig"))
|
|
||||||
cls = next(
|
|
||||||
node
|
|
||||||
for node in ast.walk(tree)
|
|
||||||
if isinstance(node, ast.ClassDef) and node.name == "ServerArgs"
|
|
||||||
)
|
|
||||||
methods = {
|
|
||||||
node.name: node
|
|
||||||
for node in cls.body
|
|
||||||
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
|
|
||||||
}
|
|
||||||
assert "_run_resolution_pipeline" in methods, "the dispatcher was renamed"
|
|
||||||
seen, stack = set(), ["_run_resolution_pipeline"]
|
|
||||||
while stack:
|
|
||||||
name = stack.pop()
|
|
||||||
if name in seen or name not in methods:
|
|
||||||
continue
|
|
||||||
seen.add(name)
|
|
||||||
for node in ast.walk(methods[name]):
|
|
||||||
if (
|
|
||||||
isinstance(node, ast.Call)
|
|
||||||
and isinstance(node.func, ast.Attribute)
|
|
||||||
and isinstance(node.func.value, ast.Name)
|
|
||||||
and node.func.value.id == "self"
|
|
||||||
):
|
|
||||||
stack.append(node.func.attr)
|
|
||||||
return {name: methods[name] for name in seen}
|
|
||||||
|
|
||||||
|
|
||||||
_DECLARERS = frozenset(
|
_DECLARERS = frozenset(
|
||||||
{
|
{
|
||||||
"_declare",
|
"_declare",
|
||||||
@@ -469,35 +438,30 @@ class TestResolutionReadsTheDeclarations(CustomTestCase):
|
|||||||
+ "\n ".join(offenders),
|
+ "\n ".join(offenders),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_no_handler_reads_a_field_off_self(self):
|
def test_the_record_hosts_no_resolution_handler(self):
|
||||||
handlers = _resolution_handlers()
|
"""The pipeline and every step it runs live under `arg_groups/`.
|
||||||
# What the dispatcher reaches inside the class is these read wrappers;
|
|
||||||
# the package side is covered by
|
While a step was a method, it could read a raw field off `self` and
|
||||||
# `test_no_hook_reads_a_field_off_the_record`. Pinned rather than
|
`test_no_handler_reads_a_field_off_self` had to say it could not. There
|
||||||
# counted: a walk that collapsed to the wrappers would clear any floor
|
is no such method left, so the invariant is now the stronger one: the
|
||||||
# low enough to admit them.
|
record hosts none of them. What the steps read is checked on the
|
||||||
self.assertEqual(
|
package side, by `test_no_hook_reads_a_field_off_the_record`.
|
||||||
set(handlers),
|
"""
|
||||||
{
|
handlers = sorted(
|
||||||
"_run_resolution_pipeline",
|
name
|
||||||
"_handle_hardware_runtime_validation",
|
for name, node in _record_members().items()
|
||||||
"_handle_page_size",
|
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef))
|
||||||
"_handle_pipeline_parallelism",
|
and (
|
||||||
"_handle_sampling_backend",
|
name.split(".")[-1].startswith(("_handle_", "_validate_"))
|
||||||
},
|
or "resolution_pipeline" in name
|
||||||
f"the walk reached {sorted(handlers)}; if the dispatcher grew or "
|
)
|
||||||
"lost a handler, add it here after checking it reads the view",
|
|
||||||
)
|
)
|
||||||
offenders = []
|
|
||||||
for name, fn in sorted(handlers.items()):
|
|
||||||
for lineno, field in _field_reads(fn, {"self"}):
|
|
||||||
offenders.append(f"server_args.py:{lineno} {name} reads self.{field}")
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
offenders,
|
handlers,
|
||||||
[],
|
[],
|
||||||
"a resolution handler reads its own field; the field holds the raw "
|
"a resolution handler is back on the record; it belongs in an "
|
||||||
"input. Bind `cfg = resolving_view(self)` and read that:\n "
|
"`arg_groups` family, where the package-side guards can see it:\n "
|
||||||
+ "\n ".join(offenders),
|
+ "\n ".join(handlers),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_no_member_recomputes_from_a_raw_field(self):
|
def test_no_member_recomputes_from_a_raw_field(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user