Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ jobs:
# The Wan VAE decode tests build tiny random AutoencoderKLWan models
# (no weights); 0.39 is the release the decoder was verified on.
python -m pip install diffusers==0.39.0
python -m pip install pytest-xdist==3.8.0
# pytest is pinned with the rest of the test stack, so a release can't
# change fixture behaviour under every PR at once.
python -m pip install pytest==9.2.0 pytest-xdist==3.8.0
# The AudioSeal watermark streaming tests build its generator with
# random weights (no download).
python -m pip install "audioseal>=0.2,<0.3"
Expand Down Expand Up @@ -128,7 +130,7 @@ jobs:
python -m pip install --upgrade pip
pip install torch==2.10.0 torchvision==0.25.0 torchaudio==2.10.0 \
--index-url https://download.pytorch.org/whl/cpu
pip install -e ".[dynamo]" pytest
pip install -e ".[dynamo]" pytest==9.2.0
- name: Bridge + registration tests
env:
HF_HUB_OFFLINE: "1"
Expand Down Expand Up @@ -177,7 +179,7 @@ jobs:
# prometheus-client: the frontend's /metrics test renders a real registry;
# fastapi, uvicorn, python-multipart and httpx: the Rust/Python chat
# parity cases run the Python app through fastapi's TestClient
pip install pytest pyzmq msgpack numpy pyyaml prometheus-client \
pip install pytest==9.2.0 pyzmq msgpack numpy pyyaml prometheus-client \
fastapi uvicorn python-multipart httpx
# cpu torch + triton: the arena test imports the tensor-transport
# stack, which reaches mstar.utils.sampling (triton at module level)
Expand Down
5 changes: 3 additions & 2 deletions scripts/ci/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,18 @@ case "$job" in
# on CPU; 3.6.0 is the version torch 2.10.0 pins.
python -m pip install triton==3.6.0
python -m pip install -e '.[dev,waypoint]'
python -m pip install pytest==9.2.0
# BAGEL's CPU graph/KV tests need these without the CUDA extras.
python -m pip install einops regex transformers
python -m pip check
else
python -m pip install -e '.[dynamo]' pytest
python -m pip install -e '.[dynamo]' pytest==9.2.0
fi
;;
rust)
python -m pip install maturin
# pyyaml: runtime tests import mstar.model.base.
python -m pip install pytest pyzmq msgpack numpy pyyaml
python -m pip install pytest==9.2.0 pyzmq msgpack numpy pyyaml
# The tensor-transport stack imports torch and Triton. Preserve this
# job's existing unpinned versions and minimal mstar installation.
python -m pip install torch --index-url https://download.pytorch.org/whl/cpu
Expand Down
20 changes: 20 additions & 0 deletions test/modular/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,26 @@ def __getattr__(self, name):
sys.modules["triton.language"] = triton.language


# --- torch flag proxies ------------------------------------------------------

@pytest.fixture
def torch_flag():
"""``monkeypatch.setattr`` for torch's flags (``torch._inductor.config``,
``torch.backends.*``), restored by assignment. Some of them are served through
``__getattr__`` / ``__setattr__``, which monkeypatch restores by deleting the
attribute since pytest 9.2, removing the flag for every later test in the
process; one fixture for all of them means nobody has to know which."""
saved = []

def set_flag(obj, name, value):
saved.append((obj, name, getattr(obj, name)))
setattr(obj, name, value)

yield set_flag
for obj, name, value in reversed(saved):
setattr(obj, name, value)


# --- platform cache ----------------------------------------------------------

@pytest.fixture(autouse=True)
Expand Down
4 changes: 2 additions & 2 deletions test/modular/test_accelerator_graph_capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ def bad():

@requires_cuda
@pytest.mark.parametrize("fails", [False, True], ids=["captured", "failed"])
def test_benchmark_is_off_inside_the_capture_and_restored_after(monkeypatch, fails):
def test_benchmark_is_off_inside_the_capture_and_restored_after(torch_flag, fails):
"""Qwen3-Omni turns cuDNN's benchmark mode on for Code2Wav's warm-up.
Inside a capture its search fails the capture, which cost Code2Wav its
bs=32 graph and kept that graph's pool."""
Expand All @@ -407,7 +407,7 @@ def run():
return x + torch.tensor([1.0], device=device) if fails else x * 2

for benchmark in (True, False):
monkeypatch.setattr(torch.backends.cudnn, "benchmark", benchmark)
torch_flag(torch.backends.cudnn, "benchmark", benchmark)
with pytest.raises(RuntimeError) if fails else nullcontext():
capture_into_graph(run, AcceleratorGraphPool(torch.cuda.graph_pool_handle()), device, None)
assert torch.backends.cudnn.benchmark is benchmark, "the caller's setting must come back"
Expand Down
10 changes: 5 additions & 5 deletions test/modular/test_audio_watermark.py
Original file line number Diff line number Diff line change
Expand Up @@ -477,7 +477,7 @@ def test_pcm16_round_trip_matches_offline_within_one_step():
assert (marked.int() - expected.int()).abs().max() <= 1


def test_watermark_runs_fp32_matmuls_and_tf32_cudnn_and_restores_the_flags(monkeypatch):
def test_watermark_runs_fp32_matmuls_and_tf32_cudnn_and_restores_the_flags(monkeypatch, torch_flag):
"""cuDNN on H100 picks a far slower conv with TF32 off; matmuls, which the
engine turns to TF32, stay fp32."""
wmk = _watermarker()
Expand All @@ -490,18 +490,18 @@ def conv(x):
return forward(x)

