config: the last runner-side instance reads read the bags
Six reads were left on `self.server_args` outside the per-instance boundary the plan reserves for the tokenizer-manager family, and each had a different reason to be there: - `scheduler.process_input_requests` (`mm_feature_transport`) and `BaseSpecWorker._build_hicache_draft_plan` (`enable_hierarchical_cache`) are plain leaves -> `get_mm()` / `get_memory()`. - `DraftBackendFactory._create_backend` read the split backend through a *runtime-computed name* (`getattr(self.server_args, backend_name)`) and then fell back to the base field by hand -- the census's documented blind spot. The two names it can be handed are exactly the pair `attention_backends()` returns with that fallback already applied, so it reads the pair and indexes it. The draft runner's own stamp still wins when it has one. - `remote_instance_weight_loader_use_transfer_engine` and `pre_capture_activation_reserve_mb` are derived members. Both are computed from published leaves only, so both get a named accessor that derives from the bags (and therefore follows a post-publish override). The first of those two has all its inputs in one bag, so it follows the established shape: one `*_of(cfg)` helper in `arg_groups/overrides.py`, the `ServerArgs` member delegating to it, and the accessor calling it on `get_model()`. `modelexpress_transport_of` splits out the JSON parse both sides need. The second spans four bags plus the configured parallel sizes, so it exists twice like the mamba pair -- and `TestDerivedPredicatesAgreeAcrossTiers` now pins both new pairs equal over their input matrices (92 subtests). `self.server_args.X` outside the tokenizer-manager family: 11 -> 5, and the five that remain are the documented ones (the encode server's own record, the nixl connector's rank arithmetic, `GrammarManager`'s handed instance). The post-capture headroom path calls the same bag-backed `pre_capture_activation_reserve_mb` accessor the configurator uses -- the accessor advertises override-following, and a reserve that reads the record while its sibling reads the bags can disagree after a post-publish override. And the conversions' orphans go with them: `RemoteInstanceWeightTransporter` kept a `server_args` field nothing reads, and `DraftBackendFactory` parked a record it no longer consults -- both drop the parameter, and the four factory call sites stop threading one.
This commit is contained in:
@@ -490,6 +490,13 @@ class TestCudaVmmFeatureTransport(unittest.TestCase):
|
||||
|
||||
|
||||
class TestSchedulerMmTransportBoundary(unittest.TestCase):
|
||||
def _publish(self, **fields):
|
||||
from sglang.srt.runtime_context import get_context
|
||||
|
||||
override = get_context().override_server_args(**fields)
|
||||
override.install()
|
||||
self.addCleanup(override.restore)
|
||||
|
||||
@staticmethod
|
||||
def _prepare_scheduler(scheduler):
|
||||
scheduler.session_controller = SimpleNamespace(maybe_reap=MagicMock())
|
||||
@@ -501,7 +508,9 @@ class TestSchedulerMmTransportBoundary(unittest.TestCase):
|
||||
from sglang.srt.managers import scheduler as scheduler_module
|
||||
|
||||
scheduler = object.__new__(scheduler_module.Scheduler)
|
||||
scheduler.server_args = SimpleNamespace(
|
||||
# The transport gate reads the published bags, so the case publishes
|
||||
# the configuration under test.
|
||||
self._publish(
|
||||
mm_feature_transport="cuda_vmm",
|
||||
enable_broadcast_mm_inputs_process=True,
|
||||
)
|
||||
@@ -548,7 +557,7 @@ class TestSchedulerMmTransportBoundary(unittest.TestCase):
|
||||
return iter(self.batch)
|
||||
|
||||
scheduler = object.__new__(scheduler_module.Scheduler)
|
||||
scheduler.server_args = SimpleNamespace(mm_feature_transport="cuda_vmm")
|
||||
self._publish(mm_feature_transport="cuda_vmm")
|
||||
self._prepare_scheduler(scheduler)
|
||||
raw_inputs = [object(), object()]
|
||||
materialized = [object(), object()]
|
||||
|
||||
@@ -391,6 +391,19 @@ class _FakeResolvedArgs:
|
||||
speculative_num_draft_tokens: A[int | None, Arg(help="d"), NS("spec")] = None
|
||||
speculative_adaptive: A[bool, Arg(help="a"), NS("spec")] = False
|
||||
speculative_adaptive_config: A[str | None, Arg(help="c"), NS("spec")] = None
|
||||
load_format: A[str, Arg(help="lf"), NS("model")] = "auto"
|
||||
remote_instance_weight_loader_backend: A[str, Arg(help="rb"), NS("model")] = "nccl"
|
||||
remote_instance_weight_loader_start_seed_via_transfer_engine: A[
|
||||
bool, Arg(help="rs"), NS("model")
|
||||
] = False
|
||||
modelexpress_config: A[str | None, Arg(help="mx"), NS("model")] = None
|
||||
disaggregation_mode: A[str, Arg(help="dm"), NS("disagg")] = "null"
|
||||
max_running_requests: A[int | None, Arg(help="mrr"), NS("schedule")] = None
|
||||
chunked_prefill_size: A[int, Arg(help="cps"), NS("schedule")] = -1
|
||||
max_prefill_tokens: A[int, Arg(help="mpt"), NS("schedule")] = 16384
|
||||
cuda_graph_config: A[object | None, Arg(help="cgc"), NS("exec.graph")] = None
|
||||
tp_size: A[int, Arg(help="tp"), NS("parallel")] = 1
|
||||
pp_size: A[int, Arg(help="pp"), NS("parallel")] = 1
|
||||
_resolved_overrides: list = dataclasses.field(default_factory=list)
|
||||
|
||||
|
||||
@@ -1013,6 +1026,74 @@ class TestDerivedPredicatesAgreeAcrossTiers(_IsolatedServerArgs):
|
||||
mamba_extra_buffer_lazy_enabled(),
|
||||
)
|
||||
|
||||
def test_activation_reserve_matches_the_member(self):
|
||||
from types import SimpleNamespace
|
||||
|
||||
from sglang.srt.runtime_context import pre_capture_activation_reserve_mb
|
||||
|
||||
graph = SimpleNamespace(decode=SimpleNamespace(max_bs=64))
|
||||
cases = (
|
||||
dict(disaggregation_mode="null", chunked_prefill_size=8192),
|
||||
dict(disaggregation_mode="null", chunked_prefill_size=-1),
|
||||
dict(
|
||||
disaggregation_mode="null",
|
||||
chunked_prefill_size=-1,
|
||||
max_prefill_tokens=1024,
|
||||
),
|
||||
dict(disaggregation_mode="decode", max_running_requests=32),
|
||||
dict(disaggregation_mode="decode", max_running_requests=None),
|
||||
dict(
|
||||
disaggregation_mode="decode",
|
||||
max_running_requests=None,
|
||||
speculative_num_draft_tokens=4,
|
||||
),
|
||||
dict(
|
||||
disaggregation_mode="null",
|
||||
chunked_prefill_size=8192,
|
||||
tp_size=8,
|
||||
pp_size=2,
|
||||
),
|
||||
)
|
||||
for case in cases:
|
||||
for gpu_mem in (None, 20 * 1024, 80 * 1024):
|
||||
with self.subTest(gpu_mem=gpu_mem, **case):
|
||||
args = _FakeResolvedArgs(cuda_graph_config=graph, **case)
|
||||
get_context().set_server_args(args)
|
||||
self.assertEqual(
|
||||
ServerArgs.pre_capture_activation_reserve_mb(args, gpu_mem),
|
||||
pre_capture_activation_reserve_mb(gpu_mem),
|
||||
)
|
||||
|
||||
def test_remote_instance_transfer_engine_matches_the_member(self):
|
||||
from sglang.srt.runtime_context import remote_instance_transfer_engine_enabled
|
||||
|
||||
backends = ("nccl", "transfer_engine", "modelexpress")
|
||||
transports = (None, '{"transport": "transfer_engine"}', '{"transport": "nixl"}')
|
||||
for seed_via_te in (False, True):
|
||||
for load_format in ("auto", "remote_instance"):
|
||||
for backend in backends:
|
||||
for mx in transports:
|
||||
with self.subTest(
|
||||
seed=seed_via_te,
|
||||
load_format=load_format,
|
||||
backend=backend,
|
||||
modelexpress=mx,
|
||||
):
|
||||
args = _FakeResolvedArgs(
|
||||
load_format=load_format,
|
||||
remote_instance_weight_loader_backend=backend,
|
||||
remote_instance_weight_loader_start_seed_via_transfer_engine=seed_via_te,
|
||||
modelexpress_config=mx,
|
||||
)
|
||||
get_context().set_server_args(args)
|
||||
for override in (None, "remote_instance", "auto"):
|
||||
self.assertEqual(
|
||||
ServerArgs.remote_instance_weight_loader_use_transfer_engine(
|
||||
args, override
|
||||
),
|
||||
remote_instance_transfer_engine_enabled(override),
|
||||
)
|
||||
|
||||
def test_attention_backends_match_the_member(self):
|
||||
from sglang.srt.runtime_context import attention_backends
|
||||
|
||||
|
||||
Reference in New Issue
Block a user