[diffusion] CI: improve diffusion comparison benchmark setting for realistic perf and auto-discover ut (#22086)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -78,6 +78,9 @@ def get_is_diffusion_model(model_path: str) -> bool:
|
||||
if is_known_non_diffusers_diffusion_model(model_path):
|
||||
return True
|
||||
|
||||
if _is_registered_diffusion_model(model_path):
|
||||
return True
|
||||
|
||||
try:
|
||||
if envs.SGLANG_USE_MODELSCOPE.get():
|
||||
from modelscope import model_file_download
|
||||
|
||||
@@ -88,7 +88,7 @@ def launch_server(server_args: ServerArgs, launch_http_server: bool = True):
|
||||
result_pipes_from_slaves_w.append(w)
|
||||
|
||||
# Launch all worker processes
|
||||
master_port = server_args.master_port or (server_args.master_port + 100)
|
||||
master_port = server_args.master_port
|
||||
scheduler_pipe_readers = []
|
||||
scheduler_pipe_writers = []
|
||||
|
||||
|
||||
@@ -188,8 +188,7 @@ class ServerArgs:
|
||||
)
|
||||
|
||||
# Master port for distributed inference
|
||||
# TODO: do not hard code
|
||||
master_port: int | None = None
|
||||
master_port: int = 30005
|
||||
|
||||
# http server endpoint config
|
||||
host: str | None = "127.0.0.1"
|
||||
@@ -386,36 +385,27 @@ class ServerArgs:
|
||||
"Warmup enabled, the launch time is expected to be longer than usual"
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _require_port(port: int, name: str) -> None:
|
||||
"""Raise if *port* is occupied (used under ``--strict-ports``)."""
|
||||
if not is_port_available(port):
|
||||
raise RuntimeError(
|
||||
f"{name} port {port} is unavailable and --strict-ports is enabled. "
|
||||
f"Either use a different port or disable --strict-ports."
|
||||
)
|
||||
|
||||
def _adjust_network_ports(self):
|
||||
if self.strict_ports:
|
||||
# Strict mode: fail if port is unavailable
|
||||
if not is_port_available(self.port):
|
||||
raise RuntimeError(
|
||||
f"Port {self.port} is unavailable and --strict-ports is enabled. "
|
||||
f"Either use a different port or remove --strict-ports to allow auto-selection."
|
||||
)
|
||||
if not is_port_available(self.scheduler_port):
|
||||
raise RuntimeError(
|
||||
f"Scheduler port {self.scheduler_port} is unavailable and --strict-ports is enabled. "
|
||||
f"Either use a different port or remove --strict-ports to allow auto-selection."
|
||||
)
|
||||
if self.master_port is not None and not is_port_available(self.master_port):
|
||||
raise RuntimeError(
|
||||
f"Master port {self.master_port} is unavailable and --strict-ports is enabled. "
|
||||
f"Either use a different port or remove --strict-ports to allow auto-selection."
|
||||
)
|
||||
self._require_port(self.port, "HTTP")
|
||||
self._require_port(self.scheduler_port, "Scheduler")
|
||||
self._require_port(self.master_port, "Master")
|
||||
else:
|
||||
self.port = self.settle_port(self.port)
|
||||
initial_scheduler_port = self.scheduler_port + (
|
||||
random.randint(0, 100) if self.scheduler_port == 5555 else 0
|
||||
)
|
||||
self.scheduler_port = self.settle_port(initial_scheduler_port)
|
||||
initial_master_port = (
|
||||
self.master_port
|
||||
if self.master_port is not None
|
||||
else (30005 + random.randint(0, 100))
|
||||
)
|
||||
self.master_port = self.settle_port(initial_master_port, 37)
|
||||
self.master_port = self.settle_port(self.master_port, 37)
|
||||
|
||||
def _adjust_parallelism(self):
|
||||
if self.tp_size is None:
|
||||
|
||||
@@ -28,17 +28,21 @@ _UPDATE_WEIGHTS_MODEL_PAIR_IDS = (
|
||||
"Qwen-Image",
|
||||
)
|
||||
|
||||
|
||||
def _discover_unit_tests() -> list[str]:
|
||||
"""Auto-discover all test_*.py files in the unit/ directory."""
|
||||
unit_dir = Path(__file__).resolve().parent / "unit"
|
||||
if not unit_dir.is_dir():
|
||||
return []
|
||||
return sorted(
|
||||
f"../unit/{f.name}" for f in unit_dir.glob("test_*.py") if f.is_file()
|
||||
)
|
||||
|
||||
|
||||
SUITES = {
|
||||
# no GPU required; safe to run on any CPU-only runner
|
||||
"unit": [
|
||||
"../unit/test_sampling_params.py",
|
||||
"../unit/test_storage.py",
|
||||
"../unit/test_lora_format_adapter.py",
|
||||
"../unit/test_server_args.py",
|
||||
"../unit/test_input_validation.py",
|
||||
"../unit/test_resolve_prompts.py",
|
||||
# add new unit tests here
|
||||
],
|
||||
# Auto-discovered from test/unit/test_*.py
|
||||
"unit": _discover_unit_tests(),
|
||||
"1-gpu": [
|
||||
"test_server_a.py",
|
||||
"test_server_b.py",
|
||||
|
||||
@@ -102,6 +102,10 @@ def diffusion_server(case: DiffusionTestCase) -> ServerContext:
|
||||
if server_args.enable_warmup:
|
||||
extra_args += " --warmup"
|
||||
|
||||
# Strict ports: fail immediately if port is occupied instead of silently
|
||||
# picking another one (which causes the test client to connect to the wrong server).
|
||||
extra_args += " --strict-ports"
|
||||
|
||||
for arg in server_args.extras:
|
||||
extra_args += f" {arg}"
|
||||
|
||||
|
||||
@@ -375,8 +375,10 @@ class ServerManager:
|
||||
# Apply custom environment variables
|
||||
env.update(self.env_vars)
|
||||
|
||||
# TODO: unify with run_command
|
||||
logger.info(f"Running command: {shlex.join(command)}")
|
||||
cmd_str = shlex.join(command)
|
||||
# Use print (not logger) so the command always appears in CI output
|
||||
# regardless of log-level configuration.
|
||||
print(f"[server-test] Running command: {cmd_str}", flush=True)
|
||||
|
||||
process = subprocess.Popen(
|
||||
command,
|
||||
@@ -412,11 +414,10 @@ class ServerManager:
|
||||
log_thread.daemon = True
|
||||
log_thread.start()
|
||||
|
||||
logger.info(
|
||||
"[server-test] Starting server pid=%s, model=%s, log=%s",
|
||||
process.pid,
|
||||
self.model,
|
||||
stdout_path,
|
||||
print(
|
||||
f"[server-test] Starting server pid={process.pid}, "
|
||||
f"model={self.model}, log={stdout_path}",
|
||||
flush=True,
|
||||
)
|
||||
|
||||
self._wait_for_ready(process, stdout_path)
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
# limitations under the License.
|
||||
"""Multimodal processor for LFM2-VL models with SigLip2 NaFlex support."""
|
||||
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
from typing import List, Union
|
||||
|
||||
from sglang.srt.managers.schedule_batch import Modality
|
||||
from sglang.srt.managers.schedule_batch import Modality, MultimodalProcessorOutput
|
||||
from sglang.srt.models.lfm2_vl import Lfm2VlForConditionalGeneration
|
||||
from sglang.srt.multimodal.processors.base_processor import (
|
||||
BaseMultimodalProcessor as SGLangBaseProcessor,
|
||||
@@ -56,7 +56,7 @@ class Lfm2VlImageProcessor(SGLangBaseProcessor):
|
||||
input_text: str,
|
||||
request_obj,
|
||||
**kwargs,
|
||||
) -> Optional[Dict[str, Any]]:
|
||||
):
|
||||
if not image_data:
|
||||
input_ids = self._tokenizer(
|
||||
input_text, return_tensors="pt", add_special_tokens=False
|
||||
@@ -77,8 +77,8 @@ class Lfm2VlImageProcessor(SGLangBaseProcessor):
|
||||
base_output, self.mm_tokens
|
||||
)
|
||||
|
||||
return {
|
||||
"input_ids": input_ids.tolist(),
|
||||
"mm_items": mm_items,
|
||||
"im_token_id": self.IMAGE_TOKEN_ID,
|
||||
}
|
||||
return MultimodalProcessorOutput(
|
||||
input_ids=input_ids.tolist(),
|
||||
mm_items=mm_items,
|
||||
im_token_id=self.IMAGE_TOKEN_ID,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user