config: the lazy imports that buy nothing become eager (#36975)
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
f0d621cfa6
commit
4d53767b09
@@ -30,9 +30,10 @@ under its own default configuration.
|
||||
"""
|
||||
|
||||
import unittest
|
||||
from unittest import mock
|
||||
from types import SimpleNamespace
|
||||
|
||||
from sglang.srt.arg_groups.kv_cache_hook import handle_page_major_kv_layout
|
||||
from sglang.srt.configs.model_config import AttentionArch
|
||||
from sglang.srt.server_args import ServerArgs
|
||||
from sglang.test.ci.ci_register import register_cpu_ci
|
||||
|
||||
@@ -67,18 +68,18 @@ def _accepts(
|
||||
"mamba_backend": "triton",
|
||||
}.items():
|
||||
object.__setattr__(sa, name, value)
|
||||
# `use_mla_backend` asks the model configuration, which this stand-in has
|
||||
# no room for; the case under test is what the handler does with the answer.
|
||||
# The handler imports it inside the function, so the source module is
|
||||
# where the patch has to go.
|
||||
with mock.patch(
|
||||
"sglang.srt.arg_groups.overrides.use_mla_backend", return_value=use_mla
|
||||
):
|
||||
try:
|
||||
handle_page_major_kv_layout(sa)
|
||||
return True
|
||||
except AssertionError:
|
||||
return False
|
||||
object.__setattr__(
|
||||
sa,
|
||||
"_model_config",
|
||||
SimpleNamespace(
|
||||
attention_arch=AttentionArch.MLA if use_mla else AttentionArch.MHA
|
||||
),
|
||||
)
|
||||
try:
|
||||
handle_page_major_kv_layout(sa)
|
||||
return True
|
||||
except AssertionError:
|
||||
return False
|
||||
|
||||
|
||||
class TestPageMajorBackendAllowlist(unittest.TestCase):
|
||||
|
||||
@@ -934,47 +934,42 @@ class TestDeclaredValuesAreNotEditedLater(CustomTestCase):
|
||||
self.addCleanup(restore)
|
||||
|
||||
def _resolve_recording_each_entry(self, **supplied):
|
||||
"""Resolve, deep-copying every stash entry the moment it is appended."""
|
||||
from sglang.srt.arg_groups import overrides
|
||||
"""Resolve, deep-copying every stash entry the moment it is appended.
|
||||
|
||||
The property is about the stash, so the seam is the stash: a list that
|
||||
snapshots on append. Every declaration path -- `declare_resolution`,
|
||||
`declare_late_resolution`, `declare_direct_writes` and the passes --
|
||||
reaches it through `.append`, whatever it was imported as.
|
||||
"""
|
||||
recorded = []
|
||||
|
||||
def watch(name):
|
||||
original = getattr(overrides, name)
|
||||
class _SnapshotOnAppend(list):
|
||||
def append(self, entry):
|
||||
super().append(entry)
|
||||
recorded.append((len(self) - 1, copy.deepcopy(entry)))
|
||||
|
||||
def wrapper(server_args, *args, **kwargs):
|
||||
result = original(server_args, *args, **kwargs)
|
||||
stash = getattr(server_args, "_resolved_overrides", None) or []
|
||||
while len(recorded) < len(stash):
|
||||
index = len(recorded)
|
||||
recorded.append((index, copy.deepcopy(stash[index])))
|
||||
return result
|
||||
class _WatchedArgs(ServerArgs):
|
||||
"""Whatever list the pipeline installs, snapshot what lands in it.
|
||||
|
||||
return original, wrapper
|
||||
The pipeline resets the stash at the start of a resolution, so the
|
||||
seam has to survive that assignment rather than precede it.
|
||||
"""
|
||||
|
||||
# Every path that appends to the stash.
|
||||
patched = {}
|
||||
for name in (
|
||||
"declare_resolution",
|
||||
"declare_late_resolution",
|
||||
"declare_direct_writes",
|
||||
"run_post_process_pass",
|
||||
):
|
||||
original, wrapper = watch(name)
|
||||
patched[name] = original
|
||||
setattr(overrides, name, wrapper)
|
||||
try:
|
||||
path = tempfile.mkdtemp(prefix="declared_values_")
|
||||
self.addCleanup(shutil.rmtree, path, ignore_errors=True)
|
||||
with open(os.path.join(path, "config.json"), "w") as handle:
|
||||
json.dump(_MINI_CONFIG, handle)
|
||||
server_args = ServerArgs(
|
||||
model_path=path, device="cuda", random_seed=42, **supplied
|
||||
)
|
||||
server_args.resolve_once()
|
||||
finally:
|
||||
for name, original in patched.items():
|
||||
setattr(overrides, name, original)
|
||||
def __setattr__(self, name, value):
|
||||
if name == "_resolved_overrides" and not isinstance(
|
||||
value, _SnapshotOnAppend
|
||||
):
|
||||
value = _SnapshotOnAppend(value)
|
||||
super().__setattr__(name, value)
|
||||
|
||||
path = tempfile.mkdtemp(prefix="declared_values_")
|
||||
self.addCleanup(shutil.rmtree, path, ignore_errors=True)
|
||||
with open(os.path.join(path, "config.json"), "w") as handle:
|
||||
json.dump(_MINI_CONFIG, handle)
|
||||
server_args = _WatchedArgs(
|
||||
model_path=path, device="cuda", random_seed=42, **supplied
|
||||
)
|
||||
server_args.resolve_once()
|
||||
return server_args, recorded
|
||||
|
||||
def test_no_entry_changes_after_it_is_recorded(self):
|
||||
|
||||
@@ -979,10 +979,7 @@ class TestFa4PageSizeAutoForce(CustomTestCase):
|
||||
return args
|
||||
|
||||
@patch("sglang.srt.arg_groups.overrides.is_sm100_supported", return_value=True)
|
||||
@patch("sglang.srt.arg_groups.overrides.use_mla_backend", return_value=False)
|
||||
def test_combined_attention_backend_fa4_forces_page_size_128(
|
||||
self, _mock_mla, _mock_sm100
|
||||
):
|
||||
def test_combined_attention_backend_fa4_forces_page_size_128(self, _mock_sm100):
|
||||
# `--attention-backend fa4` (combined): prefill/decode fields stay None.
|
||||
args = self._make_args(attention_backend="fa4")
|
||||
|
||||
@@ -994,8 +991,7 @@ class TestFa4PageSizeAutoForce(CustomTestCase):
|
||||
self.assertEqual(resolved_view(args).page_size, 128)
|
||||
|
||||
@patch("sglang.srt.arg_groups.overrides.is_sm100_supported", return_value=True)
|
||||
@patch("sglang.srt.arg_groups.overrides.use_mla_backend", return_value=False)
|
||||
def test_explicit_prefill_fa4_forces_page_size_128(self, _mock_mla, _mock_sm100):
|
||||
def test_explicit_prefill_fa4_forces_page_size_128(self, _mock_sm100):
|
||||
# `--prefill-attention-backend fa4`: the previously-covered path.
|
||||
args = self._make_args(attention_backend=None, prefill="fa4", page_size=1)
|
||||
|
||||
@@ -1869,12 +1865,7 @@ class TestCudaGraphDisaggregationRoles(CustomTestCase):
|
||||
is_multimodal=False,
|
||||
is_multimodal_piecewise_cuda_graph_supported=False,
|
||||
)
|
||||
with (
|
||||
patch("sglang.srt.utils.is_cuda", return_value=True),
|
||||
patch(
|
||||
"sglang.srt.arg_groups.overrides.use_mla_backend", return_value=False
|
||||
),
|
||||
):
|
||||
with patch("sglang.srt.utils.is_cuda", return_value=True):
|
||||
handle_cuda_graph_config(args)
|
||||
return args
|
||||
|
||||
@@ -1944,12 +1935,7 @@ class TestPrefillCudaGraphLoRACompatibility(CustomTestCase):
|
||||
is_multimodal=False,
|
||||
is_multimodal_piecewise_cuda_graph_supported=False,
|
||||
)
|
||||
with (
|
||||
patch("sglang.srt.utils.is_cuda", return_value=True),
|
||||
patch(
|
||||
"sglang.srt.arg_groups.overrides.use_mla_backend", return_value=False
|
||||
),
|
||||
):
|
||||
with patch("sglang.srt.utils.is_cuda", return_value=True):
|
||||
handle_cuda_graph_config(args)
|
||||
return args
|
||||
|
||||
@@ -2010,12 +1996,7 @@ class TestBreakableCudaGraphMultimodalAllowlist(CustomTestCase):
|
||||
is_multimodal_piecewise_cuda_graph_supported=False,
|
||||
is_multimodal_breakable_cuda_graph_supported=allowlisted,
|
||||
)
|
||||
with (
|
||||
patch("sglang.srt.utils.is_cuda", return_value=True),
|
||||
patch(
|
||||
"sglang.srt.arg_groups.overrides.use_mla_backend", return_value=False
|
||||
),
|
||||
):
|
||||
with patch("sglang.srt.utils.is_cuda", return_value=True):
|
||||
handle_cuda_graph_config(args)
|
||||
return args
|
||||
|
||||
|
||||
Reference in New Issue
Block a user