monkeypatch.setattr(first_conv, "forward", conv)
monkeypatch.setattr(torch.backends.cuda.matmul, "allow_tf32", True)
monkeypatch.setattr(torch.backends.cudnn, "allow_tf32", False)
torch_flag(torch.backends.cuda.matmul, "allow_tf32", True)
torch_flag(torch.backends.cudnn, "allow_tf32", False)
wmk.apply([torch.zeros(320)], [WatermarkStream()])
assert seen == [(False, True)]
assert torch.backends.cuda.matmul.allow_tf32 and not torch.backends.cudnn.allow_tf32


def test_precision_getters_answer_while_the_watermark_runs(monkeypatch):
def test_precision_getters_answer_while_the_watermark_runs(torch_flag):
"""Flipping ``cuda.matmul.allow_tf32`` alone made
``get_float32_matmul_precision()`` raise (a mix of the legacy and new
APIs) for every thread until the window closed."""
monkeypatch.setattr(torch.backends.cudnn, "allow_tf32", False)
torch_flag(torch.backends.cudnn, "allow_tf32", False)
previous = torch.get_float32_matmul_precision()
torch.set_float32_matmul_precision("high")
try:
Expand Down
6 changes: 3 additions & 3 deletions test/modular/test_fastconformer.py
Original file line number Diff line number Diff line change
Expand Up @@ -399,14 +399,14 @@ def test_subsampling_kernel_matches_eager_ops():

@_needs_gpu
@pytest.mark.parametrize("causal", [False, True], ids=["offline", "causal"])
def test_triton_encoder_matches_eager_and_single_requests(causal, monkeypatch):
def test_triton_encoder_matches_eager_and_single_requests(causal, monkeypatch, torch_flag):
"""The whole encoder on the GPU, fp32 without TF32: the Triton path
agrees with the eager one, and a padded batch gives each row what it
gets alone."""
from mstar.model.components import fastconformer_kernels

monkeypatch.setattr(torch.backends.cudnn, "allow_tf32", False)
monkeypatch.setattr(torch.backends.cuda.matmul, "allow_tf32", False)
torch_flag(torch.backends.cudnn, "allow_tf32", False)
torch_flag(torch.backends.cuda.matmul, "allow_tf32", False)
torch.manual_seed(16)
config = _causal_config(3) if causal else FastConformerConfig.from_hf(TINY)
enc = FastConformerEncoder(config).eval().cuda()
Expand Down
8 changes: 4 additions & 4 deletions test/modular/test_flux2_klein_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -501,7 +501,7 @@ def test_vae_decode_sizes_are_the_four_compiled_sizes_clamped_to_the_max_batch()
assert [s for s in VAE_DECODE_BATCH_SIZES if s <= small.max_batch_size] == [1, 2, 4]


def test_eager_rounding_is_live_while_tracing_and_does_not_leak(monkeypatch):
def test_eager_rounding_is_live_while_tracing_and_does_not_leak(monkeypatch, torch_flag):
"""``torch.compile`` traces lazily, so ``emulate_precision_casts`` has to be in
effect when the compiled callable is CALLED, not when it is built -- the build runs
on the worker's main thread and the traces on the GPU executor thread, and since
Expand All @@ -513,7 +513,7 @@ def test_eager_rounding_is_live_while_tracing_and_does_not_leak(monkeypatch):

calls, seen = [], []
monkeypatch.setattr(torch, "compile", lambda fn, **kw: calls.append(kw) or fn)
monkeypatch.setattr(inductor_config, "emulate_precision_casts", False)
torch_flag(inductor_config, "emulate_precision_casts", False)

module = torch.nn.Linear(2, 2)
module.forward = lambda *a, **k: seen.append(inductor_config.emulate_precision_casts)
Expand All @@ -534,7 +534,7 @@ def test_eager_rounding_is_live_while_tracing_and_does_not_leak(monkeypatch):
assert _make_model(compile_eager_rounding=False).compile_eager_rounding is False


def test_the_vae_decode_asks_for_its_own_rounding_instead_of_inheriting(monkeypatch):
def test_the_vae_decode_asks_for_its_own_rounding_instead_of_inheriting(monkeypatch, torch_flag):
"""It used to read whatever the transformer's compile left in the global config, so
the decoder's kernels depended on which node was built first."""
import torch._inductor.config as inductor_config
Expand All @@ -543,7 +543,7 @@ def test_the_vae_decode_asks_for_its_own_rounding_instead_of_inheriting(monkeypa

seen = []
monkeypatch.setattr(torch, "compile", lambda fn, **kw: fn)
monkeypatch.setattr(inductor_config, "emulate_precision_casts", False)
torch_flag(inductor_config, "emulate_precision_casts", False)

vae = torch.nn.Module()
vae.decode = lambda *a, **k: seen.append(inductor_config.emulate_precision_casts)
Expand Down
4 changes: 2 additions & 2 deletions test/modular/test_wan_vae_decode.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,8 +192,8 @@ def test_compact_feat_cache_replaces_only_views() -> None:


@pytest.mark.parametrize("before", [False, True])
def test_cudnn_benchmark_is_scoped(before, monkeypatch) -> None:
monkeypatch.setattr(torch.backends.cudnn, "benchmark", before)
def test_cudnn_benchmark_is_scoped(before, torch_flag) -> None:
torch_flag(torch.backends.cudnn, "benchmark", before)
with wan_vae.cudnn_benchmark(True):
assert torch.backends.cudnn.benchmark
assert torch.backends.cudnn.benchmark is before
Expand Down
Loading