diff --git a/python/sglang/multimodal_gen/test/server/gpu_cases.py b/python/sglang/multimodal_gen/test/server/gpu_cases.py index b79e3f816..b3181870a 100644 --- a/python/sglang/multimodal_gen/test/server/gpu_cases.py +++ b/python/sglang/multimodal_gen/test/server/gpu_cases.py @@ -1064,13 +1064,39 @@ ONE_GPU_5090_CASES = _select_5090_canary_cases(ONE_GPU_5090_CANARY_CASE_IDS) ONE_GPU_5090_CASES.append(_make_5090_flux_layerwise_cpu_offload_case()) +# Nested unit/ tests verified to pass on AMD/ROCm as-is (no code change). +# Enabled incrementally and AMD-only: the CUDA `multimodal-gen-unit-test` +# lane keeps the flat glob below. Files that still need fixes/skips are added +# in follow-up PRs. Paths are relative to the unit/ dir. +_AMD_READY_NESTED_UNIT_TESTS = ( + "realtime/test_causal_denoising.py", + "realtime/test_output_materialization.py", + "realtime/test_realtime_consistency_harness.py", + "realtime/test_realtime_control_signals.py", + "realtime/test_realtime_output_transport.py", + "realtime/test_realtime_vae.py", + "sana_wm/test_streaming_cached.py", + "sana_wm/test_streaming_stage.py", + "sana_wm/test_streaming_vae.py", +) + + def _discover_unit_tests() -> list[str]: unit_dir = Path(__file__).resolve().parent.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() - ) + # Flat unit/ tests run on every lane (unchanged). This keeps the CUDA + # `multimodal-gen-unit-test` job byte-identical. + flat = [f"../unit/{f.name}" for f in unit_dir.glob("test_*.py") if f.is_file()] + if not current_platform.is_hip(): + return sorted(flat) + # AMD/ROCm additionally runs the vetted nested-subdir tests. + nested = [ + f"../unit/{rel}" + for rel in _AMD_READY_NESTED_UNIT_TESTS + if (unit_dir / rel).is_file() + ] + return sorted(flat + nested) FILE_SUITES = { diff --git a/scripts/ci/utils/ci_coverage_report.py b/scripts/ci/utils/ci_coverage_report.py index e8a467ad8..918fcd5a6 100755 --- a/scripts/ci/utils/ci_coverage_report.py +++ b/scripts/ci/utils/ci_coverage_report.py @@ -75,8 +75,11 @@ _MM_GEN_SUBDIR_BACKENDS = { # CUDA-only for now (previously matched no rule and were dropped entirely). "single_test_file": ("CUDA",), "single_test_file/component_accuracy": ("CUDA",), - # Nested unit suites run only on the CUDA lane today (they are not part of - # the AMD `unit` suite that multimodal-gen-unit-test-amd executes). + # Nested unit suites are enabled on AMD incrementally, per file (only the + # files that pass on ROCm as-is; see _MM_GEN_FILE_BACKENDS below and + # gpu_cases _AMD_READY_NESTED_UNIT_TESTS). The subdir default stays the + # pre-existing CUDA tag for files not yet enabled on AMD (follow-up PRs + # move each file to AMD as it lands). "unit/realtime": ("CUDA",), "unit/sana_wm": ("CUDA",), "unit/progressive_resolution": ("CUDA",), @@ -84,6 +87,22 @@ _MM_GEN_SUBDIR_BACKENDS = { "unit/musa/layers": ("MUSA",), } +# Per-file backend overrides (checked before the subdir rule). Used to enable +# individual nested unit/ files on AMD incrementally, as each is verified to +# pass on ROCm. The CUDA lane does not collect these nested files (see +# gpu_cases._discover_unit_tests), so they are AMD-only here. +_MM_GEN_FILE_BACKENDS = { + "unit/realtime/test_causal_denoising.py": ("AMD",), + "unit/realtime/test_output_materialization.py": ("AMD",), + "unit/realtime/test_realtime_consistency_harness.py": ("AMD",), + "unit/realtime/test_realtime_control_signals.py": ("AMD",), + "unit/realtime/test_realtime_output_transport.py": ("AMD",), + "unit/realtime/test_realtime_vae.py": ("AMD",), + "unit/sana_wm/test_streaming_cached.py": ("AMD",), + "unit/sana_wm/test_streaming_stage.py": ("AMD",), + "unit/sana_wm/test_streaming_vae.py": ("AMD",), +} + # Filenames that match `test_*.py` by convention but contain no real tests # (utility / fixture modules). Skipped before classification. _MM_GEN_HELPER_FILENAMES = frozenset({"test_utils.py"}) @@ -147,11 +166,14 @@ def collect_multimodal_gen_tests( stem_tokens = set(filename_only[:-3].split("_")) nightly = "nightly" in stem_tokens - backends: tuple[str, ...] = () - for token, override in _MM_GEN_FILENAME_BACKEND_TOKENS.items(): - if token in stem_tokens: - backends = override - break + # Precedence: explicit per-file override, then filename token, then + # the subdir default. + backends: tuple[str, ...] = _MM_GEN_FILE_BACKENDS.get(rel.as_posix(), ()) + if not backends: + for token, override in _MM_GEN_FILENAME_BACKEND_TOKENS.items(): + if token in stem_tokens: + backends = override + break if not backends: backends = _MM_GEN_SUBDIR_BACKENDS.get(subdir, ())