config: business code no longer reads the published ServerArgs (#34081)

This commit is contained in:
Cheng Wan
2026-08-09 14:44:08 -07:00
committed by GitHub
parent 110bf7e6a8
commit 63833f8034
35 changed files with 1101 additions and 213 deletions
@@ -49,7 +49,9 @@ from sglang.srt.hardware_backend.mlx.kv_cache import (
uses_sliding_window_attention,
)
from sglang.srt.mem_cache.memory_pool import ReqToTokenPool
from sglang.srt.runtime_context import get_server_args
from sglang.srt.runtime_context import (
mamba_cache_chunk_size,
)
logger = logging.getLogger(__name__)
@@ -281,7 +283,7 @@ class MlxModelRunner:
):
return None
chunk_size = get_server_args().mamba_cache_chunk_size
chunk_size = mamba_cache_chunk_size()
track_len = prefix_len + (new_token_count // chunk_size) * chunk_size
branching_len = getattr(req, "mamba_branching_seqlen", None)
if (
@@ -40,11 +40,11 @@ from sglang.srt.model_executor.runner_backend_utils.tc_piecewise_cuda_graph impo
is_in_tc_piecewise_cuda_graph,
)
from sglang.srt.runtime_context import (
configured_pp_size,
get_device,
get_exec,
get_parallel,
get_schedule,
get_server_args,
)
from sglang.srt.state_capturer.indexer_topk import (
maybe_capture_indexer_topk,
@@ -249,7 +249,7 @@ class Indexer(DSANPUIndexerMixin, BaseFusedOp):
if _is_cuda:
self.sm_count = deep_gemm.get_num_sms()
self.half_device_sm_count = ceil_align(self.sm_count // 2, 8)
pp_size = get_server_args().pp_size
pp_size = configured_pp_size()
self.logits_with_pp_recv = pp_size > 1 and not get_pp_group().is_last_rank
else:
self.logits_with_pp_recv = False
@@ -12,7 +12,10 @@ from sglang.srt.model_executor.runner_backend_utils.breakable_cuda_graph import
from sglang.srt.model_executor.runner_backend_utils.tc_piecewise_cuda_graph import (
is_in_tc_piecewise_cuda_graph,
)
from sglang.srt.runtime_context import get_parallel, get_server_args
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.common import ceil_align, ceil_div
@@ -113,7 +116,7 @@ def is_dsa_enable_prefill_cp():
return False
from sglang.srt.configs.model_config import is_deepseek_dsa, is_deepseek_v4
hf_config = get_server_args().get_model_config().hf_config
hf_config = process_model_config().hf_config
return is_deepseek_dsa(hf_config) or is_deepseek_v4(hf_config)
@@ -25,7 +25,11 @@ from sglang.srt.layers.radix_attention import RadixAttention
from sglang.srt.mem_cache.memory_pool import HybridReqToTokenPool
from sglang.srt.model_executor.forward_batch_info import ForwardBatch, ForwardMode
from sglang.srt.model_executor.model_runner import ModelRunner
from sglang.srt.runtime_context import get_exec, get_memory, get_server_args
from sglang.srt.runtime_context import (
get_exec,
get_memory,
mamba_cache_chunk_size,
)
from sglang.srt.speculative.eagle_info import EagleDraftInput, EagleVerifyInput
from sglang.srt.speculative.spec_info import SpecInput
@@ -297,8 +301,8 @@ class MambaAttnBackendBase(AttentionBackend):
lens_to_track = (
forward_batch.mamba_track_seqlens - forward_batch.extend_prefix_lens
)
mamba_cache_chunk_size = get_server_args().mamba_cache_chunk_size
aligned_len = (lens_to_track // mamba_cache_chunk_size) * mamba_cache_chunk_size
chunk_size = mamba_cache_chunk_size()
aligned_len = (lens_to_track // chunk_size) * chunk_size
start_indices = query_start_loc[:-1] + aligned_len - conv_state_len
start_indices = start_indices[forward_batch.mamba_track_mask]
@@ -316,7 +320,7 @@ class MambaAttnBackendBase(AttentionBackend):
"""src/dst indices to track SSM states for prefix caching: aligned seqs
cache last_recurrent_state, unaligned cache intermediate `h` at the last
chunk boundary."""
mamba_cache_chunk_size = get_server_args().mamba_cache_chunk_size
chunk_size = mamba_cache_chunk_size()
# CPU to avoid kernel launches for the masking ops
mamba_track_mask = forward_batch.mamba_track_mask.cpu()
extend_seq_lens = forward_batch.extend_seq_lens.cpu()
@@ -326,9 +330,9 @@ class MambaAttnBackendBase(AttentionBackend):
prefix_lens = forward_batch.extend_prefix_lens.cpu()
if isinstance(self, Mamba2AttnBackend):
num_h_states = extend_seq_lens // mamba_cache_chunk_size
num_h_states = extend_seq_lens // chunk_size
else:
num_h_states = (extend_seq_lens - 1) // mamba_cache_chunk_size + 1
num_h_states = (extend_seq_lens - 1) // chunk_size + 1
track_ssm_src_offset = torch.zeros_like(num_h_states)
track_ssm_src_offset[1:] = torch.cumsum(num_h_states[:-1], dim=0)
@@ -338,17 +342,17 @@ class MambaAttnBackendBase(AttentionBackend):
offset_masked = track_ssm_src_offset[mamba_track_mask]
dst_masked = mamba_track_indices[mamba_track_mask]
is_aligned = (lens_masked % mamba_cache_chunk_size) == 0
is_aligned = (lens_masked % chunk_size) == 0
# Aligned: last_recurrent_state from ssm_states.
track_ssm_final_src = mamba_cache_indices[mamba_track_mask][is_aligned]
track_ssm_final_dst = dst_masked[is_aligned]
# Unaligned: intermediate state from h.
# TODO: handle mamba_cache_chunk_size % page size != 0
# TODO: handle chunk_size % page size != 0
not_aligned = ~is_aligned
track_ssm_h_src = offset_masked[not_aligned] + (
lens_masked[not_aligned] // mamba_cache_chunk_size
lens_masked[not_aligned] // chunk_size
)
track_ssm_h_dst = dst_masked[not_aligned]
@@ -62,7 +62,11 @@ from sglang.srt.models.inkling_common.kernels.sconv import (
fused_extend_sconv_metadata,
precompute_helion_extend_metadata,
)
from sglang.srt.runtime_context import get_exec, get_server_args, get_spec
from sglang.srt.runtime_context import (
get_exec,
get_spec,
mamba_cache_chunk_size,
)
from sglang.srt.speculative.eagle_info import EagleDraftExtendInput
if TYPE_CHECKING:
@@ -99,7 +103,7 @@ class InklingShortConvAttnBackend(ShortConvAttnBackend):
# [n_layers, n_slots, conv_kernel - 1, conv_dim].
self._mamba_cache = self.req_to_token_pool.mamba_pool.mamba_cache
self.conv_state_len: int = self.conv_states_shape[2]
self.mamba_cache_chunk_size = get_server_args().mamba_cache_chunk_size
self.mamba_cache_chunk_size = mamba_cache_chunk_size()
# A plain table lookup is recordable; the unified pool's translate is an
# allocator lookup and must stay in the out-of-graph replay prep.
self._slot_gather_recordable = (
@@ -19,7 +19,9 @@ import torch
from sglang.srt.layers.attention.linear.kernels.kernel_backend import (
LinearAttnKernelBase,
)
from sglang.srt.runtime_context import get_server_args
from sglang.srt.runtime_context import (
mamba_cache_chunk_size,
)
from sglang.srt.utils import is_cuda
if TYPE_CHECKING:
@@ -50,7 +52,7 @@ def maybe_build_flashinfer_checkpoint_plan(
):
return
checkpoint_every_n_tokens = get_server_args().mamba_cache_chunk_size
checkpoint_every_n_tokens = mamba_cache_chunk_size()
extend_seq_lens = forward_batch.extend_seq_lens.to(device="cpu", dtype=torch.int64)
track_mask = forward_batch.mamba_track_mask.to(device="cpu", dtype=torch.bool)
relative_track_lens = forward_batch.mamba_track_seqlens.to(
@@ -37,6 +37,7 @@ from sglang.srt.layers.attention.linear.kernels.kda_triton import TritonKDAKerne
from sglang.srt.layers.attention.linear.kernels.kernel_backend import (
LinearAttnKernelBase,
)
from sglang.srt.runtime_context import mamba_cache_chunk_size
logger = logging.getLogger(__name__)
@@ -194,11 +195,8 @@ class PtxKDAKernel(LinearAttnKernelBase):
# which may be larger (for example 256 for Nemotron-H). Returning
# the raw 64-token rows in that case would silently select the
# wrong boundary and compute wrong offsets for later sequences.
from sglang.srt.runtime_context import get_server_args
intermediate_stride_supported = (
get_server_args().mamba_cache_chunk_size == _CHUNK
)
intermediate_stride_supported = mamba_cache_chunk_size() == _CHUNK
seq_lens = (
[int(length) for length in seq_lens_cpu] if seq_lens_cpu is not None else []
)
@@ -15,7 +15,10 @@ from sglang.srt.layers.attention.linear.linear_metadata import (
from sglang.srt.layers.radix_attention import RadixAttention
from sglang.srt.model_executor.forward_batch_info import ForwardBatch
from sglang.srt.model_executor.model_runner import ModelRunner
from sglang.srt.runtime_context import get_parallel, get_server_args
from sglang.srt.runtime_context import (
get_parallel,
mamba_cache_chunk_size,
)
logger = logging.getLogger(__name__)
@@ -299,7 +302,7 @@ class LightningAttentionBackend(MambaAttnBackendBase):
if h_dst is None or h_dst.numel() == 0:
return None, None
mamba_cache_chunk_size = get_server_args().mamba_cache_chunk_size
chunk_size = mamba_cache_chunk_size()
num_prefills = metadata.num_prefills
track_mask = forward_batch.mamba_track_mask[:num_prefills]
extend_lens = forward_batch.extend_seq_lens[:num_prefills]
@@ -307,9 +310,7 @@ class LightningAttentionBackend(MambaAttnBackendBase):
track_seqlens = forward_batch.mamba_track_seqlens[:num_prefills]
lens_to_track = track_seqlens - prefix_lens
boundary_lens = (
lens_to_track // mamba_cache_chunk_size
) * mamba_cache_chunk_size
boundary_lens = (lens_to_track // chunk_size) * chunk_size
track_rows = (track_mask & (boundary_lens < extend_lens)).nonzero(
as_tuple=True
)[0]
+8 -5
View File
@@ -230,12 +230,15 @@ class ContextParallelStrategy(ABC):
def _is_dsa_active() -> bool:
from sglang.srt.runtime_context import get_server_args
from sglang.srt.runtime_context import get_parallel, get_server_args
sa = get_server_args()
# `_is_dsa_model_arch` is set nowhere in the tree, so this predicate is
# inert today (the getattr default makes it False). Kept verbatim rather
# than "fixed" here, because deciding what it should name is the CP path's
# call; the ratchet exempts it with that reason.
return bool(
getattr(sa, "enable_prefill_cp", False)
and getattr(sa, "_is_dsa_model_arch", False)
get_parallel().enable_prefill_cp
and getattr(get_server_args(), "_is_dsa_model_arch", False)
)
@@ -288,7 +291,7 @@ def get_cp_strategy() -> Optional[ContextParallelStrategy]:
server_args = get_server_args()
except ValueError:
return None
if server_args is not None and getattr(server_args, "enable_prefill_cp", False):
if server_args is not None and get_parallel().enable_prefill_cp:
init_cp_strategy(server_args)
return _STRATEGY
+6 -3
View File
@@ -27,7 +27,11 @@ from sglang.srt.distributed import (
from sglang.srt.distributed.device_communicators.pynccl_allocator import (
use_symmetric_memory,
)
from sglang.srt.runtime_context import get_flags, get_server_args
from sglang.srt.runtime_context import (
configured_attn_cp_size,
configured_moe_dp_size,
get_flags,
)
from sglang.srt.utils import get_bool_env_var, is_hip
if TYPE_CHECKING:
@@ -986,8 +990,7 @@ def is_enable_moe_cp_allgather() -> bool:
(``parallel_state.py``), so the live sizes are equal and the comparison would
always be false.
"""
server_args = get_server_args()
return server_args.attn_cp_size > server_args.moe_dp_size
return configured_attn_cp_size() > configured_moe_dp_size()
def moe_cp_all_gather_into_tensor(output: torch.Tensor, input: torch.Tensor):
+8 -7
View File
@@ -67,16 +67,17 @@ def _get_state() -> Optional[_State]:
if get_device_sm() not in (100, 103):
return None
server_args = ctx.get_server_args()
if server_args.enable_symm_mem or server_args.moe_a2a_backend != "none":
symm_mem = ctx.get_exec().comm.enable_symm_mem
a2a_backend = ctx.get_exec().moe.moe_a2a_backend
if symm_mem or a2a_backend != "none":
logger.info(
"K3 all-reduce fusion auto-probe: skipping "
"(enable_symm_mem=%s, moe_a2a_backend=%s; under symm-mem the "
"allocator contexts conflict, and under EP a2a the model's "
"symm-pool allocation contract does not hold on every AR "
"call-site. Set SGLANG_K3_AR_FUSION=1 to force.)",
server_args.enable_symm_mem,
server_args.moe_a2a_backend,
symm_mem,
a2a_backend,
)
return None
from sglang.srt.distributed.device_communicators.custom_all_reduce_v2 import (
@@ -131,11 +132,11 @@ _BUFS: List[_Buffer] = []
@cache_once
def _max_buffer_rows() -> int:
"""Rows to reserve per buffer: the largest batch the server args allow."""
server_args = ctx.get_server_args()
chunked = server_args.chunked_prefill_size
schedule = ctx.get_schedule()
chunked = schedule.chunked_prefill_size
if chunked is not None and chunked > 0:
return int(chunked)
return int(server_args.max_prefill_tokens or 0)
return int(schedule.max_prefill_tokens or 0)
def _create_buffer(
@@ -12,7 +12,10 @@ from sglang.srt.layers.moe.moe_runner.base import (
register_fused_func,
)
from sglang.srt.model_executor.cuda_graph_config import cuda_graph_fully_disabled
from sglang.srt.runtime_context import get_parallel
from sglang.srt.runtime_context import (
cutedsl_moe_max_num_tokens,
get_parallel,
)
from sglang.srt.utils.common import log_info_on_rank0, print_warning_once
if TYPE_CHECKING:
@@ -256,14 +259,11 @@ def ensure_cutedsl_wrapper(layer: torch.nn.Module) -> None:
"Install with: pip install flashinfer"
) from e
from sglang.srt.runtime_context import get_server_args
assert layer.intermediate_size_per_partition > 0, (
f"CuteDSL MoE: intermediate_size_per_partition must be > 0, "
f"got {layer.intermediate_size_per_partition}. Check EP/TP configuration."
)
server_args = get_server_args()
# CuteDSL wrapper preallocates CG buffers used by any captured graph
# that routes through this MoE — decode and prefill alike.
use_cuda_graph = not cuda_graph_fully_disabled()
@@ -277,9 +277,7 @@ def ensure_cutedsl_wrapper(layer: torch.nn.Module) -> None:
else:
# Standard allgather path: the MoE sees up to dp_size local forwards
# gathered together, so scale the per-rank forward bound by dp_size.
max_num_tokens = (
get_parallel().dp_size * server_args.cutedsl_moe_max_num_tokens()
)
max_num_tokens = get_parallel().dp_size * cutedsl_moe_max_num_tokens()
top_k = layer.top_k if layer.top_k is not None else layer.moe_runner_config.top_k
# inference_mode(False) ensures the wrapper's pre-allocated CUDA-graph
# buffers are normal tensors. This call typically happens inside
+5 -3
View File
@@ -15,7 +15,10 @@ from sglang.srt.layers.dp_attention import (
from sglang.srt.layers.moe import get_moe_a2a_backend
from sglang.srt.mem_cache.memory_pool import KVWriteLoc
from sglang.srt.model_executor.forward_context import get_token_to_kv_pool
from sglang.srt.runtime_context import get_parallel, get_server_args
from sglang.srt.runtime_context import (
get_parallel,
uses_mla_backend,
)
@dataclass
@@ -69,8 +72,7 @@ def is_prefill_cp_in_seq_split():
def is_mla_prefill_cp_enabled() -> bool:
sa = get_server_args()
return get_parallel().enable_prefill_context_parallel and sa.use_mla_backend()
return get_parallel().enable_prefill_context_parallel and uses_mla_backend()
def mla_use_prefill_cp(forward_batch, mla_enable_prefill_cp=None):
+12 -14
View File
@@ -7,6 +7,7 @@ from sglang.srt.runtime_context import (
get_schedule,
get_serving,
get_spec,
mamba_cache_chunk_size,
mamba_extra_buffer_enabled,
mamba_extra_buffer_lazy_enabled,
)
@@ -118,7 +119,7 @@ from sglang.srt.observability.req_time_stats import (
DPControllerReqTimeStats,
SchedulerReqTimeStats,
)
from sglang.srt.runtime_context import get_parallel, get_server_args
from sglang.srt.runtime_context import get_parallel
from sglang.srt.sampling.sampling_batch_info import SamplingBatchInfo
from sglang.srt.sampling.sampling_params import SamplingParams
from sglang.srt.server_args import ServerArgs
@@ -2616,21 +2617,20 @@ class ScheduleBatch(ScheduleBatchDisaggregationDecodeMixin):
self,
req: Req,
) -> _MambaRadixCacheV2TrackEntry:
server_args = get_server_args()
mamba_cache_chunk_size = server_args.mamba_cache_chunk_size
chunk_size = mamba_cache_chunk_size()
def _force_track_h(i: int) -> int:
assert i % mamba_cache_chunk_size == 0
assert i % chunk_size == 0
# There are 3 cases for mamba_track_seqlen passed to mamba_track_seqlens_cpu:
# 1) aligned with mamba_cache_chunk_size-> retrieve from last_recurrent_state
# 1) aligned with chunk_size-> retrieve from last_recurrent_state
# a) is the last position -> retrieve from last_recurrent_state
# b) is NOT the last position -> retrieve from h
# 2) unaligned with mamba_cache_chunk_size -> retrieve from h
# 2) unaligned with chunk_size -> retrieve from h
# Currently, the math calculation only supports case 1a and 2. So for 1b, we need to add 1
# to force the math calculation to retrieve the correct mamba state from h.
return i + 1
mask = req.extend_range.length >= mamba_cache_chunk_size
mask = req.extend_range.length >= chunk_size
track_index = req.mamba_ping_pong_track_buffer[req.mamba_next_track_idx].item()
mamba_track_seqlen = -1
if mask:
@@ -2647,18 +2647,16 @@ class ScheduleBatch(ScheduleBatchDisaggregationDecodeMixin):
# mamba radix cache to track which seqlen this mamba state should store at.
mamba_track_seqlen_aligned = (
len(req.prefix_indices)
+ (req.extend_range.length // mamba_cache_chunk_size)
* mamba_cache_chunk_size
+ (req.extend_range.length // chunk_size) * chunk_size
)
# mamba_track_fla_chunk_aligned is the aligned seqlen based on mamba_cache_chunk_size
# mamba_track_fla_chunk_aligned is the aligned seqlen based on chunk_size
# If mamba_track_fla_chunk_aligned != mamba_track_seqlen_aligned, which can be true when
# page_size > mamba_cache_chunk_size, we need to force the math calculation to retrieve the correct mamba state from h
# page_size > chunk_size, we need to force the math calculation to retrieve the correct mamba state from h
# by _force_track_h()
mamba_track_fla_chunk_aligned = (
len(req.prefix_indices)
+ (req.extend_range.length // mamba_cache_chunk_size)
* mamba_cache_chunk_size
+ (req.extend_range.length // chunk_size) * chunk_size
)
if mamba_track_fla_chunk_aligned != mamba_track_seqlen_aligned:
# We want to track mamba_track_seqlen_aligned, and it's not the last position,
@@ -2679,7 +2677,7 @@ class ScheduleBatch(ScheduleBatchDisaggregationDecodeMixin):
# is within the current extend batch.
branching_seqlen_aligned_mask = (
req.mamba_branching_seqlen - len(req.prefix_indices)
) % mamba_cache_chunk_size == 0
) % chunk_size == 0
if (
req.mamba_branching_seqlen > len(req.prefix_indices)
and req.mamba_branching_seqlen < mamba_track_seqlen
@@ -37,8 +37,8 @@ from sglang.srt.runtime_context import (
get_exec,
get_memory,
get_observability,
get_server_args,
mamba_extra_buffer_lazy_enabled,
max_speculative_num_draft_tokens,
)
from sglang.srt.speculative.base_spec_worker import BaseSpecWorker
from sglang.srt.state_capturer.indexer_topk import get_global_indexer_capturer
@@ -1163,7 +1163,6 @@ class SchedulerBatchResultProcessor:
keep_written_by_this_step = (
crossed and planned_pos == req.mamba_next_track_idx
)
server_args = get_server_args()
other_idx = 1 - req.mamba_next_track_idx
# Recompute the in-flight verify's plan (kv_committed_len is
# frozen since its prepare, so the recompute is exact).
@@ -1172,7 +1171,7 @@ class SchedulerBatchResultProcessor:
].item() == -1 and mamba_lazy_spec_in_window(
req,
get_exec().mamba.mamba_track_interval,
server_args.max_speculative_num_draft_tokens,
max_speculative_num_draft_tokens(),
)
if (
planned_pos is None
@@ -50,7 +50,9 @@ from sglang.srt.mem_cache.multi_ended_allocator import (
)
from sglang.srt.mem_cache.radix_cache import RadixKey
from sglang.srt.mem_cache.utils import split_node_hash_value
from sglang.srt.runtime_context import get_server_args
from sglang.srt.runtime_context import (
mamba_cache_chunk_size,
)
if TYPE_CHECKING:
from sglang.srt.managers.schedule_batch import Req
@@ -450,7 +452,7 @@ class MambaRadixCache(KVCacheEventMixin, BasePrefixCache):
)
self.req_to_token_pool: HybridReqToTokenPool = params.req_to_token_pool
self.token_to_kv_pool_allocator = params.token_to_kv_pool_allocator
self.mamba_cache_chunk_size = get_server_args().mamba_cache_chunk_size
self.mamba_cache_chunk_size = mamba_cache_chunk_size()
self.page_size = params.page_size
self.disable = params.disable
@@ -35,7 +35,10 @@ from sglang.srt.mem_cache.unified_cache.components.tree_component import (
TreeComponent,
get_and_increase_time_counter,
)
from sglang.srt.runtime_context import get_exec, get_server_args
from sglang.srt.runtime_context import (
get_exec,
mamba_cache_chunk_size,
)
if TYPE_CHECKING:
from sglang.srt.managers.schedule_batch import Req
@@ -65,7 +68,7 @@ class MambaComponent(TreeComponent):
params.page_size == 1
), f"MambaComponent requires page_size=1 when mamba_extra_buffer is disabled, got {params.page_size}"
super().__init__(cache, params)
self.mamba_cache_chunk_size = get_server_args().mamba_cache_chunk_size
self.mamba_cache_chunk_size = mamba_cache_chunk_size()
self.mamba_max_states_per_path = get_exec().mamba.mamba_max_states_per_path
# HiCache state
self._mamba_pool_host = None # set to host mamba pool when HiCache enabled
+2 -2
View File
@@ -48,6 +48,7 @@ from sglang.srt.model_loader.remote_instance_weight_loader_utils import (
register_memory_region,
)
from sglang.srt.runtime_context import (
configured_moe_dp_size,
get_exec,
get_model,
get_parallel,
@@ -1776,14 +1777,13 @@ class PreshardedModelLoader(DefaultModelLoader):
return 1
parallel = get_parallel()
server_args = get_server_args()
return {
"tp": _safe(lambda: parallel.tp_size),
"dp": _safe(lambda: parallel.moe_dp_size),
"ep": _safe(lambda: parallel.moe_ep_size),
"pp": _safe(lambda: parallel.pp_size),
"moe_dense_tp_size": parallel.moe_dense_tp_size,
"moe_dp_size": server_args.moe_dp_size,
"moe_dp_size": configured_moe_dp_size(),
"enable_dp_lm_head": parallel.enable_dp_lm_head,
"enable_fp32_lm_head": get_exec().features.enable_fp32_lm_head,
"quantization": model_config.quantization,
+2 -3
View File
@@ -193,12 +193,12 @@ from sglang.srt.models.deepseek_common.utils import (
is_wint4afp8_or_wint4a16_config,
)
from sglang.srt.runtime_context import (
attention_backends,
get_device,
get_exec,
get_forward,
get_model,
get_parallel,
get_server_args,
get_spec,
)
from sglang.srt.speculative.spec_info import SpeculativeAlgorithm
@@ -1999,8 +1999,7 @@ class DeepseekV2AttentionMLA(
# Determine attention backend name for current forward batch: prefer the
# name stamped per-runner on the backend object, else resolve from server args.
backend = get_attn_backend()
server_args = get_server_args()
default_prefill_str, default_decode_str = server_args.get_attention_backends()
default_prefill_str, default_decode_str = attention_backends()
prefill_backend_str = (
backend.prefill_attention_backend_str or default_prefill_str
)
+5 -9
View File
@@ -46,10 +46,9 @@ from sglang.srt.multimodal.mm_utils import (
run_dp_sharded_mrope_vision_model,
)
from sglang.srt.runtime_context import (
configured_tp_size,
get_exec,
get_mm,
get_parallel,
get_server_args,
)
from sglang.srt.utils import add_prefix, is_cuda, is_npu
@@ -731,13 +730,10 @@ class KimiK25ForConditionalGeneration(nn.Module):
acknowledges the entire TP group so the bounded IPC pool remains
recyclable.
"""
parallel = get_parallel()
server_args = get_server_args()
# Match MmItemMemoryPool.try_to_recycle(), which waits for the
# server TP size rather than the attention subgroup size.
ipc_consumer_count = max(
getattr(server_args, "tp_size", parallel.attn_tp_size), 1
)
# Same source as MmItemMemoryPool.try_to_recycle(), which waits on
# configured_tp_size(): the live world size agrees once dist is up,
# but a refcount that disagrees with the waiter would strand items.
ipc_consumer_count = max(configured_tp_size(), 1)
device_index = device.index
if device.type == "cuda" and device_index is None:
device_index = torch.cuda.current_device()
+10 -2
View File
@@ -111,7 +111,12 @@ from sglang.srt.multimodal.kimi_k3_image_processing import (
to_chw_uint8,
)
from sglang.srt.multimodal.mm_utils import materialize_multimodal_features
from sglang.srt.runtime_context import get_exec, get_parallel, get_server_args
from sglang.srt.runtime_context import (
configured_tp_size,
get_exec,
get_parallel,
get_server_args,
)
from sglang.srt.utils import is_blackwell_supported, is_hip, make_layers
from sglang.srt.utils.common import (
BumpAllocator,
@@ -3082,7 +3087,10 @@ class KimiK3ForConditionalGeneration(nn.Module):
def materialize_item_features(image_indices: List[int]) -> torch.Tensor:
"""Materialize only the images assigned to this vision-DP rank."""
ipc_consumer_count = max(get_parallel().tp_size, 1)
# Same source as MmItemMemoryPool.try_to_recycle(), which waits on
# configured_tp_size(): the live world size agrees once dist is up,
# but a refcount that disagrees with the waiter would strand items.
ipc_consumer_count = max(configured_tp_size(), 1)
device_index = device.index
if device.type == "cuda" and device_index is None:
device_index = torch.cuda.current_device()
+2 -3
View File
@@ -85,7 +85,7 @@ from sglang.srt.runtime_context import (
get_forward,
get_parallel,
get_schedule,
get_server_args,
process_model_config,
)
# get_bool_env_var is defined in sglang.srt.utils.common, not sglang.srt.distributed.
@@ -431,10 +431,9 @@ class MiniMaxM2QKRMSNorm:
props = torch.cuda.get_device_properties(device)
# probe the maximum tokens for one prefill
server_args = get_server_args()
max_tokens = get_schedule().chunked_prefill_size
if max_tokens is None:
max_tokens = server_args.model_config.context_len
max_tokens = process_model_config().context_len
max_tokens = max(max_tokens, get_schedule().max_prefill_tokens)
logger.info(f"[AR] Using CustomAllReduceV2 for MiniMaxM2 with {max_tokens = }")
ALIGN = 512
+9 -13
View File
@@ -61,8 +61,10 @@ from sglang.srt.models.deepseek_common.attention_forward_methods.forward_mha imp
DeepseekMHAForwardMixin,
)
from sglang.srt.runtime_context import (
attention_backends,
get_exec,
get_forward,
get_memory,
get_model,
get_parallel,
get_server_args,
@@ -609,18 +611,12 @@ class SarvamMoEMLAAttention(nn.Module):
return k
def _set_current_attention_backend(self, forward_batch: ForwardBatch) -> None:
if self._server_args is None:
self._server_args = get_server_args()
if forward_batch.forward_mode.is_decode_or_idle():
self.current_attention_backend = (
self._server_args.decode_attention_backend
or self._server_args.attention_backend
)
else:
self.current_attention_backend = (
self._server_args.prefill_attention_backend
or self._server_args.attention_backend
)
prefill_backend, decode_backend = attention_backends()
self.current_attention_backend = (
decode_backend
if forward_batch.forward_mode.is_decode_or_idle()
else prefill_backend
)
def _maybe_fp8_bmm(
self,
@@ -684,7 +680,7 @@ class SarvamMoEMLAAttention(nn.Module):
)
self._set_current_attention_backend(forward_batch)
can_use_prefix_cache = not self._server_args.disable_radix_cache
can_use_prefix_cache = not get_memory().disable_radix_cache
do_prefix_merge = has_extend_prefix and can_use_prefix_cache
if do_prefix_merge and forward_batch.num_prefix_chunks is None:
+147
View File
@@ -47,6 +47,7 @@ test-only ``override(**kw)``.
from __future__ import annotations
import dataclasses
import functools
import os
import sys
from contextlib import contextmanager
@@ -827,6 +828,10 @@ class RuntimeContext:
server_args, "enable_torch_compile", False
)
self._server_args = server_args
# The adaptive draft-token bound memoizes on the config *path*, so a new
# publication that reuses the path must not inherit the bound computed
# from the file's previous contents.
_adaptive_draft_token_bound.cache_clear()
# Snapshot resolved config into the namespace bags (the single source of
# truth for config reads). Driven by NS(...) metadata; a mock/partial
# config with no NS markers yields an empty tree (no bags projected).
@@ -1376,6 +1381,7 @@ def reset_context() -> None:
"""
_CONTEXT._server_args = None
_CONTEXT._config_bags = None
_adaptive_draft_token_bound.cache_clear()
_CONTEXT._overrides_log = []
_CONTEXT._publish_role = None
_CONTEXT.parallel._config = None
@@ -1406,3 +1412,144 @@ def mamba_extra_buffer_lazy_enabled() -> bool:
get_memory().disable_radix_cache is False
and get_exec().mamba.mamba_radix_cache_strategy == "extra_buffer_lazy"
)
# --- Derived config accessors ------------------------------------------------
#
# A few values are computed from several config fields plus the HF config, so
# they are ``ServerArgs`` members rather than namespace leaves. Business code
# must not reach for the startup record to get them: these accessors are the
# named home, and this module — which owns the slot — is the only place that
# reads it. Each one keeps the member's exact semantics, including which model
# config it derives from (always the process's, i.e. the target's).
def mamba_cache_chunk_size() -> int:
"""The caching point granularity for mamba state: ``max(the model's mamba
chunk size, page_size)``. Cached on the config after the first call."""
return get_server_args().mamba_cache_chunk_size
def max_speculative_num_draft_tokens() -> int | None:
"""The largest draft-token count speculative decoding may use.
All three inputs are ``spec`` leaves, so this derives from the bags and
follows a post-publish override; ``ServerArgs.max_speculative_num_draft_tokens``
is the pre-publish equivalent. Adaptive spec resolves the count from its
candidate-step table instead of the flat field.
"""
spec = get_spec()
if spec.speculative_num_draft_tokens is None:
return None
if not spec.speculative_adaptive:
return spec.speculative_num_draft_tokens
# The adaptive branch parses a JSON config, and this is called per decode
# batch (`spec_prepare_for_decode`), so memoize on the inputs -- keyed, not
# cached once, so a post-publish override still recomputes.
return _adaptive_draft_token_bound(spec.speculative_adaptive_config)
@functools.lru_cache(maxsize=8)
def _adaptive_draft_token_bound(cfg_path: str | None) -> int:
from sglang.srt.speculative.adaptive_spec_params import (
resolve_candidate_steps_from_config,
)
candidate_steps = resolve_candidate_steps_from_config(cfg_path=cfg_path)
# Adaptive spec requires topk=1 today, so each runtime state needs
# steps + 1 draft-token slots (mirrors the ServerArgs member).
return max(candidate_steps) + 1
def uses_mla_backend() -> bool:
"""Whether this process's model runs the MLA attention path."""
return get_server_args().use_mla_backend()
def attention_backends() -> tuple:
"""The configured ``(prefill, decode)`` backend pair, split fields falling
back to ``attention_backend``.
All three inputs are ``exec.kernel`` leaves, so this derives from the bags
and follows a post-publish override; ``ServerArgs.get_attention_backends``
is the pre-publish equivalent the resolution pipeline uses. A built runner
stamps its own resolved pair (``ModelRunner.prefill_attention_backend_str``);
read that when there is a runner in hand.
"""
from sglang.srt.arg_groups.overrides import attention_backends_of
# All three leaves live in the same bag, so the resolution pipeline's own
# helper applies directly -- one definition of the fallback rule.
return attention_backends_of(get_exec().kernel)
def process_model_config():
"""The process's ``ModelConfig`` (built once from the published config)."""
return get_server_args().get_model_config()
def cutedsl_moe_max_num_tokens() -> int:
"""The CuteDSL A2A per-rank token budget.
Every input is a published leaf (``spec``, ``schedule``, ``exec.graph``), so
this derives from the bags and follows a post-publish override;
``ServerArgs.cutedsl_moe_max_num_tokens`` is the pre-publish equivalent the
resolution pipeline uses. Max over the prefill bound, the piecewise-prefill
capture, and the decode/verify bound.
"""
from sglang.srt.model_executor.cuda_graph_config import Backend
spec = get_spec()
num_tokens_per_req = (
(spec.speculative_num_draft_tokens or 1) if spec.speculative_algorithm else 1
)
prefill_tokens = get_schedule().max_prefill_tokens
cg_config = get_exec().graph.cuda_graph_config
if cg_config is not None and cg_config.prefill.backend == Backend.TC_PIECEWISE:
prefill_tokens = max(prefill_tokens, cg_config.prefill.max_bs or 0)
decode_max_bs = (cg_config.decode.max_bs if cg_config is not None else 0) or 0
return max(prefill_tokens, decode_max_bs * num_tokens_per_req)
# --- Configured (not live) parallel sizes ------------------------------------
#
# ``get_parallel()`` shadows these names with the LIVE topology, which is the
# right answer almost everywhere. A handful of call sites need what was
# *configured* instead — before the groups exist, in a process that has none,
# or where the live value is deliberately aliased to another dimension. Each
# accessor below names that intent so no business call site has to reach for
# the startup record; the per-site reasons live in the read ratchet.
#
# They read the published leaf rather than the record: the bag is what
# ``override`` writes, and once the instance holds only the user's raw input
# the record would answer with what was *typed* instead of what resolution
# produced. Going through the bag directly is what gets past the live property
# that shadows these four names on ``get_parallel()``.
def _configured_parallel(name: str):
# The bag itself, not ParallelContext, whose live property shadows these
# four names. Read through the parallel slot the way the leaf accessor
# does — ``parallel`` is deliberately outside the per-role namespace table
# (every process reads topology config), so this must not route through
# ``config_bag()``'s role check, which would record or reject the read.
config = _CONTEXT.parallel._config
if config is None:
raise ValueError("config namespace 'parallel' not published")
return getattr(config, name)
def configured_tp_size() -> int:
return _configured_parallel("tp_size")
def configured_pp_size() -> int:
return _configured_parallel("pp_size")
def configured_moe_dp_size() -> int:
return _configured_parallel("moe_dp_size")
def configured_attn_cp_size() -> int:
return _configured_parallel("attn_cp_size")
+9 -20
View File
@@ -40,7 +40,12 @@ from sglang.srt.arg_groups.argparse_actions import (
DeprecatedStoreTrueAction,
LoRAPathAction,
)
from sglang.srt.arg_groups.overrides import resolved_view
from sglang.srt.arg_groups.overrides import (
attention_backends_of,
mamba_extra_buffer_lazy_of,
mamba_extra_buffer_of,
resolved_view,
)
from sglang.srt.configs.embedding_model_spec import BCGPrefillPolicy
from sglang.srt.configs.linear_attn_model_registry import get_linear_attn_spec_by_arch
from sglang.srt.connector import ConnectorType
@@ -8689,17 +8694,7 @@ class ServerArgs:
return attention_backends_of(resolved_view(self))
def get_attention_backends(self):
prefill_attention_backend_str = (
self.prefill_attention_backend
if self.prefill_attention_backend
else self.attention_backend
)
decode_attention_backend_str = (
self.decode_attention_backend
if self.decode_attention_backend
else self.attention_backend
)
return prefill_attention_backend_str, decode_attention_backend_str
return attention_backends_of(self)
def use_mla_backend(self):
from sglang.srt.configs.model_config import AttentionArch
@@ -8715,16 +8710,10 @@ class ServerArgs:
)
def enable_mamba_extra_buffer(self) -> bool:
return (
self.disable_radix_cache is False
and self.mamba_radix_cache_strategy in ("extra_buffer", "extra_buffer_lazy")
)
return mamba_extra_buffer_of(self)
def enable_mamba_extra_buffer_lazy(self) -> bool:
return (
self.disable_radix_cache is False
and self.mamba_radix_cache_strategy == "extra_buffer_lazy"
)
return mamba_extra_buffer_lazy_of(self)
@cached_property
def max_speculative_num_draft_tokens(self) -> Optional[int]:
+2 -3
View File
@@ -48,10 +48,10 @@ from sglang.srt.mem_cache.allocation import (
)
from sglang.srt.runtime_context import (
get_exec,
get_server_args,
get_spec,
mamba_extra_buffer_enabled,
mamba_extra_buffer_lazy_enabled,
max_speculative_num_draft_tokens,
)
from sglang.srt.utils import (
is_cpu,
@@ -1030,12 +1030,11 @@ def spec_prepare_for_decode(batch: ScheduleBatch) -> None:
"""eagle/ngram share a stateless free function; dflash keeps stateful
prep on its draft input -- the dispatcher routes.
"""
server_args = get_server_args()
if mamba_extra_buffer_lazy_enabled():
# Scheduler phase (outside forward isolation).
batch.mamba_lazy_spec_prepare(
get_exec().mamba.mamba_track_interval,
server_args.max_speculative_num_draft_tokens,
max_speculative_num_draft_tokens(),
)
if batch.spec_algorithm.is_dflash_family():
batch.spec_info.prepare_for_decode(batch)
@@ -9,7 +9,9 @@ import numpy as np
import torch
from sglang.srt.environ import envs
from sglang.srt.runtime_context import get_server_args
from sglang.srt.runtime_context import (
configured_tp_size,
)
from sglang.srt.utils.stale_shm_cleanup import make_shm_name
logger = logging.getLogger(__name__)
@@ -130,7 +132,7 @@ class MmItemMemoryChunk:
def try_to_recycle(self) -> bool:
try:
tp_num = get_server_args().tp_size
tp_num = configured_tp_size()
except Exception:
logger.info(
"server_args has not been published yet, skip this turn's recycle"