diff --git a/.buildkite/amd/scripts/bootstrap-amd-omni.sh b/.buildkite/amd/scripts/bootstrap-amd-omni.sh index 9eff6b6c7..60732d801 100755 --- a/.buildkite/amd/scripts/bootstrap-amd-omni.sh +++ b/.buildkite/amd/scripts/bootstrap-amd-omni.sh @@ -60,7 +60,8 @@ resolve_test_specs() { if ! selected_specs=$(python3 "$AMD_SUITE_SELECTOR" \ --branch "$BUILDKITE_BRANCH" \ --labels "$PR_LABELS" \ - --debug-test-yaml "${DEBUG_TEST_YAML:-}"); then + --debug-test-yaml "${DEBUG_TEST_YAML:-}" \ + --nightly "$NIGHTLY"); then exit 1 fi @@ -80,6 +81,12 @@ filter_test_specs_by_skip_ci() { case "$suite_spec" in READY_TESTS:*) level="l2" ;; MERGE_TESTS:*) level="l3" ;; + NIGHTLY_TESTS:*) + # Explicit PR and scheduled nightly selections must survive + # L2/L3 diff gating, including docs-only main commits. + runnable_specs+=("$suite_spec") + continue + ;; *) echo "ERROR: unknown AMD test suite spec '$suite_spec'" >&2 exit 1 @@ -101,7 +108,7 @@ filter_test_specs_by_skip_ci() { ":memo: CI skipped — docs or pytest skip-mark changes only" \ --style "info" 2>/dev/null || true fi - echo "No AMD L2/L3 suites remain after skip-ci filtering." + echo "No AMD suites remain after skip-ci filtering." exit 0 fi } @@ -219,8 +226,8 @@ if [[ $BUILDKITE_BRANCH == "main" ]]; then file_diff=$(get_diff_main) fi -# Resolve PR tier labels before skip-ci so ready and merge suites can be -# filtered independently for CI-YAML-only changes. +# Resolve PR tier labels before skip-ci so ready/merge suites can be filtered +# independently while an explicitly selected nightly suite passes through. resolve_test_specs filter_test_specs_by_skip_ci diff --git a/.buildkite/amd/scripts/build-ci-image.sh b/.buildkite/amd/scripts/build-ci-image.sh new file mode 100755 index 000000000..3954cd567 --- /dev/null +++ b/.buildkite/amd/scripts/build-ci-image.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: Apache-2.0 +# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project + +set -euo pipefail + +# Build and push the ROCm CI image with a registry-backed BuildKit cache. The +# AMD builders are ephemeral, so a local Docker cache cannot survive between +# jobs. Keeping the cache beside the runtime image also reuses the registry +# credentials already configured on the amd-cpu agents. + +REGISTRY="${ROCM_CI_IMAGE_REGISTRY:-rocm/vllm-omni}" +DOCKERFILE="docker/Dockerfile.rocm" +BUILDER_NAME="vllm-omni-rocm-builder" +ROCM_ARCH="${PYTORCH_ROCM_ARCH:-gfx942}" + +if [[ -z "${BUILDKITE_COMMIT:-}" ]]; then + echo "ERROR: BUILDKITE_COMMIT is not set" >&2 + exit 1 +fi + +dependency_files=( + "$DOCKERFILE" + "${DOCKERFILE}.dockerignore" + pyproject.toml + setup.py + tools/install_torchcodec_rocm.sh +) +while IFS= read -r dependency_file; do + dependency_files+=("$dependency_file") +done < <(find requirements -maxdepth 1 -type f -name '*.txt' -print | LC_ALL=C sort) + +for dependency_file in "${dependency_files[@]}"; do + if [[ ! -f "$dependency_file" ]]; then + echo "ERROR: cache-key input does not exist: $dependency_file" >&2 + exit 1 + fi +done + +CACHE_KEY=$( + { + printf 'rocm-arch=%s\n' "$ROCM_ARCH" + for dependency_file in "${dependency_files[@]}"; do + printf 'path=%s\n' "$dependency_file" + sha256sum "$dependency_file" + done + } | sha256sum | cut -c1-16 +) +CACHE_REF="${REGISTRY}:rocm-deps-cache-${CACHE_KEY}" +IMAGE_REF="${REGISTRY}:${BUILDKITE_COMMIT}" + +echo "ROCm dependency cache: ${CACHE_REF}" +echo "ROCm CI image: ${IMAGE_REF}" + +# The docker-container driver supports exporting the full cache to a registry; +# the default docker driver on CI does not. +if ! docker buildx inspect "$BUILDER_NAME" >/dev/null 2>&1; then + docker buildx create --name "$BUILDER_NAME" --driver docker-container +fi +docker buildx use "$BUILDER_NAME" +docker buildx inspect --bootstrap + +docker buildx build --push --pull --progress=plain \ + --target test \ + --build-arg "ARG_PYTORCH_ROCM_ARCH=${ROCM_ARCH}" \ + --cache-from "type=registry,ref=${CACHE_REF}" \ + --cache-to "type=registry,ref=${CACHE_REF},mode=max,compression=zstd,ignore-error=true" \ + --file "$DOCKERFILE" \ + --tag "$IMAGE_REF" . diff --git a/.buildkite/amd/scripts/select_test_suites.py b/.buildkite/amd/scripts/select_test_suites.py index b7c72f6e4..daed05bd3 100644 --- a/.buildkite/amd/scripts/select_test_suites.py +++ b/.buildkite/amd/scripts/select_test_suites.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: Apache-2.0 # SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project -"""Select AMD L2/L3 suites after Buildkite has created an AMD build. +"""Select AMD ready/merge/nightly suites after Buildkite creates a build. This repository-side selector does not decide which GitHub label events start the external ``vllm-omni-amd-ci`` pipeline. Its Buildkite PR build condition @@ -17,6 +17,7 @@ from collections.abc import Iterable SUITE_SPECS = { "ready": "READY_TESTS:test-amd-ready.yml", "merge": "MERGE_TESTS:test-amd-merge.yml", + "nightly": "NIGHTLY_TESTS:test-amd-nightly.yml", } @@ -28,7 +29,7 @@ def _parse_debug_suites(value: str) -> tuple[str, ...]: seen: set[str] = set() for suite in suites: if suite not in SUITE_SPECS: - raise ValueError(f"DEBUG_TEST_YAML entries must be 'merge' or 'ready', got {suite!r}") + raise ValueError(f"DEBUG_TEST_YAML entries must be 'merge', 'nightly', or 'ready', got {suite!r}") if suite in seen: raise ValueError(f"duplicate DEBUG_TEST_YAML suite {suite!r}") seen.add(suite) @@ -40,18 +41,27 @@ def select_amd_test_suites( branch: str, labels: Iterable[str], debug_test_yaml: str = "", + nightly: bool = False, ) -> tuple[str, ...]: """Return ordered suite names while preserving legacy unlabeled PRs.""" if debug_test_yaml: return _parse_debug_suites(debug_test_yaml) if branch == "main": - return ("merge",) + return ("nightly",) if nightly else ("merge",) label_set = {label.strip() for label in labels if label.strip()} - selected = tuple(suite for label, suite in (("ready", "ready"), ("merge-test", "merge")) if label in label_set) - # AMD historically uploaded L2 for every PR build. Keep that behavior for - # triggers such as amd-test while adding tier selection for ready/merge-test. + selected = tuple( + suite + for label, suite in ( + ("ready", "ready"), + ("merge-test", "merge"), + ("nightly-test", "nightly"), + ) + if label in label_set + ) + # AMD historically uploaded the ready suite for every admitted PR build. + # Preserve that fallback when no explicit tier label is present. return selected or ("ready",) @@ -60,6 +70,7 @@ def main() -> int: parser.add_argument("--branch", required=True) parser.add_argument("--labels", default="") parser.add_argument("--debug-test-yaml", default="") + parser.add_argument("--nightly", type=int, choices=(0, 1), default=0) args = parser.parse_args() labels = tuple(args.labels.splitlines()) @@ -68,19 +79,15 @@ def main() -> int: branch=args.branch, labels=labels, debug_test_yaml=args.debug_test_yaml, + nightly=bool(args.nightly), ) except ValueError as exc: parser.error(str(exc)) label_set = {label.strip() for label in labels if label.strip()} - if not args.debug_test_yaml and args.branch != "main" and not ({"ready", "merge-test"} & label_set): + if args.branch != "main" and not args.debug_test_yaml and not ({"ready", "merge-test", "nightly-test"} & label_set): print( - "No AMD L2/L3 tier label found; preserving the legacy ready-suite fallback.", - file=sys.stderr, - ) - if "nightly-test" in label_set: - print( - "AMD nightly-test has no suite yet and does not affect L2/L3 selection.", + "No AMD ready/merge/nightly label found; preserving the legacy ready-suite fallback.", file=sys.stderr, ) diff --git a/.buildkite/amd/test-amd-merge.yml b/.buildkite/amd/test-amd-merge.yml index b1b9e7ecc..6ee36de48 100644 --- a/.buildkite/amd/test-amd-merge.yml +++ b/.buildkite/amd/test-amd-merge.yml @@ -9,15 +9,26 @@ steps: steps: - label: "Simple · Model Executor Test · Shard %N/%t" agent_pool: mi300_1 - parallelism: 2 + parallelism: 3 depends_on: amd-build mirror_hardwares: [amdproduction] grade: Blocking + timeout_in_minutes: 90 commands: - export VLLM_ROCM_USE_AITER=0 # ignore test_teacache_extractors.py because it use rocm gemm kernel from vLLM # that is not supported on CPU - - "pytest -sv tests/model_executor -m 'core_model and cpu' --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB" + - "pytest -sv tests/model_executor -m 'core_model and cpu and not omni' --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB" + + - label: "Simple · Omni Processor Test" + agent_pool: mi300_1 + depends_on: amd-build + mirror_hardwares: [amdproduction] + grade: Blocking + timeout_in_minutes: 60 + commands: + - export VLLM_ROCM_USE_AITER=0 + - "pytest -sv tests/model_executor/models/test_omni_processing.py -m 'core_model and cpu and omni'" - label: "Simple · Diffusion Test · Shard %N/%t" agent_pool: mi300_1 @@ -25,6 +36,7 @@ steps: depends_on: amd-build mirror_hardwares: [amdproduction] grade: Blocking + timeout_in_minutes: 45 commands: - export VLLM_ROCM_USE_AITER=0 # ignore test_teacache_extractors.py because it use rocm gemm kernel from vLLM diff --git a/.buildkite/amd/test-amd-nightly.yml b/.buildkite/amd/test-amd-nightly.yml new file mode 100644 index 000000000..0da365d0c --- /dev/null +++ b/.buildkite/amd/test-amd-nightly.yml @@ -0,0 +1,66 @@ +# AMD MI300 `full_model` nightly coverage during burn-in. +# All jobs are non-blocking until the lane has stable runtime evidence. +# Historical build #11646 was red in Function Expansion and Accuracy (one +# async_chunk similarity mismatch; Seed-TTS WER 0.376480 > 0.35). + +env: + VLLM_WORKER_MULTIPROC_METHOD: spawn + HF_HUB_DOWNLOAD_TIMEOUT: 300 + HF_HUB_ETAG_TIMEOUT: 60 + +steps: + # MI325 is the repository's legacy ROCm pytest marker. The AMD template maps + # agent_pool to the current MI300 Buildkite queues independently of that mark. + - group: ":full_moon: Qwen3-Omni MI300 Nightly" + steps: + - label: "Qwen3-Omni Function Expansion" + agent_pool: mi300_2 + depends_on: amd-build + mirror_hardwares: [amdproduction] + grade: NonBlocking + timeout_in_minutes: 180 + commands: + - export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1" + - pytest -s -v tests/e2e/online_serving/test_qwen3_omni_expansion.py -m "full_model and rocm and MI325 and cards_2" --run-level "full_model" + + - label: "Qwen3-Omni Accuracy" + agent_pool: mi300_2 + depends_on: amd-build + mirror_hardwares: [amdproduction] + grade: NonBlocking + timeout_in_minutes: 180 + artifact_paths: + - tests/e2e/accuracy/qwen3_omni/results/qwen_omni_acc/*.json + commands: + - export SEED_TTS_WER_EVAL=1 + # PyTorch ROCm uses the torch.cuda device namespace. + - export SEED_TTS_EVAL_DEVICE=cuda:1 + - pytest -s -v tests/e2e/accuracy/qwen3_omni/test_qwen3_omni.py -m "full_model and rocm and MI325 and cards_2" --run-level "full_model" + # Native tests run from the image copy under /app/vllm-omni, while + # Buildkite's artifact hook searches the checkout workspace. + - | + if [[ "$$PWD" != "$${BUILDKITE_BUILD_CHECKOUT_PATH:?}" ]]; then + artifact_dir="$${BUILDKITE_BUILD_CHECKOUT_PATH}/tests/e2e/accuracy/qwen3_omni/results/qwen_omni_acc" + mkdir -p "$$artifact_dir" + cp -v tests/e2e/accuracy/qwen3_omni/results/qwen_omni_acc/*.json "$$artifact_dir/" + fi + + - label: "Qwen3-Omni Documentation Examples" + agent_pool: mi300_2 + depends_on: amd-build + mirror_hardwares: [amdproduction] + grade: NonBlocking + timeout_in_minutes: 120 + commands: + - export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1" + - pytest -s -v tests/examples/online_serving/test_qwen3_omni.py -m "full_model and rocm and MI325 and cards_2" --run-level "full_model" + + - label: "Qwen3-Omni AITER-on Smoke" + agent_pool: mi300_2 + depends_on: amd-build + mirror_hardwares: [amdproduction] + grade: NonBlocking + timeout_in_minutes: 90 + commands: + - export VLLM_ROCM_USE_AITER=1 + - pytest -s -v tests/e2e/online_serving/test_qwen3_omni_expansion.py::test_text_to_text_audio_001 -m "full_model and rocm and MI325 and cards_2" --run-level "full_model" diff --git a/.buildkite/amd/test-amd-ready.yml b/.buildkite/amd/test-amd-ready.yml index 585f089a2..e46b559f3 100644 --- a/.buildkite/amd/test-amd-ready.yml +++ b/.buildkite/amd/test-amd-ready.yml @@ -9,26 +9,39 @@ steps: steps: - label: "Simple · Model Executor Test · Shard %N/%t" agent_pool: mi300_1 - parallelism: 2 + parallelism: 3 depends_on: amd-build mirror_hardwares: [amdproduction] grade: Blocking + timeout_in_minutes: 90 commands: - export VLLM_ROCM_USE_AITER=0 # ignore test_teacache_extractors.py because it use rocm gemm kernel from vLLM # that is not supported on CPU - - "pytest -sv tests/model_executor -m 'core_model and cpu' --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB" + - "pytest -sv tests/model_executor -m 'core_model and cpu and not omni' --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB" - - label: "Simple · Diffusion Test" + - label: "Simple · Omni Processor Test" agent_pool: mi300_1 depends_on: amd-build mirror_hardwares: [amdproduction] grade: Blocking + timeout_in_minutes: 60 + commands: + - export VLLM_ROCM_USE_AITER=0 + - "pytest -sv tests/model_executor/models/test_omni_processing.py -m 'core_model and cpu and omni'" + + - label: "Simple · Diffusion Test · Shard %N/%t" + agent_pool: mi300_1 + parallelism: 4 + depends_on: amd-build + mirror_hardwares: [amdproduction] + grade: Blocking + timeout_in_minutes: 45 commands: - export VLLM_ROCM_USE_AITER=0 # ignore test_teacache_extractors.py because it use rocm gemm kernel from vLLM # that is not supported on CPU - - "pytest -sv tests/diffusion -m 'core_model and cpu' --ignore=tests/diffusion/cache/test_teacache_extractors.py" + - "pytest -sv tests/diffusion -m 'core_model and cpu' --ignore=tests/diffusion/cache/test_teacache_extractors.py --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB" - label: "Simple · Engine&Entrypoints Test" agent_pool: mi300_1 @@ -69,6 +82,27 @@ steps: - group: ":card_index_dividers: Diffusion Test" steps: + # Keep real FlashAttention execution out of the CPU-marked Simple lane. + # AITER may need to build several kernels on a cold worker, so run one + # pytest worker with job-local build directories and a bounded timeout. + - label: "ROCm · FlashAttention/AITER GPU Coverage" + agent_pool: mi300_1 + depends_on: amd-build + mirror_hardwares: [amdproduction] + grade: NonBlocking + timeout_in_minutes: 60 + commands: + - export VLLM_ROCM_USE_AITER=1 + - export AITER_JIT_DIR="/tmp/vllm-omni-aiter-$$BUILDKITE_JOB_ID" + - export TORCH_EXTENSIONS_DIR="/tmp/vllm-omni-torch-extensions-$$BUILDKITE_JOB_ID" + - mkdir -p "$$AITER_JIT_DIR" "$$TORCH_EXTENSIONS_DIR" + - >- + timeout --signal=TERM --kill-after=2m 55m + pytest -s -v -n 1 + tests/diffusion/attention/ + -m 'core_model and rocm and MI325 and cards_1' + --run-level "core_model" + - label: "Diffusion · Batch Test" agent_pool: mi300_1 depends_on: amd-build @@ -160,6 +194,39 @@ steps: # - export VLLM_WORKER_MULTIPROC_METHOD=spawn # - timeout 20m pytest -s -v tests/e2e/offline_inference/test_stable_audio_expansion.py -m "advanced_model and diffusion and L4" --run-level advanced_model +- label: "ROCm · Engine & Model Executor GPU Coverage (R2-01)" + agent_pool: mi300_1 + depends_on: amd-build + mirror_hardwares: [amdproduction] + grade: NonBlocking + timeout_in_minutes: 20 + artifact_paths: + - "artifacts/rocm-r2-01/**/*" + commands: + # Native AMD tests run from /app/vllm-omni, while Buildkite uploads + # artifacts relative to its checkout directory. + - export R2_01_ARTIFACT_DIR="$$BUILDKITE_BUILD_CHECKOUT_PATH/artifacts/rocm-r2-01" + - mkdir -p "$$R2_01_ARTIFACT_DIR" + # The CUDA ready job also covers tests/worker/test_batched_omni_output.py. + # Keep the initial ROCm burn-in scoped to the requested directories. + # Verbose pytest output and JUnit retain node IDs without a second + # collection-only pass over the same GPU-backed test tree. + # The CUDA/L4-only CosyVoice3 ragged-flow parity test cold-JITs multiple + # AITER kernels on ROCm and is covered by the CUDA ready lane. + - >- + pytest -s -v -ra + tests/engine/ tests/model_executor/ + -m 'core_model and cuda and not + (cards_2 or cards_3 or cards_4 or cards_5 or cards_6 or cards_7 or cards_8)' + -k 'not test_code2wav_streaming_batch_matches_ragged_flow_numerics' + --run-level "core_model" + --durations=0 + --junitxml="$$R2_01_ARTIFACT_DIR/pytest.xml" + 2>&1 | tee "$$R2_01_ARTIFACT_DIR/pytest.log" + - >- + tail -n 100 "$$R2_01_ARTIFACT_DIR/pytest.log" > + "$$R2_01_ARTIFACT_DIR/pytest-summary.txt" + - label: "Engine Test" agent_pool: mi300_1 depends_on: amd-build @@ -172,6 +239,71 @@ steps: pytest -s -v tests/engine/test_async_omni_engine_abort.py ' +- label: "ROCm · Entrypoints GPU Coverage (R2-02)" + agent_pool: mi300_1 + depends_on: amd-build + mirror_hardwares: [amdproduction] + grade: NonBlocking + timeout_in_minutes: 30 + env: + VLLM_WORKER_MULTIPROC_METHOD: spawn + artifact_paths: + - "artifacts/rocm-r2-02/**/*" + commands: + # Native AMD tests run from /app/vllm-omni, while Buildkite uploads + # artifacts relative to its checkout directory. + - export R2_02_ARTIFACT_DIR="$$BUILDKITE_BUILD_CHECKOUT_PATH/artifacts/rocm-r2-02" + - mkdir -p "$$R2_02_ARTIFACT_DIR" + - >- + ps -eo pid=,ppid=,lstart=,stat=,comm= > + "$$R2_02_ARTIFACT_DIR/processes-before.txt" + # Verbose pytest output and JUnit retain selected node IDs without a + # second collection-only pass over the same GPU-backed test tree. + # The inner timeout leaves five minutes for teardown verification and + # artifact generation before the Buildkite step timeout. + - >- + timeout --signal=TERM --kill-after=1m 25m + pytest -s -v -ra + tests/entrypoints/ + -m 'core_model and cuda and not + (cards_2 or cards_3 or cards_4 or cards_5 or cards_6 or cards_7 or cards_8)' + --run-level "core_model" + --durations=0 + --junitxml="$$R2_02_ARTIFACT_DIR/pytest.xml" + 2>&1 | tee "$$R2_02_ARTIFACT_DIR/pytest.log" + - >- + tail -n 100 "$$R2_02_ARTIFACT_DIR/pytest.log" > + "$$R2_02_ARTIFACT_DIR/pytest-summary.txt" + - | + sleep 5 + ps -eo pid=,ppid=,lstart=,stat=,comm= > "$$R2_02_ARTIFACT_DIR/processes-after.txt" + # Compare PID plus process start time so PID reuse cannot hide a leak. + # Double dollars preserve awk field references through Buildkite interpolation. + awk ' + NR == FNR { + if ($$9 != "ps") { + baseline[$$1 "|" $$3 "|" $$4 "|" $$5 "|" $$6 "|" $$7] = 1 + } + next + } + $$9 != "ps" { + identity = $$1 "|" $$3 "|" $$4 "|" $$5 "|" $$6 "|" $$7 + if (!(identity in baseline)) { + print + leaked = 1 + } + } + END { + if (leaked) { + print "status=FAIL leaked_processes_detected=1" + exit 1 + } + print "status=PASS leaked_processes=0" + } + ' "$$R2_02_ARTIFACT_DIR/processes-before.txt" \ + "$$R2_02_ARTIFACT_DIR/processes-after.txt" \ + 2>&1 | tee "$$R2_02_ARTIFACT_DIR/process-cleanup.txt" + # - label: "Omni Model Test Qwen3-Omni" # agent_pool: mi300_2 # depends_on: amd-build @@ -201,6 +333,12 @@ steps: depends_on: amd-build mirror_hardwares: [amdproduction] grade: Blocking + # A ROCm hardware hang aborts the interpreter with 134. Let Buildkite + # create one fresh pod instead of retrying on the poisoned GPU process. + retry: + automatic: + - exit_status: 134 + limit: 1 commands: - pytest -s -v tests/e2e/online_serving/test_cosyvoice3_tts_expansion.py -m "slow" --run-level "core_model" diff --git a/.buildkite/amd/test-template-amd-omni.j2 b/.buildkite/amd/test-template-amd-omni.j2 index e2042b96a..cca99f509 100644 --- a/.buildkite/amd/test-template-amd-omni.j2 +++ b/.buildkite/amd/test-template-amd-omni.j2 @@ -3,7 +3,8 @@ Last synced: 2026-08-04 Modifications: Use the shared MI300 queues and Omni command-passing contract #} -{% set docker_image_amd = "rocm/vllm-omni:$BUILDKITE_COMMIT" %} +{% set docker_registry_amd = "rocm/vllm-omni" %} +{% set docker_image_amd = docker_registry_amd ~ ":$BUILDKITE_COMMIT" %} {% set default_working_dir = "/app/vllm-omni" %} {# MI300 runs tests natively in Kubernetes; Docker-in-Docker is unavailable. #} @@ -74,11 +75,12 @@ steps: depends_on: ~ soft_fail: false commands: - - "docker build -f docker/Dockerfile.rocm -t {{ docker_image_amd }} --target test --build-arg ARG_PYTORCH_ROCM_ARCH=gfx942 --progress plain ." - - "docker push {{ docker_image_amd }}" + - "bash .buildkite/amd/scripts/build-ci-image.sh" key: "amd-build" env: DOCKER_BUILDKIT: "1" + PYTORCH_ROCM_ARCH: "gfx942" + ROCM_CI_IMAGE_REGISTRY: "{{ docker_registry_amd }}" retry: automatic: - exit_status: -1 # Agent was lost @@ -156,6 +158,14 @@ steps: {% for path in step.artifact_paths %} - "{{ path }}" {% endfor %} +{% endif %} +{% if step.retry %} + retry: + automatic: +{% for retry_rule in step.retry.automatic %} + - exit_status: {{ retry_rule.exit_status }} + limit: {{ retry_rule.limit }} +{% endfor %} {% endif %} {% if step.timeout_in_minutes %} timeout_in_minutes: {{ step.timeout_in_minutes }} @@ -224,6 +234,14 @@ steps: {% for path in step.artifact_paths %} - "{{ path }}" {% endfor %} +{% endif %} +{% if step.retry %} + retry: + automatic: +{% for retry_rule in step.retry.automatic %} + - exit_status: {{ retry_rule.exit_status }} + limit: {{ retry_rule.limit }} +{% endfor %} {% endif %} {% if step.timeout_in_minutes %} timeout_in_minutes: {{ step.timeout_in_minutes }} diff --git a/.buildkite/common/ci_source_file_dependencies.yml b/.buildkite/common/ci_source_file_dependencies.yml new file mode 100644 index 000000000..5dfbf8da4 --- /dev/null +++ b/.buildkite/common/ci_source_file_dependencies.yml @@ -0,0 +1,471 @@ +# Uploader-only path-prefix presets for CUDA L2–L5 and NPU L4 test YAML. +# Referenced as ``source_file_dependencies: omni_qwen3_omni_function`` (or a list of +# keys) on a step; ``upload_pipeline.py`` expands the key(s) only. +# +# YAML anchors above the registry hold model business-code paths. Job keys +# ({model}_function / _perf / _accuracy / _reliability / _doc / _cov) alias +# those anchors and add the scripts the job actually runs. Feature keys below +# are unchanged. ``source_filter_fallback`` is not a job key: when no job-key +# prefix matches, a matching diff keeps every job for that upload. +# +# YAML anchors are nested lists; the loader flattens them. + +x-qwen3-tts: &qwen3_tts + - vllm_omni/engine/async_omni_engine.py + - vllm_omni/entrypoints/omni_base.py + - vllm_omni/worker/gpu_model_runner.py + - vllm_omni/model_executor/models/qwen3_tts/ + - vllm_omni/model_executor/models/common/qwen3_code_predictor.py + - vllm_omni/model_executor/models/common/snake_activation.py + - vllm_omni/model_executor/models/common/alias_free_activation.py + - vllm_omni/model_executor/stage_input_processors/qwen3_tts.py + - vllm_omni/deploy/qwen3_tts.yaml + - vllm_omni/entrypoints/openai/serving_speech.py + - vllm_omni/entrypoints/openai/tts_adapters/ + - vllm_omni/engine/stage_pool.py + - vllm_omni/worker_v2/ + - vllm_omni/core/sched/ + - vllm_omni/distributed/omni_connectors/ + - vllm_omni/config/stage_config.py + - vllm_omni/config/omni_config.py + - vllm_omni/engine/orchestrator.py + - vllm_omni/engine/stage_engine_core_proc.py + - vllm_omni/deploy/qwen3_tts_mrv2.yaml + - vllm_omni/deploy/qwen3_tts_high_concurrency_mrv2.yaml + - vllm_omni/deploy/qwen3_tts_high_concurrency_mrv2_b4.yaml + +x-minicpmo-4-5: &minicpmo_4_5 + - vllm_omni/engine/async_omni_engine.py + - vllm_omni/entrypoints/omni_base.py + - vllm_omni/model_executor/models/minicpmo_4_5/ + - vllm_omni/model_executor/models/step_audio2/ + - vllm_omni/model_executor/models/cosyvoice3/code2wav_core/ + - vllm_omni/model_executor/models/cosyvoice3/utils.py + - vllm_omni/model_executor/stage_input_processors/minicpmo_4_5_omni.py + - vllm_omni/deploy/minicpmo_4_5.yaml + - vllm_omni/transformers_utils/chat_templates/minicpmo45_native.jinja + +x-minicpmo-4-5-duplex: &minicpmo_4_5_duplex + - vllm_omni/deploy/minicpmo_4_5_duplex.yaml + - vllm_omni/engine/duplex/ + - vllm_omni/engine/duplex_omni_engine.py + - vllm_omni/engine/duplex_orchestrator.py + - vllm_omni/engine/omni_engine_base.py + - vllm_omni/entrypoints/duplex/ + - vllm_omni/entrypoints/duplex_omni.py + - vllm_omni/entrypoints/async_omni_base.py + - vllm_omni/protocol/ + - vllm_omni/clients/ + - vllm_omni/outputs/duplex.py + - vllm_omni/model_executor/duplex_sampling.py + - vllm_omni/experimental/fullduplex/ + - vllm_omni/core/sched/ + - vllm_omni/outputs/multimodal_accumulation.py + - vllm_omni/engine/stage_init_utils.py + - vllm_omni/engine/orchestrator.py + - vllm_omni/entrypoints/cli/serve.py + - vllm_omni/entrypoints/openai/api_server.py + - vllm_omni/entrypoints/openai/duplex_capability.py + - vllm_omni/config/stage_config.py + +x-qwen2-5-omni: &qwen2_5_omni + - vllm_omni/engine/async_omni_engine.py + - vllm_omni/entrypoints/omni_base.py + - vllm_omni/model_executor/models/qwen2_5_omni/ + - vllm_omni/model_executor/stage_input_processors/qwen2_5_omni.py + - vllm_omni/deploy/qwen2_5_omni.yaml + +x-qwen3-omni: &qwen3_omni + - vllm_omni/engine/async_omni_engine.py + - vllm_omni/entrypoints/omni_base.py + - vllm_omni/entrypoints/openai/serving_chat.py + - vllm_omni/model_executor/models/qwen3_omni/ + - vllm_omni/model_executor/models/common/qwen3_code_predictor.py + - vllm_omni/model_executor/models/common/snake_activation.py + - vllm_omni/model_executor/models/qwen2_5_omni/qwen2_5_omni_thinker.py + - vllm_omni/model_executor/models/qwen3_tts/cuda_graph_decoder_wrapper.py + - vllm_omni/model_executor/stage_input_processors/qwen3_omni.py + - vllm_omni/deploy/qwen3_omni_moe.yaml + - vllm_omni/deploy/qwen3_omni_moe_thinking.yaml + +x-wan22: &wan22 + - vllm_omni/diffusion/models/wan2_2/ + - vllm_omni/diffusion/models/dmd2/ + +x-cosmos3: &cosmos3 + - vllm_omni/diffusion/models/cosmos3/ + - vllm_omni/diffusion/distributed/autoencoders/autoencoder_kl_wan.py + - vllm_omni/experimental/world_models/ + - vllm_omni/model_extras/cosmos3.py + +x-qwen-image: &qwen_image + - vllm_omni/diffusion/models/qwen_image/ + - vllm_omni/diffusion/models/dmd2/ + - vllm_omni/diffusion/distributed/autoencoders/autoencoder_kl_qwenimage.py + +x-hunyuan-image3: &hunyuan_image3 + - vllm_omni/diffusion/models/hunyuan_image3/ + - vllm_omni/model_executor/models/hunyuan_image3/ + - vllm_omni/deploy/hunyuan_image3_dit.yaml + +x-minimax-h3: &minimax_h3 + - vllm_omni/diffusion/models/minimax_h3/ + - vllm_omni/diffusion/layers/indexed_modulation.py + +x-hunyuan-video: &hunyuan_video + - vllm_omni/diffusion/models/hunyuan_video/ + - vllm_omni/model_executor/models/hunyuan_video/ + +x-ltx2: <x2 + - vllm_omni/diffusion/models/ltx2/ + - vllm_omni/model_extras/ltx2.py + +x-sana-video: &sana_video + - vllm_omni/diffusion/models/sana_video/ + - vllm_omni/model_extras/sana_video.py + +x-z-image: &z_image + - vllm_omni/diffusion/models/z_image/ + +x-stable-audio: &stable_audio + - vllm_omni/diffusion/models/stable_audio/ + +x-lingbot-video: &lingbot_video + - vllm_omni/diffusion/models/lingbot_video/ + - vllm_omni/model_extras/lingbot_video.py + +x-lingbot-world: &lingbot_world + - vllm_omni/diffusion/models/lingbot_world/ + + +source_file_dependencies: + # Hardware presets and shared test helpers. Not a job key — do not attach this + # to a step. Used only when no job-key prefix matches: then a hit keeps every job. + source_filter_fallback: + - .buildkite/common/ci_mirror_hardwares.yml + - tests/helpers/ + + # --- features --- + diffusion_distributed_attention: + - tests/diffusion/distributed/ + - tests/diffusion/attention/test_attention_sp.py + - vllm_omni/diffusion/distributed/ + - vllm_omni/diffusion/attention/ + - vllm_omni/diffusion/data.py + - vllm_omni/diffusion/models/ + + custom_pipeline: + - tests/e2e/features/custom_pipeline/ + - tests/e2e/features/helpers/custom_pipeline.py + - vllm_omni/diffusion/ + - vllm_omni/engine/ + - vllm_omni/entrypoints/ + - vllm_omni/inputs/ + - vllm_omni/outputs/ + + rlhf_verl_omni: + - tests/e2e/features/rlhf_test/test_verl_omni_e2e.py + - tests/e2e/features/helpers/verl_omni_server.py + - tests/e2e/features/helpers/custom_pipeline.py + - vllm_omni/diffusion/ + - vllm_omni/engine/ + - vllm_omni/entrypoints/ + - vllm_omni/inputs/ + - vllm_omni/outputs/ + + # Tiny-model diffusion jobs (shared across many model trees under models/). + diffusion_tiny_model: + - tests/model_tests/diffusion/ + - vllm_omni/diffusion/models/ + + diffusion_offloader: + - tests/diffusion/offloader/ + - vllm_omni/diffusion/offloader/ + + diffusion_quantization: + - tests/diffusion/quantization/ + - vllm_omni/diffusion/quantization/ + + # --- models --- + # --- omni / tts jobs --- + omni_qwen3_omni_function: + - *qwen3_omni + - tests/e2e/offline_inference/test_qwen3_omni.py + - tests/e2e/offline_inference/test_qwen3_omni_colocate_async.py + - tests/e2e/offline_inference/test_qwen3_omni_autoround_w4a16_expansion.py + - tests/e2e/offline_inference/test_qwen3_omni_modelopt_nvfp4_w4a4.py + - tests/e2e/online_serving/test_qwen3_omni.py + - tests/e2e/online_serving/test_qwen3_omni_expansion.py + - tests/e2e/online_serving/test_qwen3_omni_multi_replicas.py + + omni_qwen3_omni_accuracy: + - *qwen3_omni + - tests/e2e/accuracy/qwen3_omni/ + + omni_qwen3_omni_perf: + - *qwen3_omni + - tests/dfx/perf/scripts/run_benchmark.py + - tests/dfx/perf/tests/test_qwen3_omni_vllm_text.json + - tests/dfx/perf/tests/test_qwen3_omni_async_chunk.json + - tests/dfx/perf/tests/test_qwen3_omni_no_async_chunk.json + - tests/dfx/perf/tests/test_qwen3_omni_multi_replicas.json + + omni_qwen3_omni_reliability: + - *qwen3_omni + - tests/dfx/reliability/test_reliability_qwen3_omni.py + + omni_qwen3_omni_doc: + - *qwen3_omni + - examples/online_serving/qwen3_omni/ + - examples/online_serving/openai_chat_completion_client_for_multimodal_generation.py + - tests/examples/online_serving/test_qwen3_omni.py + + omni_qwen2_5_omni_doc: + - *qwen2_5_omni + - examples/online_serving/qwen2_5_omni/ + - examples/online_serving/openai_chat_completion_client_for_multimodal_generation.py + - tests/examples/online_serving/test_qwen2_5_omni.py + + omni_minicpmo_4_5_function: + - *minicpmo_4_5 + - tests/e2e/offline_inference/test_minicpmo_4_5.py + - tests/e2e/online_serving/test_minicpmo_4_5.py + - tests/e2e/online_serving/test_minicpmo_4_5_expansion.py + + omni_minicpmo_4_5_accuracy: + - *minicpmo_4_5 + - tests/e2e/accuracy/minicpmo_4_5/ + + omni_minicpmo_4_5_perf: + - *minicpmo_4_5 + - tests/dfx/perf/scripts/run_benchmark.py + - tests/dfx/perf/tests/test_minicpmo_4_5_ready.json + - tests/dfx/perf/tests/test_minicpmo_4_5.json + + omni_minicpmo_4_5_doc: + - *minicpmo_4_5 + - examples/online_serving/minicpmo/realtime_web/ + - examples/online_serving/minicpmo/realtime_duplex_demo.py + - tests/examples/test_minicpmo_realtime_web_server.py + - tests/examples/test_minicpmo_realtime_web_static.py + - tests/examples/test_minicpmo_realtime_duplex_simple_demo.py + + omni_minicpmo_4_5_duplex_function: + - *minicpmo_4_5 + - *minicpmo_4_5_duplex + - tests/e2e/online_serving/test_minicpmo_4_5_duplex.py + - tests/e2e/online_serving/test_minicpmo_4_5_duplex_expansion.py + - tests/e2e/online_serving/test_duplex_client_live.py + - tests/e2e/online_serving/test_minicpmo_realtime_duplex_drivers.py + - tests/e2e/online_serving/helpers/minicpmo_realtime_duplex_scenarios.py + - tests/e2e/online_serving/run_minicpmo_realtime_duplex_multi_session.py + - tests/e2e/online_serving/run_minicpmo_realtime_duplex_server_vad.py + - tests/e2e/online_serving/run_minicpmo_realtime_duplex_soft_interrupt.py + - tests/e2e/online_serving/helpers/minicpmo_4_5_duplex.py + - tests/assets/minicpmo_4_5/ + - tests/clients/ + - tests/engine/duplex/ + - tests/engine/test_duplex_omni_engine.py + - tests/engine/test_duplex_orchestrator.py + - tests/entrypoints/duplex/ + - tests/entrypoints/test_duplex_omni.py + - tests/entrypoints/openai_api/test_duplex_api_server.py + - tests/model_executor/models/minicpmo_4_5/duplex/ + - tests/protocol/ + + omni_minicpmo_4_5_duplex_perf: + - *minicpmo_4_5 + - *minicpmo_4_5_duplex + - tests/dfx/perf/scripts/run_benchmark.py + - tests/dfx/perf/tests/test_minicpmo_4_5_duplex_seed_tts.json + + tts_qwen3_tts_function: + - *qwen3_tts + - tests/e2e/features/prefill_phase/ + - tests/e2e/offline_inference/test_qwen3_tts_base.py + - tests/e2e/offline_inference/test_qwen3_tts_customvoice.py + - tests/e2e/online_serving/test_qwen3_tts_base.py + - tests/e2e/online_serving/test_qwen3_tts_base_expansion.py + - tests/e2e/online_serving/test_qwen3_tts_customvoice.py + - tests/e2e/online_serving/test_qwen3_tts_customvoice_expansion.py + + tts_qwen3_tts_perf: + - *qwen3_tts + - tests/dfx/perf/scripts/run_benchmark.py + - tests/dfx/perf/tests/test_tts.json + + tts_qwen3_tts_cov: + - *qwen3_tts + - .buildkite/common/scripts/run_cov_split.sh + - pyproject.toml + - tests/e2e/offline_inference/test_qwen3_tts_base.py + - tests/e2e/online_serving/test_qwen3_tts_base.py + + # --- diffusion jobs --- + diffusion_wan22_function: + - *wan22 + - tests/e2e/offline_inference/test_wan22_t2v.py + - tests/e2e/offline_inference/test_wan22_autoround_w4a16_expansion.py + - tests/e2e/offline_inference/test_device_postprocess_equivalence.py + - tests/e2e/online_serving/test_wan22_t2v.py + - tests/e2e/online_serving/test_wan22_expansion.py + + diffusion_wan22_accuracy: + - *wan22 + - tests/e2e/accuracy/wan22_i2v/ + - tests/e2e/accuracy/test_diffusers_backend_similarity.py + + diffusion_wan22_perf: + - *wan22 + - tests/dfx/perf/scripts/run_diffusion_benchmark.py + - tests/dfx/perf/tests/test_wan22_i2v_vllm_omni.json + + diffusion_wan22_reliability: + - *wan22 + - tests/dfx/reliability/test_reliability_wan22.py + + diffusion_image_to_video_doc: + - *wan22 + - *hunyuan_video + - *ltx2 + - *sana_video + - *lingbot_video + - examples/offline_inference/image_to_video/ + - tests/examples/offline_inference/test_image_to_video.py + + diffusion_cosmos3_function: + - *cosmos3 + - tests/e2e/online_serving/test_cosmos3.py + + diffusion_cosmos3_accuracy: + - *cosmos3 + - tests/e2e/accuracy/test_cosmos3_similarity.py + + diffusion_cosmos3_perf: + - *cosmos3 + - tests/dfx/perf/scripts/run_diffusion_benchmark.py + - tests/dfx/perf/tests/test_cosmos3_vllm_omni.json + + diffusion_qwen_image_function: + - *qwen_image + - tests/e2e/online_serving/test_qwen_image.py + - tests/e2e/online_serving/test_qwen_image_expansion.py + - tests/e2e/offline_inference/test_qwen_image_autoround_w4a16_expansion.py + + diffusion_qwen_image_accuracy: + - *qwen_image + - tests/e2e/accuracy/test_qwen_image.py + - tests/e2e/accuracy/test_diffusers_backend_similarity.py + + diffusion_qwen_image_perf: + - *qwen_image + - tests/dfx/perf/scripts/run_diffusion_benchmark.py + - tests/dfx/perf/tests/test_qwen_image_vllm_omni.json + + diffusion_text_to_image_doc: + - *qwen_image + - *z_image + - examples/offline_inference/text_to_image/ + - examples/online_serving/text_to_image/ + - tests/examples/offline_inference/test_text_to_image.py + - tests/examples/online_serving/test_text_to_image.py + - vllm_omni/diffusion/models/nextstep_1_1/ + - vllm_omni/diffusion/models/longcat_image/ + - vllm_omni/diffusion/models/ovis_image/ + - vllm_omni/diffusion/models/omnigen2/ + - vllm_omni/diffusion/models/sd3/ + - vllm_omni/diffusion/models/flux/ + - vllm_omni/diffusion/models/flux2/ + - vllm_omni/diffusion/models/flux2_klein/ + - vllm_omni/diffusion/models/hidream_image/ + - vllm_omni/diffusion/models/krea2/ + - vllm_omni/diffusion/models/lingbot_video/ + + diffusion_hunyuan_image3_function: + - *hunyuan_image3 + - tests/e2e/offline_inference/test_hunyuanimage3_i2t_expansion.py + + diffusion_hunyuan_image3_accuracy: + - *hunyuan_image3 + - tests/e2e/accuracy/test_hunyuan_image3_pixel_accuracy.py + + diffusion_hunyuan_image3_perf: + - *hunyuan_image3 + - tests/dfx/perf/scripts/run_diffusion_benchmark.py + - tests/dfx/perf/tests/test_hunyuan_image_tp2_cfgp2.json + - tests/dfx/perf/tests/test_hunyuan_image_tp2_sp2.json + - tests/dfx/perf/tests/test_hunyuan_image_tp4.json + + diffusion_hunyuan_image3_reliability: + - *hunyuan_image3 + - tests/dfx/reliability/test_reliability_hunyuan_image.py + + diffusion_minimax_h3_function: + - *minimax_h3 + - tests/e2e/online_serving/test_minimax_h3_dlo_dp2_t2va.py + - tests/e2e/online_serving/minimax_h3/ + - tests/diffusion/models/minimax_h3/ + - vllm_omni/diffusion/lora/ + - vllm_omni/diffusion/offloader/ + - vllm_omni/diffusion/distributed/ + - vllm_omni/entrypoints/openai/ + + diffusion_minimax_h3_accuracy: + - *minimax_h3 + - tests/e2e/accuracy/minimax_h3/ + + diffusion_minimax_h3_perf: + - *minimax_h3 + - tests/dfx/perf/scripts/run_diffusion_benchmark.py + - tests/dfx/perf/tests/test_minimax_h3_vllm_omni.json + + diffusion_hunyuan_video_function: + - *hunyuan_video + - tests/e2e/online_serving/test_hunyuan_video_15_expansion.py + + diffusion_hunyuan_video_accuracy: + - *hunyuan_video + - tests/e2e/accuracy/hunyuanvideo15_t2v/ + - tests/e2e/accuracy/hunyuanvideo15_i2v/ + + diffusion_hunyuan_video_perf: + - *hunyuan_video + - tests/dfx/perf/scripts/run_diffusion_benchmark.py + - tests/dfx/perf/tests/test_hunyuanvideo15_t2v_vllm_omni.json + - tests/dfx/perf/tests/test_hunyuanvideo15_i2v_vllm_omni.json + + diffusion_z_image_function: + - *z_image + - tests/e2e/online_serving/test_z_image.py + - tests/e2e/online_serving/test_zimage_expansion.py + + diffusion_sana_video_function: + - *sana_video + - tests/e2e/online_serving/test_sana_video_expansion.py + - tests/e2e/accuracy/sana_video/ + + diffusion_stable_audio_function: + - *stable_audio + - tests/e2e/offline_inference/test_stable_audio_expansion.py + - tests/e2e/online_serving/test_stable_audio_online_expansion.py + + diffusion_lingbot_function: + - *lingbot_video + - *lingbot_world + - tests/e2e/online_serving/test_lingbot_video.py + - tests/e2e/online_serving/test_lingbot_video_moe.py + - tests/e2e/offline_inference/test_lingbot_world_v2.py + + + # Invalid-param jobs: model business code only, plus the reliability scripts. + reliability_invalid_param_h100: + - *qwen3_omni + - *minicpmo_4_5 + - *qwen_image + - *wan22 + - tests/dfx/reliability/invalid_param_test/ + + reliability_invalid_param_l4: + - *qwen3_tts + - *stable_audio + - tests/dfx/reliability/invalid_param_test/ diff --git a/.buildkite/common/scripts/skip_ci.py b/.buildkite/common/scripts/skip_ci.py index 8d5fdd5e0..3b4168c01 100644 --- a/.buildkite/common/scripts/skip_ci.py +++ b/.buildkite/common/scripts/skip_ci.py @@ -44,6 +44,7 @@ L3_YAML_FILES: dict[str, str] = { L45_YAML_FILES: dict[str, str] = { ".buildkite/cuda/test-nightly.yml": "cuda", ".buildkite/cuda/test-weekly.yml": "cuda", + ".buildkite/amd/test-amd-nightly.yml": "amd", ".buildkite/npu/test-npu-nightly.yml": "npu", } diff --git a/.buildkite/common/scripts/upload_pipeline.py b/.buildkite/common/scripts/upload_pipeline.py index 749f35f5a..71ed75119 100644 --- a/.buildkite/common/scripts/upload_pipeline.py +++ b/.buildkite/common/scripts/upload_pipeline.py @@ -10,8 +10,17 @@ Bootstrap mode (``bootstrap-upload-steps.yml``): - Detect docs-only, pytest skip-mark-only, or combined skip-ci from git diff. - When only CI level YAML changes, enable **L2/L3** upload steps for affected levels only. -Test pipeline mode (e.g. test-merge.yml): - - Drop steps whose ``source_file_dependencies`` do not match changed files. +Test pipeline mode (e.g. test-merge.yml, test-nightly.yml, test-weekly.yml): + - Drop steps whose ``source_file_dependencies`` do not match changed files + (string/list keys from ci_source_file_dependencies.yml, or inline path + prefixes). Filtering applies on **PR label** uploads and on post-merge + ``main`` L3 uploads. Scheduled ``main`` uploads that pass ``--all`` + (NIGHTLY/WEEKLY) or ``--e2e`` keep every selected job and still strip + the field. If no job-key prefix matches, a change to the pipeline YAML + being uploaded or to a path under the ``source_filter_fallback`` registry + key keeps every job so command, env, and hardware edits can be validated + before merge. When any job-key prefix already matches, normal filtering + wins. - Expand uploader-only ``mirror_hardwares`` into ``agents`` (+ optional ``image`` for NPU) + ``plugins`` (see ci_mirror_hardwares.yml). - Omit ``mirror_hardwares`` to compose ``{chip}_{n}`` from pytest ``-m`` SKU @@ -87,6 +96,10 @@ BOOTSTRAP_UPLOAD_IF_KEYS = { } E2E_GROUP_MARKER = "E2E Test" CI_MIRROR_HARDWARES_PATH = ROOT / ".buildkite/common/ci_mirror_hardwares.yml" +CI_SOURCE_FILE_DEPENDENCIES_PATH = ROOT / ".buildkite/common/ci_source_file_dependencies.yml" +# Registry key whose prefixes bypass source filtering. Paths live in +# ci_source_file_dependencies.yml; do not attach this key to a job. +SOURCE_FILTER_FALLBACK_KEY = "source_filter_fallback" CUDA_HF_TOKEN_ENV = "VLLM_CI_HF_TOKEN" CUDA_HF_TOKEN_EXPORT = f'if [ -n "$${{{CUDA_HF_TOKEN_ENV}:-}}" ]; then export HF_TOKEN="$${{{CUDA_HF_TOKEN_ENV}}}"; fi' @@ -95,14 +108,7 @@ CUDA_HF_TOKEN_EXPORT = f'if [ -n "$${{{CUDA_HF_TOKEN_ENV}:-}}" ]; then export HF # ``*_UPLOAD_IF``: full gate for uploading that child pipeline. NIGHTLY_MAIN_IF = 'build.branch == "main" && build.env("NIGHTLY") == "1"' NIGHTLY_LABEL_IF = ( - f"({NIGHTLY_MAIN_IF}) || " - '(build.branch != "main" && (' - 'build.pull_request.labels includes "nightly-test" || ' - 'build.pull_request.labels includes "omni-test" || ' - 'build.pull_request.labels includes "tts-test" || ' - 'build.pull_request.labels includes "diffusion-x2iat-test" || ' - 'build.pull_request.labels includes "diffusion-x2v-test"' - "))" + f'({NIGHTLY_MAIN_IF}) || (build.branch != "main" && build.pull_request.labels includes "nightly-test")' ) WEEKLY_E2E_IF = 'build.branch == "main" && build.env("WEEKLY") == "1"' WEEKLY_MAIN_IF = 'build.branch == "main" && (build.env("WEEKLY") == "1" || build.env("NON_CRITICAL") == "1")' @@ -248,7 +254,7 @@ def _render_bootstrap_pipeline( return yaml.safe_dump(doc, sort_keys=False) -# --- Test pipeline (test-ready.yml, test-merge.yml) --- +# --- Test pipeline (test-ready.yml, test-merge.yml, test-nightly.yml) --- @lru_cache(maxsize=1) @@ -264,6 +270,117 @@ def _load_mirror_hardwares() -> dict[str, dict[str, Any]]: return presets +@lru_cache(maxsize=1) +def _load_source_file_dependencies() -> dict[str, list[str]]: + def flatten(value: Any, *, key: str) -> list[str]: + """Flatten YAML-anchor nested lists into a de-duplicated prefix list.""" + if isinstance(value, str): + if not value.strip(): + raise ValueError(f"empty path in source_file_dependencies[{key!r}]") + return [value] + if isinstance(value, list): + flattened: list[str] = [] + seen: set[str] = set() + for item in value: + for path in flatten(item, key=key): + if path not in seen: + seen.add(path) + flattened.append(path) + return flattened + raise ValueError( + f"source_file_dependencies[{key!r}] must be a list of path prefixes, got {type(value).__name__}", + ) + + if not CI_SOURCE_FILE_DEPENDENCIES_PATH.is_file(): + raise FileNotFoundError( + f"missing CI source_file_dependencies registry: {CI_SOURCE_FILE_DEPENDENCIES_PATH}", + ) + doc = yaml.safe_load(CI_SOURCE_FILE_DEPENDENCIES_PATH.read_text(encoding="utf-8")) + if not isinstance(doc, dict): + raise ValueError(f"invalid CI source_file_dependencies registry: {CI_SOURCE_FILE_DEPENDENCIES_PATH}") + presets = doc.get("source_file_dependencies") + if not isinstance(presets, dict): + raise ValueError(f"source_file_dependencies must be a mapping in {CI_SOURCE_FILE_DEPENDENCIES_PATH}") + loaded: dict[str, list[str]] = {} + for key, value in presets.items(): + if not isinstance(key, str) or not key.strip(): + raise ValueError( + f"source_file_dependencies keys must be non-empty strings in {CI_SOURCE_FILE_DEPENDENCIES_PATH}", + ) + loaded[key] = flatten(value, key=key) + return loaded + + +_REGISTRY_KEY_RE = re.compile(r"^[a-z][a-z0-9_]*$") + + +def _parse_command_text(step: dict[str, Any]) -> str: + """Parse step ``commands`` / ``command`` into a single string.""" + raw = step.get("commands", step.get("command")) + if raw is None: + return "" + if isinstance(raw, str): + return raw + if isinstance(raw, list): + return "\n".join(str(item) for item in raw if item is not None) + return str(raw) + + +def _resolve_source_file_dependencies(step: dict[str, Any]) -> list[str] | None: + """Expand a registry key (or list of keys / inline path prefixes).""" + deps = step.get("source_file_dependencies") + if deps is None: + return None + + def dedupe(*groups: list[str]) -> list[str]: + merged: list[str] = [] + seen: set[str] = set() + for group in groups: + for path in group: + if path not in seen: + seen.add(path) + merged.append(path) + return merged + + def lookup(key: str) -> list[str]: + if key == SOURCE_FILTER_FALLBACK_KEY: + raise ValueError( + f"source_file_dependencies {key!r} bypasses filtering and cannot be attached to a step " + f"({_get_step_label(step)!r})", + ) + registry = _load_source_file_dependencies() + paths = registry.get(key) + if paths is None: + known = ", ".join(sorted(registry)) + raise ValueError( + f"unknown source_file_dependencies {key!r} in step {_get_step_label(step)!r}; known: {known}", + ) + return list(paths) + + prefixes: list[str] + if isinstance(deps, str): + prefixes = lookup(deps) if _REGISTRY_KEY_RE.fullmatch(deps) else [deps] + elif isinstance(deps, list): + if not all(isinstance(item, str) for item in deps): + raise ValueError( + f"source_file_dependencies must be a string key or list of strings in step {_get_step_label(step)!r}", + ) + keyish = [bool(_REGISTRY_KEY_RE.fullmatch(item)) for item in deps] + if deps and all(keyish): + prefixes = dedupe(*(lookup(key) for key in deps)) + elif any(keyish): + raise ValueError( + f"source_file_dependencies in step {_get_step_label(step)!r} mixes registry keys and path prefixes", + ) + else: + prefixes = list(deps) + else: + raise ValueError( + f"source_file_dependencies must be a string key or list in step {_get_step_label(step)!r}", + ) + return prefixes + + @lru_cache(maxsize=1) def _cuda_mirror_chips() -> tuple[str, ...]: """Lowercase CUDA SKUs that have at least one ``{chip}_{n}`` preset. @@ -278,7 +395,7 @@ def _cuda_mirror_chips() -> tuple[str, ...]: return tuple(sorted(chips, key=lambda chip: (-len(chip), chip))) -def _read_cards_marks(expr: str) -> tuple[set[int], bool]: +def _parse_cards_marks(expr: str) -> tuple[set[int], bool]: """Parse registered ``cards_n`` / ``not cards_n`` from a pytest ``-m`` expr. Returns positive card counts and whether any ``not cards_*`` is present. @@ -295,8 +412,8 @@ def _read_cards_marks(expr: str) -> tuple[set[int], bool]: return positives, has_not_cards -def _read_hardware_marks(expr: str) -> set[str]: - """Return lowercase positive CUDA SKUs that have a mirror preset. +def _parse_hardware_marks(expr: str) -> set[str]: + """Parse lowercase positive CUDA SKUs that have a mirror preset. ``not H100`` is ignored. SKUs with no ``{chip}_*`` preset (e.g. H200) are dropped. """ @@ -338,36 +455,22 @@ def _get_mirror_hw_selector() -> str: return selector -def _read_pytest_marks(commands: Any) -> tuple[set[str], int | Literal["max"] | None]: - """Read pytest ``-m`` from step commands: CUDA SKU chips and cards count. +def _parse_pytest_marks(step: dict[str, Any]) -> tuple[set[str], int | Literal["max"] | None]: + """Parse pytest ``-m`` from step commands: CUDA SKU chips and cards count. *chips* are lowercase SKUs from positive markers (``not H100`` is ignored). *cards* is the max positive ``cards_n``, ``"max"`` when only ``not cards_*`` is present, or ``None``. """ - chunks: list[str] = [] - - def _collect(value: Any) -> None: - if value is None: - return - if isinstance(value, str): - chunks.append(value) - elif isinstance(value, list): - for part in value: - _collect(part) - else: - chunks.append(str(value)) - - _collect(commands) - text = "\n".join(chunks) + text = _parse_command_text(step) chips: set[str] = set() positives: set[int] = set() has_not_cards = False for match in _PYTEST_MARKER_ARG.finditer(text): expr = match.group(1) or match.group(2) or match.group(3) or "" - chips |= _read_hardware_marks(expr) - card_counts, not_cards = _read_cards_marks(expr) + chips |= _parse_hardware_marks(expr) + card_counts, not_cards = _parse_cards_marks(expr) positives.update(card_counts) has_not_cards = has_not_cards or not_cards @@ -484,7 +587,7 @@ def _expand_mirror_hardwares(step: dict[str, Any]) -> dict[str, Any] | None: if "mirror_hardwares" not in step: if has_pool: return step - chips, cards = _read_pytest_marks(step.get("commands")) + chips, cards = _parse_pytest_marks(step) if not chips and cards is None: return step preset_name = _compose_mirror_hardware_name(chips, cards, step_label=step_label) @@ -552,11 +655,7 @@ def _process_test_steps( processed.append(step) continue - deps = step.get("source_file_dependencies") - if deps is not None and not isinstance(deps, list): - raise ValueError( - f"source_file_dependencies must be a list in step {_get_step_label(step)!r}", - ) + deps = _resolve_source_file_dependencies(step) if changed_files is not None and deps is not None and not _match_source_file(changed_files, deps): _log(f"skip {_get_step_label(step)!r} (no changes under {deps})") continue @@ -595,10 +694,25 @@ def _select_e2e_group_steps(steps: list[Any]) -> list[Any]: return selected +def _any_source_dependency_match(steps: list[Any], changed_files: list[str]) -> bool: + """True when any step with ``source_file_dependencies`` matches *changed_files*.""" + for step in steps: + if not isinstance(step, dict): + continue + deps = _resolve_source_file_dependencies(step) + if deps is not None and _match_source_file(changed_files, deps): + return True + nested = step.get("steps") + if isinstance(nested, list) and _any_source_dependency_match(nested, changed_files): + return True + return False + + def _render_test_pipeline( doc: dict[str, Any], changed_files: list[str] | None, *, + pipeline_path: Path | None = None, e2e_only: bool = False, ) -> dict[str, Any]: """Filter steps by PR diff and strip uploader-only ``source_file_dependencies`` metadata.""" @@ -611,6 +725,13 @@ def _render_test_pipeline( return doc if e2e_only: steps = _select_e2e_group_steps(steps) + # Bypass is a fallback: only when no job-key prefix matched. + if changed_files is not None and pipeline_path is not None: + if not _any_source_dependency_match(steps, changed_files): + bypass = _source_filter_fallback_reason(changed_files, pipeline_path) + if bypass is not None: + _log(f"keep all jobs (no source_file_dependencies match; bypassed by {bypass})") + changed_files = None steps = _process_test_steps(steps, changed_files) return {**doc, "steps": steps} @@ -618,6 +739,60 @@ def _render_test_pipeline( # --- Entry (read file → bootstrap or test render → YAML string) --- +def _repo_relative_posix(path: Path) -> str: + resolved = path.resolve() + try: + return resolved.relative_to(ROOT).as_posix() + except ValueError: + return path.as_posix().replace("\\", "/") + + +def _source_filter_fallback_prefixes() -> list[str]: + """Shared uploader/registry prefixes from ``source_filter_fallback``. Not a job key.""" + registry = _load_source_file_dependencies() + prefixes = registry.get(SOURCE_FILTER_FALLBACK_KEY) + if not prefixes: + raise ValueError( + f"source_file_dependencies[{SOURCE_FILTER_FALLBACK_KEY!r}] must list shared uploader paths " + f"in {CI_SOURCE_FILE_DEPENDENCIES_PATH}", + ) + return prefixes + + +def _source_filter_fallback_reason(changed_files: list[str] | None, pipeline_path: Path) -> str | None: + """Return the changed path that should disable source filtering, if any.""" + if not changed_files: + return None + changed = set(changed_files) + pipeline_rel = _repo_relative_posix(pipeline_path) + if pipeline_rel in changed: + return pipeline_rel + prefixes = _source_filter_fallback_prefixes() + for path in changed_files: + if _match_source_file([path], prefixes): + return path + return None + + +def _changed_files_for_source_filter( + ctx, + *, + force_all: bool, + e2e_only: bool, +) -> list[str] | None: + """Return the diff to filter against, or None to keep every step. + + ``--all`` / ``--e2e`` disable filtering (scheduled NIGHTLY/WEEKLY full + uploads and weekly E2E sweeps). Post-merge ``main`` L3 and PR-label + uploads filter against the commit/PR diff. Pipeline YAML / + ``source_filter_fallback`` matches are applied later in + ``_render_test_pipeline`` only when no job-key prefix already matched. + """ + if force_all or e2e_only: + return None + return ctx.changed_files + + def _render_pipeline( path: Path, *, @@ -635,13 +810,18 @@ def _render_pipeline( text = path.read_text(encoding="utf-8") ctx = resolve_ci_context_from_git() - changed_files = None if force_all or e2e_only else ctx.changed_files + changed_files = _changed_files_for_source_filter(ctx, force_all=force_all, e2e_only=e2e_only) doc = yaml.safe_load(text) if not isinstance(doc, dict): raise ValueError(f"invalid pipeline YAML: {path}") - doc = _render_test_pipeline(doc, changed_files, e2e_only=e2e_only) + doc = _render_test_pipeline( + doc, + changed_files, + pipeline_path=path, + e2e_only=e2e_only, + ) return yaml.safe_dump(doc, sort_keys=False) diff --git a/.buildkite/cuda/bootstrap-upload-steps.yml b/.buildkite/cuda/bootstrap-upload-steps.yml index ab4254feb..3f5aa1cb1 100644 --- a/.buildkite/cuda/bootstrap-upload-steps.yml +++ b/.buildkite/cuda/bootstrap-upload-steps.yml @@ -22,7 +22,8 @@ steps: agents: queue: "cpu_queue_premerge" - # L3 Test — PR merge-test label (diff-aware) or main+WEEKLY=1 (--e2e, full E2E group) + # L3 Test — PR merge-test label or post-merge on main (both diff-aware); + # main+WEEKLY=1 uploads the E2E group only (--e2e). - label: "Upload Merge Pipeline" depends_on: image-build key: upload-merge-pipeline @@ -36,20 +37,30 @@ steps: agents: queue: "cpu_queue_premerge" - # L4 Test — main+NIGHTLY=1 (scheduled), or PR with specific label (e.g. add label then Rebuild) + # L4 Test — main+NIGHTLY=1 (full pipeline), or PR nightly-test label (diff-aware) - label: "Upload Nightly Pipeline" depends_on: image-build key: upload-nightly-pipeline commands: - - python3 .buildkite/common/scripts/upload_pipeline.py --upload .buildkite/cuda/test-nightly.yml + - | + EXTRA="" + if [ "${NIGHTLY:-}" = "1" ] && [ "${BUILDKITE_BRANCH}" = "main" ]; then + EXTRA="--all" + fi + python3 .buildkite/common/scripts/upload_pipeline.py --upload $$EXTRA .buildkite/cuda/test-nightly.yml agents: queue: "cpu_queue_premerge" - # L5 Test — main+WEEKLY=1 / NON_CRITICAL=1 (scheduled), or PR with weekly-test label + # L5 Test — main+WEEKLY=1 / NON_CRITICAL=1 (full pipeline), or PR weekly-test label (diff-aware) - label: "Upload Weekly Pipeline" depends_on: image-build key: upload-weekly-pipeline commands: - - python3 .buildkite/common/scripts/upload_pipeline.py --upload .buildkite/cuda/test-weekly.yml + - | + EXTRA="" + if [ "${BUILDKITE_BRANCH}" = "main" ]; then + EXTRA="--all" + fi + python3 .buildkite/common/scripts/upload_pipeline.py --upload $$EXTRA .buildkite/cuda/test-weekly.yml agents: queue: "cpu_queue_premerge" diff --git a/.buildkite/cuda/test-merge.yml b/.buildkite/cuda/test-merge.yml index 71eabf527..cf0af0d31 100644 --- a/.buildkite/cuda/test-merge.yml +++ b/.buildkite/cuda/test-merge.yml @@ -1,5 +1,6 @@ # CUDA CI L3 (`advanced_model` e2e) plus L1 CPU Simple Test (`core_model and cpu`). -# Uploaded by Upload Merge Pipeline: PR label `merge-test`, or post-merge on main. +# Uploaded by Upload Merge Pipeline: PR label `merge-test`, or post-merge on main +# (both diff-aware via source_file_dependencies). env: VLLM_WORKER_MULTIPROC_METHOD: spawn @@ -65,7 +66,9 @@ steps: # 0.26 startup regression is understood and fixed. timeout_in_minutes: 90 commands: - - pytest -s -v tests/entrypoints/ -m "advanced_model and cuda and H100" --run-level "advanced_model" + # Turn-based server VAD over /v1/realtime is deferred to RFC #7181 PR 5 + # (see the P0 thread on #7413); the test stays in the tree and runs again there. + - pytest -s -v tests/entrypoints/ -m "advanced_model and cuda and H100" --run-level "advanced_model" --deselect tests/entrypoints/openai_api/test_qwen3_omni_realtime_websocket.py::TestQwen3OmniRealtimeWebSocket::test_server_vad_multi_turn_without_client_commit mirror_hardwares: h100_2 - label: "Entrypoint Test with L4" @@ -78,21 +81,7 @@ steps: depends_on: upload-merge-pipeline steps: - label: "TTS · Qwen3-TTS CustomVoice Test" - source_file_dependencies: - - tests/e2e/features/prefill_phase/ - - vllm_omni/worker/gpu_model_runner.py - - tests/helpers/media.py - - tests/e2e/online_serving/test_qwen3_tts_customvoice.py - - tests/e2e/offline_inference/test_qwen3_tts_customvoice.py - - vllm_omni/model_executor/models/qwen3_tts/ - - vllm_omni/model_executor/models/common/qwen3_code_predictor.py - - vllm_omni/model_executor/models/common/snake_activation.py - - vllm_omni/model_executor/models/common/alias_free_activation.py - - vllm_omni/model_executor/stage_input_processors/qwen3_tts.py - - vllm_omni/deploy/qwen3_tts.yaml - - vllm_omni/entrypoints/openai/serving_speech.py - - vllm_omni/entrypoints/openai/tts_adapters/ - - vllm_omni/engine/stage_pool.py + source_file_dependencies: tts_qwen3_tts_function commands: - | timeout 40m bash -c " @@ -103,21 +92,7 @@ steps: mirror_hardwares: l4_1 - label: "TTS · Qwen3-TTS Base Test" - source_file_dependencies: - - tests/helpers/media.py - - tests/e2e/online_serving/test_qwen3_tts_base.py - - tests/e2e/offline_inference/test_qwen3_tts_base.py - - vllm_omni/model_executor/models/qwen3_tts/ - - vllm_omni/model_executor/models/common/qwen3_code_predictor.py - - vllm_omni/model_executor/models/common/snake_activation.py - - vllm_omni/model_executor/models/common/alias_free_activation.py - - vllm_omni/model_executor/stage_input_processors/qwen3_tts.py - - vllm_omni/deploy/qwen3_tts.yaml - - vllm_omni/entrypoints/openai/serving_speech.py - - vllm_omni/entrypoints/openai/tts_adapters/ - - vllm_omni/engine/stage_pool.py - - .buildkite/common/scripts/run_cov_split.sh - - pyproject.toml + source_file_dependencies: tts_qwen3_tts_cov # 40 -> 60: the coverage split runs the model twice. timeout_in_minutes: 60 commands: @@ -132,36 +107,14 @@ steps: mirror_hardwares: l4_1 - label: "Omni · Qwen3-Omni Test" - source_file_dependencies: - - tests/e2e/offline_inference/test_qwen3_omni.py - - tests/e2e/offline_inference/test_qwen3_omni_colocate_async.py - - tests/e2e/online_serving/test_qwen3_omni.py - - tests/helpers/runtime.py - - vllm_omni/entrypoints/openai/serving_chat.py - - vllm_omni/model_executor/models/qwen3_omni/ - - vllm_omni/model_executor/models/common/qwen3_code_predictor.py - - vllm_omni/model_executor/models/common/snake_activation.py - - vllm_omni/model_executor/models/qwen2_5_omni/qwen2_5_omni_thinker.py - - vllm_omni/model_executor/models/qwen3_tts/cuda_graph_decoder_wrapper.py - - vllm_omni/model_executor/stage_input_processors/qwen3_omni.py - - vllm_omni/deploy/qwen3_omni_moe.yaml - - vllm_omni/deploy/qwen3_omni_moe_thinking.yaml + source_file_dependencies: omni_qwen3_omni_function timeout_in_minutes: 50 commands: - pytest -s -v tests/e2e/offline_inference/test_qwen3_omni.py tests/e2e/online_serving/test_qwen3_omni.py tests/e2e/offline_inference/test_qwen3_omni_colocate_async.py -m 'advanced_model and cuda' --run-level 'advanced_model' mirror_hardwares: h100_2 - label: "Omni · MiniCPM-o 4.5 Test" - source_file_dependencies: - - tests/e2e/offline_inference/test_minicpmo_4_5.py - - tests/e2e/online_serving/test_minicpmo_4_5.py - - vllm_omni/transformers_utils/chat_templates/minicpmo45_native.jinja - - vllm_omni/model_executor/models/minicpmo_4_5/ - - vllm_omni/model_executor/models/step_audio2/ - - vllm_omni/model_executor/models/cosyvoice3/code2wav_core/ - - vllm_omni/model_executor/models/cosyvoice3/utils.py - - vllm_omni/model_executor/stage_input_processors/minicpmo_4_5_omni.py - - vllm_omni/deploy/minicpmo_4_5.yaml + source_file_dependencies: omni_minicpmo_4_5_function timeout_in_minutes: 50 commands: - pytest -s -v tests/e2e/offline_inference/test_minicpmo_4_5.py tests/e2e/online_serving/test_minicpmo_4_5.py -m 'advanced_model and cuda' --run-level 'advanced_model' @@ -174,48 +127,7 @@ steps: mirror_hardwares: h100_2 - label: "Omni · MiniCPM-o 4.5 Duplex Test" - source_file_dependencies: - - tests/assets/minicpmo_4_5/response_required_16k.wav - - tests/assets/minicpmo_4_5/soft_interrupt_16k.wav - - tests/e2e/online_serving/test_minicpmo_4_5_duplex.py - - tests/e2e/online_serving/test_minicpmo_4_5_duplex_expansion.py - - tests/e2e/online_serving/test_minicpmo_realtime_duplex_drivers.py - - tests/e2e/online_serving/helpers/minicpmo_realtime_duplex_scenarios.py - - tests/e2e/online_serving/run_minicpmo_realtime_duplex_multi_session.py - - tests/e2e/online_serving/run_minicpmo_realtime_duplex_server_vad.py - - tests/e2e/online_serving/run_minicpmo_realtime_duplex_soft_interrupt.py - - vllm_omni/deploy/minicpmo_4_5.yaml - - tests/e2e/online_serving/helpers/minicpmo_4_5_duplex.py - - vllm_omni/engine/duplex/ - - vllm_omni/entrypoints/duplex/ - # Public duplex client library + its unit suites: client-side - # changes must re-run the duplex e2e group. The live client probe - # (test_duplex_client_live.py, single GPU, core tier) runs in the - # ready pipeline's duplex group. - - vllm_omni/clients/ - - tests/clients/ - - vllm_omni/entrypoints/duplex_request_client.py - - vllm_omni/outputs/duplex.py - - vllm_omni/model_executor/duplex_sampling.py - - tests/engine/duplex/ - - tests/entrypoints/duplex/ - - tests/model_executor/models/minicpmo_4_5/duplex/ - # Legacy Realtime probe client + video stacking used by the e2e drivers. - - vllm_omni/experimental/fullduplex/ - - vllm_omni/model_executor/models/minicpmo_4_5/ - - vllm_omni/model_executor/models/step_audio2/ - - vllm_omni/model_executor/models/cosyvoice3/code2wav_core/ - - vllm_omni/model_executor/models/cosyvoice3/utils.py - - vllm_omni/model_executor/stage_input_processors/minicpmo_4_5_omni.py - - vllm_omni/core/sched/ - - vllm_omni/outputs/multimodal_accumulation.py - - vllm_omni/engine/stage_init_utils.py - - vllm_omni/engine/async_omni_engine.py - - vllm_omni/engine/orchestrator.py - - vllm_omni/entrypoints/cli/serve.py - - vllm_omni/entrypoints/openai/api_server.py - - vllm_omni/entrypoints/openai/duplex_capability.py - - vllm_omni/config/stage_config.py + source_file_dependencies: omni_minicpmo_4_5_duplex_function timeout_in_minutes: 50 commands: - pytest -s -v tests/e2e/online_serving/test_minicpmo_4_5_duplex.py -m 'advanced_model and cuda' --run-level 'advanced_model' @@ -234,11 +146,7 @@ steps: mirror_hardwares: h100_1 - label: "Diffusion · Qwen Image Test" - source_file_dependencies: - - tests/e2e/online_serving/test_qwen_image.py - - vllm_omni/diffusion/models/qwen_image/ - - vllm_omni/diffusion/models/dmd2/ - - vllm_omni/diffusion/distributed/autoencoders/autoencoder_kl_qwenimage.py + source_file_dependencies: diffusion_qwen_image_function commands: - | timeout 40m bash -c ' @@ -248,11 +156,7 @@ steps: mirror_hardwares: h100_1 - label: "Diffusion · Wan22 Test" - source_file_dependencies: - - tests/e2e/offline_inference/test_wan22_t2v.py - - tests/e2e/online_serving/test_wan22_t2v.py - - vllm_omni/diffusion/models/wan2_2/ - - vllm_omni/diffusion/models/dmd2/ + source_file_dependencies: diffusion_wan22_function commands: - | timeout 40m bash -c " @@ -262,9 +166,7 @@ steps: mirror_hardwares: h100_1 - label: "Diffusion · HunyuanVideo-1.5 Test" - source_file_dependencies: - - tests/e2e/online_serving/test_hunyuan_video_15_expansion.py - - vllm_omni/diffusion/models/hunyuan_video/ + source_file_dependencies: diffusion_hunyuan_video_function commands: - | timeout 40m bash -c " @@ -274,17 +176,7 @@ steps: mirror_hardwares: h100_1 - label: "Diffusion · MiniMax-H3 L3 DLO DP2 and FastH3" - source_file_dependencies: - - tests/e2e/online_serving/minimax_h3/ - - tests/helpers/assertions.py - - tests/helpers/mark.py - - tests/helpers/media.py - - tests/helpers/runtime.py - - vllm_omni/diffusion/models/minimax_h3/ - - vllm_omni/diffusion/lora/ - - vllm_omni/diffusion/offloader/ - - vllm_omni/diffusion/distributed/ - - vllm_omni/entrypoints/openai/ + source_file_dependencies: diffusion_minimax_h3_function # Keep four server lifecycles in one Buildkite job, but never in one # pytest process. DLO uses multiprocessing shared-memory queues; the # parent's resource_tracker can retain a stale /psm_* entry during diff --git a/.buildkite/cuda/test-nightly.yml b/.buildkite/cuda/test-nightly.yml index c85e9abc1..adc94f9e9 100644 --- a/.buildkite/cuda/test-nightly.yml +++ b/.buildkite/cuda/test-nightly.yml @@ -12,138 +12,145 @@ steps: - group: ":card_index_dividers: Omni Model Test" key: nightly-omni-test-group depends_on: upload-nightly-pipeline - if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test" || build.pull_request.labels includes "omni-test" + if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test" steps: - label: ":full_moon: Omni · Function Test with H100 · Single-GPU" + source_file_dependencies: + - omni_qwen3_omni_function + - omni_minicpmo_4_5_function timeout_in_minutes: 120 commands: - pytest -sv tests/e2e --run-level "full_model" -m "full_model and H100 and B200 and omni and cards_1" --ignore=tests/e2e/accuracy --ignore=tests/e2e/online_serving/test_minicpmo_4_5_duplex_expansion.py - label: ":full_moon: Omni · Function Test with H100 · 2-GPU" + source_file_dependencies: + - omni_qwen3_omni_function + - omni_minicpmo_4_5_function timeout_in_minutes: 90 commands: - pytest -sv tests/e2e --run-level "full_model" -m "full_model and H100 and B200 and omni and cards_2" --ignore=tests/e2e/accuracy --ignore=tests/e2e/online_serving/test_qwen3_omni_multi_replicas.py - label: ":full_moon: Omni · MiniCPM-o 4.5 Duplex Test" + source_file_dependencies: omni_minicpmo_4_5_duplex_function timeout_in_minutes: 50 commands: - - pytest -s -v tests/e2e/online_serving/test_minicpmo_4_5_duplex_expansion.py -m "full_model and cuda and H100 and omni and cards_1" --run-level "full_model" - mirror_hardwares: h100_1 + - pytest -s -v tests/e2e/online_serving/test_minicpmo_4_5_duplex_expansion.py -m "full_model and cuda and H100 and B200 and omni and cards_1" --run-level "full_model" - label: ":full_moon: Omni · Doc Test with L4 · 4-GPU" + source_file_dependencies: omni_qwen2_5_omni_doc timeout_in_minutes: 90 commands: - export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1" - - pytest -s -v tests/examples/ -m "full_model and omni and L4 and cards_4" --run-level "full_model" - mirror_hardwares: l4_4 + - pytest -s -v tests/examples/ -m "full_model and omni and L4 and B200 and cards_4" --run-level "full_model" - label: ":full_moon: Omni · Doc Test with H100 · 2-GPU" + source_file_dependencies: omni_qwen3_omni_doc timeout_in_minutes: 90 commands: - - pytest -s -v tests/examples/ -m "full_model and omni and H100 and cards_2" --run-level "full_model" - mirror_hardwares: h100_2 + - pytest -s -v tests/examples/ -m "full_model and omni and H100 and B200 and cards_2" --run-level "full_model" - label: ":full_moon: Omni · Accuracy Test" + source_file_dependencies: omni_qwen3_omni_accuracy timeout_in_minutes: 180 commands: - export SEED_TTS_WER_EVAL=1 - export SEED_TTS_EVAL_DEVICE=cuda:1 - | set +e - pytest -s -v tests/e2e/accuracy/qwen3_omni/test_qwen3_omni.py -m "full_model" --run-level full_model + pytest -s -v tests/e2e/accuracy/qwen3_omni/test_qwen3_omni.py -m "full_model and H100 and B200 and cards_2" --run-level full_model EXIT=$$? buildkite-agent artifact upload "tests/e2e/accuracy/qwen3_omni/results/qwen_omni_acc/*.json" exit $$EXIT - mirror_hardwares: h100_2 - label: ":full_moon: Omni · MiniCPM-o 4.5 · Accuracy Test" + source_file_dependencies: omni_minicpmo_4_5_accuracy timeout_in_minutes: 180 commands: - export SEED_TTS_WER_EVAL=1 - export SEED_TTS_EVAL_DEVICE=cuda:1 - | set +e - pytest -s -v tests/e2e/accuracy/minicpmo_4_5/test_minicpmo_4_5.py -m "full_model and cuda" --run-level full_model + pytest -s -v tests/e2e/accuracy/minicpmo_4_5/test_minicpmo_4_5.py -m "full_model and H100 and B200 and cuda and (cards_1 or cards_2)" --run-level full_model EXIT=$$? buildkite-agent artifact upload "tests/e2e/accuracy/minicpmo_4_5/results/*.json" exit $$EXIT - mirror_hardwares: h100_2 - label: ":full_moon: Omni · Perf Test · No Async Chunk" + source_file_dependencies: omni_qwen3_omni_perf key: nightly-omni-performance-no-async-chunk timeout_in_minutes: 300 commands: - export BENCHMARK_DIR=tests/dfx/perf/results - | set +e - pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen3_omni_no_async_chunk.json + pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen3_omni_no_async_chunk.json -m "H100 and B200 and cards_2" EXIT=$$? buildkite-agent artifact upload "tests/dfx/perf/results/*.json" exit $$EXIT - mirror_hardwares: h100_2 - label: ":full_moon: Omni · Perf Test · Async Chunk" + source_file_dependencies: omni_qwen3_omni_perf key: nightly-omni-performance-async-chunk timeout_in_minutes: 180 commands: - export BENCHMARK_DIR=tests/dfx/perf/results - | set +e - pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen3_omni_async_chunk.json -m "H100 and full_model" + pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen3_omni_async_chunk.json -m "H100 and B200 and full_model and cards_2" EXIT=$$? buildkite-agent artifact upload "tests/dfx/perf/results/*.json" exit $$EXIT - mirror_hardwares: h100_2 - label: ":full_moon: Omni · MiniCPM-o 4.5 · Perf Test" + source_file_dependencies: omni_minicpmo_4_5_perf key: nightly-omni-performance-minicpmo-4-5 timeout_in_minutes: 180 commands: - export BENCHMARK_DIR=tests/dfx/perf/results - | set +e - pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5.json + pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5.json -m "H100 and B200 and cards_1" EXIT=$$? buildkite-agent artifact upload "tests/dfx/perf/results/*.json" exit $$EXIT - mirror_hardwares: h100_1 - label: ":full_moon: Omni · MiniCPM-o 4.5 · Duplex Seed-TTS Perf Test" + source_file_dependencies: omni_minicpmo_4_5_duplex_perf key: nightly-omni-performance-minicpmo-4-5-duplex-seed-tts timeout_in_minutes: 180 commands: - export BENCHMARK_DIR=tests/dfx/perf/results - | set +e - pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5_duplex_seed_tts.json + pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5_duplex_seed_tts.json -m "H100 and B200 and cards_1" EXIT=$$? buildkite-agent artifact upload "tests/dfx/perf/results/*.json" exit $$EXIT - mirror_hardwares: h100_1 - label: ":full_moon: Omni · Multi-Replica Startup Test with 4x H100" + source_file_dependencies: omni_qwen3_omni_function timeout_in_minutes: 45 commands: - - pytest -s -v tests/e2e/online_serving/test_qwen3_omni_multi_replicas.py -m "full_model" --run-level "core_model" - mirror_hardwares: h100_4 + - pytest -s -v tests/e2e/online_serving/test_qwen3_omni_multi_replicas.py -m "full_model and H100 and B200 and cards_4" --run-level "core_model" - group: ":card_index_dividers: TTS Model Test" key: nightly-tts-test-group depends_on: upload-nightly-pipeline - if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test" || build.pull_request.labels includes "tts-test" + if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test" steps: - label: ":full_moon: TTS · Function Test with L4" + source_file_dependencies: tts_qwen3_tts_function timeout_in_minutes: 120 commands: - export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1" - export VLLM_USE_DEEP_GEMM="0" - export VLLM_MOE_USE_DEEP_GEMM="0" - - pytest -s -v tests/e2e/ -m "full_model and L4 and tts" --run-level "full_model" --ignore=tests/e2e/accuracy - mirror_hardwares: l4_1 + - pytest -s -v tests/e2e/ -m "full_model and L4 and B200 and tts and cards_1" --run-level "full_model" --ignore=tests/e2e/accuracy - label: ":full_moon: TTS · Perf Test · Single-GPU" + source_file_dependencies: tts_qwen3_tts_perf key: nightly-tts-performance-single timeout_in_minutes: 180 commands: @@ -151,13 +158,13 @@ steps: - export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1" - | set +e - pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_tts.json -m "H100 and cards_1" + pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_tts.json -m "H100 and B200 and cards_1" EXIT=$$? buildkite-agent artifact upload "tests/dfx/perf/results/*.json" exit $$EXIT - mirror_hardwares: h100_1 - label: ":full_moon: TTS · Perf Test · 2-GPU" + source_file_dependencies: tts_qwen3_tts_perf key: nightly-tts-performance-2gpu timeout_in_minutes: 180 commands: @@ -165,11 +172,10 @@ steps: - export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1" - | set +e - pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_tts.json -m "H100 and cards_2" + pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_tts.json -m "H100 and B200 and cards_2" EXIT=$$? buildkite-agent artifact upload "tests/dfx/perf/results/*.json" exit $$EXIT - mirror_hardwares: h100_2 - group: ":card_index_dividers: Tiny Model Tests [Multi-GPU]" key: nightly-tiny-model-test-group @@ -180,6 +186,7 @@ steps: steps: - label: ":full_moon: Tiny Model Tests · Diffusion (Multi-GPU accelerations) · 2-GPU" + source_file_dependencies: diffusion_tiny_model timeout_in_minutes: 30 # NOTE: Single-GPU (core_model) tiny model tests run on the ready label, # so nightly only adds the multi-GPU parallelism configurations. @@ -189,91 +196,85 @@ steps: # for the CI, since these tests should pass irrespective of whether or not we use # the full weights or not. commands: - - pytest -sv tests/model_tests/diffusion -m 'full_model and cuda and cards_2' --run-level "core_model" - mirror_hardwares: l4_2 + - pytest -sv tests/model_tests/diffusion -m 'full_model and L4 and B200 and cuda and cards_2' --run-level "core_model" - label: ":full_moon: Tiny Model Tests · Diffusion (Multi-GPU accelerations) · 4-GPU" + source_file_dependencies: diffusion_tiny_model timeout_in_minutes: 30 # CFG+TP extra_test_groups request 2×2=4 devices (see get_required_device_count). commands: - - pytest -sv tests/model_tests/diffusion -m 'full_model and cuda and cards_4' --run-level "core_model" - mirror_hardwares: l4_4 + - pytest -sv tests/model_tests/diffusion -m 'full_model and L4 and B200 and cuda and cards_4' --run-level "core_model" - group: ":card_index_dividers: Diffusion X2I(&A&T) Model Test" key: nightly-diffusion-x2iat-group depends_on: upload-nightly-pipeline if: >- build.env("NIGHTLY") == "1" || - build.pull_request.labels includes "nightly-test" || - build.pull_request.labels includes "diffusion-x2iat-test" + build.pull_request.labels includes "nightly-test" steps: - label: ":full_moon: Diffusion X2I(&A&T) · Function Test with H100 · Single-GPU" + source_file_dependencies: diffusion_qwen_image_function timeout_in_minutes: 120 commands: - >- pytest -sv tests/e2e/online_serving/test_qwen_image_expansion.py + -m "full_model and diffusion and H100 and B200 and cards_1" + --run-level "full_model" + + - label: ":robot_face: Robot Policy OpenPI · π0.5 · H100 · Single-GPU" + timeout_in_minutes: 120 + commands: + - pip install --no-deps "openpi-client @ git+https://github.com/Physical-Intelligence/openpi.git@215abfb217dbac7d5f1273282331b9b1866c0479#subdirectory=packages/openpi-client" + - >- + pytest -sv + tests/e2e/online_serving/test_pi05_expansion.py -m "full_model and diffusion and H100 and cards_1" --run-level "full_model" mirror_hardwares: h100_1 - label: ":full_moon: Diffusion X2I(&A&T) · Function Test with H100 · 2-GPU" + source_file_dependencies: diffusion_qwen_image_function timeout_in_minutes: 120 commands: - >- pytest -sv tests/e2e/online_serving/test_qwen_image_expansion.py - -m "full_model and diffusion and H100 and cards_2" + -m "full_model and diffusion and H100 and B200 and cards_2" --run-level "full_model" - mirror_hardwares: h100_2 - - label: ":full_moon: Diffusion X2I(&A&T) · Boogu Edit CFG · 3-GPU" + - label: ":full_moon: Diffusion X2I(&A&T) · Function Test with L4 · Single-GPU" + source_file_dependencies: diffusion_qwen_image_function timeout_in_minutes: 120 commands: - - >- - pytest -sv - tests/e2e/online_serving/test_boogu_image_edit_expansion.py - -k "test_double_guidance_cfg_parallel and cfg_parallel_3_full" - -m "slow and diffusion and cuda and H100 and cards_3" - --run-level "full_model" - mirror_hardwares: h100_3 + - pytest -sv tests/e2e/offline_inference/test_qwen_image_autoround_w4a16_expansion.py -m "full_model and diffusion and L4 and B200 and cards_1" --run-level "full_model" - - label: ":full_moon: Diffusion X2I(&A&T) · Function Test with L4 · 4-GPU" - timeout_in_minutes: 120 - commands: - - pytest -sv tests/e2e/ -k "not test_wan and not hunyuan" -m "full_model and diffusion and L4 and cards_4" --run-level "full_model" --ignore=tests/e2e/accuracy - mirror_hardwares: l4_4 - label: ":full_moon: Diffusion X2I(&A&T) · Doc Test" + source_file_dependencies: diffusion_text_to_image_doc timeout_in_minutes: 60 commands: - - pytest -s -v tests/examples/*/test_text_to_image.py -m "full_model and example and H100" --run-level "full_model" - mirror_hardwares: h100_2 + - pytest -s -v tests/examples/*/test_text_to_image.py -m "full_model and example and H100 and B200 and (cards_1 or cards_2)" --run-level "full_model" - label: ":full_moon: Diffusion X2I(&A&T) · Accuracy Test" + source_file_dependencies: diffusion_qwen_image_accuracy timeout_in_minutes: 180 commands: - export VLLM_HTTP_TIMEOUT_KEEP_ALIVE=120 - - pytest -s -v tests/e2e/accuracy/test_qwen_image.py --run-level full_model - - pytest -s -v tests/e2e/accuracy/test_diffusers_backend_similarity.py -k '2i_matches_diffusers' -m full_model --run-level full_model - mirror_hardwares: h100_1 + - pytest -s -v tests/e2e/accuracy/test_qwen_image.py -m "H100 and B200 and cards_1" --run-level full_model + - pytest -s -v tests/e2e/accuracy/test_diffusers_backend_similarity.py -k '2i_matches_diffusers' -m "full_model and H100 and B200 and cards_1" --run-level full_model - label: ":full_moon: HunyuanImage3-DIT · Accuracy Test" + source_file_dependencies: diffusion_hunyuan_image3_accuracy timeout_in_minutes: 180 commands: - export HUNYUAN_IMAGE3_MODEL="tencent/HunyuanImage-3.0-Instruct" - export HUNYUAN_IMAGE3_DEVICES="0,1,2,3" - - pytest -s -v tests/e2e/accuracy/test_hunyuan_image3_pixel_accuracy.py -m full_model --run-level full_model - mirror_hardwares: h100_4 - - - label: ":full_moon: HiDream-O1-Image · Accuracy Test" - timeout_in_minutes: 180 - commands: - - pytest -s -v tests/e2e/accuracy/test_hidream_o1_image.py -m full_model --run-level full_model - mirror_hardwares: h100_2 + - pytest -s -v tests/e2e/accuracy/test_hunyuan_image3_pixel_accuracy.py -m "full_model and H100 and B200 and cards_4" --run-level full_model - label: ":full_moon: Diffusion X2I(&A&T) · Perf Test · Qwen-Image · Single-GPU" + source_file_dependencies: diffusion_qwen_image_perf key: nightly-diffusion-x2iat-performance-qwen-image-single timeout_in_minutes: 180 commands: @@ -281,168 +282,182 @@ steps: - export CACHE_DIT_VERSION=1.5.0 - | set +e - pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen_image_vllm_omni.json -m "H100 and cards_1" + pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen_image_vllm_omni.json -m "H100 and B200 and cards_1" EXIT=$$? buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json" buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log" exit $$EXIT - mirror_hardwares: h100_1 - label: ":full_moon: Diffusion X2I(&A&T) · Perf Test · Qwen-Image · 4-GPU" + source_file_dependencies: diffusion_qwen_image_perf key: nightly-diffusion-x2iat-performance-qwen-image-4gpu timeout_in_minutes: 180 commands: - export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results - - export DIFFUSION_ATTENTION_BACKEND=FLASH_ATTN - export CACHE_DIT_VERSION=1.5.0 + # Do not pin DIFFUSION_ATTENTION_BACKEND: H100 auto-selects FLASH_ATTN; + # B200 rejects explicit FLASH_ATTN without FA4 and uses CUDNN/TRTLLM. - | set +e - pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen_image_vllm_omni.json -m "H100 and cards_4" + pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen_image_vllm_omni.json -m "H100 and B200 and cards_4" EXIT=$$? buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json" buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log" exit $$EXIT - mirror_hardwares: h100_4 - group: ":card_index_dividers: Diffusion X2V Model Test" key: nightly-diffusion-x2v-group depends_on: upload-nightly-pipeline if: >- build.env("NIGHTLY") == "1" || - build.pull_request.labels includes "nightly-test" || - build.pull_request.labels includes "diffusion-x2v-test" + build.pull_request.labels includes "nightly-test" steps: - label: ":full_moon: Diffusion X2V · Wan2.2 T2V Function Test · Single-GPU" + source_file_dependencies: diffusion_wan22_function timeout_in_minutes: 90 commands: - - pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "t2v" -m "full_model and cuda and H100 and cards_1" --run-level "full_model" - mirror_hardwares: h100_1 + - pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "t2v" -m "full_model and cuda and H100 and B200 and cards_1" --run-level "full_model" - label: ":full_moon: Diffusion X2V · Wan2.2 T2V Function Test · 2-GPU" + source_file_dependencies: diffusion_wan22_function timeout_in_minutes: 90 commands: - - pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "t2v" -m "full_model and cuda and H100 and cards_2" --run-level "full_model" - mirror_hardwares: h100_2 + - pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "t2v" -m "full_model and cuda and H100 and B200 and cards_2" --run-level "full_model" - label: ":full_moon: Diffusion X2V · Wan2.2 I2V/TI2V Function Test · Single-GPU" + source_file_dependencies: diffusion_wan22_function timeout_in_minutes: 90 commands: - - pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "i2v" -m "full_model and cuda and H100 and cards_1" --run-level "full_model" - mirror_hardwares: h100_1 + - pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "i2v" -m "full_model and cuda and H100 and B200 and cards_1" --run-level "full_model" - label: ":full_moon: Diffusion X2V · Wan2.2 I2V/TI2V Function Test · 2-GPU" + source_file_dependencies: diffusion_wan22_function timeout_in_minutes: 90 commands: - - pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "i2v" -m "full_model and cuda and H100 and cards_2" --run-level "full_model" - mirror_hardwares: h100_2 + - pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "i2v" -m "full_model and cuda and H100 and B200 and cards_2" --run-level "full_model" - label: ":full_moon: Diffusion X2V · HunyuanVideo-1.5 Function Test" + source_file_dependencies: diffusion_hunyuan_video_function timeout_in_minutes: 90 commands: - - pytest -s -v tests/e2e/online_serving/test_hunyuan_video_15_expansion.py -m "full_model and cuda" --run-level "full_model" - mirror_hardwares: h100_2 + - pytest -s -v tests/e2e/online_serving/test_hunyuan_video_15_expansion.py -m "full_model and H100 and B200 and cuda and (cards_1 or cards_2)" --run-level "full_model" - - label: ":full_moon: Diffusion X2V · MAGI-2 Preview Serving Smoke" - timeout_in_minutes: 180 + - label: ":full_moon: Diffusion X2V · LingBot Function Test" + source_file_dependencies: diffusion_lingbot_function + timeout_in_minutes: 120 commands: - - pytest -s -v tests/e2e/online_serving/test_magi2.py -m "advanced_model and diffusion and cuda and H100 and cards_4" --run-level "advanced_model" - mirror_hardwares: h100_4 + - >- + pytest -s -v + tests/e2e/online_serving/test_lingbot_video.py + tests/e2e/online_serving/test_lingbot_video_moe.py + tests/e2e/offline_inference/test_lingbot_world_v2.py + -m "full_model and diffusion and H100 and B200 and cards_1" + --run-level "full_model" - label: ":full_moon: Diffusion X2V · Doc Test" + source_file_dependencies: diffusion_image_to_video_doc timeout_in_minutes: 60 commands: - - pytest -s -v tests/examples/offline_inference/test_image_to_video.py -m "full_model and example and H100" --run-level "full_model" - mirror_hardwares: h100_1 + - pytest -s -v tests/examples/offline_inference/test_image_to_video.py -m "full_model and example and H100 and B200 and cards_1" --run-level "full_model" - - label: ":full_moon: Diffusion X2V · Other Function Test" + - label: ":full_moon: Diffusion X2V · Wan2.2 Autoround Function Test" + source_file_dependencies: diffusion_wan22_function timeout_in_minutes: 90 commands: - - pytest -s -v tests/e2e/offline_inference/test_wan22_autoround_w4a16_expansion.py -m "full_model and cuda" --run-level "full_model" - mirror_hardwares: h100_2 + - pytest -s -v tests/e2e/offline_inference/test_wan22_autoround_w4a16_expansion.py -m "full_model and H100 and B200 and cuda and (cards_1 or cards_2)" --run-level "full_model" + + - label: ":full_moon: Diffusion X2V · Wan2.2 Device-Postprocess Equivalence Test" + source_file_dependencies: diffusion_wan22_function + timeout_in_minutes: 90 + commands: + - | + VLLM_OMNI_DEVICE_POSTPROCESS_MODEL=Wan-AI/Wan2.2-TI2V-5B-Diffusers \ + pytest -s -v tests/e2e/offline_inference/test_device_postprocess_equivalence.py -m "full_model and H100 and B200 and cuda and cards_1" --run-level "full_model" - label: ":full_moon: Diffusion X2V · Wan2.2 Accuracy Test" + source_file_dependencies: diffusion_wan22_accuracy timeout_in_minutes: 180 commands: - - pytest -s -v tests/e2e/accuracy/wan22_i2v/test_wan22_i2v_video_similarity.py -m full_model --run-level full_model - - pytest -s -v tests/e2e/accuracy/test_diffusers_backend_similarity.py -k '2v_matches_diffusers' -m full_model --run-level full_model - mirror_hardwares: h100_2 + - pytest -s -v tests/e2e/accuracy/wan22_i2v/test_wan22_i2v_video_similarity.py -m "full_model and H100 and B200 and (cards_1 or cards_2)" --run-level full_model + - pytest -s -v tests/e2e/accuracy/test_diffusers_backend_similarity.py -k '2v_matches_diffusers' -m "full_model and H100 and B200 and cards_1" --run-level full_model - label: ":full_moon: Diffusion X2V · MiniMax H3 I2VA/Ref2VA Accuracy Test" + source_file_dependencies: diffusion_minimax_h3_accuracy timeout_in_minutes: 180 commands: - - pytest -s -v tests/e2e/accuracy/minimax_h3/test_minimax_h3_i2va_ref2va_similarity.py -m full_model --run-level full_model - mirror_hardwares: h100_4 + - pytest -s -v tests/e2e/accuracy/minimax_h3/test_minimax_h3_i2va_ref2va_similarity.py -m "full_model and H100 and B200 and cards_4" --run-level full_model - - label: ":full_moon: Diffusion X2V · Other Accuracy Test" + - label: ":full_moon: Diffusion X2V · HunyuanVideo-1.5 Accuracy Test" + source_file_dependencies: diffusion_hunyuan_video_accuracy timeout_in_minutes: 180 commands: - - pytest -s -v tests/e2e/accuracy/hunyuanvideo15_t2v/test_hunyuanvideo15_t2v_video_similarity.py -m full_model --run-level full_model - - pytest -s -v tests/e2e/accuracy/hunyuanvideo15_i2v/test_hunyuanvideo15_i2v_video_similarity.py -m full_model --run-level full_model - mirror_hardwares: h100_2 + - pytest -s -v tests/e2e/accuracy/hunyuanvideo15_t2v/test_hunyuanvideo15_t2v_video_similarity.py -m "full_model and H100 and B200 and (cards_1 or cards_2)" --run-level full_model + - pytest -s -v tests/e2e/accuracy/hunyuanvideo15_i2v/test_hunyuanvideo15_i2v_video_similarity.py -m "full_model and H100 and B200 and (cards_1 or cards_2)" --run-level full_model - label: ":full_moon: Diffusion X2V · Perf Test · Single-GPU" + source_file_dependencies: diffusion_wan22_perf key: nightly-diffusion-x2v-performance-single timeout_in_minutes: 180 commands: - export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results - | set +e - pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_wan22_i2v_vllm_omni.json -m "H100 and cards_1" + pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_wan22_i2v_vllm_omni.json -m "H100 and B200 and cards_1" EXIT=$$? buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json" buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log" exit $$EXIT - mirror_hardwares: h100_1 - label: ":full_moon: Diffusion X2V · Perf Test · 2-GPU" + source_file_dependencies: + - diffusion_wan22_perf + - diffusion_cosmos3_perf key: nightly-diffusion-x2v-performance-2gpu timeout_in_minutes: 180 commands: - export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results - - export DIFFUSION_ATTENTION_BACKEND=FLASH_ATTN - | set +e - pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_wan22_i2v_vllm_omni.json -m "H100 and cards_2" + pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_wan22_i2v_vllm_omni.json -m "H100 and B200 and cards_2" EXIT1=$$? - pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_cosmos3_vllm_omni.json -m "H100 and cards_2" + pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_cosmos3_vllm_omni.json -m "H100 and B200 and cards_2" EXIT2=$$? buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json" buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log" if [ $$EXIT1 -ne 0 ]; then exit $$EXIT1; fi exit $$EXIT2 - mirror_hardwares: h100_2 - label: ":full_moon: Diffusion X2V · Perf Test · HunyuanVideo-1.5" + source_file_dependencies: diffusion_hunyuan_video_perf key: nightly-diffusion-x2v-performance-hunyuanvideo15 timeout_in_minutes: 180 commands: - export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results - | set +e - pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_hunyuanvideo15_t2v_vllm_omni.json + pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_hunyuanvideo15_t2v_vllm_omni.json -m "H100 and B200 and (cards_1 or cards_2)" EXIT1=$$? - pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_hunyuanvideo15_i2v_vllm_omni.json + pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_hunyuanvideo15_i2v_vllm_omni.json -m "H100 and B200 and (cards_1 or cards_2)" EXIT2=$$? buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json" buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log" if [ $$EXIT1 -ne 0 ]; then exit $$EXIT1; fi exit $$EXIT2 - mirror_hardwares: h100_2 - label: ":full_moon: Diffusion X2V · Perf Test · MiniMax-H3" + source_file_dependencies: diffusion_minimax_h3_perf key: nightly-diffusion-x2v-performance-minimax-h3 timeout_in_minutes: 180 commands: - export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results - | set +e - pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_minimax_h3_vllm_omni.json + pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_minimax_h3_vllm_omni.json -m "H100 and B200 and cards_4" EXIT=$$? buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json" buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log" exit $$EXIT - mirror_hardwares: h100_4 - group: ":card_index_dividers: Diffusion Test" key: nightly-diffusion-test-group @@ -450,59 +465,59 @@ steps: if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test" steps: - label: ":full_moon: Diffusion · Distributed Test with L4 · 2-GPU" + source_file_dependencies: diffusion_distributed_attention timeout_in_minutes: 60 commands: - - pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and L4 and cards_2' --run-level "full_model" - mirror_hardwares: l4_2 + - pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and L4 and B200 and cards_2' --run-level "full_model" - label: ":full_moon: Diffusion · Distributed Test with L4 · 3-GPU" + source_file_dependencies: diffusion_distributed_attention timeout_in_minutes: 60 commands: - - pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and L4 and cards_3' --run-level "full_model" - mirror_hardwares: l4_3 + - pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and L4 and B200 and cards_3' --run-level "full_model" - label: ":full_moon: Diffusion · Distributed Test with L4 · 4-GPU" + source_file_dependencies: diffusion_distributed_attention timeout_in_minutes: 60 commands: - - pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and L4 and cards_4' --run-level "full_model" - mirror_hardwares: l4_4 + - pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and L4 and B200 and cards_4' --run-level "full_model" - label: ":full_moon: Diffusion · Distributed Test with H100 · 2-GPU" + source_file_dependencies: diffusion_distributed_attention timeout_in_minutes: 60 commands: - - pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and H100 and cards_2' --run-level "full_model" - mirror_hardwares: h100_2 + - pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and H100 and B200 and cards_2' --run-level "full_model" - label: ":full_moon: Diffusion · Distributed Test with H100 · 4-GPU" + source_file_dependencies: diffusion_distributed_attention timeout_in_minutes: 60 commands: - - pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and H100 and cards_4' --run-level "full_model" - mirror_hardwares: h100_4 + - pytest -sv tests/diffusion/distributed/ -m 'full_model and cuda and H100 and B200 and cards_4' --run-level "full_model" - label: ":full_moon: Diffusion · Offloader Test" + source_file_dependencies: diffusion_offloader timeout_in_minutes: 60 commands: - - pytest -sv tests/diffusion/offloader -m "full_model and cuda" - mirror_hardwares: l4_1 + - pytest -sv tests/diffusion/offloader -m "full_model and L4 and B200 and cuda and cards_1" - label: ":full_moon: Diffusion · Quantization Test with H100 · Single-GPU" + source_file_dependencies: diffusion_quantization timeout_in_minutes: 60 commands: - - pytest -sv tests/diffusion/quantization -m 'full_model and cuda and H100' --run-level "full_model" - mirror_hardwares: h100_1 + - pytest -sv tests/diffusion/quantization -m 'full_model and cuda and H100 and B200 and cards_1' --run-level "full_model" - label: ":full_moon: Diffusion · MiniMax H3 FP8 Quality Test with H100 · 2-GPU" + source_file_dependencies: diffusion_minimax_h3_function timeout_in_minutes: 60 commands: - - pytest -sv tests/diffusion/models/minimax_h3/test_minimax_h3_quantization_quality.py -m 'full_model and cuda and H100' --run-level "full_model" - mirror_hardwares: h100_2 + - pytest -sv tests/diffusion/models/minimax_h3/test_minimax_h3_quantization_quality.py -m 'full_model and cuda and H100 and B200 and cards_2' --run-level "full_model" - label: ":full_moon: Diffusion · Quantization Test with L4" + source_file_dependencies: diffusion_quantization timeout_in_minutes: 60 commands: - pip install "vllm-gguf-plugin==0.0.4" - - pytest -sv tests/diffusion/quantization -m 'full_model and cuda and L4' --run-level "full_model" - mirror_hardwares: l4_1 + - pytest -sv tests/diffusion/quantization -m 'full_model and cuda and L4 and B200 and cards_1' --run-level "full_model" # NOTE: ":email: Nightly Collection & Email" is deprecated and will be removed soon. # Do not add new depends_on entries or extend this step. diff --git a/.buildkite/cuda/test-ready.yml b/.buildkite/cuda/test-ready.yml index b5fc335e7..1f07b0721 100644 --- a/.buildkite/cuda/test-ready.yml +++ b/.buildkite/cuda/test-ready.yml @@ -38,6 +38,12 @@ steps: depends_on: upload-ready-pipeline steps: + - label: "Diffusion · FlashAttention Test" + timeout_in_minutes: 20 + commands: + - timeout 15m pytest -s -v tests/diffusion/attention/ -m 'core_model and cuda and L4 and cards_1' --run-level "core_model" + mirror_hardwares: l4_1 + - label: "Diffusion · Offloader Test" commands: - timeout 40m pytest -s -v tests/diffusion/offloader -m "core_model and cuda" --run-level "core_model" @@ -54,16 +60,19 @@ steps: mirror_hardwares: l4_1 - label: "Diffusion · Distributed Test · Single-GPU" + source_file_dependencies: diffusion_distributed_attention commands: - timeout 20m pytest -sv tests/diffusion/distributed -m 'core_model and cuda and L4 and cards_1' --run-level "core_model" mirror_hardwares: l4_1 - label: "Diffusion · Distributed Test · 2-GPU" + source_file_dependencies: diffusion_distributed_attention commands: - timeout 20m pytest -sv tests/diffusion/distributed -m 'core_model and cuda and L4 and cards_2' --run-level "core_model" mirror_hardwares: l4_2 - label: "Diffusion · Distributed & Attention Test · 4-GPU" + source_file_dependencies: diffusion_distributed_attention commands: - timeout 20m pytest -sv tests/diffusion/distributed -m 'core_model and cuda and L4 and cards_4' --run-level "core_model" - timeout 20m pytest -sv tests/diffusion/attention/test_attention_sp.py -m 'core_model and cuda and L4 and cards_4' --run-level "core_model" @@ -93,7 +102,7 @@ steps: commands: - | timeout 15m bash -c " - pytest -sv tests/engine/ tests/model_executor/ tests/worker/test_batched_omni_output.py -m 'core_model and cuda' --run-level 'core_model' + pytest -sv tests/engine/ tests/model_executor/ tests/worker/test_batched_omni_output.py tests/worker_v2/ -m 'core_model and cuda' --run-level 'core_model' " mirror_hardwares: l4_1 @@ -120,29 +129,14 @@ steps: depends_on: upload-ready-pipeline steps: - label: "Custom Pipeline Test" - source_file_dependencies: - - tests/e2e/features/custom_pipeline/ - - tests/e2e/features/helpers/custom_pipeline.py - - vllm_omni/diffusion/ - - vllm_omni/engine/ - - vllm_omni/entrypoints/ - - vllm_omni/inputs/ - - vllm_omni/outputs/ + source_file_dependencies: custom_pipeline commands: - timeout 20m pytest -s -v tests/e2e/features/custom_pipeline/ -m "core_model" mirror_hardwares: l4_1 - label: "RLHF · VeRL-Omni E2E Test" - source_file_dependencies: - - tests/e2e/features/rlhf_test/test_verl_omni_e2e.py - - tests/e2e/features/helpers/verl_omni_server.py - - tests/e2e/features/helpers/custom_pipeline.py - - vllm_omni/diffusion/ - - vllm_omni/engine/ - - vllm_omni/entrypoints/ - - vllm_omni/inputs/ - - vllm_omni/outputs/ + source_file_dependencies: rlhf_verl_omni commands: - | timeout 20m bash -c " @@ -151,17 +145,7 @@ steps: mirror_hardwares: l4_1 - label: "Omni · Qwen3-Omni Test" - source_file_dependencies: - - tests/e2e/online_serving/test_qwen3_omni.py - - tests/helpers/runtime.py - - vllm_omni/entrypoints/openai/serving_chat.py - - vllm_omni/model_executor/models/qwen3_omni/ - - vllm_omni/model_executor/models/common/qwen3_code_predictor.py - - vllm_omni/model_executor/models/common/snake_activation.py - - vllm_omni/model_executor/models/qwen2_5_omni/qwen2_5_omni_thinker.py - - vllm_omni/model_executor/models/qwen3_tts/cuda_graph_decoder_wrapper.py - - vllm_omni/model_executor/stage_input_processors/qwen3_omni.py - - vllm_omni/deploy/qwen3_omni_moe.yaml + source_file_dependencies: omni_qwen3_omni_function commands: - | timeout 20m bash -c " @@ -170,14 +154,7 @@ steps: mirror_hardwares: h100_2 - label: "Omni · MiniCPM-o 4.5 Offline Test" - source_file_dependencies: - - tests/e2e/offline_inference/test_minicpmo_4_5.py - - vllm_omni/model_executor/models/minicpmo_4_5/ - - vllm_omni/model_executor/models/step_audio2/ - - vllm_omni/model_executor/models/cosyvoice3/code2wav_core/ - - vllm_omni/model_executor/models/cosyvoice3/utils.py - - vllm_omni/model_executor/stage_input_processors/minicpmo_4_5_omni.py - - vllm_omni/deploy/minicpmo_4_5.yaml + source_file_dependencies: omni_minicpmo_4_5_function commands: - | timeout 20m bash -c " @@ -186,15 +163,7 @@ steps: mirror_hardwares: h100_1 - label: "Omni · MiniCPM-o 4.5 Online Test" - source_file_dependencies: - - tests/e2e/online_serving/test_minicpmo_4_5.py - - vllm_omni/transformers_utils/chat_templates/minicpmo45_native.jinja - - vllm_omni/model_executor/models/minicpmo_4_5/ - - vllm_omni/model_executor/models/step_audio2/ - - vllm_omni/model_executor/models/cosyvoice3/code2wav_core/ - - vllm_omni/model_executor/models/cosyvoice3/utils.py - - vllm_omni/model_executor/stage_input_processors/minicpmo_4_5_omni.py - - vllm_omni/deploy/minicpmo_4_5.yaml + source_file_dependencies: omni_minicpmo_4_5_function commands: - | timeout 20m bash -c " @@ -203,48 +172,7 @@ steps: mirror_hardwares: h100_1 - label: "Omni · MiniCPM-o 4.5 Duplex Test" - source_file_dependencies: - - tests/assets/minicpmo_4_5/response_required_16k.wav - - tests/assets/minicpmo_4_5/soft_interrupt_16k.wav - - tests/e2e/online_serving/test_minicpmo_4_5_duplex.py - - tests/e2e/online_serving/test_minicpmo_4_5_duplex_expansion.py - - tests/e2e/online_serving/test_minicpmo_realtime_duplex_drivers.py - - tests/e2e/online_serving/helpers/minicpmo_realtime_duplex_scenarios.py - - tests/e2e/online_serving/run_minicpmo_realtime_duplex_multi_session.py - - tests/e2e/online_serving/run_minicpmo_realtime_duplex_server_vad.py - - tests/e2e/online_serving/run_minicpmo_realtime_duplex_soft_interrupt.py - - vllm_omni/deploy/minicpmo_4_5.yaml - - tests/e2e/online_serving/helpers/minicpmo_4_5_duplex.py - - vllm_omni/engine/duplex/ - - vllm_omni/entrypoints/duplex/ - # Public duplex client library + its unit suites: client-side - # changes must re-run the duplex e2e group, which includes the - # live client probe (test_duplex_client_live.py, single GPU). - - vllm_omni/clients/ - - tests/clients/ - - tests/e2e/online_serving/test_duplex_client_live.py - - vllm_omni/entrypoints/duplex_request_client.py - - vllm_omni/outputs/duplex.py - - vllm_omni/model_executor/duplex_sampling.py - - tests/engine/duplex/ - - tests/entrypoints/duplex/ - - tests/model_executor/models/minicpmo_4_5/duplex/ - # Legacy Realtime probe client + video stacking used by the e2e drivers. - - vllm_omni/experimental/fullduplex/ - - vllm_omni/model_executor/models/minicpmo_4_5/ - - vllm_omni/model_executor/models/step_audio2/ - - vllm_omni/model_executor/models/cosyvoice3/code2wav_core/ - - vllm_omni/model_executor/models/cosyvoice3/utils.py - - vllm_omni/model_executor/stage_input_processors/minicpmo_4_5_omni.py - - vllm_omni/core/sched/ - - vllm_omni/outputs/multimodal_accumulation.py - - vllm_omni/engine/stage_init_utils.py - - vllm_omni/engine/async_omni_engine.py - - vllm_omni/engine/orchestrator.py - - vllm_omni/entrypoints/cli/serve.py - - vllm_omni/entrypoints/openai/api_server.py - - vllm_omni/entrypoints/openai/duplex_capability.py - - vllm_omni/config/stage_config.py + source_file_dependencies: omni_minicpmo_4_5_duplex_function commands: - | timeout 35m bash -c " @@ -254,29 +182,14 @@ steps: - label: "Omni · MiniCPM-o 4.5 Perf Test" timeout_in_minutes: 60 - source_file_dependencies: - - tests/dfx/perf/tests/test_minicpmo_4_5_ready.json - - vllm_omni/deploy/minicpmo_4_5.yaml - - vllm_omni/model_executor/models/minicpmo_4_5/ - - vllm_omni/model_executor/stage_input_processors/minicpmo_4_5_omni.py + source_file_dependencies: omni_minicpmo_4_5_perf commands: - export BENCHMARK_DIR=tests/dfx/perf/results - pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5_ready.json -m 'core_model and cuda' mirror_hardwares: h100_1 - label: "TTS · Qwen3-TTS CustomVoice Test" - source_file_dependencies: - - tests/helpers/media.py - - tests/e2e/online_serving/test_qwen3_tts_customvoice.py - - vllm_omni/model_executor/models/qwen3_tts/ - - vllm_omni/model_executor/models/common/qwen3_code_predictor.py - - vllm_omni/model_executor/models/common/snake_activation.py - - vllm_omni/model_executor/models/common/alias_free_activation.py - - vllm_omni/model_executor/stage_input_processors/qwen3_tts.py - - vllm_omni/deploy/qwen3_tts.yaml - - vllm_omni/entrypoints/openai/serving_speech.py - - vllm_omni/entrypoints/openai/tts_adapters/ - - vllm_omni/engine/stage_pool.py + source_file_dependencies: tts_qwen3_tts_function commands: - | timeout 20m bash -c " @@ -286,10 +199,7 @@ steps: mirror_hardwares: l4_1 - label: "Diffusion · Wan22 Test" - source_file_dependencies: - - tests/e2e/online_serving/test_wan22_t2v.py - - vllm_omni/diffusion/models/wan2_2/ - - vllm_omni/diffusion/models/dmd2/ + source_file_dependencies: diffusion_wan22_function commands: - | timeout 40m bash -c " @@ -299,12 +209,7 @@ steps: mirror_hardwares: h100_1 - label: "Diffusion · Cosmos3 Test" - source_file_dependencies: - - tests/e2e/online_serving/test_cosmos3.py - - vllm_omni/diffusion/models/cosmos3/ - - vllm_omni/diffusion/distributed/autoencoders/autoencoder_kl_wan.py - - vllm_omni/experimental/world_models/ - - vllm_omni/model_extras/cosmos3.py + source_file_dependencies: diffusion_cosmos3_function commands: - | timeout 40m bash -c " @@ -315,14 +220,7 @@ steps: - label: "Diffusion · MiniMax-H3 DLO DP2 T2VA Test" timeout_in_minutes: 90 - source_file_dependencies: - - tests/e2e/online_serving/test_minimax_h3_dlo_dp2_t2va.py - - tests/helpers/assertions.py - - tests/helpers/runtime.py - - vllm_omni/diffusion/models/minimax_h3/ - - vllm_omni/diffusion/offloader/ - - vllm_omni/diffusion/distributed/ - - vllm_omni/entrypoints/openai/ + source_file_dependencies: diffusion_minimax_h3_function commands: - | timeout 80m bash -c " @@ -344,11 +242,7 @@ steps: mirror_hardwares: h100_1 - label: "Diffusion · Qwen Image Test" - source_file_dependencies: - - tests/e2e/online_serving/test_qwen_image.py - - vllm_omni/diffusion/models/qwen_image/ - - vllm_omni/diffusion/models/dmd2/ - - vllm_omni/diffusion/distributed/autoencoders/autoencoder_kl_qwenimage.py + source_file_dependencies: diffusion_qwen_image_function commands: - | timeout 40m bash -c " @@ -358,9 +252,7 @@ steps: mirror_hardwares: h100_1 - label: "Diffusion · HunyuanVideo-1.5 Test" - source_file_dependencies: - - tests/e2e/online_serving/test_hunyuan_video_15_expansion.py - - vllm_omni/diffusion/models/hunyuan_video/ + source_file_dependencies: diffusion_hunyuan_video_function commands: - | timeout 40m bash -c " diff --git a/.buildkite/cuda/test-weekly.yml b/.buildkite/cuda/test-weekly.yml index 614af9572..70ab59356 100644 --- a/.buildkite/cuda/test-weekly.yml +++ b/.buildkite/cuda/test-weekly.yml @@ -29,36 +29,42 @@ steps: steps: - label: "Reliability Test · qwen3-omni" + source_file_dependencies: omni_qwen3_omni_reliability timeout_in_minutes: 180 commands: - pytest -s -v tests/dfx/reliability/test_reliability_qwen3_omni.py -m "slow" mirror_hardwares: h100_2 - label: "Reliability Test · wan22" + source_file_dependencies: diffusion_wan22_reliability timeout_in_minutes: 180 commands: - pytest -s -v tests/dfx/reliability/test_reliability_wan22.py -m "slow" mirror_hardwares: h100_2 - label: "Reliability Test · hunyuan-image" + source_file_dependencies: diffusion_hunyuan_image3_reliability timeout_in_minutes: 180 commands: - pytest -s -v tests/dfx/reliability/test_reliability_hunyuan_image.py -m "slow" mirror_hardwares: h100_4 - label: "Reliability Test · Invalid parameters · H100 · Single-GPU" + source_file_dependencies: reliability_invalid_param_h100 timeout_in_minutes: 90 commands: - pytest -s -v tests/dfx/reliability/invalid_param_test/ -m "slow and H100 and cards_1" mirror_hardwares: h100_1 - label: "Reliability Test · Invalid parameters · H100 · 2-GPU" + source_file_dependencies: reliability_invalid_param_h100 timeout_in_minutes: 90 commands: - pytest -s -v tests/dfx/reliability/invalid_param_test/ -m "slow and H100 and cards_2" mirror_hardwares: h100_2 - label: "Reliability Test · Invalid parameters · L4" + source_file_dependencies: reliability_invalid_param_l4 timeout_in_minutes: 120 commands: - pytest -s -v tests/dfx/reliability/invalid_param_test/ -m "slow and L4" @@ -70,6 +76,7 @@ steps: steps: - label: ":full_moon: Omni · Perf Test · vLLM Text" + source_file_dependencies: omni_qwen3_omni_perf key: weekly-omni-performance-vllm-text timeout_in_minutes: 180 commands: @@ -96,6 +103,7 @@ steps: mirror_hardwares: h100_2 - label: ":full_moon: Omni · Perf Test · Multi-Replica" + source_file_dependencies: omni_qwen3_omni_perf key: weekly-omni-performance-multi-replicas timeout_in_minutes: 180 commands: @@ -183,13 +191,14 @@ steps: # from downgrading transformers; see # examples/offline_inference/text_to_speech/README.md. - label: "TTS · Gepard-1.0 · L4" - timeout_in_minutes: 60 + timeout_in_minutes: 90 commands: - export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1" - printf '%s\n' "transformers>=5.5.3" "huggingface-hub>=1.0" > /tmp/gepard-overrides.txt - uv pip install --python "$(python3 -c 'import sys; print(sys.executable)')" "nemo_toolkit[tts]==2.7.3" --overrides /tmp/gepard-overrides.txt - >- pytest -s -v tests/e2e/offline_inference/test_gepard_tts.py + tests/e2e/online_serving/test_gepard_tts.py -m "tts and cuda" --run-level "full_model" mirror_hardwares: l4_1 @@ -221,24 +230,277 @@ steps: --run-level "full_model" mirror_hardwares: l4_4 - - label: "Diffusion · H100 · Single-GPU" - timeout_in_minutes: 150 + # Split the old shared H100 Single-GPU sweep: one pytest process collected + # every slow+cards_1 diffusion file and exceeded 150 minutes. + - label: "Diffusion · Qwen-Image · H100 · Single-GPU" + timeout_in_minutes: 120 commands: - >- pytest -sv - tests/e2e/ -m "slow and diffusion and H100 and cards_1" + tests/e2e/online_serving/test_qwen_image_edit.py + tests/e2e/online_serving/test_qwen_image_edit_expansion.py + tests/e2e/online_serving/test_qwen_image_layered.py + tests/e2e/online_serving/test_qwen_image_layered_expansion.py + tests/e2e/accuracy/test_qwen_image_edit.py + tests/e2e/accuracy/test_qwen_image_layered.py + -m "slow and diffusion and H100 and cards_1" --run-level "full_model" mirror_hardwares: h100_1 - - label: "Diffusion · H100 · 2-GPU" + - label: "Diffusion · Wan2.1 VACE · H100 · Single-GPU" timeout_in_minutes: 90 commands: - >- pytest -sv - tests/e2e/ -m "slow and diffusion and H100 and cards_2" + tests/e2e/online_serving/test_wan_2_1_vace_expansion.py + -m "slow and diffusion and H100 and cards_1" + --run-level "full_model" + mirror_hardwares: h100_1 + + - label: "Diffusion · LongCat · H100 · Single-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/online_serving/test_longcat_image_expansion.py + tests/e2e/online_serving/test_longcat_image_edit_expansion.py + -m "slow and diffusion and H100 and cards_1" + --run-level "full_model" + mirror_hardwares: h100_1 + + - label: "Diffusion · Bagel · H100 · Single-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/online_serving/test_bagel.py + tests/e2e/online_serving/test_bagel_expansion.py + tests/e2e/offline_inference/test_bagel.py + tests/e2e/offline_inference/test_bagel_expansion.py + -m "slow and diffusion and H100 and cards_1" + --run-level "full_model" + mirror_hardwares: h100_1 + + - label: "Diffusion · Boogu · H100 · Single-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/online_serving/test_boogu_image.py + tests/e2e/online_serving/test_boogu_image_edit.py + tests/e2e/online_serving/test_boogu_image_expansion.py + tests/e2e/online_serving/test_boogu_image_edit_expansion.py + -m "slow and diffusion and H100 and cards_1" + --run-level "full_model" + mirror_hardwares: h100_1 + + - label: "Diffusion · Flux · H100 · Single-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/online_serving/test_flux_2_dev_expansion.py + tests/e2e/offline_inference/test_flux1_schnell_expansion.py + -m "slow and diffusion and H100 and cards_1" + --run-level "full_model" + mirror_hardwares: h100_1 + + - label: "Diffusion · LTX · H100 · Single-GPU" + timeout_in_minutes: 120 + commands: + - >- + pytest -sv + tests/e2e/online_serving/test_ltx.py + tests/e2e/online_serving/test_ltx25.py + tests/e2e/accuracy/ltx/test_ltx_official_similarity.py + tests/e2e/accuracy/ltx/test_ltx25_official_similarity.py + -m "slow and diffusion and H100 and cards_1" + --run-level "full_model" + mirror_hardwares: h100_1 + + - label: "Diffusion · Krea2 · H100 · Single-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/online_serving/test_krea2_expansion.py + tests/e2e/offline_inference/test_krea2_expansion.py + -m "slow and diffusion and H100 and cards_1" + --run-level "full_model" + mirror_hardwares: h100_1 + + - label: "Diffusion · HiDream-I1 · H100 · Single-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/online_serving/test_hidream_i1_full_expansion.py + -m "slow and diffusion and H100 and cards_1" + --run-level "full_model" + mirror_hardwares: h100_1 + + - label: "Diffusion · SANA-Video · H100 · Single-GPU" + source_file_dependencies: diffusion_sana_video_function + timeout_in_minutes: 180 + commands: + - export SANA_VIDEO_GOLDEN_BASE_URL=https://vllm-public-assets.s3.us-west-2.amazonaws.com/omni-assets/sana-video/v2 + - >- + pytest -sv + tests/e2e/online_serving/test_sana_video_expansion.py + tests/e2e/accuracy/sana_video/ + -m "slow and diffusion and H100 and cards_1" + --run-level "full_model" + mirror_hardwares: h100_1 + + - label: "Diffusion · SenseNova-U1 · H100 · Single-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/offline_inference/test_sensenova_u1_expansion.py + tests/e2e/offline_inference/test_sensenova_u1_text2img_expansion.py + tests/e2e/offline_inference/test_sensenova_u1_img2img_expansion.py + -m "slow and diffusion and H100 and cards_1" + --run-level "full_model" + mirror_hardwares: h100_1 + + - label: "Diffusion · MammothModa2 · H100 · Single-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/offline_inference/test_mammoth_moda2_expansion.py + -m "slow and diffusion and H100 and cards_1" + --run-level "full_model" + mirror_hardwares: h100_1 + + - label: "Diffusion · Helios · H100 · Single-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/accuracy/test_video_streaming_output_similarity.py + -m "slow and diffusion and H100 and cards_1" + --run-level "full_model" + mirror_hardwares: h100_1 + + # Split the old shared H100 2-GPU sweep: one pytest process collected every + # slow+cards_2 diffusion file and exceeded 90 minutes. + - label: "Diffusion · Qwen-Image · H100 · 2-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/online_serving/test_qwen_image_edit_expansion.py + tests/e2e/online_serving/test_qwen_image_layered_expansion.py + -m "slow and diffusion and H100 and cards_2" --run-level "full_model" mirror_hardwares: h100_2 + - label: "Diffusion · Wan2.1 VACE · H100 · 2-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/online_serving/test_wan_2_1_vace_expansion.py + -m "slow and diffusion and H100 and cards_2" + --run-level "full_model" + mirror_hardwares: h100_2 + + - label: "Diffusion · LongCat · H100 · 2-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/online_serving/test_longcat_image_expansion.py + tests/e2e/online_serving/test_longcat_image_edit_expansion.py + -m "slow and diffusion and H100 and cards_2" + --run-level "full_model" + mirror_hardwares: h100_2 + + - label: "Diffusion · Bagel · H100 · 2-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/online_serving/test_bagel_expansion.py + -m "slow and diffusion and H100 and cards_2" + --run-level "full_model" + mirror_hardwares: h100_2 + + - label: "Diffusion · Boogu · H100 · 2-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/online_serving/test_boogu_image_expansion.py + tests/e2e/online_serving/test_boogu_image_edit_expansion.py + -m "slow and diffusion and H100 and cards_2" + --run-level "full_model" + mirror_hardwares: h100_2 + + - label: "Diffusion · Flux · H100 · 2-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/online_serving/test_flux_2_dev_expansion.py + tests/e2e/offline_inference/test_flux1_kontext_expansion.py + -m "slow and diffusion and H100 and cards_2" + --run-level "full_model" + mirror_hardwares: h100_2 + + - label: "Diffusion · GLM-Image · H100 · 2-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/online_serving/test_glm_image_expansion.py + tests/e2e/offline_inference/test_glm_image_autoround_w4a16_expansion.py + -m "slow and diffusion and H100 and cards_2" + --run-level "full_model" + mirror_hardwares: h100_2 + + - label: "Diffusion · LTX · H100 · 2-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/online_serving/test_ltx.py + -m "slow and diffusion and H100 and cards_2" + --run-level "full_model" + mirror_hardwares: h100_2 + + - label: "Diffusion · Krea2 · H100 · 2-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/offline_inference/test_krea2_expansion.py + -m "slow and diffusion and H100 and cards_2" + --run-level "full_model" + mirror_hardwares: h100_2 + + - label: "Diffusion · DreamZero · H100 · 2-GPU" + timeout_in_minutes: 90 + commands: + - >- + pytest -sv + tests/e2e/online_serving/test_dreamzero_expansion.py + tests/e2e/accuracy/test_dreamzero.py + -m "slow and diffusion and H100 and cards_2" + --run-level "full_model" + mirror_hardwares: h100_2 + + - label: "Diffusion · H100 · 3-GPU" + timeout_in_minutes: 120 + commands: + - >- + pytest -sv + tests/e2e/ -m "slow and diffusion and H100 and cards_3" + --run-level "full_model" + mirror_hardwares: h100_3 + - label: "Diffusion · H100 · 4-GPU" timeout_in_minutes: 90 commands: @@ -246,4 +508,33 @@ steps: pytest -sv tests/e2e/ -m "slow and diffusion and H100 and cards_4" --run-level "full_model" + --ignore=tests/e2e/online_serving/test_magi2.py + mirror_hardwares: h100_4 + + # Dedicated: HiDream-O1 accuracy needs a long TP2 run; the shared H100 + # 2-GPU sweep is only 90 minutes. + - label: "Diffusion · HiDream-O1-Image Accuracy · H100 · 2-GPU" + timeout_in_minutes: 180 + commands: + - pytest -s -v tests/e2e/accuracy/test_hidream_o1_image.py -m "slow and diffusion and cuda and H100 and cards_2" --run-level "full_model" + mirror_hardwares: h100_2 + + # Dedicated: Boogu CFG-parallel size 3 needs 3 GPUs; weekly has no H100 3-GPU sweep. + - label: "Diffusion · Boogu Edit CFG · H100 · 3-GPU" + timeout_in_minutes: 120 + commands: + - >- + pytest -sv + tests/e2e/online_serving/test_boogu_image_edit_expansion.py + -k "test_double_guidance_cfg_parallel and cfg_parallel_3_full" + -m "slow and diffusion and cuda and H100 and cards_3" + --run-level "full_model" + mirror_hardwares: h100_3 + + # Dedicated: MAGI-2 Preview serving smoke needs ~30 min server init; the + # shared H100 4-GPU sweep is only 90 minutes. + - label: "Diffusion · MAGI-2 Preview Serving Smoke · H100 · 4-GPU" + timeout_in_minutes: 180 + commands: + - pytest -s -v tests/e2e/online_serving/test_magi2.py -m "slow and diffusion and cuda and H100 and cards_4" --run-level "full_model" mirror_hardwares: h100_4 diff --git a/.buildkite/intel/pipeline-intel.yml b/.buildkite/intel/pipeline-intel.yml index d6134b028..1e2f86af2 100644 --- a/.buildkite/intel/pipeline-intel.yml +++ b/.buildkite/intel/pipeline-intel.yml @@ -10,7 +10,7 @@ steps: DOCKER_BUILDKIT: "1" # Buildkite will automatically replace this with the actual commit hash VLLM_IMAGE_TAG: "${BUILDKITE_COMMIT}" - VLLM_VERSION: "v0.28.0" + VLLM_VERSION: "v0.29.0" priority: 100 timeout_in_minutes: 60 soft_fail: false diff --git a/.buildkite/npu/bootstrap-upload-steps.yml b/.buildkite/npu/bootstrap-upload-steps.yml index 398fbc6dc..d88fcc70b 100644 --- a/.buildkite/npu/bootstrap-upload-steps.yml +++ b/.buildkite/npu/bootstrap-upload-steps.yml @@ -93,7 +93,7 @@ steps: command: | python3 .buildkite/common/scripts/upload_pipeline.py --upload .buildkite/npu/test-npu-ready.yml - # L4 Test — main+NIGHTLY=1 (scheduled), or PR with specific label (e.g. add label then Rebuild) + # L4 Test — main+NIGHTLY=1 (scheduled), or PR nightly-test label - label: "Upload Nightly Pipeline" depends_on: - image-build-a2 @@ -102,6 +102,11 @@ steps: - image-build-310p key: upload-nightly-pipeline commands: - - python3 .buildkite/common/scripts/upload_pipeline.py --upload .buildkite/npu/test-npu-nightly.yml + - | + EXTRA="" + if [ "${NIGHTLY:-}" = "1" ] && [ "${BUILDKITE_BRANCH}" = "main" ]; then + EXTRA="--all" + fi + python3 .buildkite/common/scripts/upload_pipeline.py --upload $$EXTRA .buildkite/npu/test-npu-nightly.yml agents: queue: "cpu_queue_premerge" diff --git a/.buildkite/npu/pipeline-npu-a3.yml b/.buildkite/npu/pipeline-npu-a3.yml index a57f5f8e5..3544b384d 100644 --- a/.buildkite/npu/pipeline-npu-a3.yml +++ b/.buildkite/npu/pipeline-npu-a3.yml @@ -96,13 +96,7 @@ # key: upload-nightly-pipeline # if: >- # (build.branch == "main" && build.env("NIGHTLY") == "1") || - # (build.branch != "main" && ( - # build.pull_request.labels includes "nightly-test" || - # build.pull_request.labels includes "omni-test" || - # build.pull_request.labels includes "tts-test" || - # build.pull_request.labels includes "diffusion-x2iat-test" || - # build.pull_request.labels includes "diffusion-x2v-test" - # )) + # (build.branch != "main" && build.pull_request.labels includes "nightly-test") # commands: # - buildkite-agent pipeline upload .buildkite/npu/test-npu-nightly.yml # agents: diff --git a/.buildkite/npu/test-npu-nightly.yml b/.buildkite/npu/test-npu-nightly.yml index e049783ce..0c39a3f93 100644 --- a/.buildkite/npu/test-npu-nightly.yml +++ b/.buildkite/npu/test-npu-nightly.yml @@ -4,10 +4,10 @@ steps: depends_on: upload-nightly-pipeline if: >- build.env("NIGHTLY") == "1" || - build.pull_request.labels includes "nightly-test" || - build.pull_request.labels includes "omni-test" + build.pull_request.labels includes "nightly-test" steps: - label: ":full_moon: Omni · Perf Test · No Async Chunk" + source_file_dependencies: omni_qwen3_omni_perf key: nightly-omni-performance-no-async-chunk timeout_in_minutes: 180 mirror_hardwares: a3_npu_4 @@ -24,6 +24,7 @@ steps: buildkite-agent artifact upload "tests/dfx/perf/results/*.json" exit $$EXIT - label: ":full_moon: Omni · Perf Test · Async Chunk" + source_file_dependencies: omni_qwen3_omni_perf key: nightly-omni-performance-async-chunk timeout_in_minutes: 180 mirror_hardwares: a3_npu_4 @@ -40,6 +41,7 @@ steps: buildkite-agent artifact upload "tests/dfx/perf/results/*.json" exit $$EXIT - label: ":full_moon: Omni · MiniCPM-o 4.5 Test" + source_file_dependencies: omni_minicpmo_4_5_function mirror_hardwares: a3_npu_2 env: VLLM_WORKER_MULTIPROC_METHOD: spawn @@ -48,6 +50,7 @@ steps: commands: - pytest -s -v tests/e2e/offline_inference/test_minicpmo_4_5.py tests/e2e/online_serving/test_minicpmo_4_5.py tests/e2e/online_serving/test_minicpmo_4_5_expansion.py -m 'full_model' --run-level 'full_model' - label: ":full_moon: Omni · MiniCPM-o 4.5 · Duplex Test" + source_file_dependencies: omni_minicpmo_4_5_duplex_function timeout_in_minutes: 180 mirror_hardwares: a3_npu_2 env: @@ -62,6 +65,7 @@ steps: -m "npu and A3 and omni" --run-level full_model - label: ":full_moon: Omni · MiniCPM-o 4.5 · Accuracy Test" + source_file_dependencies: omni_minicpmo_4_5_accuracy timeout_in_minutes: 180 mirror_hardwares: a3_npu_2 env: @@ -82,6 +86,7 @@ steps: buildkite-agent artifact upload "tests/e2e/accuracy/minicpmo_4_5/results/*.json" exit $$EXIT - label: ":full_moon: Omni · MiniCPM-o 4.5 · Perf Test" + source_file_dependencies: omni_minicpmo_4_5_perf key: nightly-omni-performance-minicpmo-4-5-npu timeout_in_minutes: 180 mirror_hardwares: a3_npu_2 @@ -98,6 +103,7 @@ steps: buildkite-agent artifact upload "tests/dfx/perf/results/*.json" exit $$EXIT - label: ":full_moon: Omni · MiniCPM-o 4.5 · Perf Test (A2)" + source_file_dependencies: omni_minicpmo_4_5_perf key: nightly-omni-performance-minicpmo-4-5-npu-a2 timeout_in_minutes: 180 mirror_hardwares: a2b3_npu_1 @@ -115,6 +121,7 @@ steps: buildkite-agent artifact upload "tests/dfx/perf/results/*.json" exit $$EXIT - label: ":full_moon: Omni · MiniCPM-o 4.5 · Duplex Seed-TTS Perf Test" + source_file_dependencies: omni_minicpmo_4_5_duplex_perf key: nightly-omni-performance-minicpmo-4-5-duplex-seed-tts-npu timeout_in_minutes: 180 mirror_hardwares: a3_npu_2 @@ -133,9 +140,10 @@ steps: - group: ":card_index_dividers: TTS Model Test" key: nightly-tts-test-group depends_on: upload-nightly-pipeline - if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test" || build.pull_request.labels includes "tts-test" + if: build.env("NIGHTLY") == "1" || build.pull_request.labels includes "nightly-test" steps: - label: ":full_moon: TTS · Perf Test" + source_file_dependencies: tts_qwen3_tts_perf timeout_in_minutes: 180 mirror_hardwares: a3_npu_2 env: @@ -151,15 +159,15 @@ steps: EXIT=$$? buildkite-agent artifact upload "tests/dfx/perf/results/*.json" exit $$EXIT - - group: ":card_index_dividers: Diffusion I2I Model Test" - key: nightly-HunyuanImage3-x2i-test-group + - group: ":card_index_dividers: Diffusion X2I(&A&T) Model Test" + key: nightly-diffusion-x2iat-group depends_on: upload-nightly-pipeline if: >- build.env("NIGHTLY") == "1" || - build.pull_request.labels includes "nightly-test" || - build.pull_request.labels includes "diffusion-x2iat-test" + build.pull_request.labels includes "nightly-test" steps: - label: ":full_moon: HunyuanImage3-DIT · Accuracy Test" + source_file_dependencies: diffusion_hunyuan_image3_accuracy timeout_in_minutes: 180 mirror_hardwares: a3_npu_4 env: @@ -169,15 +177,8 @@ steps: DIFFUSION_ATTENTION_BACKEND: TORCH_SDPA commands: - pytest -s -v tests/e2e/accuracy/test_hunyuan_image3_pixel_accuracy.py -m "full_model and A3" --run-level full_model - - group: ":card_index_dividers: Diffusion Benchmark Perf Test" - key: nightly-diffusion-benchmark-group - depends_on: upload-nightly-pipeline - if: >- - build.env("NIGHTLY") == "1" || - build.pull_request.labels includes "nightly-test" || - build.pull_request.labels includes "diffusion-x2iat-test" - steps: - label: ":full_moon: Diffusion Perf · HunyuanImage3 TP=2 CFGP=2" + source_file_dependencies: diffusion_hunyuan_image3_perf timeout_in_minutes: 180 mirror_hardwares: a3_npu_4 env: @@ -194,6 +195,7 @@ steps: buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log" exit $$EXIT - label: ":full_moon: Diffusion Perf · HunyuanImage3 TP=2 SP=2" + source_file_dependencies: diffusion_hunyuan_image3_perf timeout_in_minutes: 180 mirror_hardwares: a3_npu_4 env: @@ -210,6 +212,7 @@ steps: buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log" exit $$EXIT - label: ":full_moon: Diffusion Perf · HunyuanImage3 TP=4" + source_file_dependencies: diffusion_hunyuan_image3_perf timeout_in_minutes: 180 mirror_hardwares: a3_npu_4 env: @@ -230,10 +233,41 @@ steps: depends_on: upload-nightly-pipeline if: >- build.env("NIGHTLY") == "1" || - build.pull_request.labels includes "nightly-test" || - build.pull_request.labels includes "diffusion-x2v-test" + build.pull_request.labels includes "nightly-test" steps: - - label: ":full_moon: Diffusion X2V · Function Test" + - label: ":full_moon: Diffusion X2V · HunyuanVideo-1.5 Function Test" + source_file_dependencies: diffusion_hunyuan_video_function + timeout_in_minutes: 180 + mirror_hardwares: a2b3_npu_4 + env: + VLLM_WORKER_MULTIPROC_METHOD: spawn + VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1" + HF_TOKEN: "${HF_TOKEN}" + HF_HUB_OFFLINE: "1" + commands: + - pytest -s -v tests/e2e/online_serving/test_hunyuan_video_15_expansion.py -m "npu and A2" --run-level "full_model" + - label: ":full_moon: Diffusion X2V · HunyuanVideo-1.5 Perf Test" + source_file_dependencies: diffusion_hunyuan_video_perf + key: nightly-diffusion-x2v-performance-hunyuanvideo15 + timeout_in_minutes: 180 + mirror_hardwares: a3_npu_2 + env: + VLLM_WORKER_MULTIPROC_METHOD: spawn + VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1" + HF_TOKEN: "${HF_TOKEN}" + HF_HUB_OFFLINE: "1" + DIFFUSION_ATTENTION_BACKEND: TORCH_SDPA + commands: + - export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results + - | + set +e + pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py -m "npu and A3" --test-config-file tests/dfx/perf/tests/test_hunyuanvideo15_t2v_vllm_omni.json + EXIT=$$? + buildkite-agent artifact upload "tests/dfx/perf/results/diffusion_result_*.json" + buildkite-agent artifact upload "tests/dfx/perf/results/logs/*.log" + exit $$EXIT + - label: ":full_moon: Diffusion X2V · Wan 2.2 Function Test" + source_file_dependencies: diffusion_wan22_function mirror_hardwares: a2b3_npu_4 env: VLLM_WORKER_MULTIPROC_METHOD: spawn @@ -241,7 +275,8 @@ steps: HF_TOKEN: "${HF_TOKEN}" commands: - pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k npu_i2v --run-level "full_model" - - label: ":full_moon: Diffusion X2V · Perf Test" + - label: ":full_moon: Diffusion X2V · Wan 2.2 Perf Test" + source_file_dependencies: diffusion_wan22_perf key: nightly-diffusion-x2v-performance timeout_in_minutes: 180 mirror_hardwares: a3_npu_4 diff --git a/.claude/skills/vllm-omni-test/SKILL.md b/.claude/skills/vllm-omni-test/SKILL.md index 2d4226788..f0fb009d5 100644 --- a/.claude/skills/vllm-omni-test/SKILL.md +++ b/.claude/skills/vllm-omni-test/SKILL.md @@ -468,10 +468,10 @@ When the user asks for **invalid parameter validation**, **invalid request bodie | **Invalid parameters Test · H100** | `pytest -s -v tests/dfx/reliability/invalid_param_test/ -m "slow and H100"` | Diffusion / omni / video invalid-param tests with `H100` hardware mark | | **Invalid parameters Test · L4** | `pytest -s -v tests/dfx/reliability/invalid_param_test/ -m "slow and L4"` | TTS / lighter models marked `L4` | -- **Trigger:** `build.env("WEEKLY") == "1"` or PR label `weekly-test`. +- **Trigger:** `build.env("WEEKLY") == "1"` (all weekly jobs) or PR label `weekly-test` (Reliability / Perf, then filtered by `source_file_dependencies`). - **Default:** extending an existing `invalid_param_test` script needs **no YAML edit** — the weekly steps already sweep the whole directory. - **Edit YAML only** when adding a **new hardware queue**, a **new top-level script** that must run in isolation, or a **model-specific weekly shard** (mirror neighboring reliability steps). -- Weekly steps **do not** use `source_file_dependencies`. +- Weekly Reliability / Perf jobs declare `source_file_dependencies`. Filtering applies only on the `weekly-test` label; `WEEKLY=1` on `main` keeps every job in those groups. CPU coverage (`WEEKLY=1` only) and the E2E Tests group (`NON_CRITICAL=1` only) do **not** use this field. **Example — append to `test_invalid_image_generation.py`:** @@ -644,7 +644,7 @@ If the test is not already collected by an existing pipeline command (for exampl | **L2** | `test-ready.yml` with `core_model` + `source_file_dependencies` | merge / nightly pipelines | | **Invalid param** | `test-weekly.yml` — **Invalid parameters Test** group (`-m "slow and H100"` / `-m "slow and L4"`). Usually **no YAML edit** when appending cases to existing `invalid_param_test` scripts | `test-ready.yml`, `test-merge.yml`, `test-nightly.yml` | -`test-nightly.yml` shards use **explicit pytest file paths** in `commands` (and PR labels like `diffusion-x2iat-test`); they generally **do not** use `source_file_dependencies`. Only suggest merge/ready YAML when the requested level is L3/L2 (or the user explicitly asks for multi-level CI). +`test-nightly.yml` shards use **explicit pytest file paths** in `commands` plus `source_file_dependencies`; PR trigger is `nightly-test` (path filter), or `NIGHTLY=1` on `main` (all jobs). Only suggest merge/ready YAML when the requested level is L3/L2 (or the user explicitly asks for multi-level CI). **`test-nightly.yml` top-level groups** (each uses `full_model` + type marker in pytest `-m`): @@ -653,7 +653,7 @@ If the test is not already collected by an existing pipeline command (for exampl | **Omni Model Test** | `omni` | Function / doc / accuracy / **perf** for Qwen-Omni family | | **TTS Model Test** | `tts` | `-m "full_model and L4 and tts"` (and H100 variants when enabled); **Perf Test** uses `run_benchmark.py` + `test_tts.json` | | **Diffusion X2I(&A&T) Model Test** | `diffusion` | Image/audio/text diffusion; explicit file shards for **Function**; **Perf Test · <Model>** uses `run_diffusion_benchmark.py` + JSON config | -| **Diffusion X2V Model Test** | `diffusion` | Video-only (Wan, HunyuanVideo, …); PR label `diffusion-x2v-test`; separate **Perf** steps when in-tree | +| **Diffusion X2V Model Test** | `diffusion` | Video-only (Wan, HunyuanVideo, …); separate **Perf** steps when in-tree | Guidelines when editing YAML: diff --git a/.claude/skills/vllm-omni-test/references/test-routing.md b/.claude/skills/vllm-omni-test/references/test-routing.md index 5b90957d6..a61324e6d 100644 --- a/.claude/skills/vllm-omni-test/references/test-routing.md +++ b/.claude/skills/vllm-omni-test/references/test-routing.md @@ -37,7 +37,7 @@ Every model-centric e2e test must declare **exactly one** type marker: | **Diffusion X2I(&A&T) Model Test** | x2**i** / x2**a** / x2**t** — image, audio, text (non-video) | Qwen-Image*, BAGEL, FLUX, SD3, Z-Image, LongCat, DreamZero | | **Diffusion X2V Model Test** | x2**v** — video only | Wan2.2, HunyuanVideo 1.5, Wan VACE | -PR labels for selective nightly runs: `diffusion-x2iat-test`, `diffusion-x2v-test` (plus `nightly-test` / `NIGHTLY=1`). +PR label for L4 on a branch: `nightly-test` (jobs then filtered by `source_file_dependencies`). Scheduled `main` uses `NIGHTLY=1` and runs every nightly job. L5 Reliability / Perf use `weekly-test` with the same path filter; CPU coverage and the weekly E2E group are env-only (`WEEKLY=1` / `NON_CRITICAL=1`) and are not source-filtered. ## Level and Marker Mapping @@ -238,7 +238,7 @@ pytest -s -v dfx/reliability/invalid_param_test/ -m "slow and L4" pytest -s -v dfx/reliability/invalid_param_test/test_invalid_image_generation.py::test_images_generations_invalid_requests -m "slow and H100" ``` -**Trigger:** `WEEKLY=1` or PR label `weekly-test`. Appending cases to existing scripts usually needs **no YAML edit** (directory sweep). No `source_file_dependencies` on weekly steps. +**Trigger:** `WEEKLY=1` (all jobs) or PR label `weekly-test` (Reliability / Perf, filtered by `source_file_dependencies`). Appending cases to existing scripts usually needs **no YAML edit** (directory sweep). ### Platform-targeted examples diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c92c7b22f..e77f70914 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -67,6 +67,11 @@ # File-level overrides within entrypoints/ /vllm_omni/entrypoints/openai/errors.py @alex-jw-brooks @NickCao /vllm_omni/entrypoints/cli/benchmark/ @alex-jw-brooks @Bounty-hunter +# Shared wire codec: protocol/realtime (OpenAI Realtime GA) and protocol/duplex +# (vLLM-Omni's extension of it) — RFC #6592 P0a. Layer-neutral by design — the +# engine depends on it — so it is owned by the serving-boundary document rather +# than by any one consumer. — docs/design/module/entrypoints.md +/vllm_omni/protocol/ @alex-jw-brooks @linyueqian @NickCao # Error contracts — docs/design/module/error_contracts.md /vllm_omni/errors.py @alex-jw-brooks @NickCao diff --git a/README.md b/README.md index 5063f9a3f..2cd6a574a 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ vLLM-Omni is flexible and easy to use with: vLLM-Omni seamlessly supports most popular open-source models on HuggingFace, including: - **Omni-modality models** (e.g. Qwen3-Omni, MiniCPM-o 4.5, Cosmos3, HunyuanImage, BAGEL) -- **TTS models** (e.g. Qwen3-TTS, IndexTTS 2.5, dots.tts, CosyVoice3) +- **TTS models** (e.g. Qwen3-TTS, IndexTTS 2.5, CosyVoice3) - **Diffusion models** — image, video, and audio generation (e.g. MiniMax H3, LTX-2.5, SANA-Video, Wan2.2) - **Robot-policy and action models** (e.g. π0, GR00T-N1.7, DreamZero-DROID, InternVLA-A1) diff --git a/apps/ComfyUI-vLLM-Omni/README.md b/apps/ComfyUI-vLLM-Omni/README.md index cbd53a9a0..f33e26b40 100644 --- a/apps/ComfyUI-vLLM-Omni/README.md +++ b/apps/ComfyUI-vLLM-Omni/README.md @@ -13,7 +13,6 @@ It can send model inference requests to either a locally running vLLM-Omni servi > [!TIP] > If you run both ComfyUI and vLLM-Omni on the same device, you can create separate virtual environments and use different Python versions for them. - ## Installation Copy this folder to the `custom_nodes` subfolder of your ComfyUI installation. Your directory should look like `ComfyUI/custom_nodes/ComfyUI-vLLM-Omni`. @@ -21,9 +20,10 @@ Copy this folder to the `custom_nodes` subfolder of your ComfyUI installation. Y If you are running ComfyUI during copying, you should restart ComfyUI to load this extension. > [!TIP] -> You can use utility websites such as https://download-directory.github.io/ to download a subdirectory of a repo. Also checkout community discussions (e.g., https://stackoverflow.com/questions/7106012/download-a-single-folder-or-directory-from-a-github-repository) for more info. +> You can use utility websites such as to download a subdirectory of a repo. Also checkout community discussions (e.g., ) for more info. On the device and virtual environment you run ComfyUI, launch ComfyUI with + ```bash cd ComfyUI @@ -35,6 +35,7 @@ python main.py --cpu ``` On the device and virtual environment you run vLLM-Omni, start a model service with + ```bash vllm serve The_Model_ID_to_Serve --omni --port 8000 ``` @@ -48,14 +49,30 @@ This extension offers the following nodes based on the output modalities (at **C - **Generate Image** for text-to-image and image-to-image tasks - **Generate Video** for text-to-video, first-frame/image-to-video, and reference-conditioned video +- **FastH3 Deployment** for routing text-to-video requests to a MiniMax-H3 server with FastH3 fused at startup - **Multimodality Understanding** for multimodality-to-text and multimodality-to-audio tasks - **TTS** and **TTS Voice Clone** for TTS tasks +- **Generate Music** for lyrics-and-description-to-music generation This extension also offers example workflows (at **ComfyUI sidebar -> Templates -> vLLM-Omni**) > [!NOTE] > The node UI and feature designs are intended to match vLLM-Omni online serving interfaces. It cannot offer more than what the interfaces support. +Every node carries the vLLM-Omni mark in its title bar and is tinted by what it outputs, so a graph is readable at a glance: + +| Colour | Nodes | What they produce | +| --- | --- | --- | +| Blue | Generate Image, Generate Video, Multimodality Understanding, TTS, TTS Voice Clone | A generated image, video, audio, or text. These are the only nodes that reach a server. | +| Amber | AR / Diffusion / Multi-Stage Sampling Params | Sampling parameters that apply to any model | +| Purple | Qwen TTS Params, Wan Video Params, MiniMax-H3 Video Params | Parameters that only one model family accepts | +| Red | LoRA, FastH3 Deployment | Which weights the server is expected to have loaded | +| Teal | Video References | Reference media | + +Recolouring a node by hand (right click -> Colors) overrides its tint, and the choice is kept. + +**Generate Video** takes a clip length in seconds (`duration`), not a frame count. Frames stay the wire unit and are derived with the node's `fps`, so the length is always measured against the rate that is actually served; models that accept only certain frame counts still round to their own lattice server-side. Graphs saved before this widget existed stored `num_frames` in its place and are converted on load, using the fps recorded alongside it -- the browser console names every node it rewrites. + To build a simple workflow yourself, - Drag a generation node onto the canvas. @@ -117,11 +134,134 @@ You can configure per-stage sampling parameters for multi-stage models.

> [!TIP] -> Connect a **frame** image for first-frame / image-to-video (e.g., Wan I2V, MiniMax-H3 FL2VA). +> Connect **frame** for backward-compatible first-frame / image-to-video behavior. For MiniMax-H3 FL2VA, +> connect **first_frame**, **last_frame**, or both to condition the start frame, end frame, or both. > > For reference-conditioned generation (MiniMax-H3 Ref2VA), connect a **Video References** node instead. > -> Do not use `frame` and `references` together. Task routing is automatic from which inputs you connect. +> Do not combine `frame` with `first_frame` or `last_frame`, and do not combine any frame input with +> `references`. Task routing is automatic from which inputs you connect. + +For MiniMax-H3 Ref2VA, **Video References** accepts up to 9 images (`image_1`–`image_9`), +3 videos (`video_1`–`video_3`), and 3 audio clips (`audio_1`–`audio_3`), with at most +12 connected inputs in total. Any mixture containing at least one image or video +is supported; empty and audio-only references are rejected. For example, you can +combine 6 images, 3 videos, and 3 audio clips in one request. + +Within each media type, references follow slot-number order, skipping unconnected +slots. For example, connecting `image_2` and `image_9` sends `image_2` as the first +image and `image_9` as the second. Each image slot uses the first image in its batch. +Existing connections to `image_1`, `image_2`, `audio_1`, `audio_2`, `video_1`, and +`video_2` remain valid in saved workflows. + +#### MiniMax-H3 Reference to Video + +Load [MiniMax-H3 Reference to Video](example_workflows/vLLM-Omni%20MiniMax-H3%20Reference%20to%20Video.json) +from **Templates → ComfyUI-vLLM-Omni**, or drag the JSON onto the canvas. +It adapts the [official ComfyUI R2V workflow](https://github.com/Comfy-Org/workflow_templates/blob/main/templates/video_minimax_h3_r2v.json) +to remote vLLM-Omni execution. Model loading, sampling, and VAE decoding run on +the server; ComfyUI loads references and saves the returned video. + +Use an extension version containing the audio-preserving output fix from +[#7456](https://github.com/vllm-project/vllm-omni/pull/7456). Older versions can +drop the server's audio while decoding the response. + +1. Start a Ref2VA-capable service using the [MiniMax-H3 recipe](../../recipes/MiniMaxAI/MiniMax-H3.md). + Set **Generate Video** to its `/v1` URL and served model name. +2. Select your own image in **Load Image**. The template's filenames are placeholders + relative to ComfyUI's input directory; no sample assets or model weights are bundled. +3. Connect **Load Video** and **Load Audio** when needed. Duplicate the loaders to + fill more reference slots, or disconnect the image when using video-only input. + Keep the references connected to **Generate Video** and leave `frame` disconnected. +4. Match prompt tags such as ``, `