Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e384cae198 | ||
|
|
a94b2580a1 | ||
|
|
d150a4fde7 | ||
|
|
aa69acbd09 | ||
|
|
0e4b28f491 | ||
|
|
f446468c03 | ||
|
|
d15b7ca3e1 | ||
|
|
072bfc02dd | ||
|
|
3d035bfa19 | ||
|
|
1c917b2751 | ||
|
|
17285c2f55 | ||
|
|
1e2a6446f7 | ||
|
|
39c16d75a9 | ||
|
|
0db262de2a | ||
|
|
2e096788a6 | ||
|
|
b2c9376539 | ||
|
|
3ad64c6a12 | ||
|
|
855719e331 | ||
|
|
bd4f9acfd3 | ||
|
|
f09bdcbc7d | ||
|
|
b39f599b09 | ||
|
|
72ee535fcd | ||
|
|
c2daa471c3 | ||
|
|
493fc64397 | ||
|
|
3781214675 | ||
|
|
42059f19d5 | ||
|
|
faa12af454 | ||
|
|
4882a36c41 | ||
|
|
3d34b8b977 | ||
|
|
cfbf1392c5 | ||
|
|
dc72559d5d | ||
|
|
260db8bab5 | ||
|
|
4f7c08c0eb | ||
|
|
ea0a24465b | ||
|
|
fc163cd90f | ||
|
|
016861385f | ||
|
|
15e38ac173 | ||
|
|
70bdd49402 | ||
|
|
73b623f2f7 | ||
|
|
5730af0a95 | ||
|
|
37c11e6e4f | ||
|
|
13c2de684c | ||
|
|
b2011a3edd | ||
|
|
b3270dec8d | ||
|
|
ebb4abde0a | ||
|
|
c6e38860e9 | ||
|
|
b1da47b781 | ||
|
|
8d34d3b5de | ||
|
|
cd3867c373 | ||
|
|
718d9a4cd7 | ||
|
|
273ffce130 | ||
|
|
10906e3a6d | ||
|
|
48e4f6a385 | ||
|
|
53df9fe62b | ||
|
|
b57dc70ec4 | ||
|
|
480e10ba9c | ||
|
|
b58feb1420 | ||
|
|
38cf9adc38 | ||
|
|
9c61d5b67b | ||
|
|
47b1893676 | ||
|
|
bd17618c11 | ||
|
|
6f55a06fab | ||
|
|
efaf4276f9 | ||
|
|
ea24deefcc | ||
|
|
c3f80502e0 | ||
|
|
8dc3d504d8 | ||
|
|
7099583404 | ||
|
|
ac0067078b | ||
|
|
26e003715c | ||
|
|
a630b0c2ec | ||
|
|
adf6d0c1ea | ||
|
|
14bd8f8772 | ||
|
|
14f2c16fb2 | ||
|
|
9683b7f4b4 | ||
|
|
07ceb3324a | ||
|
|
b4b907e7b6 | ||
|
|
f208f907bc | ||
|
|
284e05c88b | ||
|
|
c3de04e127 | ||
|
|
4cd667875f | ||
|
|
e1c5f59aab | ||
|
|
02069a5bbf | ||
|
|
cd9ae66b3a | ||
|
|
0a1846aa45 | ||
|
|
b283215c28 | ||
|
|
199ef7779c | ||
|
|
3c6648d8a5 | ||
|
|
d7216ef514 | ||
|
|
2fdbf2234a | ||
|
|
265d80b4dd | ||
|
|
5d09cf27a9 | ||
|
|
170d498771 | ||
|
|
2a9f6aaa8e | ||
|
|
5664e69dbf | ||
|
|
e96d3fe2a6 | ||
|
|
309d9c3ea8 | ||
|
|
65b3d41b3a | ||
|
|
4616823125 | ||
|
|
611c083587 | ||
|
|
baba7d1e2e | ||
|
|
9d2bb23ff6 | ||
|
|
3875f8ded4 | ||
|
|
9798bc3a8d | ||
|
|
68bf8c2c42 | ||
|
|
444485650b | ||
|
|
2a315e1a2d | ||
|
|
d1e230c95b | ||
|
|
09b6a1604a | ||
|
|
555336e887 | ||
|
|
136cb27b05 | ||
|
|
ce6ab0ca46 | ||
|
|
f39b8684eb | ||
|
|
e57574ae29 | ||
|
|
7b76b6446d | ||
|
|
a70d4d4b3c | ||
|
|
1260ceaae6 | ||
|
|
6f36fd3b78 | ||
|
|
35cacf020c | ||
|
|
d671e6b0db | ||
|
|
b95c73742d | ||
|
|
fe54ecc388 | ||
|
|
4b6d6d5cf7 | ||
|
|
f7a5146093 | ||
|
|
8ecd1f6d5c | ||
|
|
ffd11c181e | ||
|
|
728640f4d9 | ||
|
|
022d7a7695 | ||
|
|
b300f66656 | ||
|
|
bc73546c06 | ||
|
|
2b08419d8b | ||
|
|
5d50bdc2ab | ||
|
|
8a5bf2fb3f | ||
|
|
596c16a550 | ||
|
|
90a08c0eda | ||
|
|
dbc0dd6d85 | ||
|
|
83d1f11449 | ||
|
|
4b66f62e10 | ||
|
|
f41451f64c | ||
|
|
bbe6ccc512 | ||
|
|
bbb709cfb5 | ||
|
|
c98517ce7f | ||
|
|
d77a35a32b | ||
|
|
877beeaa49 | ||
|
|
8b8d3f56db | ||
|
|
c57178c0e1 | ||
|
|
9a59475015 | ||
|
|
12f8168179 | ||
|
|
72a02b492a | ||
|
|
5358f5db01 | ||
|
|
e677360168 | ||
|
|
208c6776a8 | ||
|
|
fcf1085395 | ||
|
|
38a2500bdf | ||
|
|
7cd826d28c | ||
|
|
31384cb39c | ||
|
|
5be7541d01 | ||
|
|
9b0df3909a | ||
|
|
a15b5b4bcd | ||
|
|
3c3989ed04 | ||
|
|
854bff7fe5 | ||
|
|
b792578d89 | ||
|
|
bdb1d996be | ||
|
|
8b0a6779d4 | ||
|
|
58007c0084 | ||
|
|
1ff2753469 | ||
|
|
4697bd1be0 | ||
|
|
2ce15ab7a0 | ||
|
|
584d78c673 | ||
|
|
89015d5cad | ||
|
|
348cf95a89 | ||
|
|
22dd96ec5c | ||
|
|
e04210d690 | ||
|
|
4ab1b4ff9c | ||
|
|
06e733d3cd | ||
|
|
af3faa6c1e | ||
|
|
322600bfb2 | ||
|
|
c4a14091c9 | ||
|
|
6d4e4ffc7c | ||
|
|
f97af75d1d | ||
|
|
73a312d5b6 | ||
|
|
1a56953d7a | ||
|
|
1f65814fab | ||
|
|
4f9b65074d | ||
|
|
12a5f6fbf3 | ||
|
|
53afbf3a0c | ||
|
|
ee118ab492 |
No files matched your search
@@ -1,153 +1,103 @@
|
||||
#!/bin/bash
|
||||
# vllm-omni customized version
|
||||
# Based on: vllm/.buildkite/scripts/hardware_ci/run-amd-test.sh
|
||||
# Last synced: 2025-12-15
|
||||
# Modifications: docker image name for vllm-omni
|
||||
|
||||
# This script runs test inside the corresponding ROCm docker container.
|
||||
set -o pipefail
|
||||
# Run vLLM-Omni ROCm tests directly in the MI300 Kubernetes pod. The pod's
|
||||
# container image is selected by test-template-amd-omni.j2; MI300 has no DinD.
|
||||
set -euo pipefail
|
||||
|
||||
# Export Python path
|
||||
export PYTHONPATH=".."
|
||||
: "${PYTHONFAULTHANDLER:=1}"
|
||||
: "${HF_HOME:=/home/buildkite-agent/huggingface}"
|
||||
: "${HF_HUB_DOWNLOAD_TIMEOUT:=300}"
|
||||
: "${HF_HUB_ETAG_TIMEOUT:=60}"
|
||||
: "${MIOPEN_DEBUG_CONV_DIRECT:=0}"
|
||||
: "${MIOPEN_DEBUG_CONV_GEMM:=0}"
|
||||
: "${VLLM_ROCM_USE_AITER:=0}"
|
||||
export PYTHONFAULTHANDLER HF_HOME HF_HUB_DOWNLOAD_TIMEOUT HF_HUB_ETAG_TIMEOUT
|
||||
export MIOPEN_DEBUG_CONV_DIRECT MIOPEN_DEBUG_CONV_GEMM VLLM_ROCM_USE_AITER
|
||||
export PYTORCH_ROCM_ARCH=""
|
||||
export PYTHONPATH="${PYTHONPATH:-..}"
|
||||
|
||||
if [[ "${VLLM_CI_DOCKER_DISABLED:-0}" != "1" ]]; then
|
||||
echo "Error: MI300 CI must run natively with Docker disabled." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -n "${TEST_COMMANDS:-}" ]]; then
|
||||
commands="${TEST_COMMANDS}"
|
||||
else
|
||||
commands="$*"
|
||||
fi
|
||||
if [[ -z "${commands}" ]]; then
|
||||
echo "Error: No test commands provided." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "--- Native in-pod ROCm CI"
|
||||
|
||||
job_id="${BUILDKITE_JOB_ID:-${BUILDKITE_PARALLEL_JOB:-local}}"
|
||||
job_id="${job_id//[^A-Za-z0-9_.-]/_}"
|
||||
native_cache_root="/tmp/vllm-omni-native-${job_id}"
|
||||
TMPDIR="${native_cache_root}/tmp"
|
||||
TORCHINDUCTOR_CACHE_DIR="${native_cache_root}/torchinductor"
|
||||
TRITON_CACHE_DIR="${native_cache_root}/triton"
|
||||
VLLM_CACHE_ROOT="${native_cache_root}/vllm"
|
||||
XDG_CACHE_HOME="${native_cache_root}/xdg"
|
||||
HF_DATASETS_CACHE="${native_cache_root}/huggingface/datasets"
|
||||
export TMPDIR TORCHINDUCTOR_CACHE_DIR TRITON_CACHE_DIR VLLM_CACHE_ROOT
|
||||
export XDG_CACHE_HOME HF_DATASETS_CACHE
|
||||
mkdir -p "${TMPDIR}" "${TORCHINDUCTOR_CACHE_DIR}" "${TRITON_CACHE_DIR}" \
|
||||
"${VLLM_CACHE_ROOT}" "${XDG_CACHE_HOME}" "${HF_HOME}" \
|
||||
"${HF_DATASETS_CACHE}"
|
||||
|
||||
if [[ "${VLLM_CI_REQUIRE_PERSISTENT_HF_CACHE:-0}" == "1" ]]; then
|
||||
if ! command -v findmnt >/dev/null 2>&1; then
|
||||
echo "Error: findmnt is required to verify the Hugging Face cache mount." >&2
|
||||
exit 1
|
||||
fi
|
||||
hf_mount=$(findmnt -n -T "${HF_HOME}" -o TARGET 2>/dev/null || true)
|
||||
if [[ -z "${hf_mount}" || "${hf_mount}" == "/" ]]; then
|
||||
echo "Error: MI300 CI requires a persistent volume at or above ${HF_HOME}." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Print ROCm version
|
||||
echo "--- ROCm info"
|
||||
rocminfo
|
||||
|
||||
# cleanup older docker images
|
||||
cleanup_docker() {
|
||||
# Get Docker's root directory
|
||||
docker_root=$(docker info -f '{{.DockerRootDir}}')
|
||||
if [ -z "$docker_root" ]; then
|
||||
echo "Failed to determine Docker root directory."
|
||||
exit 1
|
||||
fi
|
||||
echo "Docker root directory: $docker_root"
|
||||
# Check disk usage of the filesystem where Docker's root directory is located
|
||||
disk_usage=$(df "$docker_root" | tail -1 | awk '{print $5}' | sed 's/%//')
|
||||
# Define the threshold
|
||||
threshold=70
|
||||
if [ "$disk_usage" -gt "$threshold" ]; then
|
||||
echo "Disk usage is above $threshold%. Cleaning up Docker images and volumes..."
|
||||
# Remove dangling images (those that are not tagged and not used by any container)
|
||||
docker image prune -f
|
||||
# Remove unused volumes / force the system prune for old images as well.
|
||||
docker volume prune -f && docker system prune --force --filter "until=72h" --all
|
||||
echo "Docker images and volumes cleanup completed."
|
||||
else
|
||||
echo "Disk usage is below $threshold%. No cleanup needed."
|
||||
fi
|
||||
}
|
||||
expected_gpus="${VLLM_CI_EXPECTED_GPU_COUNT:-1}"
|
||||
python3 - <<'PY'
|
||||
import os
|
||||
|
||||
# Call the cleanup docker function
|
||||
cleanup_docker
|
||||
import torch
|
||||
|
||||
echo "--- Pulling container"
|
||||
## Temporary change to use AMD Docker Hub to store the vllm-omni image
|
||||
# to bypass the rate limit issue with ECR Public Gallery.
|
||||
# Images are now stored in a separate repository for vllm-omni, instead of vllm-ci.
|
||||
# TODO: @tjtanaa point back to ECR Public Gallery
|
||||
# once the amd agents are configured to use ECR Public Gallery.
|
||||
# image_name="public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:${BUILDKITE_COMMIT}-rocm-omni"
|
||||
image_name="rocm/vllm-omni:${BUILDKITE_COMMIT}"
|
||||
container_name="rocm_${BUILDKITE_COMMIT}_$(tr -dc A-Za-z0-9 < /dev/urandom | head -c 10; echo)"
|
||||
expected = int(os.environ.get("VLLM_CI_EXPECTED_GPU_COUNT", "1"))
|
||||
assert torch.version.hip, "PyTorch is not a ROCm build"
|
||||
assert torch.cuda.is_available(), "ROCm GPU is not available to PyTorch"
|
||||
actual = torch.cuda.device_count()
|
||||
assert actual == expected, f"Expected {expected} ROCm GPU(s), found {actual}"
|
||||
PY
|
||||
|
||||
# TODO: @tjtanaa uncomment this once the amd agents are configured to use ECR Public Gallery.
|
||||
# # Install AWS CLI to authenticate to ECR Public Gallery to get higher rate limit for pulling images
|
||||
# sudo apt-get update && sudo apt-get install -y awscli
|
||||
## Use safe docker login helper to prevent race conditions
|
||||
# source "$(dirname "${BASH_SOURCE[0]}")/../../common/scripts/docker_login_ecr_public.sh"
|
||||
# safe_docker_login_ecr_public
|
||||
|
||||
## Pull the container from AMD Docker Hub
|
||||
|
||||
docker pull "${image_name}"
|
||||
|
||||
remove_docker_container() {
|
||||
docker ps -aq --filter "name=${container_name}" | xargs -r docker rm -f || true
|
||||
docker image rm -f "${image_name}" || true
|
||||
}
|
||||
trap remove_docker_container EXIT
|
||||
|
||||
echo "--- Running container"
|
||||
|
||||
HF_CACHE="$(realpath ~)/huggingface"
|
||||
mkdir -p "${HF_CACHE}"
|
||||
HF_MOUNT="/root/.cache/huggingface"
|
||||
|
||||
if [[ -n "${TEST_COMMAND:-}" ]]; then
|
||||
commands="$TEST_COMMAND"
|
||||
else
|
||||
commands="$@"
|
||||
fi
|
||||
echo "Commands:$commands"
|
||||
|
||||
PARALLEL_JOB_COUNT=8
|
||||
MYPYTHONPATH=".."
|
||||
|
||||
# Test that we're launching on the machine that has
|
||||
# proper access to GPUs
|
||||
render_gid=$(getent group render | cut -d: -f3)
|
||||
if [[ -z "$render_gid" ]]; then
|
||||
echo "Error: 'render' group not found. This is required for GPU access." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# check if the command contains shard flag, we will run all shards in parallel because the host have 8 GPUs.
|
||||
# TODO: @tjtanaa reenable to run VLLM_ROCM_USE_AITER=1 when AITER is shipped with prebuilt kernels.
|
||||
if [[ $commands == *"--shard-id="* ]]; then
|
||||
# assign job count as the number of shards used
|
||||
commands=$(echo "$commands" | sed -E "s/--num-shards[[:blank:]]*=[[:blank:]]*[0-9]*/--num-shards=${PARALLEL_JOB_COUNT} /g" | sed 's/ \\ / /g')
|
||||
for GPU in $(seq 0 $(($PARALLEL_JOB_COUNT-1))); do
|
||||
# assign shard-id for each shard
|
||||
commands_gpu=$(echo "$commands" | sed -E "s/--shard-id[[:blank:]]*=[[:blank:]]*[0-9]*/--shard-id=${GPU} /g" | sed 's/ \\ / /g')
|
||||
echo "Shard ${GPU} commands:$commands_gpu"
|
||||
echo "Render devices: $BUILDKITE_AGENT_META_DATA_RENDER_DEVICES"
|
||||
docker run \
|
||||
--device /dev/kfd $BUILDKITE_AGENT_META_DATA_RENDER_DEVICES \
|
||||
--network=host \
|
||||
--shm-size=16gb \
|
||||
--group-add "$render_gid" \
|
||||
-e MIOPEN_DEBUG_CONV_DIRECT=0 \
|
||||
-e MIOPEN_DEBUG_CONV_GEMM=0 \
|
||||
-e VLLM_ROCM_USE_AITER=0 \
|
||||
-e HIP_VISIBLE_DEVICES="${GPU}" \
|
||||
-e HF_TOKEN \
|
||||
-v "${HF_CACHE}:${HF_MOUNT}" \
|
||||
-e "HF_HOME=${HF_MOUNT}" \
|
||||
-e "PYTHONPATH=${MYPYTHONPATH}" \
|
||||
--name "${container_name}_${GPU}" \
|
||||
"${image_name}" \
|
||||
/bin/bash -c "${commands_gpu}" \
|
||||
|& while read -r line; do echo ">>Shard $GPU: $line"; done &
|
||||
PIDS+=($!)
|
||||
done
|
||||
#wait for all processes to finish and collect exit codes
|
||||
for pid in "${PIDS[@]}"; do
|
||||
wait "${pid}"
|
||||
STATUS+=($?)
|
||||
done
|
||||
for st in "${STATUS[@]}"; do
|
||||
if [[ ${st} -ne 0 ]]; then
|
||||
echo "One of the processes failed with $st"
|
||||
exit "${st}"
|
||||
echo "Commands:${commands}"
|
||||
if /bin/bash -o pipefail -c '
|
||||
set -E
|
||||
test_status=0
|
||||
trap '\''
|
||||
command_status=$?
|
||||
# Keep running subsequent commands, but retain a failure for the final exit.
|
||||
# Prefer a test failure over pytest "no tests collected" when both occur.
|
||||
if (( test_status == 0 || (test_status == 5 && command_status != 5) )); then
|
||||
test_status=${command_status}
|
||||
fi
|
||||
done
|
||||
'\'' ERR
|
||||
eval "$1"
|
||||
exit "${test_status}"
|
||||
' _ "${commands}"; then
|
||||
exit 0
|
||||
else
|
||||
echo "Render devices: $BUILDKITE_AGENT_META_DATA_RENDER_DEVICES"
|
||||
docker run \
|
||||
--device /dev/kfd $BUILDKITE_AGENT_META_DATA_RENDER_DEVICES \
|
||||
--network=host \
|
||||
--shm-size=16gb \
|
||||
--group-add "$render_gid" \
|
||||
-e MIOPEN_DEBUG_CONV_DIRECT=0 \
|
||||
-e MIOPEN_DEBUG_CONV_GEMM=0 \
|
||||
-e VLLM_ROCM_USE_AITER=0 \
|
||||
-e HF_TOKEN \
|
||||
-v "${HF_CACHE}:${HF_MOUNT}" \
|
||||
-e "HF_HOME=${HF_MOUNT}" \
|
||||
-e "PYTHONPATH=${MYPYTHONPATH}" \
|
||||
--name "${container_name}" \
|
||||
"${image_name}" \
|
||||
/bin/bash -c "${commands}"
|
||||
exit_code=$?
|
||||
fi
|
||||
|
||||
if [[ ${exit_code} -eq 5 && "${VLLM_CI_ALLOW_NO_TESTS:-0}" == "1" ]]; then
|
||||
echo "Pytest collected no tests; VLLM_CI_ALLOW_NO_TESTS=1, treating exit code 5 as success."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
exit "${exit_code}"
|
||||
@@ -7,54 +7,64 @@ steps:
|
||||
|
||||
- group: ":card_index_dividers: Simple Test"
|
||||
steps:
|
||||
- label: "Simple · Diffusion & Model Executor Test (1/2)"
|
||||
agent_pool: mi325_1
|
||||
- label: "Simple · Model Executor Test · Shard %N/%t"
|
||||
agent_pool: mi300_1
|
||||
parallelism: 2
|
||||
depends_on: amd-build
|
||||
timeout_in_minutes: 70
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
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
|
||||
# CPU tests on ROCm gpu machines are very slow, so we give them more time.
|
||||
- "timeout 60m pytest -sv tests/diffusion -m 'core_model and cpu' --ignore=tests/diffusion/cache/test_teacache_extractors.py --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
- "pytest -sv tests/model_executor -m 'core_model and cpu' --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB"
|
||||
|
||||
- label: "Simple · Diffusion & Model Executor Test (2/2)"
|
||||
agent_pool: mi325_1
|
||||
- label: "Simple · Diffusion Test · Shard %N/%t"
|
||||
agent_pool: mi300_1
|
||||
parallelism: 2
|
||||
depends_on: amd-build
|
||||
timeout_in_minutes: 70
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
# CPU tests on ROCm gpu machines are very slow, so we give them more time.
|
||||
- "timeout 60m pytest -sv tests/model_executor -m 'core_model and cpu' --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
# 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 --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB"
|
||||
|
||||
- label: "Simple · Engine&Entrypoints Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
- "pytest -sv tests/entrypoints tests/engine -m 'core_model and cpu'"
|
||||
|
||||
- label: "Simple · Other Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
timeout_in_minutes: 50
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
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
|
||||
- "timeout 40m pytest -sv tests/diffusion tests/model_executor -m 'core_model and cpu' --ignore=tests/diffusion/cache/test_teacache_extractors.py --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
- "pytest -sv tests/ -m 'core_model and cpu' --ignore=tests/diffusion --ignore=tests/model_executor --ignore=tests/entrypoints --ignore=tests/engine --ignore=tests/diffusion/cache/test_teacache_extractors.py"
|
||||
|
||||
- group: ":card_index_dividers: Diffusion Test"
|
||||
steps:
|
||||
- label: "Diffusion · LoRA Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
artifact_paths:
|
||||
- lora-server.log
|
||||
commands:
|
||||
- timeout 20m pytest -s -v tests/diffusion/lora/test_images_generations_lora.py
|
||||
- pytest -sv tests/diffusion/lora/ -m 'advanced_model and cuda' --run-level "advanced_model" 2>&1 | tee lora-server.log
|
||||
|
||||
- label: "Diffusion Model CPU offloading Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -62,7 +72,7 @@ steps:
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- |
|
||||
timeout 20m bash -c '
|
||||
bash -c '
|
||||
set +e
|
||||
pytest -s -v tests/diffusion/offloader/test_diffusion_cpu_offload.py
|
||||
EXIT1=\$?
|
||||
@@ -72,7 +82,7 @@ steps:
|
||||
'
|
||||
|
||||
- label: "Diffusion Sequence Parallelism Test (Need 4 GPUs)"
|
||||
agent_pool: mi325_4
|
||||
agent_pool: mi300_4
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -84,7 +94,7 @@ steps:
|
||||
|
||||
# merge-only tests
|
||||
- label: "Diffusion Tensor Parallelism Test"
|
||||
agent_pool: mi325_2
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -92,7 +102,7 @@ steps:
|
||||
- pytest -s -v tests/diffusion/distributed/test_tensor_parallel.py
|
||||
|
||||
- label: "Diffusion Model Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -100,7 +110,7 @@ steps:
|
||||
- timeout 30m pytest -s -v tests/e2e/offline_inference/test_z_image.py
|
||||
|
||||
- label: "Diffusion GPU Worker Test"
|
||||
agent_pool: mi325_2
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -108,7 +118,7 @@ steps:
|
||||
- timeout 20m pytest -s -v tests/diffusion/test_diffusion_worker.py
|
||||
|
||||
- label: "Diffusion · Wan22 Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -121,7 +131,7 @@ steps:
|
||||
|
||||
## ISSUE depends on `diffusers` package: https://github.com/huggingface/diffusers/issues/13274
|
||||
# - label: "Audio Generation Model Test"
|
||||
# agent_pool: mi325_1
|
||||
# agent_pool: mi300_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
@@ -132,7 +142,7 @@ steps:
|
||||
# - 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: "Engine Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -147,7 +157,7 @@ steps:
|
||||
- group: ":card_index_dividers: E2E Test"
|
||||
steps:
|
||||
- label: "Omni Model Test Qwen2-5-Omni"
|
||||
agent_pool: mi325_4
|
||||
agent_pool: mi300_4
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
commands:
|
||||
@@ -155,7 +165,7 @@ steps:
|
||||
- pytest -s -v tests/e2e/*/test_qwen2_5_omni_expansion.py --run-level "core_model"
|
||||
|
||||
- label: "Omni Model Test Qwen3-Omni"
|
||||
agent_pool: mi325_2
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -163,22 +173,23 @@ steps:
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- pytest -s -v tests/e2e/offline_inference/test_qwen3_omni.py tests/e2e/online_serving/test_qwen3_omni.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
|
||||
- label: "Qwen3-TTS CustomVoice E2E Test"
|
||||
agent_pool: mi325_1
|
||||
- label: "Qwen3-TTS CustomVoice E2E Test · Shard %N/%t"
|
||||
agent_pool: mi300_1
|
||||
parallelism: 2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- |
|
||||
timeout 50m bash -c '
|
||||
bash -c '
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen3_tts_customvoice.py tests/e2e/offline_inference/test_qwen3_tts_customvoice.py -m "advanced_model" --run-level "advanced_model"
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen3_tts_customvoice.py tests/e2e/offline_inference/test_qwen3_tts_customvoice.py -m "advanced_model" --run-level "advanced_model" --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB
|
||||
'
|
||||
|
||||
- label: "Qwen3-TTS Base E2E Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -196,7 +207,7 @@ steps:
|
||||
# Need to debug before reneable numerical changes across large PRs
|
||||
# # split Bagel Model Test with H100 (Real Weights) into three tests
|
||||
# - label: "Bagel Text2Img Model Test (1/3)"
|
||||
# agent_pool: mi325_1
|
||||
# agent_pool: mi300_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
@@ -208,7 +219,7 @@ steps:
|
||||
# - timeout 30m pytest -s -v tests/e2e/offline_inference/test_bagel.py -m "advanced_model" --run-level "advanced_model" -k "shared_memory" -k "rocm"
|
||||
|
||||
# - label: "Bagel Img2Img Model Test (2/3)"
|
||||
# agent_pool: mi325_1
|
||||
# agent_pool: mi300_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
@@ -220,7 +231,7 @@ steps:
|
||||
# - timeout 30m pytest -s -v tests/e2e/offline_inference/test_bagel.py -m "advanced_model" --run-level "advanced_model" -k "rocm"
|
||||
|
||||
# - label: "Bagel Online Serving Test (3/3)"
|
||||
# agent_pool: mi325_1
|
||||
# agent_pool: mi300_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
|
||||
@@ -7,8 +7,9 @@ steps:
|
||||
|
||||
- group: ":card_index_dividers: Simple Test"
|
||||
steps:
|
||||
- label: "Simple · Diffusion & Model Executor Test"
|
||||
agent_pool: mi325_1
|
||||
- label: "Simple · Model Executor Test · Shard %N/%t"
|
||||
agent_pool: mi300_1
|
||||
parallelism: 2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -16,10 +17,30 @@ steps:
|
||||
- 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
|
||||
- "timeout 40m pytest -sv tests/diffusion tests/model_executor -m 'core_model and cpu' --ignore=tests/diffusion/cache/test_teacache_extractors.py --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
- "pytest -sv tests/model_executor -m 'core_model and cpu' --num-shards=$$BUILDKITE_PARALLEL_JOB_COUNT --shard-id=$$BUILDKITE_PARALLEL_JOB"
|
||||
|
||||
- label: "Simple · Diffusion Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
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"
|
||||
|
||||
- label: "Simple · Engine&Entrypoints Test"
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_ROCM_USE_AITER=0
|
||||
- "pytest -sv tests/entrypoints tests/engine -m 'core_model and cpu'"
|
||||
|
||||
- label: "Simple · Other Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -27,19 +48,19 @@ steps:
|
||||
- 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
|
||||
- "timeout 40m pytest -sv tests/diffusion tests/model_executor -m 'core_model and cpu' --ignore=tests/diffusion/cache/test_teacache_extractors.py --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
- "pytest -sv tests/ -m 'core_model and cpu' --ignore=tests/diffusion --ignore=tests/model_executor --ignore=tests/entrypoints --ignore=tests/engine --ignore=tests/diffusion/cache/test_teacache_extractors.py"
|
||||
|
||||
- label: "Custom Pipeline Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- timeout 20m pytest -s -v tests/e2e/features/custom_pipeline/ -m "core_model"
|
||||
- pytest -s -v tests/e2e/features/custom_pipeline/ -m "core_model"
|
||||
|
||||
|
||||
- label: "Voxtral TTS CUDA Unit Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -49,33 +70,25 @@ steps:
|
||||
- group: ":card_index_dividers: Diffusion Test"
|
||||
steps:
|
||||
- label: "Diffusion · Batch Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- timeout 20m pytest -sv tests/diffusion/batching -m 'core_model and cuda' --run-level "core_model"
|
||||
- pytest -sv tests/diffusion/batching -m 'core_model and cuda' --run-level "core_model"
|
||||
|
||||
- label: "Diffusion · Offloader Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
commands:
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- |
|
||||
timeout 20m bash -c '
|
||||
set +e
|
||||
pytest -s -v tests/diffusion/offloader/test_diffusion_cpu_offload.py
|
||||
EXIT1=\$?
|
||||
pytest -s -v tests/diffusion/offloader/test_diffusion_layerwise_offload.py
|
||||
EXIT2=\$?
|
||||
exit \$((EXIT1 | EXIT2))
|
||||
'
|
||||
- pytest -s -v tests/diffusion/offloader -m "core_model and cuda" --run-level "core_model"
|
||||
|
||||
- label: "Diffusion · Cache Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -83,10 +96,10 @@ steps:
|
||||
- export GPU_ARCHS=gfx942
|
||||
- export VLLM_LOGGING_LEVEL=DEBUG
|
||||
- export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
- timeout 15m pytest -s -v -m "core_model and cache and diffusion and not distributed_cuda and L4"
|
||||
- pytest -sv tests/diffusion/cache -m 'core_model and cuda' --run-level "core_model"
|
||||
|
||||
- label: "Diffusion Sequence Parallelism Test"
|
||||
agent_pool: mi325_2
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -96,7 +109,7 @@ steps:
|
||||
- timeout 20m pytest -s -v tests/diffusion/distributed/test_sequence_parallel.py -m core_model
|
||||
|
||||
- label: "Diffusion GPU Worker Test"
|
||||
agent_pool: mi325_2
|
||||
agent_pool: mi300_2
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -104,7 +117,7 @@ steps:
|
||||
- timeout 20m pytest -s -v tests/diffusion/test_diffusion_worker.py
|
||||
|
||||
- label: "Diffusion · Model Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -112,7 +125,7 @@ steps:
|
||||
- timeout 15m pytest -sv tests/diffusion/models/ -m 'core_model and cuda' --run-level "core_model"
|
||||
|
||||
- label: "Diffusion · Wan22 Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -126,7 +139,7 @@ steps:
|
||||
|
||||
## ISSUE depends on `diffusers` package: https://github.com/huggingface/diffusers/issues/13274
|
||||
# - label: "Audio Generation Model Test"
|
||||
# agent_pool: mi325_1
|
||||
# agent_pool: mi300_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
@@ -137,7 +150,7 @@ steps:
|
||||
# - 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: "Engine Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -149,7 +162,7 @@ steps:
|
||||
'
|
||||
|
||||
# - label: "Omni Model Test Qwen3-Omni"
|
||||
# agent_pool: mi325_2
|
||||
# agent_pool: mi300_2
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
@@ -162,7 +175,7 @@ steps:
|
||||
- group: ":card_index_dividers: E2E Test"
|
||||
steps:
|
||||
- label: "Qwen3-TTS E2E Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -173,7 +186,7 @@ steps:
|
||||
- timeout 30m pytest -s -v tests/e2e/online_serving/test_qwen3_tts_customvoice.py -m "core_model" --run-level "core_model"
|
||||
|
||||
- label: "CosyVoice3-TTS E2E Test"
|
||||
agent_pool: mi325_1
|
||||
agent_pool: mi300_1
|
||||
depends_on: amd-build
|
||||
mirror_hardwares: [amdproduction]
|
||||
grade: Blocking
|
||||
@@ -186,7 +199,7 @@ steps:
|
||||
# TODO: Bagel test on ROCm is very unstable. @tjtanaa
|
||||
# Need to debug before reneable numerical changes across large PRs
|
||||
# - label: "Bagel Text2Img Model Test"
|
||||
# agent_pool: mi325_1
|
||||
# agent_pool: mi300_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
@@ -198,7 +211,7 @@ steps:
|
||||
# - timeout 30m pytest -s -v tests/e2e/offline_inference/test_bagel.py -m "core_model" --run-level "core_model" -k "rocm"
|
||||
|
||||
# - label: "Bagel Img2Img Model Test"
|
||||
# agent_pool: mi325_1
|
||||
# agent_pool: mi300_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
@@ -210,7 +223,7 @@ steps:
|
||||
# - timeout 30m pytest -s -v tests/e2e/offline_inference/test_bagel.py -m "core_model" --run-level "core_model" -k "rocm"
|
||||
|
||||
# - label: "Bagel Online Serving Test"
|
||||
# agent_pool: mi325_1
|
||||
# agent_pool: mi300_1
|
||||
# depends_on: amd-build
|
||||
# mirror_hardwares: [amdproduction]
|
||||
# grade: Blocking
|
||||
|
||||
@@ -1,11 +1,65 @@
|
||||
{# vllm-omni customized version
|
||||
Based on: https://github.com/vllm-project/ci-infra/blob/main/buildkite/test-template-amd.j2
|
||||
Last synced: 2025-12-15
|
||||
Modifications: Removed unused CUDA/NVIDIA logic, keeping only AMD tests
|
||||
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 default_working_dir = "/app/vllm-omni" %}
|
||||
|
||||
{# MI300 runs tests natively in Kubernetes; Docker-in-Docker is unavailable. #}
|
||||
{% macro amd_native_k8s_plugin(indent, step) -%}
|
||||
{{ indent }}plugins:
|
||||
{{ indent }} - kubernetes:
|
||||
{{ indent }} podSpecPatch:
|
||||
{{ indent }} automountServiceAccountToken: false
|
||||
{{ indent }} securityContext:
|
||||
{{ indent }} seccompProfile:
|
||||
{{ indent }} type: RuntimeDefault
|
||||
{{ indent }} imagePullSecrets:
|
||||
{{ indent }} - name: docker-config
|
||||
{{ indent }} containers:
|
||||
{{ indent }} - name: container-0
|
||||
{{ indent }} image: {{ docker_image_amd }}
|
||||
{{ indent }} imagePullPolicy: Always
|
||||
{{ indent }} securityContext:
|
||||
{{ indent }} allowPrivilegeEscalation: false
|
||||
{{ indent }} capabilities:
|
||||
{{ indent }} add:
|
||||
{{ indent }} - IPC_LOCK
|
||||
{{ indent }} resources:
|
||||
{{ indent }} limits:
|
||||
{{ indent }} amd.com/gpu: "{{ step.agent_pool[-1:] }}"
|
||||
{{ indent }} requests:
|
||||
{{ indent }} amd.com/gpu: "{{ step.agent_pool[-1:] }}"
|
||||
{{ indent }} volumeMounts:
|
||||
{{ indent }} - name: devshm
|
||||
{{ indent }} mountPath: /dev/shm
|
||||
{{ indent }} env:
|
||||
{{ indent }} - name: AMD_CI_RUNTIME
|
||||
{{ indent }} value: native
|
||||
{{ indent }} - name: NATIVE_CI
|
||||
{{ indent }} value: "true"
|
||||
{{ indent }} - name: VLLM_CI_DOCKER_DISABLED
|
||||
{{ indent }} value: "1"
|
||||
{{ indent }} - name: VLLM_CI_EXPECTED_GPU_COUNT
|
||||
{{ indent }} value: "{{ step.agent_pool[-1:] }}"
|
||||
{{ indent }} - name: HF_HOME
|
||||
{{ indent }} value: /home/buildkite-agent/huggingface
|
||||
{{ indent }} - name: MIOPEN_DEBUG_CONV_DIRECT
|
||||
{{ indent }} value: "0"
|
||||
{{ indent }} - name: MIOPEN_DEBUG_CONV_GEMM
|
||||
{{ indent }} value: "0"
|
||||
{{ indent }} - name: VLLM_ROCM_USE_AITER
|
||||
{{ indent }} value: "0"
|
||||
{{ indent }} - name: PYTORCH_ROCM_ARCH
|
||||
{{ indent }} value: ""
|
||||
{{ indent }} volumes:
|
||||
{{ indent }} - name: devshm
|
||||
{{ indent }} emptyDir:
|
||||
{{ indent }} medium: Memory
|
||||
{{ indent }} sizeLimit: 16Gi
|
||||
{%- endmacro %}
|
||||
|
||||
{% if env %}
|
||||
env:
|
||||
{% for name in env %}
|
||||
@@ -53,19 +107,31 @@ steps:
|
||||
{% if step.agent_pool %}
|
||||
queue: amd_{{ step.agent_pool }}
|
||||
{% else %}
|
||||
queue: amd_mi325_1
|
||||
queue: amd_mi300_1
|
||||
{% endif %}
|
||||
{{ amd_native_k8s_plugin(" ", step) }}
|
||||
{% set cmd_body = (step.command or (step.commands | join("\n"))) | trim %}
|
||||
{% set indented_cmd = cmd_body | replace("\n", "\n ") %}
|
||||
command: bash .buildkite/amd/scripts/run-amd-test.sh
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
AMD_CI_RUNTIME: "native"
|
||||
NATIVE_CI: "true"
|
||||
VLLM_CI_DOCKER_DISABLED: "1"
|
||||
VLLM_CI_EXPECTED_GPU_COUNT: "{{ step.agent_pool[-1:] }}"
|
||||
VLLM_CI_REQUIRE_PERSISTENT_HF_CACHE: "1"
|
||||
HF_HOME: "/home/buildkite-agent/huggingface"
|
||||
HF_HUB_DOWNLOAD_TIMEOUT: "300"
|
||||
HF_HUB_ETAG_TIMEOUT: "60"
|
||||
MIOPEN_DEBUG_CONV_DIRECT: "0"
|
||||
MIOPEN_DEBUG_CONV_GEMM: "0"
|
||||
VLLM_ROCM_USE_AITER: "0"
|
||||
PYTORCH_ROCM_ARCH: ""
|
||||
{% if step.env %}
|
||||
{% for name in step.env %}
|
||||
{{ name }}: "{{ step.env[name] }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
TEST_COMMAND: |-
|
||||
TEST_COMMANDS: |-
|
||||
(command rocm-smi || true) && cd {{ (step.working_dir or default_working_dir) | safe }}
|
||||
{% if env %}
|
||||
{% for name in env %}
|
||||
@@ -82,6 +148,15 @@ steps:
|
||||
{% endif %}
|
||||
{{ indented_cmd | safe }}
|
||||
priority: 100
|
||||
{% if step.parallelism %}
|
||||
parallelism: {{ step.parallelism }}
|
||||
{% endif %}
|
||||
{% if step.artifact_paths %}
|
||||
artifact_paths:
|
||||
{% for path in step.artifact_paths %}
|
||||
- "{{ path }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if step.timeout_in_minutes %}
|
||||
timeout_in_minutes: {{ step.timeout_in_minutes }}
|
||||
{% endif %}
|
||||
@@ -100,19 +175,31 @@ steps:
|
||||
{% if step.agent_pool %}
|
||||
queue: amd_{{ step.agent_pool }}
|
||||
{% else %}
|
||||
queue: amd_mi325_1
|
||||
queue: amd_mi300_1
|
||||
{% endif %}
|
||||
{{ amd_native_k8s_plugin(" ", step) }}
|
||||
{% set cmd_body = (step.command or (step.commands | join("\n"))) | trim %}
|
||||
{% set indented_cmd = cmd_body | replace("\n", "\n ") %}
|
||||
command: bash .buildkite/amd/scripts/run-amd-test.sh
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
AMD_CI_RUNTIME: "native"
|
||||
NATIVE_CI: "true"
|
||||
VLLM_CI_DOCKER_DISABLED: "1"
|
||||
VLLM_CI_EXPECTED_GPU_COUNT: "{{ step.agent_pool[-1:] }}"
|
||||
VLLM_CI_REQUIRE_PERSISTENT_HF_CACHE: "1"
|
||||
HF_HOME: "/home/buildkite-agent/huggingface"
|
||||
HF_HUB_DOWNLOAD_TIMEOUT: "300"
|
||||
HF_HUB_ETAG_TIMEOUT: "60"
|
||||
MIOPEN_DEBUG_CONV_DIRECT: "0"
|
||||
MIOPEN_DEBUG_CONV_GEMM: "0"
|
||||
VLLM_ROCM_USE_AITER: "0"
|
||||
PYTORCH_ROCM_ARCH: ""
|
||||
{% if step.env %}
|
||||
{% for name in step.env %}
|
||||
{{ name }}: "{{ step.env[name] }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
TEST_COMMAND: |-
|
||||
TEST_COMMANDS: |-
|
||||
(command rocm-smi || true) && cd {{ (step.working_dir or default_working_dir) | safe }}
|
||||
{% if env %}
|
||||
{% for name in env %}
|
||||
@@ -129,6 +216,15 @@ steps:
|
||||
{% endif %}
|
||||
{{ indented_cmd | safe }}
|
||||
priority: 100
|
||||
{% if step.parallelism %}
|
||||
parallelism: {{ step.parallelism }}
|
||||
{% endif %}
|
||||
{% if step.artifact_paths %}
|
||||
artifact_paths:
|
||||
{% for path in step.artifact_paths %}
|
||||
- "{{ path }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% if step.timeout_in_minutes %}
|
||||
timeout_in_minutes: {{ step.timeout_in_minutes }}
|
||||
{% endif %}
|
||||
|
||||
@@ -8,7 +8,12 @@
|
||||
# NPU naming: {queue}_{resource_class}
|
||||
# a2b3_npu_1 — ascend-a2b3, resource_class npu-1 (A2/B3 CI image)
|
||||
# a2b3_npu_4 — ascend-a2b3, resource_class npu-4
|
||||
# a3_npu_2 — ascend-a3, resource_class npu-2 (A3 CI image tag …:$BUILDKITE_COMMIT-a3)
|
||||
# a3_npu_2 — ascend-a3, resource_class npu-2
|
||||
#
|
||||
# The ``l4_*`` presets run under the ``docker`` plugin, which does not put
|
||||
# ``buildkite-agent`` on PATH inside the container the way the ``kubernetes``
|
||||
# presets do, so they set ``mount-buildkite-agent: true``; without it any step
|
||||
# calling ``buildkite-agent`` (artifact upload, annotate, meta-data) fails there.
|
||||
|
||||
x-npu-k8s-plugins: &npu_k8s_plugins
|
||||
- kubernetes:
|
||||
@@ -26,6 +31,7 @@ mirror_hardwares:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
mount-buildkite-agent: true
|
||||
shm-size: "8gb"
|
||||
environment:
|
||||
- HF_HOME=/fsx/hf_cache
|
||||
@@ -41,6 +47,7 @@ mirror_hardwares:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
mount-buildkite-agent: true
|
||||
shm-size: "8gb"
|
||||
environment:
|
||||
- HF_HOME=/fsx/hf_cache
|
||||
|
||||
Executable
+98
@@ -0,0 +1,98 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run a model's E2E tests once per entry mode as separate coverage runs and upload
|
||||
# the reports, so per-mode attribution survives (see vllm-project/vllm-omni#5332).
|
||||
#
|
||||
# Usage: run_cov_split.sh --model-id <id> [--offline <paths>] [--online <paths>] \
|
||||
# -- <pytest args...>
|
||||
#
|
||||
# --model-id Names the artifacts: coverage-<id>-{offline,online}-<step id>.xml.gz.
|
||||
# Use the model's directory name under vllm_omni/*/models/.
|
||||
# --offline Pytest path(s) for the offline half. Repeatable.
|
||||
# --online Pytest path(s) for the online half. Repeatable.
|
||||
# -- Everything after this is forwarded verbatim to every pytest run,
|
||||
# quoting preserved: the job's own -m expression, --run-level, and
|
||||
# anything else it needs (e.g. --test-config-file).
|
||||
#
|
||||
# At least one of --offline/--online is required, so a job with only one mode runs
|
||||
# just that half. Total runtime is bounded by the step's timeout_in_minutes.
|
||||
#
|
||||
# Coverage + artifact upload run only on scheduled weekly E2E sweeps
|
||||
# (WEEKLY=1 and BUILDKITE_BRANCH=main — same gate as bootstrap --e2e).
|
||||
# All other invocations (PR merge-test, regular main merge, local) run the
|
||||
# same combined pytest as the job used before coverage was added.
|
||||
#
|
||||
# Exits non-zero if any half or the upload failed.
|
||||
set -uo pipefail
|
||||
|
||||
MODEL_ID=""
|
||||
OFFLINE=()
|
||||
ONLINE=()
|
||||
PYTEST_ARGS=()
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--model-id) MODEL_ID="$2"; shift 2 ;;
|
||||
--offline) OFFLINE+=("$2"); shift 2 ;;
|
||||
--online) ONLINE+=("$2"); shift 2 ;;
|
||||
--) shift; PYTEST_ARGS=("$@"); break ;;
|
||||
*) echo "run_cov_split.sh: unknown argument: $1" >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ -z "${MODEL_ID}" ]]; then
|
||||
echo "run_cov_split.sh: missing --model-id" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if ((${#OFFLINE[@]} == 0 && ${#ONLINE[@]} == 0)); then
|
||||
echo "run_cov_split.sh: need at least one of --offline / --online" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
_should_run_coverage() {
|
||||
[[ "${WEEKLY:-}" == "1" && "${BUILDKITE_BRANCH:-}" == "main" ]]
|
||||
}
|
||||
|
||||
if ! _should_run_coverage; then
|
||||
PATHS=("${OFFLINE[@]}" "${ONLINE[@]}")
|
||||
echo "--- pytest (no coverage): ${MODEL_ID}"
|
||||
pytest -s -v "${PATHS[@]}" "${PYTEST_ARGS[@]}"
|
||||
exit $?
|
||||
fi
|
||||
|
||||
# Two steps can test the same model, and artifacts are scoped to the build (a
|
||||
# nightly one carries the ready, merge and nightly tiers at once), so unsuffixed
|
||||
# reports would share a path -- a glob download then races to rename onto one file.
|
||||
# Not BUILDKITE_JOB_ID: the step id survives retries, so attempts collapse under
|
||||
# Buildkite's latest-attempt lookup instead of accumulating. A parallel step would
|
||||
# need BUILDKITE_PARALLEL_JOB as well; no pilot is one.
|
||||
REPORT_SUFFIX="${BUILDKITE_STEP_ID:-local}"
|
||||
OFFLINE_REPORT="coverage-${MODEL_ID}-offline-${REPORT_SUFFIX}.xml"
|
||||
ONLINE_REPORT="coverage-${MODEL_ID}-online-${REPORT_SUFFIX}.xml"
|
||||
|
||||
run_half() {
|
||||
local mode="$1"
|
||||
shift
|
||||
local report="coverage-${MODEL_ID}-${mode}-${REPORT_SUFFIX}.xml"
|
||||
echo "--- coverage: ${MODEL_ID} ${mode}"
|
||||
pytest -s -v "$@" "${PYTEST_ARGS[@]}" --cov=vllm_omni --cov-report="xml:${report}"
|
||||
local status=$?
|
||||
# Cobertura lists every statement in vllm_omni whether or not it ran, so the
|
||||
# report is ~7MB no matter how little the job covers. The repetition is what
|
||||
# dominates it, and gzip takes that to ~400KB.
|
||||
gzip -9 -f "${report}" || status=1
|
||||
return "${status}"
|
||||
}
|
||||
|
||||
# Clear both modes, not just the ones being run: the upload glob matches both, so
|
||||
# a report left by an earlier run would otherwise be published as if the mode it
|
||||
# belongs to had run this time.
|
||||
rm -f "${OFFLINE_REPORT}" "${ONLINE_REPORT}" "${OFFLINE_REPORT}.gz" "${ONLINE_REPORT}.gz"
|
||||
|
||||
EXIT=0
|
||||
((${#OFFLINE[@]})) && { run_half offline "${OFFLINE[@]}" || EXIT=1; }
|
||||
((${#ONLINE[@]})) && { run_half online "${ONLINE[@]}" || EXIT=1; }
|
||||
|
||||
buildkite-agent artifact upload "coverage-${MODEL_ID}-*-${REPORT_SUFFIX}.xml.gz" || EXIT=1
|
||||
|
||||
exit "${EXIT}"
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
"""Render and optionally upload Buildkite pipeline YAML with diff-aware logic.
|
||||
|
||||
Bootstrap mode (``bootstrap-upload-steps.yml``):
|
||||
@@ -58,11 +59,12 @@ BOOTSTRAP_UPLOAD_IF_KEYS = {
|
||||
E2E_GROUP_MARKER = "E2E Test"
|
||||
CI_MIRROR_HARDWARES_PATH = ROOT / ".buildkite/common/ci_mirror_hardwares.yml"
|
||||
|
||||
CUDA_NIGHTLY_ONLY = (
|
||||
'(build.pull_request.labels includes "nightly-test") || (build.branch == "main" && build.env("NIGHTLY") == "1")'
|
||||
)
|
||||
NPU_NIGHTLY_ONLY = (
|
||||
'(build.branch == "main" && build.env("NIGHTLY") == "1") || '
|
||||
# Bootstrap Buildkite ``if`` expressions.
|
||||
# ``*_MAIN_IF``: main + env schedule. ``*_LABEL_IF``: PR label (and/or composed with MAIN).
|
||||
# ``*_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" || '
|
||||
@@ -71,6 +73,19 @@ NPU_NIGHTLY_ONLY = (
|
||||
'build.pull_request.labels includes "diffusion-x2v-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")'
|
||||
WEEKLY_LABEL_IF = f'({WEEKLY_MAIN_IF}) || (build.branch != "main" && build.pull_request.labels includes "weekly-test")'
|
||||
READY_LABEL_IF = 'build.branch != "main" && build.pull_request.labels includes "ready"'
|
||||
MERGE_LABEL_IF = 'build.branch != "main" && build.pull_request.labels includes "merge-test"'
|
||||
MERGE_MAIN_IF = (
|
||||
'build.branch == "main" && build.env("NIGHTLY") != "1" && '
|
||||
'build.env("WEEKLY") != "1" && build.env("NON_CRITICAL") != "1"'
|
||||
)
|
||||
READY_UPLOAD_IF = f"({WEEKLY_E2E_IF}) || ({READY_LABEL_IF})"
|
||||
MERGE_UPLOAD_IF = f"({WEEKLY_E2E_IF}) || (({MERGE_MAIN_IF}) || ({MERGE_LABEL_IF}))"
|
||||
BOOTSTRAP_DISABLED_IF = "false"
|
||||
BOOTSTRAP_ENABLED_IF = "true"
|
||||
|
||||
|
||||
# --- Logging ---
|
||||
@@ -102,74 +117,47 @@ def _format_bootstrap_if(expr: str) -> str:
|
||||
|
||||
|
||||
def _compute_bootstrap_if_exprs(*, decision, platform: str) -> dict[str, str]:
|
||||
disabled = "false"
|
||||
nightly_main = 'build.branch == "main" && build.env("NIGHTLY") == "1"'
|
||||
nightly_only = NPU_NIGHTLY_ONLY if platform == "npu" else CUDA_NIGHTLY_ONLY
|
||||
|
||||
if platform == "npu":
|
||||
ready_pr = (
|
||||
'build.branch != "main" && ('
|
||||
'build.pull_request.labels includes "npu-test" || '
|
||||
'build.pull_request.labels includes "ready"'
|
||||
")"
|
||||
)
|
||||
nightly_label_if = nightly_only
|
||||
weekly_label_if = disabled
|
||||
merge_base = disabled
|
||||
ready_upload = READY_LABEL_IF
|
||||
merge_upload = BOOTSTRAP_DISABLED_IF
|
||||
weekly_label_if = BOOTSTRAP_DISABLED_IF
|
||||
else:
|
||||
ready_pr = 'build.branch != "main" && build.pull_request.labels includes "ready"'
|
||||
merge_main = 'build.branch == "main" && build.env("NIGHTLY") != "1" && build.env("WEEKLY") != "1"'
|
||||
merge_pr = 'build.branch != "main" && build.pull_request.labels includes "merge-test"'
|
||||
nightly_label_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"'
|
||||
"))"
|
||||
)
|
||||
weekly_label_if = (
|
||||
'(build.branch == "main" && build.env("WEEKLY") == "1") || '
|
||||
'(build.branch != "main" && build.pull_request.labels includes "weekly-test")'
|
||||
)
|
||||
merge_base = f"({nightly_main}) || (({merge_main}) || ({merge_pr}))"
|
||||
|
||||
ready_base = f"({nightly_main}) || ({ready_pr})"
|
||||
weekly_main = 'build.branch == "main" && build.env("WEEKLY") == "1"'
|
||||
ready_upload = READY_UPLOAD_IF
|
||||
merge_upload = MERGE_UPLOAD_IF
|
||||
weekly_label_if = WEEKLY_LABEL_IF
|
||||
|
||||
if decision.skip_all:
|
||||
# Docs / skip-mark only: no PR-label escape hatch. Main scheduled
|
||||
# NIGHTLY=1 still runs L4 + L2/L3 (--e2e); WEEKLY=1 still runs L5.
|
||||
image_expr = f"({nightly_main}) || ({weekly_main})" if platform == "cuda" else nightly_main
|
||||
ready_expr = nightly_main
|
||||
merge_expr = nightly_main if platform == "cuda" else disabled
|
||||
nightly_expr = nightly_main
|
||||
weekly_expr = weekly_main if platform == "cuda" else disabled
|
||||
# NIGHTLY=1 still runs L4; WEEKLY=1 / NON_CRITICAL=1 still run L5.
|
||||
# main+WEEKLY=1 also uploads L2/L3 (those steps then pass --e2e).
|
||||
image_expr = f"({NIGHTLY_MAIN_IF}) || ({WEEKLY_MAIN_IF})" if platform == "cuda" else NIGHTLY_MAIN_IF
|
||||
ready_expr = WEEKLY_E2E_IF if platform == "cuda" else BOOTSTRAP_DISABLED_IF
|
||||
merge_expr = WEEKLY_E2E_IF if platform == "cuda" else BOOTSTRAP_DISABLED_IF
|
||||
nightly_expr = NIGHTLY_MAIN_IF
|
||||
weekly_expr = WEEKLY_MAIN_IF if platform == "cuda" else BOOTSTRAP_DISABLED_IF
|
||||
elif decision.skip_l2_l3:
|
||||
l2_enabled = decision.is_run("npu", "l2") if platform == "npu" else decision.is_run("cuda", "l2")
|
||||
l3_enabled = platform == "cuda" and decision.is_run("cuda", "l3")
|
||||
|
||||
ready_expr = ready_base if l2_enabled else disabled
|
||||
merge_expr = merge_base if l3_enabled else disabled
|
||||
nightly_expr = nightly_label_if
|
||||
weekly_expr = weekly_label_if if platform == "cuda" else disabled
|
||||
ready_expr = ready_upload if l2_enabled else BOOTSTRAP_DISABLED_IF
|
||||
merge_expr = merge_upload if l3_enabled else BOOTSTRAP_DISABLED_IF
|
||||
nightly_expr = NIGHTLY_LABEL_IF
|
||||
weekly_expr = weekly_label_if if platform == "cuda" else BOOTSTRAP_DISABLED_IF
|
||||
|
||||
image_parts = [f"({nightly_label_if})"]
|
||||
image_parts = [f"({NIGHTLY_LABEL_IF})"]
|
||||
if platform == "cuda":
|
||||
image_parts.append(f"({weekly_label_if})")
|
||||
if l2_enabled:
|
||||
image_parts.insert(0, f"({ready_base})")
|
||||
image_parts.insert(0, f"({ready_upload})")
|
||||
if l3_enabled:
|
||||
image_parts.insert(1 if l2_enabled else 0, f"({merge_base})")
|
||||
image_parts.insert(1 if l2_enabled else 0, f"({merge_upload})")
|
||||
image_expr = " || ".join(image_parts)
|
||||
else:
|
||||
image_expr = "true"
|
||||
ready_expr = ready_base
|
||||
merge_expr = merge_base if platform == "cuda" else disabled
|
||||
nightly_expr = nightly_label_if
|
||||
weekly_expr = weekly_label_if if platform == "cuda" else disabled
|
||||
image_expr = BOOTSTRAP_ENABLED_IF
|
||||
ready_expr = ready_upload
|
||||
merge_expr = merge_upload if platform == "cuda" else BOOTSTRAP_DISABLED_IF
|
||||
nightly_expr = NIGHTLY_LABEL_IF
|
||||
weekly_expr = weekly_label_if if platform == "cuda" else BOOTSTRAP_DISABLED_IF
|
||||
|
||||
return {
|
||||
"image": _format_bootstrap_if(image_expr),
|
||||
|
||||
@@ -8,28 +8,28 @@ steps:
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
# L2 Test — PR ready label (diff-aware) or main+NIGHTLY=1 (--e2e, full E2E group)
|
||||
# L2 Test — PR ready label (diff-aware) or main+WEEKLY=1 (--e2e, full E2E group)
|
||||
- label: "Upload Ready Pipeline"
|
||||
depends_on: image-build
|
||||
key: upload-ready-pipeline
|
||||
commands:
|
||||
- |
|
||||
EXTRA=""
|
||||
if [ "${NIGHTLY:-}" = "1" ] && [ "${BUILDKITE_BRANCH}" = "main" ]; then
|
||||
if [ "${WEEKLY:-}" = "1" ] && [ "${BUILDKITE_BRANCH}" = "main" ]; then
|
||||
EXTRA="--e2e"
|
||||
fi
|
||||
python3 .buildkite/common/scripts/upload_pipeline.py --upload $$EXTRA .buildkite/cuda/test-ready.yml
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
# L3 Test — PR merge-test label (diff-aware) or main+NIGHTLY=1 (--e2e, full E2E group)
|
||||
# L3 Test — PR merge-test label (diff-aware) or main+WEEKLY=1 (--e2e, full E2E group)
|
||||
- label: "Upload Merge Pipeline"
|
||||
depends_on: image-build
|
||||
key: upload-merge-pipeline
|
||||
commands:
|
||||
- |
|
||||
EXTRA=""
|
||||
if [ "${NIGHTLY:-}" = "1" ] && [ "${BUILDKITE_BRANCH}" = "main" ]; then
|
||||
if [ "${WEEKLY:-}" = "1" ] && [ "${BUILDKITE_BRANCH}" = "main" ]; then
|
||||
EXTRA="--e2e"
|
||||
fi
|
||||
python3 .buildkite/common/scripts/upload_pipeline.py --upload $$EXTRA .buildkite/cuda/test-merge.yml
|
||||
@@ -45,7 +45,7 @@ steps:
|
||||
agents:
|
||||
queue: "cpu_queue_premerge"
|
||||
|
||||
# L5 Test — main+WEEKLY=1 (scheduled), or PR with weekly-test label
|
||||
# L5 Test — main+WEEKLY=1 / NON_CRITICAL=1 (scheduled), or PR with weekly-test label
|
||||
- label: "Upload Weekly Pipeline"
|
||||
depends_on: image-build
|
||||
key: upload-weekly-pipeline
|
||||
|
||||
@@ -9,23 +9,27 @@ steps:
|
||||
depends_on: upload-merge-pipeline
|
||||
steps:
|
||||
- label: "Simple · Model Executor Test"
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- "timeout 20m pytest -sv tests/model_executor -m 'core_model and cpu' --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
- "pytest -sv tests/model_executor -m 'core_model and cpu'"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Simple · Diffusion Test"
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- "timeout 20m pytest -sv tests/diffusion -m 'core_model and cpu' --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
- "pytest -sv tests/diffusion -m 'core_model and cpu'"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Simple · Engine&Entrypoints Test"
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- "timeout 20m pytest -sv tests/entrypoints tests/engine -m 'core_model and cpu' --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
- "pytest -sv tests/entrypoints tests/engine -m 'core_model and cpu'"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Simple · Other Test"
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- "timeout 20m pytest -sv tests/ -m 'core_model and cpu' --ignore=tests/diffusion --ignore=tests/model_executor --ignore=tests/entrypoints --ignore=tests/engine --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
- "pytest -sv tests/ -m 'core_model and cpu' --ignore=tests/diffusion --ignore=tests/model_executor --ignore=tests/entrypoints --ignore=tests/engine"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- group: ":card_index_dividers: Diffusion Test"
|
||||
@@ -76,6 +80,9 @@ steps:
|
||||
- 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
|
||||
commands:
|
||||
@@ -92,38 +99,37 @@ steps:
|
||||
- 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
|
||||
- .buildkite/common/scripts/run_cov_split.sh
|
||||
- pyproject.toml
|
||||
# 40 -> 60: the coverage split runs the model twice.
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_ALLOW_LONG_MAX_MODEL_LEN=1
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen3_tts_base.py tests/e2e/offline_inference/test_qwen3_tts_base.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "TTS · Higgs-Audio-V3 Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_higgs_audio_v3.py
|
||||
- vllm_omni/model_executor/models/higgs_audio_v3/
|
||||
- vllm_omni/model_executor/stage_input_processors/higgs_audio_v3.py
|
||||
- vllm_omni/deploy/higgs_multimodal_qwen3.yaml
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
export VLLM_USE_DEEP_GEMM=0
|
||||
export VLLM_MOE_USE_DEEP_GEMM=0
|
||||
pytest -s -v tests/e2e/online_serving/test_higgs_audio_v3.py -m 'advanced_model' --run-level 'advanced_model'
|
||||
"
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_ALLOW_LONG_MAX_MODEL_LEN=1
|
||||
.buildkite/common/scripts/run_cov_split.sh \
|
||||
--model-id qwen3_tts \
|
||||
--offline tests/e2e/offline_inference/test_qwen3_tts_base.py \
|
||||
--online tests/e2e/online_serving/test_qwen3_tts_base.py \
|
||||
-- -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Omni · Qwen3-Omni Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/offline_inference/test_qwen3_omni.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
|
||||
timeout_in_minutes: 50
|
||||
@@ -135,10 +141,20 @@ steps:
|
||||
source_file_dependencies:
|
||||
- tests/e2e/offline_inference/test_minicpmo_4_5.py
|
||||
- tests/e2e/online_serving/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
|
||||
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'
|
||||
# h100_2, not h100_1: advanced_model asserts transcribe every audio
|
||||
# response with Whisper, and tests/helpers/media.py only uses an
|
||||
# accelerator for Whisper when a spare GPU exists. On a single card it
|
||||
# grades on CPU: ~8-10 min per clip vs ~30 s, which alone overruns the
|
||||
# 50-minute job timeout (build 2956).
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Omni · MiniCPM-o 4.5 Duplex Test"
|
||||
@@ -148,65 +164,38 @@ steps:
|
||||
- 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/minicpmo_realtime_duplex_scenarios.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_soft_interrupt.py
|
||||
- tests/helpers/minicpmo_4_5_duplex.py
|
||||
- vllm_omni/deploy/minicpmo_4_5.yaml
|
||||
- tests/e2e/online_serving/helpers/minicpmo_4_5_duplex.py
|
||||
- vllm_omni/deploy/minicpmo_4_5_duplex.yaml
|
||||
- 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
|
||||
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'
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "TTS · VoxCPM2 Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/offline_inference/test_voxcpm2_tts.py
|
||||
- tests/e2e/online_serving/test_voxcpm2_tts.py
|
||||
- vllm_omni/model_executor/models/voxcpm2/
|
||||
- vllm_omni/deploy/voxcpm2.yaml
|
||||
timeout_in_minutes: 30
|
||||
commands:
|
||||
- |
|
||||
timeout 30m bash -c "
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
pytest -s -v tests/e2e/offline_inference/test_voxcpm2_tts.py tests/e2e/online_serving/test_voxcpm2_tts.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Diffusion · Qwen Image Edit Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_qwen_image_edit.py
|
||||
- vllm_omni/diffusion/models/qwen_image/
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_qwen_image_edit.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
mirror_hardwares: h100_1
|
||||
- label: "Diffusion · Bagel Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/offline_inference/test_bagel.py
|
||||
- tests/e2e/online_serving/test_bagel.py
|
||||
- vllm_omni/model_executor/models/bagel/
|
||||
- vllm_omni/diffusion/models/bagel/
|
||||
- vllm_omni/model_executor/stage_input_processors/bagel.py
|
||||
- vllm_omni/deploy/bagel.yaml
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/offline_inference/test_bagel.py tests/e2e/online_serving/test_bagel.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
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
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c '
|
||||
@@ -215,23 +204,12 @@ steps:
|
||||
'
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Qwen Image Layered Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_qwen_image_layered.py
|
||||
- vllm_omni/diffusion/models/qwen_image/
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen_image_layered.py -m 'advanced_model and cuda' --run-level 'advanced_model'
|
||||
"
|
||||
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/
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
@@ -239,21 +217,3 @@ steps:
|
||||
pytest -s -v tests/e2e/offline_inference/test_wan22_t2v.py tests/e2e/online_serving/test_wan22_t2v.py -m 'advanced_model and cuda and diffusion' --run-level 'advanced_model'
|
||||
"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Z Image Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/offline_inference/test_z_image.py
|
||||
- tests/e2e/online_serving/test_z_image.py
|
||||
- vllm_omni/diffusion/models/z_image/
|
||||
timeout_in_minutes: 30
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/offline_inference/test_z_image.py tests/e2e/online_serving/test_z_image.py -m 'advanced_model and cuda and diffusion' --run-level 'advanced_model'
|
||||
mirror_hardwares: l4_1
|
||||
- label: "Diffusion · FLUX.2 Klein Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/offline_inference/test_flux2_klein.py
|
||||
- vllm_omni/diffusion/models/flux2_klein/
|
||||
timeout_in_minutes: 30
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/offline_inference/test_flux2_klein.py -m 'advanced_model and cuda and diffusion' --run-level 'advanced_model'
|
||||
mirror_hardwares: l4_1
|
||||
@@ -22,7 +22,7 @@ steps:
|
||||
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" --run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: Omni · Doc Test with L4"
|
||||
timeout_in_minutes: 90
|
||||
@@ -50,6 +50,19 @@ steps:
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Accuracy Test"
|
||||
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
|
||||
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"
|
||||
key: nightly-omni-performance-no-async-chunk
|
||||
timeout_in_minutes: 300
|
||||
@@ -76,31 +89,31 @@ steps:
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Omni · Perf Test · vLLM Text"
|
||||
key: nightly-omni-performance-vllm-text
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Perf Test"
|
||||
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_qwen3_omni_vllm_text.json
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_2
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: Omni · Perf Test · Multi-Replica"
|
||||
key: nightly-omni-performance-multi-replicas
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Duplex Seed-TTS Perf Test"
|
||||
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_qwen3_omni_multi_replicas.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
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_3
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: Omni · Multi-Replica Startup Test with 4x H100"
|
||||
timeout_in_minutes: 45
|
||||
@@ -120,19 +133,7 @@ steps:
|
||||
- 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 --ignore=tests/e2e/online_serving/test_voxcpm2_tts_expansion.py
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: ":full_moon: TTS · Accuracy Test · VoxCPM2"
|
||||
timeout_in_minutes: 30
|
||||
commands:
|
||||
- |
|
||||
timeout 30m bash -c "
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
export VLLM_ALLOW_LONG_MAX_MODEL_LEN=1
|
||||
pytest -s -v tests/e2e/online_serving/test_voxcpm2_tts_expansion.py -m 'full_model and cuda and tts' --run-level 'full_model'
|
||||
"
|
||||
- pytest -s -v tests/e2e/ -m "full_model and L4 and tts" --run-level "full_model" --ignore=tests/e2e/accuracy
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: ":full_moon: TTS · Perf Test"
|
||||
@@ -149,35 +150,6 @@ steps:
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: TTS · VoxCPM2 · Perf Test"
|
||||
key: nightly-tts-performance-voxcpm2
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- 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_voxcpm2.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: TTS · Higgs-Audio-V3 · Perf Test"
|
||||
key: nightly-tts-performance-higgs-audio-v3
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- export VLLM_USE_DEEP_GEMM="0"
|
||||
- export VLLM_MOE_USE_DEEP_GEMM="0"
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_higgs_audio_v3.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- group: ":card_index_dividers: Tiny Model Tests [Multi-GPU]"
|
||||
key: nightly-tiny-model-test-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
@@ -207,8 +179,7 @@ steps:
|
||||
build.pull_request.labels includes "nightly-test" ||
|
||||
build.pull_request.labels includes "diffusion-x2iat-test"
|
||||
steps:
|
||||
# Use explicit file shards so single-card cases do not reserve 2+ GPUs,
|
||||
# and Bagel feature coverage is not duplicated via a broad tests/e2e sweep.
|
||||
# Use explicit file shards so single-card cases do not reserve 2+ GPUs.
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Function Test with H100 · Single-GPU"
|
||||
timeout_in_minutes: 120
|
||||
@@ -216,15 +187,6 @@ steps:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_qwen_image_expansion.py
|
||||
tests/e2e/online_serving/test_qwen_image_edit_expansion.py
|
||||
tests/e2e/online_serving/test_qwen_image_layered_expansion.py
|
||||
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
|
||||
tests/e2e/online_serving/test_bagel_expansion.py
|
||||
tests/e2e/online_serving/test_krea2_expansion.py
|
||||
tests/e2e/offline_inference/test_krea2_expansion.py
|
||||
-m "full_model and diffusion and H100 and not distributed_cuda"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
@@ -235,47 +197,14 @@ steps:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_qwen_image_expansion.py
|
||||
tests/e2e/online_serving/test_qwen_image_edit_expansion.py
|
||||
tests/e2e/offline_inference/test_krea2_expansion.py
|
||||
-m "full_model and diffusion and H100 and distributed_cuda"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Function Test with H100 · Multi-GPU Layered/LongCat/FLUX"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_qwen_image_layered_expansion.py
|
||||
-m "full_model and diffusion and H100 and distributed_cuda"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Function Test with H100 · Multi-GPU Bagel"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_bagel_expansion.py
|
||||
-m "full_model and diffusion and H100 and distributed_cuda"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · GLM-Image Function Test with H100"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
tests/e2e/online_serving/test_glm_image_expansion.py
|
||||
tests/e2e/offline_inference/test_glm_image_autoround_w4a16_expansion.py
|
||||
-m "full_model and diffusion and H100"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Function Test with L4"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- pytest -sv tests/e2e/ -k "not test_wan and not test_bagel_expansion and not hunyuan" -m "full_model and diffusion and L4" --run-level "full_model" --ignore=tests/e2e/accuracy
|
||||
- pytest -sv tests/e2e/ -k "not test_wan and not hunyuan" -m "full_model and diffusion and L4" --run-level "full_model" --ignore=tests/e2e/accuracy
|
||||
mirror_hardwares: l4_4
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Doc Test"
|
||||
@@ -288,7 +217,7 @@ steps:
|
||||
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_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
|
||||
|
||||
@@ -300,13 +229,19 @@ steps:
|
||||
- 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
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Perf Test · Qwen-Image"
|
||||
key: nightly-diffusion-x2iat-performance-qwen-image
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- export DIFFUSION_ATTENTION_BACKEND=FLASH_ATTN
|
||||
- export CACHE_DIT_VERSION=1.3.0
|
||||
- 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
|
||||
@@ -316,70 +251,6 @@ steps:
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_4
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Perf Test · Qwen-Image-Edit"
|
||||
key: nightly-diffusion-x2iat-performance-qwen-image-edit
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- export DIFFUSION_ATTENTION_BACKEND=FLASH_ATTN
|
||||
- export CACHE_DIT_VERSION=1.3.0
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen_image_edit_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
|
||||
mirror_hardwares: h100_4
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Perf Test · Qwen-Image-Edit-2511"
|
||||
key: nightly-diffusion-x2iat-performance-qwen-image-edit-2511
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- export DIFFUSION_ATTENTION_BACKEND=FLASH_ATTN
|
||||
- export CACHE_DIT_VERSION=1.3.0
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen_image_edit_2511_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
|
||||
mirror_hardwares: h100_4
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Perf Test · Qwen-Image-Layered"
|
||||
key: nightly-diffusion-x2iat-performance-qwen-image-layered
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- export DIFFUSION_ATTENTION_BACKEND=FLASH_ATTN
|
||||
- export CACHE_DIT_VERSION=1.3.0
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_qwen_image_layered_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
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Perf Test · BAGEL"
|
||||
key: nightly-diffusion-x2iat-performance-bagel
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- export DIFFUSION_ATTENTION_BACKEND=FLASH_ATTN
|
||||
- export CACHE_DIT_VERSION=1.3.0
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_bagel_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
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- group: ":card_index_dividers: Diffusion X2V Model Test"
|
||||
key: nightly-diffusion-x2v-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
@@ -401,12 +272,6 @@ steps:
|
||||
- pytest -s -v tests/e2e/online_serving/test_wan22_expansion.py -k "i2v" -m "full_model and cuda" --run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · LingBot Video MoE Function Test"
|
||||
timeout_in_minutes: 90
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_lingbot_video_moe.py -k "video_generation" -m "full_model and cuda" --run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Doc Test"
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
@@ -417,7 +282,6 @@ steps:
|
||||
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"
|
||||
- pytest -s -v tests/e2e/online_serving/test_wan_2_1_vace_expansion.py tests/e2e/online_serving/test_ltx2_expansion.py -m "full_model and cuda" --run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Wan2.2 Accuracy Test"
|
||||
@@ -427,10 +291,10 @@ steps:
|
||||
- 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
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · MiniMax H3 T2VA Accuracy Test"
|
||||
- label: ":full_moon: Diffusion X2V · MiniMax H3 I2VA/Ref2VA Accuracy Test"
|
||||
timeout_in_minutes: 180
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/accuracy/minimax_h3/test_minimax_h3_t2va_similarity.py -m full_model --run-level full_model
|
||||
- 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
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Other Accuracy Test"
|
||||
@@ -438,8 +302,6 @@ steps:
|
||||
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
|
||||
- pytest -s -v 'tests/e2e/accuracy/ltx/test_ltx_official_similarity.py::test_ltx_one_stage_matches_official[ltx2_3_i2v]' -m full_model --run-level full_model
|
||||
- pytest -s -v tests/e2e/accuracy/test_video_streaming_output_similarity.py -m full_model --run-level full_model
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Diffusion X2V · Perf Test"
|
||||
@@ -517,16 +379,6 @@ steps:
|
||||
- pytest -sv tests/diffusion/quantization -m 'full_model and cuda and L4' --run-level "full_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: ":bar_chart: Testcase Statistics"
|
||||
key: nightly-testcase-statistics
|
||||
timeout_in_minutes: 120
|
||||
depends_on: upload-nightly-pipeline
|
||||
if: build.env("NIGHTLY") == "1"
|
||||
commands:
|
||||
- python tools/nightly/buildkite_testcase_statistics.py -o tests/dfx/perf/results/buildkite_testcase_statistics.html
|
||||
- buildkite-agent artifact upload "tests/dfx/perf/results/*.html"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
# NOTE: ":email: Nightly Collection & Email" is deprecated and will be removed soon.
|
||||
# Do not add new depends_on entries or extend this step.
|
||||
- label: ":email: Nightly Collection & Email"
|
||||
@@ -534,35 +386,19 @@ steps:
|
||||
depends_on:
|
||||
- nightly-omni-performance-no-async-chunk
|
||||
- nightly-omni-performance-async-chunk
|
||||
- nightly-omni-performance-vllm-text
|
||||
- nightly-omni-performance-multi-replicas
|
||||
- nightly-tts-performance
|
||||
- nightly-tts-performance-higgs-audio-v3
|
||||
- nightly-diffusion-x2iat-performance-qwen-image
|
||||
- nightly-diffusion-x2iat-performance-qwen-image-edit
|
||||
- nightly-diffusion-x2iat-performance-qwen-image-edit-2511
|
||||
- nightly-diffusion-x2iat-performance-qwen-image-layered
|
||||
- nightly-diffusion-x2iat-performance-bagel
|
||||
- nightly-diffusion-x2v-performance
|
||||
- nightly-testcase-statistics
|
||||
if: build.env("NIGHTLY") == "1" && build.env("EMAIL_DISTRIBUTION") == "1"
|
||||
commands:
|
||||
- pip install openpyxl
|
||||
- export DEFAULT_INPUT_DIR=tests/dfx/perf/results
|
||||
- export DEFAULT_OUTPUT_DIR=tests/dfx/perf/results
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-tts-performance
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-tts-performance-higgs-audio-v3
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-omni-performance-no-async-chunk
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-omni-performance-async-chunk
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-omni-performance-vllm-text
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-omni-performance-multi-replicas
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-diffusion-x2iat-performance-qwen-image
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-diffusion-x2iat-performance-qwen-image-edit
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-diffusion-x2iat-performance-qwen-image-edit-2511
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-diffusion-x2iat-performance-qwen-image-layered
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-diffusion-x2iat-performance-bagel
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.json" . --step nightly-diffusion-x2v-performance
|
||||
- buildkite-agent artifact download "tests/dfx/perf/results/*.html" . --step nightly-testcase-statistics
|
||||
- python tools/nightly/generate_nightly_perf_excel.py
|
||||
- python tools/nightly/generate_nightly_perf_html.py
|
||||
- python tools/nightly/send_nightly_email.py --report-file "tests/dfx/perf/results/*.xlsx, tests/dfx/perf/results/*.html"
|
||||
|
||||
@@ -9,23 +9,27 @@ steps:
|
||||
depends_on: upload-ready-pipeline
|
||||
steps:
|
||||
- label: "Simple · Model Executor Test"
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- "timeout 20m pytest -sv tests/model_executor -m 'core_model and cpu' --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
- "pytest -sv tests/model_executor -m 'core_model and cpu'"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Simple · Diffusion Test"
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- "timeout 20m pytest -sv tests/diffusion -m 'core_model and cpu' --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
- "pytest -sv tests/diffusion -m 'core_model and cpu'"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Simple · Engine&Entrypoints Test"
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- "timeout 20m pytest -sv tests/entrypoints tests/engine -m 'core_model and cpu' --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
- "pytest -sv tests/entrypoints tests/engine -m 'core_model and cpu'"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Simple · Other Test"
|
||||
timeout_in_minutes: 20
|
||||
commands:
|
||||
- "timeout 20m pytest -sv tests/ -m 'core_model and cpu' --ignore=tests/diffusion --ignore=tests/model_executor --ignore=tests/entrypoints --ignore=tests/engine --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml"
|
||||
- "pytest -sv tests/ -m 'core_model and cpu' --ignore=tests/diffusion --ignore=tests/model_executor --ignore=tests/entrypoints --ignore=tests/engine"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- group: ":card_index_dividers: Diffusion Test"
|
||||
@@ -76,7 +80,7 @@ steps:
|
||||
|
||||
- label: "Tiny Model Tests · Diffusion (base)"
|
||||
commands:
|
||||
- timeout 15m pytest -sv tests/model_tests/diffusion -m 'core_model and cuda' --run-level "core_model"
|
||||
- timeout 15m pytest -sv -n 4 tests/model_tests/diffusion -m 'core_model and cuda' --run-level "core_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Engine&Model Executor Test"
|
||||
@@ -128,6 +132,21 @@ steps:
|
||||
image: public.ecr.aws/q9t5s3a7/vllm-ci-test-repo:$BUILDKITE_COMMIT
|
||||
always-pull: true
|
||||
propagate-environment: true
|
||||
# vLLM 0.27 added a pre-flight capacity check in
|
||||
# distributed/device_communicators/shm_broadcast.py. Without this
|
||||
# the container gets Docker's 64 MiB default and every test in
|
||||
# this step dies at engine start with
|
||||
# RuntimeError: Insufficient space in /dev/shm:
|
||||
# 240 MiB required, 64 MiB available
|
||||
# (9 failed in 8.7s on build #2949). vLLM 0.26 had no such check
|
||||
# and allocated regardless, so this step passed on main while
|
||||
# being under-provisioned the whole time — 0.27 turned a silent
|
||||
# risk into an explicit error.
|
||||
#
|
||||
# This is the only inline docker plugin block in .buildkite/cuda/;
|
||||
# every other step inherits common/ci_mirror_hardwares.yml, which
|
||||
# already sets 8gb. Matching that rather than inventing a value.
|
||||
shm-size: "8gb"
|
||||
environment:
|
||||
- "HF_HOME=/fsx/hf_cache"
|
||||
volumes:
|
||||
@@ -153,7 +172,13 @@ steps:
|
||||
- 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
|
||||
commands:
|
||||
@@ -166,24 +191,34 @@ steps:
|
||||
- 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
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
pytest -s -v tests/e2e/offline_inference/test_minicpmo_4_5.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: h100_2
|
||||
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/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
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
pytest -s -v tests/e2e/online_serving/test_minicpmo_4_5.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: h100_2
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Omni · MiniCPM-o 4.5 Duplex Test"
|
||||
source_file_dependencies:
|
||||
@@ -192,45 +227,53 @@ steps:
|
||||
- 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/minicpmo_realtime_duplex_scenarios.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_soft_interrupt.py
|
||||
- tests/helpers/minicpmo_4_5_duplex.py
|
||||
- vllm_omni/deploy/minicpmo_4_5.yaml
|
||||
- tests/e2e/online_serving/helpers/minicpmo_4_5_duplex.py
|
||||
- vllm_omni/deploy/minicpmo_4_5_duplex.yaml
|
||||
- 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
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
pytest -s -v tests/e2e/online_serving/test_minicpmo_4_5_duplex.py -m 'core_model and cuda' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: h100_2
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "TTS · VoxCPM2 Test"
|
||||
- label: "Omni · MiniCPM-o 4.5 Perf Test"
|
||||
timeout_in_minutes: 60
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_voxcpm2_tts.py
|
||||
- vllm_omni/model_executor/models/voxcpm2/
|
||||
- vllm_omni/deploy/voxcpm2.yaml
|
||||
timeout_in_minutes: 30
|
||||
- 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
|
||||
commands:
|
||||
- |
|
||||
timeout 30m bash -c "
|
||||
export VLLM_LOGGING_LEVEL=DEBUG
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
pytest -s -v tests/e2e/online_serving/test_voxcpm2_tts.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: l4_1
|
||||
- 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/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
|
||||
commands:
|
||||
@@ -245,6 +288,9 @@ steps:
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/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
|
||||
commands:
|
||||
@@ -257,52 +303,11 @@ steps:
|
||||
"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "TTS · Higgs-Audio-V3 Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_higgs_audio_v3.py
|
||||
- vllm_omni/model_executor/models/higgs_audio_v3/
|
||||
- vllm_omni/model_executor/stage_input_processors/higgs_audio_v3.py
|
||||
- vllm_omni/deploy/higgs_multimodal_qwen3.yaml
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
export VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
export VLLM_USE_DEEP_GEMM=0
|
||||
export VLLM_MOE_USE_DEEP_GEMM=0
|
||||
pytest -s -v tests/e2e/online_serving/test_higgs_audio_v3.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Diffusion · Qwen Image Edit Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_qwen_image_edit.py
|
||||
- vllm_omni/diffusion/models/qwen_image/
|
||||
commands:
|
||||
- |
|
||||
timeout 20m bash -c "
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen_image_edit.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Bagel Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_bagel.py
|
||||
- vllm_omni/model_executor/models/bagel/
|
||||
- vllm_omni/diffusion/models/bagel/
|
||||
- vllm_omni/model_executor/stage_input_processors/bagel.py
|
||||
- vllm_omni/deploy/bagel.yaml
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_bagel.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: h100_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/
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
@@ -315,6 +320,9 @@ steps:
|
||||
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
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
@@ -327,6 +335,8 @@ steps:
|
||||
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
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
@@ -334,15 +344,3 @@ steps:
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen_image.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
- label: "Diffusion · Qwen Image Layered Test"
|
||||
source_file_dependencies:
|
||||
- tests/e2e/online_serving/test_qwen_image_layered.py
|
||||
- vllm_omni/diffusion/models/qwen_image/
|
||||
commands:
|
||||
- |
|
||||
timeout 40m bash -c "
|
||||
export VLLM_IMAGE_FETCH_TIMEOUT=60
|
||||
pytest -s -v tests/e2e/online_serving/test_qwen_image_layered.py -m 'core_model' --run-level 'core_model'
|
||||
"
|
||||
mirror_hardwares: h100_1
|
||||
@@ -5,59 +5,91 @@ env:
|
||||
HF_HUB_ETAG_TIMEOUT: 60
|
||||
|
||||
steps:
|
||||
|
||||
- label: "Reliability Test - qwen3-omni"
|
||||
timeout_in_minutes: 180
|
||||
- label: "Simple · CPU Coverage Test"
|
||||
key: weekly-simple-cpu-coverage
|
||||
depends_on: upload-weekly-pipeline
|
||||
if: build.env("WEEKLY") == "1" || build.pull_request.labels includes "weekly-test"
|
||||
if: build.env("WEEKLY") == "1"
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/test_reliability_qwen3_omni.py -m "slow"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Reliability Test - wan22"
|
||||
timeout_in_minutes: 180
|
||||
depends_on: upload-weekly-pipeline
|
||||
if: build.env("WEEKLY") == "1" || build.pull_request.labels includes "weekly-test"
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/test_reliability_wan22.py -m "slow"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Reliability Test - hunyuan-image"
|
||||
timeout_in_minutes: 180
|
||||
depends_on: upload-weekly-pipeline
|
||||
if: build.env("WEEKLY") == "1" || build.pull_request.labels includes "weekly-test"
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/test_reliability_hunyuan_image.py -m "slow"
|
||||
mirror_hardwares: h100_4
|
||||
|
||||
- label: "Reliability Test - voxcpm2"
|
||||
timeout_in_minutes: 180
|
||||
depends_on: upload-weekly-pipeline
|
||||
if: build.env("WEEKLY") == "1" || build.pull_request.labels includes "weekly-test"
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/test_reliability_voxcpm2.py -m "slow"
|
||||
- |
|
||||
set +e
|
||||
REPORT="coverage-core-model-cpu-$${BUILDKITE_STEP_ID:-local}.xml"
|
||||
pytest -sv tests/ -m 'core_model and cpu' --cov=vllm_omni --cov-report=term-missing:skip-covered --cov-report=xml:$${REPORT}
|
||||
EXIT=$$?
|
||||
gzip -9 -f "$${REPORT}"
|
||||
buildkite-agent artifact upload "$${REPORT}.gz"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- group: "Reliability Test - Invalid parameters Test"
|
||||
- group: "Reliability Test"
|
||||
depends_on: upload-weekly-pipeline
|
||||
if: build.env("WEEKLY") == "1" || build.pull_request.labels includes "weekly-test"
|
||||
steps:
|
||||
|
||||
- label: "Invalid parameters Test · H100"
|
||||
- label: "Reliability Test · qwen3-omni"
|
||||
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"
|
||||
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"
|
||||
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"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/invalid_param_test/ -m "slow and H100"
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "Invalid parameters Test · L4"
|
||||
- label: "Reliability Test · Invalid parameters · L4"
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- pytest -s -v tests/dfx/reliability/invalid_param_test/ -m "slow and L4"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- group: ":card_index_dividers: E2E Tests"
|
||||
- group: "Perf Test"
|
||||
depends_on: upload-weekly-pipeline
|
||||
if: build.env("WEEKLY") == "1" || build.pull_request.labels includes "weekly-test"
|
||||
steps:
|
||||
|
||||
- label: ":full_moon: Omni · Perf Test · vLLM Text"
|
||||
key: weekly-omni-performance-vllm-text
|
||||
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_vllm_text.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: ":full_moon: Omni · Perf Test · Multi-Replica"
|
||||
key: weekly-omni-performance-multi-replicas
|
||||
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_multi_replicas.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
mirror_hardwares: h100_3
|
||||
|
||||
- group: ":card_index_dividers: E2E Tests"
|
||||
depends_on: upload-weekly-pipeline
|
||||
if: build.env("NON_CRITICAL") == "1"
|
||||
steps:
|
||||
|
||||
- label: "Omni · L4"
|
||||
@@ -83,7 +115,7 @@ steps:
|
||||
mirror_hardwares: h100_2
|
||||
|
||||
- label: "TTS · L4"
|
||||
timeout_in_minutes: 90
|
||||
timeout_in_minutes: 120
|
||||
commands:
|
||||
- export VLLM_ALLOW_LONG_MAX_MODEL_LEN="1"
|
||||
- export VLLM_USE_DEEP_GEMM="0"
|
||||
@@ -108,6 +140,22 @@ steps:
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_1
|
||||
|
||||
# Own step: the image has no NanoCodec, so this file import-skips out of
|
||||
# the mark-selected TTS steps above. The overrides keep nemo_toolkit[tts]
|
||||
# from downgrading transformers; see
|
||||
# examples/offline_inference/text_to_speech/README.md.
|
||||
- label: "TTS · Gepard-1.0 · L4"
|
||||
timeout_in_minutes: 60
|
||||
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
|
||||
-m "tts and cuda"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: l4_1
|
||||
|
||||
- label: "Diffusion · L4"
|
||||
timeout_in_minutes: 60
|
||||
commands:
|
||||
@@ -118,7 +166,7 @@ steps:
|
||||
mirror_hardwares: l4_4
|
||||
|
||||
- label: "Diffusion · H100 · Single-GPU"
|
||||
timeout_in_minutes: 120
|
||||
timeout_in_minutes: 150
|
||||
commands:
|
||||
- >-
|
||||
pytest -sv
|
||||
@@ -133,4 +181,4 @@ steps:
|
||||
pytest -sv
|
||||
tests/e2e/ -m "slow and diffusion and H100 and distributed_cuda"
|
||||
--run-level "full_model"
|
||||
mirror_hardwares: h100_2
|
||||
mirror_hardwares: h100_4
|
||||
@@ -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.26.0"
|
||||
VLLM_VERSION: "v0.27.0"
|
||||
priority: 100
|
||||
timeout_in_minutes: 60
|
||||
soft_fail: false
|
||||
@@ -34,8 +34,23 @@ docker_build() {
|
||||
docker build "${out[@]}" "$@" -f docker/Dockerfile.xpu .
|
||||
}
|
||||
|
||||
build_vllm_base() (
|
||||
local vllm_source_dir
|
||||
vllm_source_dir=$(mktemp -d)
|
||||
trap 'rm -rf "${vllm_source_dir}"' EXIT
|
||||
|
||||
git clone --depth 1 --branch "${VLLM_VERSION}" \
|
||||
https://github.com/vllm-project/vllm "${vllm_source_dir}"
|
||||
|
||||
local out=("${export_args[@]/'{{IMAGE}}'/${base_image_name}}")
|
||||
docker build "${out[@]}" \
|
||||
--target vllm-openai \
|
||||
-f "${vllm_source_dir}/docker/Dockerfile.xpu" \
|
||||
"${vllm_source_dir}"
|
||||
)
|
||||
|
||||
if [ -z "$(docker images -q "${base_image_name}")" ]; then
|
||||
docker_build "${base_image_name}" --target vllm-base --build-arg "VLLM_VERSION=${VLLM_VERSION}"
|
||||
build_vllm_base
|
||||
fi
|
||||
|
||||
# Try building the docker image
|
||||
@@ -72,8 +87,9 @@ time timeout -k 30 30m docker run \
|
||||
echo $ZE_AFFINITY_MASK
|
||||
pip install tblib==3.1.0
|
||||
cd /workspace/vllm-omni
|
||||
pytest -v -s -m "core_model and xpu and B60"
|
||||
XPU_TEST_PATHS="tests/diffusion tests/dfx tests/e2e"
|
||||
pytest -v -s $XPU_TEST_PATHS -m "core_model and xpu and B60"
|
||||
pytest -v -s tests/diffusion/quantization/test_mxfp8_config.py
|
||||
pytest -v -s -m "advanced_model and xpu and B60"
|
||||
pytest -v -s -m "omni and xpu and B60"
|
||||
pytest -v -s $XPU_TEST_PATHS -m "advanced_model and xpu and B60"
|
||||
pytest -v -s $XPU_TEST_PATHS -m "omni and xpu and B60"
|
||||
'
|
||||
@@ -39,7 +39,7 @@ steps:
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
- label: ":robot: Omni · MiniCPM-o 4.5 Test"
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 Test"
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
@@ -47,6 +47,89 @@ steps:
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
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"
|
||||
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}"
|
||||
commands:
|
||||
- >-
|
||||
pytest -s -v
|
||||
tests/e2e/online_serving/test_minicpmo_4_5_duplex.py
|
||||
tests/e2e/online_serving/test_minicpmo_4_5_duplex_expansion.py
|
||||
-m "npu and A3 and omni"
|
||||
--run-level full_model
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Accuracy Test"
|
||||
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}"
|
||||
commands:
|
||||
# Pin the Seed-TTS scorer to the second card: _get_eval_device() otherwise
|
||||
# auto-picks npu:0, which the omni server under test already fills with its
|
||||
# KV cache, so Whisper OOMs on `.to(device)` and every clip reports
|
||||
# "ASR / WER failed".
|
||||
- export SEED_TTS_WER_EVAL=1
|
||||
- export SEED_TTS_EVAL_DEVICE=npu:1
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/e2e/accuracy/minicpmo_4_5/test_minicpmo_4_5.py -m "full_model and npu and A3" --run-level full_model
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/e2e/accuracy/minicpmo_4_5/results/*.json"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Perf Test"
|
||||
key: nightly-omni-performance-minicpmo-4-5-npu
|
||||
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}"
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py -m "npu and A3" --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Perf Test (A2)"
|
||||
key: nightly-omni-performance-minicpmo-4-5-npu-a2
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a2b3_npu_1
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
HF_HUB_OFFLINE: "1"
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py -m "npu and A2" --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
- label: ":full_moon: Omni · MiniCPM-o 4.5 · Duplex Seed-TTS Perf Test"
|
||||
key: nightly-omni-performance-minicpmo-4-5-duplex-seed-tts-npu
|
||||
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}"
|
||||
commands:
|
||||
- export BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_benchmark.py -m "npu and A3" --test-config-file tests/dfx/perf/tests/test_minicpmo_4_5_duplex_seed_tts.json
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
- group: ":card_index_dividers: TTS Model Test"
|
||||
key: nightly-tts-test-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
@@ -68,33 +151,6 @@ steps:
|
||||
EXIT=$$?
|
||||
buildkite-agent artifact upload "tests/dfx/perf/results/*.json"
|
||||
exit $$EXIT
|
||||
- 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"
|
||||
steps:
|
||||
- label: ":full_moon: Diffusion X2I(&A&T) · Perf Test · Qwen-Image-Edit-2511"
|
||||
key: nightly-diffusion-x2iat-performance-qwen-image-edit-2511
|
||||
timeout_in_minutes: 180
|
||||
mirror_hardwares: a3_npu_8
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
DIFFUSION_ATTENTION_BACKEND: TORCH_SDPA
|
||||
commands:
|
||||
- export DIFFUSION_BENCHMARK_DIR=tests/dfx/perf/results
|
||||
- export CACHE_DIT_VERSION=1.3.0
|
||||
- |
|
||||
set +e
|
||||
pytest -s -v tests/dfx/perf/scripts/run_diffusion_benchmark.py -m npu --test-config-file tests/dfx/perf/tests/test_qwen_image_edit_2511_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
|
||||
- group: ":card_index_dividers: Diffusion I2I Model Test"
|
||||
key: nightly-HunyuanImage3-x2i-test-group
|
||||
depends_on: upload-nightly-pipeline
|
||||
|
||||
@@ -1,31 +1,49 @@
|
||||
steps:
|
||||
- label: "Platforms Test"
|
||||
key: ready-platforms-test
|
||||
depends_on: upload-ready-pipeline
|
||||
mirror_hardwares: a3_npu_2
|
||||
commands:
|
||||
- >-
|
||||
pytest -s -v
|
||||
tests/platforms/npu/test_minicpmo_code2wav_npugraph.py
|
||||
-m 'core_model and npu and A3 and omni'
|
||||
--run-level 'core_model'
|
||||
|
||||
- group: ":card_index_dividers: Omni Model Test"
|
||||
key: ready-omni-group
|
||||
depends_on: upload-ready-pipeline
|
||||
steps:
|
||||
- label: ":robot: Omni · MiniCPM-o 4.5 Test"
|
||||
agents:
|
||||
queue: "ascend-a3"
|
||||
resource_class: "npu-2"
|
||||
image: "swr.cn-southwest-2.myhuaweicloud.com/modelfoundry/vllm-omni-ci-npu:${BUILDKITE_COMMIT}-a3"
|
||||
plugins:
|
||||
- kubernetes:
|
||||
podSpecPatch:
|
||||
imagePullSecrets:
|
||||
- name: swr-secret
|
||||
- label: "Omni · MiniCPM-o 4.5 Test"
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
HF_TOKEN: "${HF_TOKEN}"
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/offline_inference/test_minicpmo_4_5.py tests/e2e/online_serving/test_minicpmo_4_5.py -m 'core_model' --run-level 'core_model'
|
||||
- pytest -s -v tests/e2e/offline_inference/test_minicpmo_4_5.py tests/e2e/online_serving/test_minicpmo_4_5.py -m 'core_model and npu and A3 and omni' --run-level 'core_model'
|
||||
- label: "Omni · MiniCPM-o 4.5 Duplex Test"
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
commands:
|
||||
- pytest -s -v tests/e2e/online_serving/test_minicpmo_4_5_duplex.py -m 'core_model and npu and A3 and omni' --run-level 'core_model'
|
||||
- label: "Omni · MiniCPM-o 4.5 Perf Test"
|
||||
timeout_in_minutes: 60
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
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 npu and A3 and omni'
|
||||
|
||||
- group: ":card_index_dividers: TTS Model Test"
|
||||
key: ready-tts-group
|
||||
depends_on: upload-ready-pipeline
|
||||
steps:
|
||||
- label: ":sound: TTS · Qwen3-TTS CustomVoice Test"
|
||||
mirror_hardwares: a2b3_npu_1
|
||||
mirror_hardwares: a3_npu_2
|
||||
env:
|
||||
VLLM_WORKER_MULTIPROC_METHOD: spawn
|
||||
VLLM_ALLOW_LONG_MAX_MODEL_LEN: "1"
|
||||
|
||||
@@ -40,9 +40,11 @@ steps:
|
||||
commands:
|
||||
- "bash .buildkite/release/scripts/publish-release-wheels-pypi.sh"
|
||||
|
||||
# Auto-skip when NIGHTLY=1 (scheduled); otherwise require manual unblock.
|
||||
- block: "Unblock to build release Docker images"
|
||||
depends_on: ~
|
||||
key: block-build-release-images
|
||||
if: build.env("NIGHTLY") != "1"
|
||||
|
||||
- group: "Build release Docker images"
|
||||
key: "build-release-images"
|
||||
@@ -63,7 +65,7 @@ steps:
|
||||
--progress plain \
|
||||
-f docker/Dockerfile.cuda .
|
||||
- "docker push public.ecr.aws/q9t5s3a7/vllm-omni-release-repo:$BUILDKITE_COMMIT-$(uname -m)"
|
||||
# re-tag to default image tag and push, just in case arm64 build fails
|
||||
# Fallback default tag (no arch suffix) if arm64 build fails.
|
||||
- "docker tag public.ecr.aws/q9t5s3a7/vllm-omni-release-repo:$BUILDKITE_COMMIT-$(uname -m) public.ecr.aws/q9t5s3a7/vllm-omni-release-repo:$BUILDKITE_COMMIT"
|
||||
- "docker push public.ecr.aws/q9t5s3a7/vllm-omni-release-repo:$BUILDKITE_COMMIT"
|
||||
env:
|
||||
@@ -86,6 +88,26 @@ steps:
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
|
||||
# NIGHTLY=1 only: promote ECR images to DockerHub nightly tags, then prune.
|
||||
- label: "Publish nightly multi-arch image to DockerHub"
|
||||
depends_on:
|
||||
- build-release-image-x86
|
||||
- build-release-image-arm64
|
||||
if: build.env("NIGHTLY") == "1"
|
||||
key: publish-nightly-images-dockerhub
|
||||
agents:
|
||||
queue: small_cpu_queue_release
|
||||
commands:
|
||||
- "bash .buildkite/release/scripts/publish-release-images.sh nightly"
|
||||
- "bash .buildkite/release/scripts/cleanup-nightly-builds.sh"
|
||||
plugins:
|
||||
- docker-login#v3.0.0:
|
||||
username: vllmbot
|
||||
password-env: DOCKERHUB_TOKEN
|
||||
env:
|
||||
DOCKER_BUILDKIT: "1"
|
||||
DOCKERHUB_USERNAME: "vllmbot"
|
||||
|
||||
- block: "Publish release images to DockerHub"
|
||||
key: block-publish-release-images
|
||||
depends_on:
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Clean up old nightly builds from DockerHub (vllm/vllm-omni), keeping the
|
||||
# newest 14 tags with the nightly- prefix.
|
||||
|
||||
set -ex
|
||||
|
||||
TAG_PREFIX="nightly-"
|
||||
REPO="vllm/vllm-omni"
|
||||
REPO_API_URL="https://hub.docker.com/v2/repositories/${REPO}/tags"
|
||||
|
||||
echo "Cleaning up tags with prefix: $TAG_PREFIX in repository: $REPO"
|
||||
|
||||
if [ -z "$DOCKERHUB_TOKEN" ]; then
|
||||
echo "Error: DOCKERHUB_TOKEN environment variable is not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$DOCKERHUB_USERNAME" ]; then
|
||||
echo "Error: DOCKERHUB_USERNAME environment variable is not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Getting DockerHub bearer token..."
|
||||
set +x
|
||||
BEARER_TOKEN=$(curl -s -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{\"username\": \"$DOCKERHUB_USERNAME\", \"password\": \"$DOCKERHUB_TOKEN\"}" \
|
||||
"https://hub.docker.com/v2/users/login" | jq -r '.token')
|
||||
set -x
|
||||
|
||||
if [ -z "$BEARER_TOKEN" ] || [ "$BEARER_TOKEN" = "null" ]; then
|
||||
echo "Error: Failed to get DockerHub bearer token"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
get_all_tags() {
|
||||
local page=1
|
||||
local all_tags=""
|
||||
# Hub `name` is a partial match (not a strict prefix). Use it to narrow the
|
||||
# list, then enforce startswith() client-side. Exhaust API pages; do not
|
||||
# stop merely because a page has no matching tags after filtering.
|
||||
local name_query
|
||||
name_query=$(printf '%s' "$TAG_PREFIX" | jq -sRr @uri)
|
||||
|
||||
while true; do
|
||||
set +x
|
||||
local response
|
||||
response=$(curl -s -H "Authorization: Bearer $BEARER_TOKEN" \
|
||||
"$REPO_API_URL?page=$page&page_size=100&name=${name_query}")
|
||||
set -x
|
||||
|
||||
local page_count
|
||||
page_count=$(echo "$response" | jq -r '.results | length')
|
||||
if [ -z "$page_count" ] || [ "$page_count" = "0" ] || [ "$page_count" = "null" ]; then
|
||||
break
|
||||
fi
|
||||
|
||||
local tags
|
||||
tags=$(echo "$response" | jq -r --arg prefix "$TAG_PREFIX" \
|
||||
'.results[] | select(.name | startswith($prefix)) | "\(.last_updated)|\(.name)"')
|
||||
|
||||
if [ -n "$tags" ]; then
|
||||
all_tags="$all_tags$tags"$'\n'
|
||||
fi
|
||||
page=$((page + 1))
|
||||
done
|
||||
|
||||
echo "$all_tags" | sort -r | cut -d'|' -f2
|
||||
}
|
||||
|
||||
delete_tag() {
|
||||
local tag_name="$1"
|
||||
echo "Deleting tag: $tag_name"
|
||||
|
||||
local delete_url="https://hub.docker.com/v2/repositories/${REPO}/tags/$tag_name"
|
||||
set +x
|
||||
local response http_code body
|
||||
response=$(curl -s -w "\n%{http_code}" -X DELETE \
|
||||
-H "Authorization: Bearer $BEARER_TOKEN" "$delete_url")
|
||||
set -x
|
||||
http_code=$(printf '%s\n' "$response" | tail -n1)
|
||||
body=$(printf '%s\n' "$response" | sed '$d')
|
||||
|
||||
if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then
|
||||
echo "Successfully deleted tag: $tag_name (HTTP ${http_code})"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local detail=""
|
||||
if echo "$body" | jq -e '.detail' > /dev/null 2>&1; then
|
||||
detail=$(echo "$body" | jq -r '.detail')
|
||||
elif [ -n "$body" ]; then
|
||||
detail="$body"
|
||||
else
|
||||
detail="(empty response body)"
|
||||
fi
|
||||
echo "Error: Failed to delete tag $tag_name (HTTP ${http_code}): ${detail}"
|
||||
return 1
|
||||
}
|
||||
|
||||
echo "Fetching all tags from DockerHub..."
|
||||
all_tags=$(get_all_tags)
|
||||
|
||||
if [ -z "$all_tags" ]; then
|
||||
echo "No tags found to clean up"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
total_tags=$(echo "$all_tags" | wc -l)
|
||||
echo "Found $total_tags tags"
|
||||
|
||||
tags_to_keep=14
|
||||
tags_to_delete=$((total_tags - tags_to_keep))
|
||||
|
||||
if [ $tags_to_delete -le 0 ]; then
|
||||
echo "No tags need to be deleted (only $total_tags tags found, keeping $tags_to_keep)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Will delete $tags_to_delete old tags, keeping the newest $tags_to_keep"
|
||||
|
||||
tags_to_delete_list=$(echo "$all_tags" | tail -n +$((tags_to_keep + 1)))
|
||||
|
||||
if [ -z "$tags_to_delete_list" ]; then
|
||||
echo "No tags to delete"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Deleting old tags..."
|
||||
delete_failures=0
|
||||
while IFS= read -r tag; do
|
||||
if [ -n "$tag" ]; then
|
||||
if ! delete_tag "$tag"; then
|
||||
delete_failures=$((delete_failures + 1))
|
||||
fi
|
||||
sleep 1
|
||||
fi
|
||||
done <<< "$tags_to_delete_list"
|
||||
|
||||
if [ "$delete_failures" -gt 0 ]; then
|
||||
echo "Cleanup finished with ${delete_failures} deletion failure(s)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Cleanup completed successfully"
|
||||
@@ -1,50 +1,87 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
# Publish release Docker images from ECR to DockerHub.
|
||||
# Pulls per-arch images, tags with `latest` and versioned tags, pushes them,
|
||||
# then creates and pushes a multi-arch manifest.
|
||||
# Publish Docker images from ECR staging to DockerHub.
|
||||
#
|
||||
# Usage:
|
||||
# publish-release-images.sh # release mode (default)
|
||||
# publish-release-images.sh release
|
||||
# publish-release-images.sh nightly
|
||||
#
|
||||
# Release tags: latest, v<version>
|
||||
# Nightly tags: nightly, nightly-<commit>
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
RELEASE_VERSION=$(buildkite-agent meta-data get release-version --default "" | sed 's/^v//')
|
||||
if [ -z "${RELEASE_VERSION}" ]; then
|
||||
echo "ERROR: release-version metadata not set"
|
||||
exit 1
|
||||
fi
|
||||
MODE="${1:-release}"
|
||||
|
||||
COMMIT="$BUILDKITE_COMMIT"
|
||||
DOCKERHUB_REPO="vllm/vllm-omni"
|
||||
ECR_REPO="public.ecr.aws/q9t5s3a7/vllm-omni-release-repo"
|
||||
COMMIT="$BUILDKITE_COMMIT"
|
||||
PRIMARY_TAGS=()
|
||||
EXTRA_MANIFEST_TAGS=()
|
||||
|
||||
case "${MODE}" in
|
||||
release)
|
||||
RELEASE_VERSION=$(buildkite-agent meta-data get release-version --default "" | sed 's/^v//')
|
||||
if [ -z "${RELEASE_VERSION}" ]; then
|
||||
echo "ERROR: release-version metadata not set"
|
||||
exit 1
|
||||
fi
|
||||
PRIMARY_TAGS=("latest" "v${RELEASE_VERSION}")
|
||||
;;
|
||||
nightly)
|
||||
# Commit-pinned manifest reuses nightly-{x86_64,aarch64} arch images.
|
||||
PRIMARY_TAGS=("nightly")
|
||||
EXTRA_MANIFEST_TAGS=("nightly-${COMMIT}")
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 {release|nightly}"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "========================================"
|
||||
echo "Publishing release images v${RELEASE_VERSION}"
|
||||
echo "Publishing ${MODE} images to ${DOCKERHUB_REPO}"
|
||||
echo " Commit: ${COMMIT}"
|
||||
echo " Primary tags: ${PRIMARY_TAGS[*]}"
|
||||
if [ ${#EXTRA_MANIFEST_TAGS[@]} -gt 0 ]; then
|
||||
echo " Extra manifests: ${EXTRA_MANIFEST_TAGS[*]}"
|
||||
fi
|
||||
echo "========================================"
|
||||
|
||||
# Login to ECR to pull staging images
|
||||
aws ecr-public get-login-password --region us-east-1 | \
|
||||
docker login --username AWS --password-stdin public.ecr.aws/q9t5s3a7
|
||||
|
||||
docker pull "${ECR_REPO}:${COMMIT}-x86_64"
|
||||
docker pull "${ECR_REPO}:${COMMIT}-aarch64"
|
||||
SRC_X86="${ECR_REPO}:${COMMIT}-x86_64"
|
||||
SRC_ARM="${ECR_REPO}:${COMMIT}-aarch64"
|
||||
|
||||
docker tag "${ECR_REPO}:${COMMIT}-x86_64" "${DOCKERHUB_REPO}:latest-x86_64"
|
||||
docker tag "${ECR_REPO}:${COMMIT}-x86_64" "${DOCKERHUB_REPO}:v${RELEASE_VERSION}-x86_64"
|
||||
docker push "${DOCKERHUB_REPO}:latest-x86_64"
|
||||
docker push "${DOCKERHUB_REPO}:v${RELEASE_VERSION}-x86_64"
|
||||
docker pull "${SRC_X86}"
|
||||
docker pull "${SRC_ARM}"
|
||||
|
||||
docker tag "${ECR_REPO}:${COMMIT}-aarch64" "${DOCKERHUB_REPO}:latest-aarch64"
|
||||
docker tag "${ECR_REPO}:${COMMIT}-aarch64" "${DOCKERHUB_REPO}:v${RELEASE_VERSION}-aarch64"
|
||||
docker push "${DOCKERHUB_REPO}:latest-aarch64"
|
||||
docker push "${DOCKERHUB_REPO}:v${RELEASE_VERSION}-aarch64"
|
||||
publish_manifest() {
|
||||
local tag="$1"
|
||||
local arch_tag_base="$2"
|
||||
docker manifest rm "${DOCKERHUB_REPO}:${tag}" || true
|
||||
docker manifest create \
|
||||
"${DOCKERHUB_REPO}:${tag}" \
|
||||
"${DOCKERHUB_REPO}:${arch_tag_base}-x86_64" \
|
||||
"${DOCKERHUB_REPO}:${arch_tag_base}-aarch64"
|
||||
docker manifest push "${DOCKERHUB_REPO}:${tag}"
|
||||
}
|
||||
|
||||
docker manifest rm "${DOCKERHUB_REPO}:latest" || true
|
||||
docker manifest rm "${DOCKERHUB_REPO}:v${RELEASE_VERSION}" || true
|
||||
docker manifest create "${DOCKERHUB_REPO}:latest" "${DOCKERHUB_REPO}:latest-x86_64" "${DOCKERHUB_REPO}:latest-aarch64"
|
||||
docker manifest create "${DOCKERHUB_REPO}:v${RELEASE_VERSION}" "${DOCKERHUB_REPO}:v${RELEASE_VERSION}-x86_64" "${DOCKERHUB_REPO}:v${RELEASE_VERSION}-aarch64"
|
||||
docker manifest push "${DOCKERHUB_REPO}:latest"
|
||||
docker manifest push "${DOCKERHUB_REPO}:v${RELEASE_VERSION}"
|
||||
for tag in "${PRIMARY_TAGS[@]}"; do
|
||||
docker tag "${SRC_X86}" "${DOCKERHUB_REPO}:${tag}-x86_64"
|
||||
docker tag "${SRC_ARM}" "${DOCKERHUB_REPO}:${tag}-aarch64"
|
||||
docker push "${DOCKERHUB_REPO}:${tag}-x86_64"
|
||||
docker push "${DOCKERHUB_REPO}:${tag}-aarch64"
|
||||
publish_manifest "${tag}" "${tag}"
|
||||
done
|
||||
|
||||
ARCH_BASE="${PRIMARY_TAGS[0]}"
|
||||
for tag in "${EXTRA_MANIFEST_TAGS[@]}"; do
|
||||
publish_manifest "${tag}" "${ARCH_BASE}"
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Successfully published release images for v${RELEASE_VERSION}"
|
||||
echo "Successfully published ${MODE} images"
|
||||
@@ -610,6 +610,24 @@ See the [Profiling Single-Stage Diffusion](../../../docs/contributing/profiling.
|
||||
|
||||
---
|
||||
|
||||
## Pre-commit conventions
|
||||
|
||||
New library files must pass the local gates in
|
||||
[docs/contributing/README.md](../../../docs/contributing/README.md#linting).
|
||||
That page is the full hook list (SPDX, forbidden imports including Hugging Face
|
||||
Hub / Triton / pickle, `torch.cuda`, mypy, test marks, markdownlint, Buildkite,
|
||||
shellcheck). In particular:
|
||||
|
||||
- SPDX copyright is `vLLM-Omni project` (stale `vLLM project` is rewritten).
|
||||
- Use `import regex as re` and `pybase64` in `vllm_omni/`; do not import stdlib
|
||||
`re` or `base64`. Hugging Face Hub downloads go through
|
||||
`vllm.transformers_utils.repo_utils`.
|
||||
- Do not add `torch.cuda.*` call sites; use `current_omni_platform`.
|
||||
- New `tests/**/test_*.py` files need a CI level mark and a hardware mark.
|
||||
- Do not expand `CHECK_IMPORTS[*].allowed_files` or `ALLOWED_FILES` without review.
|
||||
- GitHub Actions skips SPDX/shellcheck/mypy-3.10/test-marks/markdownlint; run
|
||||
`pre-commit` locally.
|
||||
|
||||
## Iterative Development Tips
|
||||
|
||||
1. **Start minimal**: Basic generation first, no parallelism/caching
|
||||
|
||||
@@ -138,9 +138,12 @@ A shared buffer silently corrupts audio across concurrent requests — the sympt
|
||||
- Load codec weights (may need lazy loading from separate checkpoint)
|
||||
- Implement `forward()`: codec codes -> audio waveform
|
||||
- Return `OmniOutput` with `multimodal_outputs`
|
||||
5. **Create stage config YAML** defining both stages, memory allocation, and model paths
|
||||
6. **Create stage input processor** for prompt building
|
||||
7. **Write end2end.py** test script
|
||||
5. **Define and register the pipeline topology** in
|
||||
`vllm_omni/model_executor/models/<model>/pipeline.py`
|
||||
6. **Create the deploy YAML** under `vllm_omni/deploy/` for placement,
|
||||
memory sizing, connectors, and runtime overrides
|
||||
7. **Create stage input processor** for prompt building and inter-stage handoff
|
||||
8. **Write end2end.py** test script
|
||||
|
||||
### Critical Parameters to Get Right
|
||||
|
||||
@@ -174,7 +177,7 @@ These bugs appear in almost every new TTS PR. Check all before the first push. S
|
||||
- **All return paths must emit `model_outputs`** — if any early-return branch skips setting `model_outputs`, the serving layer silently drops that step's audio (fish speech: `fix: ensure ALL return paths emit model_outputs`)
|
||||
- **Per-request state isolation** — for batched concurrent requests, key all state by request ID; a shared buffer corrupts audio across requests (fish speech: `fix: per-request vocode + delta emission`)
|
||||
- **Codec tensor device** — move codec codes to the codec decoder's device before calling decode; mismatches cause silent CPU fallback or crashes (fish speech: `fix: use model device for CUDA stream`)
|
||||
- **AR stage `max_num_seqs`** — set to at least 4 in production configs; for single-stage models this is the only stage. For two-stage models, Stage 0 (AR) needs `max_num_seqs ≥ 4` to pipeline concurrent requests; Stage 1 (codec decoder) typically uses `max_num_seqs: 1` intentionally. Default of 1 everywhere causes audio gaps under concurrency because the codec window round-robins across requests (RFC #2568)
|
||||
- **AR stage `max_num_seqs`** — set to at least 4 in production deploy configs; for single-stage models this is the only stage. For two-stage models, Stage 0 (AR) needs `max_num_seqs ≥ 4` to pipeline concurrent requests; Stage 1 (codec decoder) is model-specific and may intentionally use `max_num_seqs: 1`. Defaulting the AR stage to 1 causes audio gaps under concurrency because the codec window round-robins across requests (RFC #2568)
|
||||
|
||||
### Optional Dependency Handling
|
||||
|
||||
@@ -190,18 +193,18 @@ pattern, signature constraints, and MOSS-TTS-Nano reference.
|
||||
When the upstream model cannot be cleanly split into an AR stage and a
|
||||
separate decoder, run the full pipeline inside a single AR worker and
|
||||
stream audio through a per-request `inference_stream()` generator keyed by
|
||||
`_omni_req_id`. Stage config must set `worker_type: ar`,
|
||||
`engine_output_type: audio`, `final_output: true`, `is_comprehension: true`,
|
||||
and `async_chunk: false` at the top level. Only extract params from
|
||||
`_omni_req_id`. Define one `StagePipelineConfig` with
|
||||
`execution_type=StageExecutionType.LLM_AR`, `engine_output_type="audio"`,
|
||||
`final_output=True`, and `owns_tokenizer=True`. Set `async_chunk: false` in
|
||||
the deploy YAML. Only extract params from
|
||||
`additional_information` that you actually forward, or pre-commit fails
|
||||
`ruff F841`.
|
||||
|
||||
Full walkthrough with the complete `forward()` / `_create_stream_gen()`
|
||||
skeleton and stage-config fields:
|
||||
skeleton plus pipeline/deploy definitions:
|
||||
[references/single-stage-ar.md](references/single-stage-ar.md). For an
|
||||
in-tree reference, look for any single-stage AR model under
|
||||
`vllm_omni/model_executor/models/` — e.g. the MOSS-TTS-Nano integration when
|
||||
it lands.
|
||||
`vllm_omni/model_executor/models/`, such as MOSS-TTS-Nano.
|
||||
|
||||
**VoxCPM2 is a different pattern** and should not reuse this skeleton — it
|
||||
runs the base LM under vLLM PagedAttention with external side-computation.
|
||||
@@ -210,7 +213,8 @@ See `plan/voxcpm2_native_ar_design.md`.
|
||||
### Deliverables
|
||||
|
||||
- Model files in `vllm_omni/model_executor/models/<model_name>/`
|
||||
- Stage config YAML
|
||||
- Registered `pipeline.py` topology
|
||||
- Deploy YAML under `vllm_omni/deploy/`
|
||||
- Working `end2end.py` at `examples/offline_inference/text_to_speech/<model>/end2end.py`
|
||||
- New section in `examples/offline_inference/text_to_speech/README.md` (table row + per-model section). Do **not** create a top-level `examples/offline_inference/<model>/` dir or a per-model `README.md` inside `text_to_speech/<model>/` — the hub README is the documented surface and the mkdocs `generate_examples` hook only descends one level into `examples/<category>/`.
|
||||
|
||||
@@ -400,21 +404,29 @@ See [vllm-omni-test skill](../vllm-omni-test/SKILL.md) § **Runtime send helpers
|
||||
|
||||
### Steps
|
||||
|
||||
1. **Update stage config YAML**:
|
||||
1. **Update the pipeline topology** so the producing stage declares its async
|
||||
handoff processor with `async_chunk_process_next_stage_input_func`.
|
||||
2. **Update the deploy YAML** to enable async chunk and configure the connector:
|
||||
```yaml
|
||||
async_chunk: true
|
||||
codec_chunk_frames: 25 # frames per chunk
|
||||
codec_left_context_frames: 25 # overlap for smooth boundaries
|
||||
|
||||
connectors:
|
||||
connector_of_shared_memory:
|
||||
name: SharedMemoryConnector
|
||||
extra:
|
||||
codec_streaming: true
|
||||
codec_chunk_frames: 25
|
||||
codec_left_context_frames: 25
|
||||
```
|
||||
2. **Implement chunk handling in Stage 1**:
|
||||
3. **Implement chunk handling in Stage 1**:
|
||||
- Accept partial input (chunk of codec codes)
|
||||
- Handle left context for smooth audio boundaries
|
||||
- Return partial audio in `OmniOutput`
|
||||
3. **Test streaming**:
|
||||
4. **Test streaming**:
|
||||
- Verify audio quality matches non-streaming output
|
||||
- Check for artifacts at chunk boundaries
|
||||
- Measure TTFA (time to first audio)
|
||||
4. **Update online serving** to support `stream=true` with PCM output
|
||||
5. **Update online serving** to support `stream=true` with PCM output
|
||||
|
||||
### Streaming Architecture
|
||||
|
||||
@@ -435,7 +447,8 @@ Stage 0 (AR) Stage 1 (Decoder)
|
||||
|
||||
### Deliverables
|
||||
|
||||
- Updated stage config with async_chunk enabled
|
||||
- Updated pipeline async handoff processor and deploy config with
|
||||
`async_chunk: true`
|
||||
- Smooth streaming audio without boundary artifacts
|
||||
- TTFA metrics
|
||||
|
||||
@@ -507,14 +520,15 @@ Use this checklist when integrating a new TTS model:
|
||||
- [ ] Config classes created with `model_type` registration
|
||||
- [ ] Stage 0 (AR) implemented and generates correct tokens
|
||||
- [ ] Stage 1 (Decoder) produces correct audio from tokens — dtype float32 for codec decoder
|
||||
- [ ] Stage 1 `max_num_seqs` ≥ 4 in production config (default 1 causes gaps under concurrency)
|
||||
- [ ] AR stage `max_num_seqs` ≥ 4 in the production deploy config unless the model has a tested lower limit
|
||||
- [ ] Optional dependency fallbacks handled at `load_weights()` time (torchaudio/soundfile/etc.)
|
||||
- [ ] Streaming: codec codes accumulated across AR steps (not reset per step)
|
||||
- [ ] Streaming: delta audio emitted per chunk, not full re-decoded waveform
|
||||
- [ ] Streaming: all `forward()` return paths emit `model_outputs`
|
||||
- [ ] Streaming: per-request state keyed by request ID (not shared across requests)
|
||||
- [ ] Streaming: codec tensors moved to codec decoder device before decode
|
||||
- [ ] Stage config YAML created
|
||||
- [ ] Pipeline topology defined in `pipeline.py` and registered in `OMNI_PIPELINES`
|
||||
- [ ] Deploy YAML created under `vllm_omni/deploy/`
|
||||
- [ ] `end2end.py` produces audio matching reference quality
|
||||
- [ ] README.md written
|
||||
|
||||
@@ -531,7 +545,8 @@ Use this checklist when integrating a new TTS model:
|
||||
- [ ] Documentation added (offline + online docs, nav, supported models)
|
||||
|
||||
### Phase 4: Async Chunk
|
||||
- [ ] Stage config updated with `async_chunk: true`
|
||||
- [ ] Pipeline declares the async handoff processor
|
||||
- [ ] Deploy config sets `async_chunk: true` and connector chunk parameters
|
||||
- [ ] Stage 1 handles partial chunks correctly
|
||||
- [ ] No audio artifacts at chunk boundaries
|
||||
- [ ] Streaming via API (`stream=true`) works
|
||||
@@ -548,7 +563,7 @@ Use this checklist when integrating a new TTS model:
|
||||
- [ ] `pre-commit run --files <changed>` passes before every push
|
||||
- [ ] Every commit has `Signed-off-by` matching the author email (`git commit -s`)
|
||||
- [ ] `git config user.email` matches the email registered on your GitHub account
|
||||
- [ ] Details and failure-recovery commands: [references/precommit-dco.md](references/precommit-dco.md)
|
||||
- [ ] Hook list, failure table, and DCO recovery: [references/precommit-dco.md](references/precommit-dco.md)
|
||||
|
||||
## References
|
||||
|
||||
|
||||
@@ -30,6 +30,18 @@ but the changes are correct — stage the modified files and re-commit.
|
||||
| `ruff F841` | Variable extracted but never forwarded to model call | Remove the extraction or wire it through |
|
||||
| `ruff E402` | Import added below function definitions | Move to top-level import block |
|
||||
| `ruff format` | Line length, spacing, quote style | Accept auto-fix, stage, re-commit |
|
||||
| `check-spdx-header` | Missing header, or copyright still says `vLLM project` | Two-line Omni header (`vLLM-Omni project`); restage the rewrite |
|
||||
| `check-forbidden-imports` | Stdlib `re`/`base64`, pickle, Hugging Face Hub API, or direct Triton/TileLang | `import regex as re` and `pybase64`; use `vllm.transformers_utils.repo_utils`. Do **not** add the file to `allowed_files` without review |
|
||||
| `check-torch-cuda-call` | New `torch.cuda.*` call site | Use `current_omni_platform` / `OmniPlatform`; do not grow `ALLOWED_FILES` without review |
|
||||
| `check-tts-adapter-migration` | New `self._tts_model_type` branch in `serving_speech.py` | Put per-model logic in `tts_adapters/`. Lower `MAX_MODEL_TYPE_BRANCHES` when removing branches; do not raise it without review |
|
||||
| `check-test-ci-coverage` | New `tests/**/test_*.py` missing level or hardware mark | Add `core_model`/`advanced_model`/… plus `cpu`/`cuda`/`hardware_test(` |
|
||||
| `mypy-3.10` | Type error on changed `vllm_omni/` files | Fix the types; model trees are excluded. Extra versions: `pre-commit run --hook-stage manual mypy-3.12` |
|
||||
| `markdownlint-cli2` | Docs/README markdown lint | Accept auto-fix under `docs/` / `recipes/` / root README |
|
||||
| `check-buildkite` | Invalid `.buildkite/*.yml` | Fix the YAML; do not grow `SKIP_FILES` without review |
|
||||
| `shellcheck` | No `shellcheck` on PATH, or script warning | `apt-get`/`dnf`/`brew install shellcheck`, or `shellcheck.exe` on Windows PATH |
|
||||
|
||||
Canonical policy, CI `SKIP` list, and allowlist locations:
|
||||
[docs/contributing/README.md](../../../docs/contributing/README.md#linting).
|
||||
|
||||
## DCO sign-off
|
||||
|
||||
|
||||
@@ -86,12 +86,51 @@ class YourModelForCausalLM(nn.Module):
|
||||
- Handle both `"audio"` (incremental) and `"result"` (final combined) event
|
||||
types from upstream models.
|
||||
|
||||
## Stage config
|
||||
## Pipeline and deploy config
|
||||
|
||||
Single stage with `worker_type: ar`, `engine_output_type: audio`,
|
||||
`final_output: true`, `is_comprehension: true`, and `async_chunk: false` at
|
||||
the top level. Omitting any of these causes silent misclassification in the
|
||||
serving layer.
|
||||
Define the fixed single-stage topology in `pipeline.py`:
|
||||
|
||||
```python
|
||||
from vllm_omni.config.stage_config import (
|
||||
PipelineConfig,
|
||||
StageExecutionType,
|
||||
StagePipelineConfig,
|
||||
)
|
||||
|
||||
YOUR_TTS_PIPELINE = PipelineConfig(
|
||||
model_type="your_model_name",
|
||||
default_deploy_config_name="your_model_name.yaml",
|
||||
model_arch="YourModelForCausalLM",
|
||||
stages=(
|
||||
StagePipelineConfig(
|
||||
stage_id=0,
|
||||
model_stage="your_model_name",
|
||||
execution_type=StageExecutionType.LLM_AR,
|
||||
input_sources=(),
|
||||
owns_tokenizer=True,
|
||||
engine_output_type="audio",
|
||||
final_output=True,
|
||||
final_output_type="audio",
|
||||
),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
Register it in `vllm_omni/config/pipeline_registry.py`. Keep placement and
|
||||
runtime sizing in `vllm_omni/deploy/your_model_name.yaml`:
|
||||
|
||||
```yaml
|
||||
async_chunk: false
|
||||
|
||||
stages:
|
||||
- stage_id: 0
|
||||
devices: "0"
|
||||
max_num_seqs: 4
|
||||
gpu_memory_utilization: 0.8
|
||||
```
|
||||
|
||||
Do not move `execution_type`, output ownership, tokenizer ownership, or model
|
||||
architecture into the deploy YAML; those are pipeline topology.
|
||||
|
||||
## Lint discipline
|
||||
|
||||
@@ -101,8 +140,5 @@ pre-commit.
|
||||
|
||||
## Reference implementation
|
||||
|
||||
Look for any single-stage AR model under
|
||||
`vllm_omni/model_executor/models/` — e.g. `moss_tts_nano/` when its
|
||||
integration lands. If none is in tree yet, follow the skeleton above and
|
||||
cross-check against the `is_comprehension: true` / `async_chunk: false`
|
||||
dispatch in `vllm_omni/entrypoints/openai/serving_speech.py`.
|
||||
Use `vllm_omni/model_executor/models/moss_tts_nano/pipeline.py` and
|
||||
`vllm_omni/deploy/moss_tts_nano.yaml` as the in-tree reference.
|
||||
@@ -0,0 +1,135 @@
|
||||
---
|
||||
name: find-simplifications
|
||||
description: Find evidence-backed simplification candidates in vLLM-Omni and, when requested, turn them into focused proposals or code changes. Use for audits of dead, duplicated, speculative, over-generalized, unnecessarily defensive, or hand-rolled code. Use review-pr for ordinary correctness review and diffusion-perf-opt for performance-first optimization.
|
||||
---
|
||||
|
||||
# Find vLLM-Omni Simplifications
|
||||
|
||||
Find a small number of well-proven ways to reduce code, state, APIs, or maintenance cost without weakening supported behavior. Treat this as an architecture and ownership audit, not a dead-code search or style cleanup.
|
||||
|
||||
The default deliverable is a read-only report. Do not add TODOs, design documents, issues, or code unless the user asks for those changes.
|
||||
|
||||
## Establish the Contract
|
||||
|
||||
Before judging a candidate:
|
||||
|
||||
1. Read the repository instructions supplied by the host.
|
||||
2. Read [`docs/design/architecture_overview.md`](../../../docs/design/architecture_overview.md).
|
||||
3. Select only the relevant active module and feature documents from [`docs/design/index.md`](../../../docs/design/index.md). Archived design pages are historical context, not current contracts.
|
||||
4. Identify the comparison base with `git merge-base HEAD origin/main`; do not assume the current branch represents the intended baseline.
|
||||
5. If tests or CI coverage may change, use [`vllm-omni-test`](../vllm-omni-test/SKILL.md) for test placement, markers, and commands.
|
||||
|
||||
Separate an implementation accident from an intentional boundary. In particular:
|
||||
|
||||
- vLLM-Omni extends and sometimes overrides upstream vLLM. A similar upstream implementation is evidence for reuse only after comparing API, lifecycle, and multi-stage semantics.
|
||||
- Registries, import strings, model configuration, deployment YAML, plugins, and optional dependencies create dynamic consumers that a static reference count can miss.
|
||||
- Hardware backends, model families, execution modes, and connector implementations may be intentionally parallel. Do not propose collapsing one only because it is inactive in the local environment.
|
||||
- Stage, replica, request, cache, and transport state can look redundant while representing different owners. Prove that two fields or barriers encode the same fact before merging them.
|
||||
- A shorter hot path is not a simplification if it adds synchronization, tensor copies, host materialization, recompilation, or a measurable quality/performance regression.
|
||||
|
||||
## Strong Candidates
|
||||
|
||||
A strong candidate removes a meaningful surface and has a clear replacement or deletion boundary. Examples include:
|
||||
|
||||
- A public method, configuration option, registry entry, route, message field, or event has no production consumer and no compatibility obligation.
|
||||
- Tests or documentation are the only consumers of behavior that is not part of a supported contract.
|
||||
- Multiple layers mirror the same request, lifecycle, cache-validity, readiness, or topology state.
|
||||
- AR, diffusion, platform, or model-specific implementations duplicate a stable common operation and can share it without hiding performance-critical differences.
|
||||
- An inherited upstream vLLM primitive is reimplemented locally without an Omni-specific semantic difference.
|
||||
- Compatibility or fallback branches protect environments the project no longer supports.
|
||||
- Serialization, IPC, output formatting, or connector code materializes the same payload more than once or converts between equivalent representations.
|
||||
- A helper, abstraction, package split, or extension point has only one real implementation and adds more indirection than policy.
|
||||
- Hand-written infrastructure can be replaced by an existing project dependency, Python standard-library feature, PyTorch primitive, or upstream vLLM facility with net deletion and equal observability.
|
||||
- Tests maintain large mocks, snapshots, or expected data solely for an unused API or representation.
|
||||
|
||||
Do not elevate typo fixes, formatting, isolated renames, or vague complexity complaints into simplification candidates. Bundle small cleanups only when they support one substantive removal.
|
||||
|
||||
## Survey by Ownership Boundary
|
||||
|
||||
For broad audits, cover the largest or riskiest production deltas first. Useful domains are:
|
||||
|
||||
- `vllm_omni/engine/`: orchestration, stage pools, request state, output convergence, cancellation, and replica lifecycle.
|
||||
- `vllm_omni/worker/` and AR model execution: upstream vLLM overlays, scheduler/cache state, collective RPC, adapters, and weight loading.
|
||||
- `vllm_omni/diffusion/`: request/step execution, batching, output materialization, IPC, offload, parallelism, and model pipelines.
|
||||
- `vllm_omni/entrypoints/`: duplicated validation/defaulting, offline/online parity, streaming, and route compatibility.
|
||||
- Connectors and distributed code: ownership, copies, barriers, handles, cleanup, and failure propagation across process/device/node boundaries.
|
||||
- Platform backends: genuine vendor differences versus copied control flow that has drifted.
|
||||
- Configuration, registries, recipes, and examples: duplicate sources of truth and options that never reach a runtime consumer.
|
||||
- Tests and CI: redundant fixtures, mocks of obsolete contracts, and expensive coverage that can move to a cheaper level without losing the guarded behavior.
|
||||
|
||||
When the user explicitly requests a repository-wide or many-candidate audit and parallel agent work is available and authorized, divide these domains among agents and require the same evidence format from each. Otherwise survey them sequentially.
|
||||
|
||||
## Prove or Reject Each Candidate
|
||||
|
||||
Use `rg` first, then read every relevant caller and implementation. Search exact Python symbols plus serialized names, route paths, configuration keys, registry strings, YAML values, and CLI spellings.
|
||||
|
||||
Classify evidence:
|
||||
|
||||
- **Production:** `vllm_omni/`, runtime configuration, registries, serving entrypoints, connectors, recipes used for supported deployments, and executable loader paths.
|
||||
- **Validation/support:** `tests/`, benchmarks, examples, docs, CI, and developer tooling.
|
||||
- **External/dynamic:** upstream vLLM contracts, third-party plugins, model repositories, optional backends, and string-loaded objects. State what was checked and what remains unknown.
|
||||
|
||||
For each candidate, answer:
|
||||
|
||||
1. What exact surface would disappear or merge?
|
||||
2. Who owns the state or behavior today?
|
||||
3. Which production consumers exist, including dynamic consumers?
|
||||
4. What supported behavior, compatibility, performance, memory, or observability could change?
|
||||
5. What is the smallest validation that would catch a bad simplification?
|
||||
6. Is the result net deletion after tests, adapters, migration glue, and documentation are counted?
|
||||
|
||||
Reject or downgrade the candidate when a live consumer exists and removal is actually a feature decision; when an active design contract explains the separation; when the change only moves complexity; or when hardware/model evidence is unavailable for a performance-sensitive claim.
|
||||
|
||||
## Lifecycle and Data-Movement Audits
|
||||
|
||||
For asynchronous or distributed code, map the ownership graph before recommending deletion:
|
||||
|
||||
```text
|
||||
request admission -> orchestrator -> stage/replica -> worker/device
|
||||
-> connector or IPC boundary -> output aggregation -> terminal cleanup
|
||||
```
|
||||
|
||||
Associate every lock, event, sentinel, queue, readiness flag, timeout, abort path, and cache marker with an owner and transition. Coalesce mechanisms only when they represent the same state and have the same failure boundary. Preserve separate mechanisms when they protect publication versus rollback, local versus remote ownership, first-terminal-outcome arbitration, or cleanup after partial failure.
|
||||
|
||||
For tensors and media, also trace device, process, and ownership transitions. Count GPU-to-CPU copies, shared-memory/object-store handles, serialization, decode/encode steps, and unlink/release responsibility. Prefer eliminating a transfer or representation over merely hiding it behind a helper.
|
||||
|
||||
## Dependency Replacements
|
||||
|
||||
Prefer facilities already available in the repository before adding a dependency. For a proposed replacement:
|
||||
|
||||
- Name the exact local behavior it covers and any semantics that remain in glue code.
|
||||
- Check maintenance, license, optional-dependency boundaries, platform support, and transitive footprint.
|
||||
- Compare net deletion, test burden, import/startup cost, and runtime behavior.
|
||||
- Benchmark when the replaced code is on a model, scheduler, connector, serialization, or serving hot path.
|
||||
|
||||
A wrapper that retains the same state machine or conversion logic is not a simplification.
|
||||
|
||||
## Deliver the Result
|
||||
|
||||
Report only candidates supported by concrete evidence. For each one include:
|
||||
|
||||
- **Surface:** files and symbols involved.
|
||||
- **Evidence:** production consumers found, dynamic paths checked, and relevant design contract.
|
||||
- **Simplification:** exactly what to remove, merge, inline, or reuse.
|
||||
- **Benefit:** deleted API/state/code, reduced data movement, or reduced maintenance/test burden.
|
||||
- **Risk and validation:** behavior that could change and the narrowest useful tests or measurements.
|
||||
- **Confidence:** high or medium, with the unresolved evidence named for medium-confidence items.
|
||||
|
||||
Also list representative ideas that were rejected when that prevents repeated investigation. Prefer three high-confidence candidates over a long speculative inventory.
|
||||
|
||||
If the user asks for a durable design proposal, place it under `docs/design/feature/` and register it in `docs/design/index.md`; use current design-document conventions and keep implementation details proportional to the decision. If the user asks for implementation, make the smallest coherent change, update affected tests/docs, and preserve public compatibility unless the user explicitly accepts a breaking change.
|
||||
|
||||
## Folding Work from Another Branch
|
||||
|
||||
Diff the source branch against its own merge base with `origin/main`, not against the current feature branch. Port only independently justified candidates. Consolidate overlaps into the candidate with stronger evidence, and do not preserve a candidate count by carrying weaker duplicates.
|
||||
|
||||
## Validation
|
||||
|
||||
Match validation to the outgoing diff:
|
||||
|
||||
- Documentation or skill changes: run the repository skill validator when available, check links/paths, search for stale source-specific terminology, and run `git diff --check`.
|
||||
- Python changes: run the narrowest relevant pytest coverage through the repository environment, then lint/format the changed files.
|
||||
- Distributed, model, hardware, performance, or accuracy changes: run available CPU/static checks and state the exact GPU/NPU/model gap; never present simulated evidence as device validation.
|
||||
- Before submission, use [`precheck-pr`](../precheck-pr/SKILL.md) for the branch-level self-review.
|
||||
|
||||
When summarizing, distinguish checks that passed from checks that were not runnable, and state the snapshot or branch against which the audit was performed.
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: precheck-pr
|
||||
description: Self-check your branch before creating a PR — catch dead code, verify accuracy/perf claims, validate PR title format, and confirm merge readiness. Use when the user says "precheck", "self review", "pre-submit check", or "check my PR before I open it." Never posts to GitHub.
|
||||
description: Self-check your branch before creating a PR — catch dead code, prevent new model-specific Python examples, verify accuracy/perf claims, validate PR title format, and confirm merge readiness. Use when the user says "precheck", "self review", "pre-submit check", or "check my PR before I open it." Never posts to GitHub.
|
||||
---
|
||||
|
||||
# PR Pre-Check
|
||||
@@ -65,6 +65,12 @@ Ask: "Quick mode or full mode?" Then walk the checklist for the detected PR type
|
||||
|
||||
**Also run the Code-Quality sweep on every PR**, regardless of type or mode: the five diff-scoped checks in [references/code-quality.md](references/code-quality.md) — kwargs fragility, broad-except swallow, `Any`/wrong type hints, hot-path `.clone()`/`deepcopy`, and event-loop blocking — plus the advisory conventions (log level, structured logging, synchronization, cleanup, dependencies, naming) in [checklists.md](references/checklists.md). These count only lines the PR *adds* — the pre-existing backlog across the repo is out of scope.
|
||||
|
||||
**Also run the Examples-Policy check on every PR** using [references/examples-policy.md](references/examples-policy.md). Inspect only Python paths introduced by the diff. Treat a new model-, checkpoint-, vendor-, or family-specific Python example as blocking; do not report pre-existing example debt.
|
||||
|
||||
**Also run the Simplification pass on every PR** using [find-simplifications](../find-simplifications/SKILL.md). Keep it diff-scoped: inspect added or modified public APIs, state, abstractions, fallback and compatibility paths, data movement, and only the adjacent ownership needed to prove a candidate. Do not expand the pass into a repository-wide audit. Zero candidates is a valid pass; report only evidence-backed opportunities. Mark a candidate as blocking only when it proves a correctness or merge-readiness problem, such as newly unreachable code. Otherwise report it as a warning.
|
||||
|
||||
**Also confirm local pre-commit gates** from [docs/contributing/README.md](../../../docs/contributing/README.md#linting). GitHub Actions `SKIP` does not prove they passed. Full new-hook list: Omni SPDX (`vLLM-Omni project`); forbidden imports (stdlib `re`/`base64`, pickle, Hugging Face Hub API, Triton/TileLang); no new `torch.cuda` call sites; shellcheck (macOS/Windows must install the binary); mypy-3.10; test files have CI level + hardware marks; TTS `_tts_model_type` branches in `serving_speech.py` must not increase; markdownlint on `docs/`; Buildkite YAML schema. ✗ for growing `allowed_files` / `ALLOWED_FILES` or raising `MAX_MODEL_TYPE_BRANCHES` without review.
|
||||
|
||||
### Step 5: Print Report
|
||||
|
||||
```
|
||||
@@ -77,6 +83,8 @@ Pre-check report for <branch>
|
||||
───────────────── ──────
|
||||
PR title format ✓
|
||||
Code quality ⚠ 1 broad except, 2 Any hints
|
||||
Examples policy ✗ new model-specific Python example
|
||||
Simplification ⚠ helper duplicates an existing owner
|
||||
PR desc integrity ✓
|
||||
Registry/config ✓
|
||||
Dead code ⚠ 2 warnings
|
||||
|
||||
@@ -47,6 +47,19 @@ Diff-scoped sweep for five fragility patterns that are pervasive in the existing
|
||||
|
||||
Roll the ⚠/✗ counts into the report as a single **Code quality** dimension row.
|
||||
|
||||
---
|
||||
|
||||
## All PRs: Examples Policy (run on every PR, quick & full)
|
||||
|
||||
Inspect Python files introduced under `examples/` using
|
||||
[examples-policy.md](examples-policy.md). This is a diff-scoped ratchet: existing
|
||||
model-specific examples may be edited or removed without triggering the check.
|
||||
|
||||
- [ ] **No new model-specific Python examples:** the diff adds, copies, or renames no Python file whose path or behavior is specific to one model, checkpoint, vendor, or model family. ✗ for any violation. Route inference through a shared task/protocol entrypoint, model request behavior through `vllm_omni/model_extras`, and commands through task docs or `recipes/`.
|
||||
- [ ] **New generic example code is justified:** any new task-neutral Python file under `examples/` is an actual user-facing entrypoint rather than reusable production logic, a benchmark, an app, a setup tool, or a reproducer. ⚠ when the placement is questionable.
|
||||
|
||||
Roll the result into the report as a separate **Examples policy** dimension.
|
||||
|
||||
### Conventions (eyeball — no grep)
|
||||
|
||||
Judgment calls that don't grep cleanly — apply them while reading the diff, not as a mechanical check:
|
||||
@@ -151,6 +164,7 @@ Diffusion models live under `vllm_omni/diffusion/`. In addition to the New Model
|
||||
- [ ] **PR body matches diff:** description doesn't claim changes not in the diff
|
||||
- [ ] **Branch is rebased:** `git merge-base HEAD origin/main` is recent, no merge conflicts
|
||||
- [ ] **CI gates passing:** DCO, pre-commit, build — check `gh pr view --json statusCheckRollup` if a PR already exists
|
||||
- [ ] **Local pre-commit gates:** full list in [Linting](../../../../docs/contributing/README.md#linting). Blocking when the diff introduces: stale `vLLM project` SPDX; stdlib `re`/`base64` or pickle in library code; new `torch.cuda` call sites; `tests/**/test_*.py` without level+hardware marks; new `_tts_model_type` branches in `serving_speech.py`; invalid `.buildkite` YAML. macOS/Windows need a native `shellcheck`. ✗ for growing `CHECK_IMPORTS[*].allowed_files`, `ALLOWED_FILES`, or `MAX_MODEL_TYPE_BRANCHES` without review.
|
||||
|
||||
### Full (adds)
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
# Examples Python Policy
|
||||
|
||||
Prevent new model-specific Python examples without forcing cleanup of the
|
||||
existing backlog. Run this check on every PR in quick and full modes.
|
||||
|
||||
## Scope
|
||||
|
||||
Set the merge base as in the main workflow, then list Python paths introduced
|
||||
by the PR, including additions, copies, and renames:
|
||||
|
||||
```bash
|
||||
BASE="$(git merge-base HEAD origin/main)"
|
||||
git diff --name-status --diff-filter=ACR --find-renames --find-copies \
|
||||
"${BASE}"...HEAD -- 'examples/**/*.py'
|
||||
```
|
||||
|
||||
Inspect destination paths for copies and renames. Existing model-specific files
|
||||
that are only modified or deleted are grandfathered and must not be reported.
|
||||
|
||||
## Blocking classification
|
||||
|
||||
Mark ✗ when a newly introduced Python file does any of the following:
|
||||
|
||||
- Names or scopes a path to one model, checkpoint, vendor, or model family.
|
||||
- Hard-codes a model identifier, model-specific prompt, request shape, output
|
||||
conversion, or launch configuration behind an otherwise generic filename.
|
||||
- Duplicates an existing task/protocol runner to demonstrate one model.
|
||||
- Adds a per-model helper below a generic task hub such as `text_to_speech/`.
|
||||
|
||||
Do not infer safety from a generic filename alone. For example, a file named
|
||||
`text_to_audio.py` is still model-specific if it only implements one model's
|
||||
contract.
|
||||
|
||||
## Acceptable additions
|
||||
|
||||
A new Python example may pass when it is a genuinely model-neutral,
|
||||
user-facing task or protocol entrypoint. It must accept model selection through
|
||||
configuration and keep model-specific behavior out of the script.
|
||||
|
||||
Use ⚠ when the file is model-neutral but reusable logic appears misplaced under
|
||||
`examples/`. Route code by purpose:
|
||||
|
||||
| Code purpose | Preferred location |
|
||||
|---|---|
|
||||
| Model prompt, defaults, request/output adaptation | `vllm_omni/model_extras/` or production model modules |
|
||||
| Runnable model command and validation evidence | Task documentation or `recipes/` |
|
||||
| UI or interactive application | `apps/` |
|
||||
| Benchmark or evaluator | `benchmarks/` |
|
||||
| Regression reproducer | `tests/` |
|
||||
| Download, conversion, or setup utility | `tools/` |
|
||||
|
||||
If a model cannot use an existing shared runner, report the missing generic
|
||||
capability. Do not solve the gap by adding a model-specific Python example.
|
||||
|
||||
## Report format
|
||||
|
||||
Add one row to the pre-check report:
|
||||
|
||||
```text
|
||||
Examples policy ✓ no new Python example paths
|
||||
Examples policy ⚠ generic helper belongs in tools/
|
||||
Examples policy ✗ examples/offline_inference/new_model/end2end.py is model-specific
|
||||
Examples policy ✗ examples/offline_inference/x_to_y_model_name.py is model-specific
|
||||
```
|
||||
|
||||
For a blocker, name the path, the model-specific behavior, and the appropriate
|
||||
shared runner or destination. Do not propose deleting unrelated existing
|
||||
examples as part of the PR.
|
||||
+41
-28
@@ -1,9 +1,9 @@
|
||||
# Claude Skills for vLLM-Omni
|
||||
# Repository Skills for vLLM-Omni
|
||||
|
||||
This directory contains Claude Code skills maintained for the `vllm-omni`
|
||||
repository. These skills capture repeatable workflows for common contributor
|
||||
tasks such as model integration, pull request review, and release note
|
||||
generation.
|
||||
This directory contains repository-scale skills maintained for `vllm-omni`.
|
||||
They capture repeatable workflows for common contributor and maintainer tasks
|
||||
such as model integration, CI-aligned testing, performance optimization, and
|
||||
pull request review.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
@@ -14,31 +14,44 @@ include:
|
||||
- `references/`: focused reference material used by the skill
|
||||
- `scripts/`: small helper scripts used by the skill
|
||||
|
||||
## Using the Skills
|
||||
|
||||
Coding agents that discover repository skills can invoke the relevant skill by
|
||||
name. For other agents, point them to the skill's `SKILL.md` and ask them to
|
||||
read it before changing code. Combine a domain skill with `vllm-omni-test` when
|
||||
tests or CI coverage change, then use `precheck-pr` for the contributor's final
|
||||
self-check.
|
||||
|
||||
## Available Skills
|
||||
|
||||
- `add-diffusion-model`: guides integration of a new diffusion model into
|
||||
`vllm-omni`
|
||||
- `diffusion-perf-opt`: guides diffusion model performance optimization,
|
||||
including profiling traces, parallel strategies, stage timing analysis, and
|
||||
benchmark-driven tuning
|
||||
- `quantization`: guides quantization method selection, model integration,
|
||||
checkpoint loading, and quality/performance validation for vLLM-Omni
|
||||
- `add-omni-model`: covers addition of new omni-modality model support
|
||||
- `add-tts-model`: covers integration of new TTS models and related serving
|
||||
workflows
|
||||
- `generate-release-note`: helps prepare release notes for repository changes
|
||||
- `precheck-pr`: self-check a branch before creating a PR — validates PR title
|
||||
format, catches dead code, verifies accuracy/perf claims, and confirms merge
|
||||
readiness
|
||||
- `vllm-omni-test`: guides generation and execution of CI-aligned tests (L1–L4),
|
||||
pytest marker selection (`core_model` / `advanced_model` / `full_model`,
|
||||
`omni` / `tts` / `diffusion`), Buildkite wiring (`test-ready.yml`,
|
||||
`test-merge.yml`, `test-nightly.yml`, `test-weekly.yml`), and copy-paste
|
||||
local plus CI-like `pytest` commands; see `references/test-routing.md` for
|
||||
level-to-command mapping
|
||||
- `review-pr`: provides a structured workflow for reviewing pull requests
|
||||
- `vllm-omni-npu-model-runner-upgrade`: upgrades NPU model runners to align with the
|
||||
latest vllm-ascend NPUModelRunner
|
||||
- [`add-diffusion-model`](add-diffusion-model/SKILL.md): guides integration of
|
||||
a new diffusion model into `vllm-omni`
|
||||
- [`add-tts-model`](add-tts-model/SKILL.md): covers integration of new TTS
|
||||
models and related serving workflows
|
||||
- [`diffusion-perf-opt`](diffusion-perf-opt/SKILL.md): guides diffusion model
|
||||
performance optimization, including profiling traces, parallel strategies,
|
||||
stage timing analysis, and benchmark-driven tuning
|
||||
- [`find-simplifications`](find-simplifications/SKILL.md): finds evidence-backed
|
||||
opportunities to remove or merge dead, duplicated, speculative,
|
||||
over-generalized, or unnecessarily defensive vLLM-Omni code
|
||||
- [`precheck-pr`](precheck-pr/SKILL.md): self-checks a branch before creating a
|
||||
PR by validating title format, dead code, simplification opportunities,
|
||||
accuracy and performance claims, and merge readiness
|
||||
- [`quantization`](quantization/SKILL.md): guides quantization method selection,
|
||||
model integration, checkpoint loading, and quality/performance validation
|
||||
for vLLM-Omni
|
||||
- [`review-pr`](review-pr/SKILL.md): provides a frozen-snapshot, contract-aware
|
||||
workflow for maintainers and reviewers; contributors should use
|
||||
`precheck-pr` for self-review
|
||||
- [`vllm-omni-npu-model-runner-upgrade`](vllm-omni-npu-upgrade/SKILL.md):
|
||||
upgrades NPU model runners to align with the latest vllm-ascend
|
||||
`NPUModelRunner`
|
||||
- [`vllm-omni-test`](vllm-omni-test/SKILL.md): guides generation and execution
|
||||
of CI-aligned tests (L1–L4), pytest marker selection (`core_model` /
|
||||
`advanced_model` / `full_model`, `omni` / `tts` / `diffusion`), Buildkite
|
||||
wiring (`test-ready.yml`, `test-merge.yml`, `test-nightly.yml`,
|
||||
`test-weekly.yml`), and copy-paste local plus CI-like `pytest` commands; see
|
||||
`references/test-routing.md` for level-to-command mapping
|
||||
|
||||
## Maintenance Guidelines
|
||||
|
||||
|
||||
@@ -21,7 +21,10 @@ Make every finding:
|
||||
- **Calibrated:** match severity to user and maintainer impact.
|
||||
|
||||
Do not report unrelated backlog, style already enforced by pre-commit, or a
|
||||
missing test that would not protect changed behavior.
|
||||
missing test that would not protect changed behavior. Do report new allowlist
|
||||
or budget entries in `check_forbidden_imports.py` / `check_torch_cuda.py` /
|
||||
`check_tts_adapter.py` / `check_buildkite.py` unless the PR justifies them:
|
||||
those are policy changes, not lint noise.
|
||||
|
||||
## Select the input and depth
|
||||
|
||||
@@ -92,11 +95,13 @@ If docs and live code disagree, verify the code/tests and report the drift.
|
||||
|
||||
| Reference | Read when |
|
||||
| --- | --- |
|
||||
| [model-addition-checklist.md](references/checks/model-addition-checklist.md) | A model, architecture, loader, processor, registry, or stage config is added. |
|
||||
| [model-addition-checklist.md](references/checks/model-addition-checklist.md) | A model, architecture, loader, processor, registry, pipeline config, or deploy config is added. |
|
||||
| [perf-verification.md](references/checks/perf-verification.md) | The PR makes a latency, throughput, memory, or quality claim. |
|
||||
| [test-quality-evaluation.md](references/checks/test-quality-evaluation.md) | Tests change, are absent for risky code, or may not exercise production behavior. |
|
||||
| [tests-docs-checklist.md](references/checks/tests-docs-checklist.md) | Coverage, CI markers, examples, user docs, or PR evidence need review. |
|
||||
| [verification.md](references/checks/verification.md) | Hardware, a server, or a runnable affected path is available for active verification. |
|
||||
| [examples-policy.md](../precheck-pr/references/examples-policy.md) | The PR adds, copies, or renames Python under `examples/`; apply the canonical policy shared with `precheck-pr`. |
|
||||
| [find-simplifications](../find-simplifications/SKILL.md) | Every review; run a diff-scoped subtraction and simplification pass after correctness blockers. |
|
||||
|
||||
### Delivery and reviewer coordination
|
||||
|
||||
@@ -152,6 +157,13 @@ contract they protect or use only the applicable evidence checks.
|
||||
Apply every category in [general-checks.md](references/process/general-checks.md) before
|
||||
lower-priority comments.
|
||||
|
||||
If the diff census contains an added, copied, or renamed Python path under
|
||||
`examples/`, read and apply the canonical
|
||||
[examples policy](../precheck-pr/references/examples-policy.md). Treat a new
|
||||
model-specific Python example as blocking. Do not flag model-specific example
|
||||
debt that the PR only modifies or removes, and do not run the rest of the
|
||||
author-oriented `precheck-pr` workflow.
|
||||
|
||||
For each changed value or behavior, trace:
|
||||
|
||||
```text
|
||||
@@ -172,9 +184,13 @@ promotion gate. Candidate or draft rules are questions, not blockers, unless
|
||||
current code, tests, or policy enforce them. Inspect both sides of any config,
|
||||
registry, serialization, connector, cache, or stage boundary.
|
||||
|
||||
When a diff adds or expands a helper, class, fallback, compatibility branch, or
|
||||
public behavior, run a subtraction pass: remove out-of-scope behavior and check
|
||||
whether each new abstraction can be deleted, merged, moved, or inlined.
|
||||
Read and apply [find-simplifications](../find-simplifications/SKILL.md) on every
|
||||
review. Constrain it to the diff and the adjacent ownership, callers, or
|
||||
consumers needed to prove a candidate. Check whether added or expanded helpers,
|
||||
classes, state, fallback and compatibility branches, data movement, or public
|
||||
behavior can be deleted, merged, moved, or inlined. Zero candidates is a valid
|
||||
result. Do not widen the review into repository backlog or report speculative
|
||||
style preferences as simplification findings.
|
||||
|
||||
### 6. Verify the changed path
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Model Addition Checklist
|
||||
|
||||
Read this reference when a PR adds or expands a model architecture, pipeline,
|
||||
loader, processor, registry entry, or stage configuration.
|
||||
loader, processor, registry entry, pipeline config, or deploy config.
|
||||
|
||||
Official docs: [model contribution guides](https://docs.vllm.ai/projects/vllm-omni/en/latest/contributing/model/),
|
||||
[adding an omni model](https://docs.vllm.ai/projects/vllm-omni/en/latest/contributing/model/adding_omni_model/),
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
Primary design: [vLLM-Omni Configuration](https://docs.vllm.ai/projects/vllm-omni/en/latest/design/module/vllm_omni_config/).
|
||||
|
||||
Use for config construction, deploy YAML, registries, schema, defaults,
|
||||
aliases, CLI projection, stage config, and topology. Inspect the reviewed
|
||||
aliases, CLI projection, pipeline config, and topology. Inspect the reviewed
|
||||
page's status: while its contract remains deferred or draft, current code and
|
||||
tests—not proposed precedence rules—are authoritative.
|
||||
|
||||
|
||||
@@ -111,6 +111,17 @@ Mark early findings as preliminary and continue. This is not a GitHub comment.
|
||||
but do not publish review events without separate authorization.
|
||||
- Record DCO, pre-commit, required CI, and mergeability. Pending or unknown gates
|
||||
do not block source review.
|
||||
- GitHub Actions `SKIP` omits SPDX, shellcheck, markdownlint, mypy-3.10, and
|
||||
test-mark coverage. A green GHA pre-commit job does not prove those local
|
||||
gates passed. New files still need the full Linting list: Omni SPDX
|
||||
(`vLLM-Omni project`), no stdlib `re`/`base64` in `vllm_omni/`, no new
|
||||
pickle / Hugging Face Hub API / `torch.cuda` call sites, test marks, TTS
|
||||
adapter ratchet, Buildkite schema, and native shellcheck on macOS/Windows.
|
||||
See [Linting](https://vllm-omni.readthedocs.io/en/latest/contributing/#linting).
|
||||
- Expanding `CHECK_IMPORTS[*].allowed_files`, `ALLOWED_FILES`,
|
||||
`MAX_MODEL_TYPE_BRANCHES`, or Buildkite `SKIP_FILES` is a policy change.
|
||||
Do not rubber-stamp allowlist/budget growth; require justification and
|
||||
prefer fixing the call site.
|
||||
- Treat a failed gate as its own evidence. Do not restate its formatting/lint
|
||||
output as a new code-review finding.
|
||||
- Open CI logs only when the first failing step overlaps the frozen diff or
|
||||
|
||||
@@ -48,7 +48,7 @@ compatibility changes.
|
||||
|
||||
| Signal | Read | Optional repo-local skill |
|
||||
| --- | --- | --- |
|
||||
| New or expanded model, loader, processor, registry, or stage config | [model-addition-checklist.md](../checks/model-addition-checklist.md) | [`add-tts-model`](../../../add-tts-model/SKILL.md) or [`add-diffusion-model`](../../../add-diffusion-model/SKILL.md) |
|
||||
| New or expanded model, loader, processor, registry, pipeline config, or deploy config | [model-addition-checklist.md](../checks/model-addition-checklist.md) | [`add-tts-model`](../../../add-tts-model/SKILL.md) or [`add-diffusion-model`](../../../add-diffusion-model/SKILL.md) |
|
||||
| Latency, throughput, memory, scaling, precision, or quality claim | [perf-verification.md](../checks/perf-verification.md) | [`diffusion-perf-opt`](../../../diffusion-perf-opt/SKILL.md) for diffusion |
|
||||
| Tests changed, absent for risky behavior, or test-only | [test-quality-evaluation.md](../checks/test-quality-evaluation.md) | [`vllm-omni-test`](../../../vllm-omni-test/SKILL.md) |
|
||||
| CI, examples, docs, public behavior, or contributor evidence | [tests-docs-checklist.md](../checks/tests-docs-checklist.md) | None |
|
||||
|
||||
@@ -110,10 +110,10 @@ After choosing offline/online/docs/perf, classify the **product under test** and
|
||||
|-----------|------------------------------|----------------------------|----------------------------------------|
|
||||
| **What it is** | Multimodal LLM pipeline (thinker/talker/stages; text + vision + audio I/O) | Speech synthesis / voice models | Generative diffusion (noise → image, audio, text, or video) |
|
||||
| **Examples** | Qwen2.5-Omni, Qwen3-Omni | Qwen3-TTS, VoxCPM2, Higgs-Audio, Step-Audio2 | Qwen-Image, BAGEL, Wan2.2, HunyuanVideo |
|
||||
| **Offline runner** | `omni_runner` + `omni_runner_handler`, `generate_multimodal` | `Omni(...).generate` or stage YAML + TTS params | `Omni(...).generate` + `OmniDiffusionSamplingParams` |
|
||||
| **Offline runner** | `omni_runner` + `omni_runner_handler`, `generate_multimodal` | `Omni(...).generate` with deploy YAML + TTS params | `Omni(...).generate` + `OmniDiffusionSamplingParams` |
|
||||
| **Online client** | `openai_client.send_omni_request` (chat completions, modalities) | `openai_client.send_audio_speech_request` (`/v1/audio/speech`) | `send_diffusion_request` (chat/T2I), `send_video_diffusion_request` (`/v1/videos`, X2V), or `send_images_generations_http_request` / `send_images_edits_http_request` (DALL-E routes) |
|
||||
| **Typical assertions** | Stage outputs, text/audio keywords via `OmniRunnerHandler` / response handler | WAV bytes, stream chunks, speech endpoint contract | Image/video dimensions, `final_output_type`, `assert_diffusion_response` |
|
||||
| **Stage / deploy YAML** | Per-model omni stage configs (`ci/qwen3_omni_moe.yaml`, …) | `qwen3_tts.yaml`, `voxcpm2.yaml`, … | Often default serve; parallel/offload YAML for heavy DiT |
|
||||
| **Deploy YAML** | Per-model deploy configs (`ci/qwen3_omni_moe.yaml`, …) | `qwen3_tts.yaml`, `voxcpm2.yaml`, … | Often default serve; parallel/offload YAML for heavy DiT |
|
||||
| **Nightly group** (`test-nightly.yml`) | **Omni Model Test** — `-m "full_model and omni"` | **TTS Model Test** — `-m "full_model and tts"` | **Diffusion X2I(&A&T)** *or* **Diffusion X2V** (see Step 3 table; same `diffusion` marker, different YAML group / file shard) |
|
||||
| **L4 pressure** | Expansion per modality/model as needed | Expansion + accuracy/perf in TTS group | X2I: merge feature combos per [#1832](https://github.com/vllm-project/vllm-omni/issues/1832); X2V: separate nightly group |
|
||||
|
||||
@@ -274,6 +274,7 @@ def test_text_to_video_001(omni_server, openai_client) -> None:
|
||||
|
||||
**3. Cross-cutting rules**
|
||||
|
||||
- New `.py` files need the Omni SPDX header (`Copyright contributors to the vLLM-Omni project`, not `vLLM project`). `tests/` may keep stdlib `re`/`base64`; pickle is still banned unless the file is already on the pickle allowlist. Every collected `tests/**/test_*.py` needs a CI **level** mark and a **hardware** mark/helper (`check-test-ci-coverage` runs locally; GHA skips it). Do not grow `allowed_files` to land a test. Policy: [docs/contributing/README.md](../../../docs/contributing/README.md#linting).
|
||||
- Reuse existing fixtures for the chosen scenario; do not mix “online client” assumptions into offline `OmniRunner` tests without a clear reason.
|
||||
- Avoid external network dependency in assertions unless the scenario is explicitly “online serving” or doc examples that require a model hub (then align with CI secrets/cache).
|
||||
- Keep **one test function = one intent** (one modality combo, one endpoint contract, or one acceleration combo).
|
||||
|
||||
@@ -79,8 +79,6 @@
|
||||
/vllm_omni/model_executor/models/ @tzhouam @gcanlin @Sy0307 @amy-why-3459 @linyueqian
|
||||
/vllm_omni/model_extras/ @tzhouam @gcanlin @princepride
|
||||
/vllm_omni/plugins/ @gcanlin @tjtanaa @xuechendi
|
||||
# Config override within model_executor — docs/design/module/vllm_omni_config.md
|
||||
/vllm_omni/model_executor/stage_configs/ @lishunyang12 @alex-jw-brooks
|
||||
|
||||
# Execution platforms (hardware backends) — docs/design/module/execution_platforms.md
|
||||
/vllm_omni/platforms/ @gcanlin @tjtanaa @xuechendi
|
||||
|
||||
@@ -83,7 +83,7 @@ body:
|
||||
|
||||
omni = Omni(
|
||||
model="Qwen/Qwen-Image",
|
||||
stage_configs_path="/path/to/stage_configs.yaml",
|
||||
deploy_config="/path/to/deploy_config.yaml",
|
||||
)
|
||||
|
||||
prompts = [{"prompt": "A scenic watercolor painting of a lighthouse at sunset"}]
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ pull_request_rules:
|
||||
> # For mypy (substitute "3.10" with the failing version if needed)
|
||||
> pre-commit run --hook-stage manual mypy-3.10
|
||||
> # For markdownlint
|
||||
> pre-commit run --hook-stage manual markdownlint
|
||||
> pre-commit run markdownlint-cli2
|
||||
> ```
|
||||
> </details>
|
||||
|
||||
|
||||
@@ -24,9 +24,7 @@ jobs:
|
||||
python-version: "3.12"
|
||||
cache: 'pip'
|
||||
- uses: pre-commit/action@v3.0.1
|
||||
# Don't run the pytest mark check against everything in the CI
|
||||
# for now since a lot of files are still missing them. This check
|
||||
# is used to help contributors remember to add the marks when they
|
||||
# commit.
|
||||
# Don't run historical-debt hooks against the whole tree in CI yet.
|
||||
# They still run locally on changed files.
|
||||
env:
|
||||
SKIP: check-test-ci-coverage
|
||||
SKIP: check-test-ci-coverage,markdownlint-cli2,shellcheck,check-spdx-header,mypy-3.10
|
||||
+7
-1
@@ -46,6 +46,8 @@ htmlcov/
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
coverage-*.xml
|
||||
coverage-*.xml.gz
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
@@ -240,9 +242,9 @@ data/
|
||||
datasets/
|
||||
*.csv
|
||||
*.json
|
||||
!recipes/cosmos3/negative_prompt.json
|
||||
!tests/dfx/perf/tests/*.json
|
||||
!apps/ComfyUI-vLLM-Omni/example_workflows/*.json
|
||||
!tests/assets/soulxsinger/*.json
|
||||
*.jsonl
|
||||
*.parquet
|
||||
|
||||
@@ -252,6 +254,7 @@ outputs/
|
||||
results/
|
||||
generated/
|
||||
output_*/
|
||||
/tests/e2e/accuracy/artifacts/
|
||||
|
||||
# Configuration overrides
|
||||
configs/local.yaml
|
||||
@@ -275,3 +278,6 @@ tests/.ci_generated/
|
||||
|
||||
# Local Lance precision-matching dump scripts (not part of the repo)
|
||||
lance_compare/
|
||||
|
||||
# Linting binaries downloaded by local pre-commit hooks
|
||||
shellcheck*/
|
||||
@@ -0,0 +1,17 @@
|
||||
# Keep these rules aligned with vLLM so MkDocs Material syntax is tolerated.
|
||||
MD007:
|
||||
indent: 4
|
||||
MD013: false
|
||||
# GitHub READMEs start with a centered logo, not an H1.
|
||||
MD041: false
|
||||
MD024:
|
||||
siblings_only: true
|
||||
MD025:
|
||||
# Allow front matter title to be different from the first heading in the document.
|
||||
front_matter_title: ""
|
||||
MD031:
|
||||
list_items: false
|
||||
MD033: false
|
||||
MD046: false
|
||||
MD052: false
|
||||
MD059: false
|
||||
+92
-10
@@ -24,7 +24,7 @@ repos:
|
||||
- id: ruff-format
|
||||
|
||||
- repo: https://github.com/crate-ci/typos
|
||||
rev: typos-dict-v0.13.13
|
||||
rev: v1.49.0
|
||||
hooks:
|
||||
- id: typos
|
||||
# only for staged files
|
||||
@@ -38,7 +38,19 @@ repos:
|
||||
- id: actionlint
|
||||
files: ^\.github/workflows/.*\.ya?ml$
|
||||
|
||||
- repo: https://github.com/DavidAnson/markdownlint-cli2
|
||||
rev: v0.23.2
|
||||
hooks:
|
||||
- id: markdownlint-cli2
|
||||
language_version: lts
|
||||
args: [--fix]
|
||||
files: (^docs/|^recipes/|(^|/)README\.md$|^CONTRIBUTING\.md$)
|
||||
# Agent skill docs and CLAUDE.md are not user-facing docs/READMEs.
|
||||
exclude: (^|/)CLAUDE\.md$|^\.claude/|^\.cursor/
|
||||
|
||||
# Keep `local` last so `suggestion` stays the final hook. Autofix repos
|
||||
# (ruff, typos, markdownlint, trailing-whitespace, etc.) must run first;
|
||||
# otherwise their "files were modified" output displaces the SKIP tip.
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: signoff-commit
|
||||
@@ -54,6 +66,45 @@ repos:
|
||||
verbose: true
|
||||
stages: [commit-msg]
|
||||
|
||||
# TODO: Use https://github.com/pre-commit/mirrors-mypy when mypy setup
|
||||
# is less awkward. Local wrapper groups files so follow_imports=skip on
|
||||
# tests does not leak into library code.
|
||||
# mypy-3.10 runs on git commit (changed files). CI SKIPs it because
|
||||
# --all-files is not clean yet. Extra versions are manual-stage only
|
||||
# (not in default `pre-commit run --all-files`):
|
||||
# pre-commit run --hook-stage manual mypy-3.12
|
||||
- id: mypy-3.10
|
||||
name: Run mypy for Python 3.10
|
||||
entry: python tools/pre_commit/mypy.py "3.10"
|
||||
<<: &mypy_common
|
||||
language: python
|
||||
types_or: [python, pyi]
|
||||
require_serial: true
|
||||
additional_dependencies:
|
||||
- mypy==1.11.1
|
||||
- regex
|
||||
- types-cachetools
|
||||
- types-setuptools
|
||||
- types-PyYAML
|
||||
- types-requests
|
||||
- types-torch
|
||||
- pydantic
|
||||
- id: mypy-3.11
|
||||
name: Run mypy for Python 3.11
|
||||
entry: python tools/pre_commit/mypy.py "3.11"
|
||||
<<: *mypy_common
|
||||
stages: [manual]
|
||||
- id: mypy-3.12
|
||||
name: Run mypy for Python 3.12
|
||||
entry: python tools/pre_commit/mypy.py "3.12"
|
||||
<<: *mypy_common
|
||||
stages: [manual]
|
||||
- id: mypy-3.13
|
||||
name: Run mypy for Python 3.13
|
||||
entry: python tools/pre_commit/mypy.py "3.13"
|
||||
<<: *mypy_common
|
||||
stages: [manual]
|
||||
|
||||
- id: check-test-ci-coverage
|
||||
name: Ensure test files have pytestmarks
|
||||
entry: python tools/pre_commit/check_test_marks.py
|
||||
@@ -66,12 +117,50 @@ repos:
|
||||
entry: python tools/pre_commit/check_tts_adapter.py
|
||||
language: python
|
||||
pass_filenames: false
|
||||
files: ^(vllm_omni/entrypoints/openai/(serving_speech\.py|tts_adapters/__init__\.py)|tools/pre_commit/check_tts_adapter\.py)$
|
||||
files: ^(vllm_omni/entrypoints/openai/serving_speech\.py|tools/pre_commit/check_tts_adapter\.py)$
|
||||
# The budget-is-now-slack reminder is printed on a PASSING run, and
|
||||
# pre-commit hides output from passing hooks unless the hook is verbose.
|
||||
verbose: true
|
||||
|
||||
# Keep `suggestion` last
|
||||
- id: shellcheck
|
||||
name: Lint shell scripts
|
||||
# language: script breaks on Windows (shebang path loses slashes).
|
||||
# Invoke the vLLM-style wrapper with bash so Linux CI and Win/Git Bash work.
|
||||
entry: bash
|
||||
args: [tools/pre_commit/shellcheck.sh]
|
||||
language: system
|
||||
types: [shell]
|
||||
|
||||
- id: check-spdx-header
|
||||
name: Check SPDX headers
|
||||
entry: python tools/pre_commit/check_spdx_header.py
|
||||
language: python
|
||||
types_or: [python, pyi, rust, proto, shell]
|
||||
files: \.(py|pyi|rs|proto|sh)$
|
||||
|
||||
- id: check-forbidden-imports
|
||||
name: Check forbidden imports
|
||||
entry: python tools/pre_commit/check_forbidden_imports.py
|
||||
language: python
|
||||
types: [python]
|
||||
additional_dependencies: [regex]
|
||||
|
||||
- id: check-torch-cuda-call
|
||||
name: Prevent new torch.cuda API calls
|
||||
entry: python tools/pre_commit/check_torch_cuda.py
|
||||
language: python
|
||||
types: [python]
|
||||
additional_dependencies: [regex]
|
||||
|
||||
- id: check-buildkite
|
||||
name: Validate Buildkite Pipelines
|
||||
entry: python tools/pre_commit/check_buildkite.py
|
||||
language: python
|
||||
files: ^\.buildkite/.*\.ya?ml$
|
||||
additional_dependencies: [pyyaml, check-jsonschema==0.38.0]
|
||||
|
||||
# Keep `suggestion` as the final hook. Run after autofix hooks so the
|
||||
# bypass/SKIP tip is not displaced.
|
||||
- id: suggestion
|
||||
name: Suggestion
|
||||
entry: bash -c 'echo "To bypass all the pre-commit hooks, add --no-verify to git commit. To skip a specific hook, prefix the commit command with SKIP=<hook-id>."'
|
||||
@@ -79,10 +168,3 @@ repos:
|
||||
verbose: true
|
||||
pass_filenames: false
|
||||
# Insert new entries above the `suggestion` entry
|
||||
|
||||
- id: check-pickle-imports
|
||||
name: Prevent new pickle/cloudpickle imports
|
||||
entry: python tools/pre_commit/check_pickle_imports.py
|
||||
language: python
|
||||
types: [python]
|
||||
additional_dependencies: [regex]
|
||||
+7
-2
@@ -11,10 +11,15 @@ build:
|
||||
post_checkout:
|
||||
- git fetch --unshallow || true
|
||||
pre_install:
|
||||
# `pre_install` runs before RTD upgrades pip, and the seeded pip 23.1
|
||||
# rejects the `typing_extensions` wheel torch needs (fixed in pip 23.2).
|
||||
- python -m pip install --upgrade pip
|
||||
# Pre-install CPU torch so the subsequent `pip install .[docs]` does not
|
||||
# pull ~2 GB of CUDA 13 libs (cuBLAS/cuDNN/NCCL/...) that exceed RTD's
|
||||
# 1 GB memory cap and time out the mkdocs build.
|
||||
- python -m pip install --index-url https://download.pytorch.org/whl/cpu torch
|
||||
# 1 GB memory cap and time out the mkdocs build. Wheel-only: `--index-url`
|
||||
# replaces PyPI, so an sdist fallback cannot reach its build deps. The
|
||||
# quotes keep YAML from reading `:all:` as a mapping key.
|
||||
- "python -m pip install --only-binary=:all: --index-url https://download.pytorch.org/whl/cpu torch"
|
||||
|
||||
mkdocs:
|
||||
configuration: mkdocs.yml
|
||||
|
||||
+7
-1
@@ -1,5 +1,11 @@
|
||||
# Contributing to vLLM-Omni
|
||||
|
||||
You may find information about contributing to vLLM-Omni on [Contributing](https://vllm-omni.readthedocs.io/en/latest/contributing/)
|
||||
You may find information about contributing to vLLM-Omni on [Contributing](https://vllm-omni.readthedocs.io/en/latest/contributing/).
|
||||
|
||||
Local `pre-commit` gates (SPDX, forbidden imports, `torch.cuda`, shellcheck,
|
||||
mypy, test marks, TTS adapter ratchet, markdownlint, Buildkite schema, and
|
||||
how to extend allowlists) are documented in the
|
||||
[Linting](https://vllm-omni.readthedocs.io/en/latest/contributing/#linting)
|
||||
section of that guide.
|
||||
|
||||
Before submitting a PR, run the [precheck-pr skill](https://github.com/vllm-project/vllm-omni/blob/main/.claude/skills/precheck-pr/SKILL.md) with the code agent for a self-check against project conventions.
|
||||
@@ -12,10 +12,11 @@ Easy, fast, and cheap omni-modality model serving for everyone
|
||||
| <a href="https://vllm-omni.readthedocs.io/en/latest/"><b>Documentation</b></a> | <a href="https://deepwiki.com/vllm-project/vllm-omni"><b>DeepWiki</b></a> | <a href="https://discuss.vllm.ai"><b>User Forum</b></a> | <a href="https://slack.vllm.ai"><b>Developer Slack</b></a> | <a href="docs/assets/WeChat.jpg"><b>WeChat</b></a> | <a href="https://arxiv.org/abs/2602.02204"><b>Paper</b></a> | <a href="https://docs.google.com/presentation/d/1aPj0OGl_-ZVoib-Qne5dGDAlrRFB-PdHl6E-EE99g8E/edit?usp=sharing"><b>Slides</b></a> |
|
||||
</p>
|
||||
|
||||
|
||||
---
|
||||
|
||||
*Latest News* 🔥
|
||||
|
||||
- [2026/08] [VeRL-Omni](https://github.com/verl-project/verl-omni) `v0.2.0` is released: faster diffusion RL powered by vLLM-Omni (request-level/step-wise batching with FA3), rebuilt Qwen3-Omni multimodal training (DPO & GSPO), plus LTX-2.3, Qwen-Image-Edit support and more. See the [release notes](https://github.com/verl-project/verl-omni/releases/tag/v0.2.0).
|
||||
- [2026/08] We released [0.26.0](https://github.com/vllm-project/vllm-omni/releases/tag/v0.26.0) - aligned with the vLLM 0.26 release line, featuring [MiniMax H3](recipes/MiniMaxAI/MiniMax-H3.md) joint video/audio generation, an experimental full-duplex realtime runtime for [MiniCPM-o 4.5](recipes/OpenBMB/MiniCPM-o-4_5.md), distributed layerwise diffusion offload, and broader model, hardware, streaming, TTS, and quantization support.
|
||||
- [2026/07] We released [0.24.0](https://github.com/vllm-project/vllm-omni/releases/tag/v0.24.0) - aligned with the vLLM 0.24 release line, expanding production-ready coverage across TTS, speech, diffusion, image/video generation, and robot-policy serving, with major Omni stage runtime refactoring, diffusion request-level batching, async output materialization, quantization/cache/memory improvements, and broad CUDA/ROCm/XPU/NPU support.
|
||||
- [2026/06] Starting with [0.14.0](https://github.com/vllm-project/vllm-omni/releases/tag/v0.14.0), vLLM-Omni publishes a stable release aligned with every even-numbered upstream vLLM minor version. [0.16.0](https://github.com/vllm-project/vllm-omni/releases/tag/v0.16.0), [0.18.0](https://github.com/vllm-project/vllm-omni/releases/tag/v0.18.0), [0.20.0](https://github.com/vllm-project/vllm-omni/releases/tag/v0.20.0), and [0.22.0](https://github.com/vllm-project/vllm-omni/releases/tag/v0.22.0) continued this cadence, expanding omni and world-model support with [NVIDIA Cosmos3](recipes/cosmos3/Cosmos3-Nano.md) and DreamZero, adding models such as MiniCPM-o 4.5, MOSS-TTS, and Lance, and advancing TTS, diffusion, distributed execution, quantization, RL integration through [VeRL-Omni](https://github.com/verl-project/verl-omni), and CUDA/ROCm/MUSA/NPU/XPU coverage.
|
||||
@@ -88,11 +89,18 @@ If you use vLLM-Omni for your research, please cite our [paper](https://arxiv.or
|
||||
```
|
||||
|
||||
## Join the Community
|
||||
|
||||
Feel free to ask questions, provide feedbacks and discuss with fellow users of vLLM-Omni in `#sig-omni` slack channel at [slack.vllm.ai](https://slack.vllm.ai) or vLLM user forum at [discuss.vllm.ai](https://discuss.vllm.ai).
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://www.star-history.com/#vllm-project/vllm-omni&type=date&legend=top-left)
|
||||
<a href="https://www.star-history.com/?repos=vllm-project%2Fvllm-omni&type=date&legend=top-left">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=vllm-project/vllm-omni&type=date&theme=dark&legend=top-left&sealed_token=ExgLDZJoQEg27Zfhhut2LqN0GYO6Fw2PWLwPE6JYBUp2BgM3hmsYlwaIVopnUEfbRXidQ4nisumrTdKYydiKhy1SZXipw47qY2_tiUDhCpsPXeXtPuEVKVzBwKs3pw0tiHsJgtSfwXx5yjHXck0Y2SblzFWeJYCkTe1WLGTbUAOIETjXXQJjyCGZvKz5" />
|
||||
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=vllm-project/vllm-omni&type=date&legend=top-left&sealed_token=ExgLDZJoQEg27Zfhhut2LqN0GYO6Fw2PWLwPE6JYBUp2BgM3hmsYlwaIVopnUEfbRXidQ4nisumrTdKYydiKhy1SZXipw47qY2_tiUDhCpsPXeXtPuEVKVzBwKs3pw0tiHsJgtSfwXx5yjHXck0Y2SblzFWeJYCkTe1WLGTbUAOIETjXXQJjyCGZvKz5" />
|
||||
<img alt="Star History Chart" src="https://api.star-history.com/chart?repos=vllm-project/vllm-omni&type=date&legend=top-left&sealed_token=ExgLDZJoQEg27Zfhhut2LqN0GYO6Fw2PWLwPE6JYBUp2BgM3hmsYlwaIVopnUEfbRXidQ4nisumrTdKYydiKhy1SZXipw47qY2_tiUDhCpsPXeXtPuEVKVzBwKs3pw0tiHsJgtSfwXx5yjHXck0Y2SblzFWeJYCkTe1WLGTbUAOIETjXXQJjyCGZvKz5" />
|
||||
</picture>
|
||||
</a>
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -158,7 +158,6 @@ def _build_omni_kwargs(args, quantization=None):
|
||||
def _generate_image(omni, args, prompt, seed):
|
||||
"""Generate a single image and return (PIL.Image, time_seconds, memory_gib)."""
|
||||
from vllm_omni.inputs.data import OmniDiffusionSamplingParams
|
||||
from vllm_omni.outputs import OmniRequestOutput
|
||||
from vllm_omni.platforms import current_omni_platform
|
||||
|
||||
generator = torch.Generator(device=current_omni_platform.device_type).manual_seed(seed)
|
||||
@@ -176,7 +175,7 @@ def _generate_image(omni, args, prompt, seed):
|
||||
elapsed = time.perf_counter() - start
|
||||
peak_mem = torch.accelerator.max_memory_allocated() / (1024**3)
|
||||
|
||||
req_out = OmniRequestOutput.unwrap_result(outputs)
|
||||
req_out = outputs[0] if isinstance(outputs, list) else outputs
|
||||
if not req_out.images:
|
||||
raise ValueError("Could not extract image output from result.")
|
||||
img = req_out.images[0]
|
||||
@@ -206,15 +205,15 @@ def _generate_video(omni, args, prompt, seed):
|
||||
elapsed = time.perf_counter() - start
|
||||
peak_mem = torch.accelerator.max_memory_allocated() / (1024**3)
|
||||
|
||||
first = outputs[0]
|
||||
if hasattr(first, "request_output") and isinstance(first.request_output, list):
|
||||
inner = first.request_output[0]
|
||||
if isinstance(inner, OmniRequestOutput) and hasattr(inner, "images"):
|
||||
frames = inner.images[0] if inner.images else None
|
||||
else:
|
||||
frames = inner
|
||||
elif hasattr(first, "images") and first.images:
|
||||
frames = first.images[0]
|
||||
if isinstance(outputs, list) and isinstance(outputs[0], OmniRequestOutput):
|
||||
first = outputs[0]
|
||||
elif isinstance(outputs, OmniRequestOutput):
|
||||
first = outputs
|
||||
else:
|
||||
raise ValueError("Could not extract video frames from output.")
|
||||
|
||||
if hasattr(first, "images"):
|
||||
frames = first.images[0] if first.images else None
|
||||
else:
|
||||
raise ValueError("Could not extract video frames from output.")
|
||||
|
||||
|
||||
@@ -300,7 +300,7 @@ def benchmark(args: argparse.Namespace) -> None:
|
||||
output_idx = 0
|
||||
for stage_outputs in omni.generate(all_prompts, sampling_params_list, py_generator=True):
|
||||
if stage_outputs.final_output_type == "image":
|
||||
request_output = stage_outputs.request_output
|
||||
request_output = stage_outputs
|
||||
request_id = getattr(request_output, "request_id", "")
|
||||
|
||||
images = getattr(request_output, "images", [])
|
||||
|
||||
@@ -167,9 +167,11 @@ def main() -> None:
|
||||
]
|
||||
native_cmd = [
|
||||
sys.executable,
|
||||
"examples/offline_inference/text_to_video/text_to_video_lingbot.py",
|
||||
"examples/offline_inference/text_to_video/text_to_video.py",
|
||||
"--model",
|
||||
args.model,
|
||||
"--model-class-name",
|
||||
"LingBotVideoPipeline",
|
||||
"--prompt",
|
||||
args.prompt,
|
||||
"--output",
|
||||
|
||||
@@ -18,8 +18,8 @@ vllm serve Qwen/Qwen3-TTS-12Hz-1.7B-Base --omni --port 8000
|
||||
```
|
||||
|
||||
The server auto-loads its Deploy YAML from `vllm_omni/deploy/qwen3_tts.yaml`
|
||||
(Pipeline + Deploy schema introduced in #2383). No `--stage-configs-path` or
|
||||
`--deploy-config` flag is needed for any registered model.
|
||||
(Pipeline + Deploy schema introduced in #2383). No explicit `--deploy-config`
|
||||
flag is needed for a registered model.
|
||||
|
||||
### 2. Run the benchmark (`vllm bench serve --omni`)
|
||||
|
||||
@@ -139,6 +139,34 @@ python benchmarks/tts/bench_tts.py \
|
||||
--output-dir ./results
|
||||
```
|
||||
|
||||
#### Fixed IndexTTS 2.5 performance sweep
|
||||
|
||||
IndexTTS 2.5 is registered in `model_configs.yaml` like the other TTS models.
|
||||
Use `--served-model-name` when the server was launched from a local native
|
||||
bundle instead of the registry key. The command below reproduces the acceptance
|
||||
workload: Seed-TTS Eval EN, `n=500`, concurrency `4/8/16/32`, five warmups, and
|
||||
dataset seed 0.
|
||||
|
||||
```bash
|
||||
python benchmarks/tts/bench_tts.py \
|
||||
--model IndexTeam/IndexTTS-2.5 \
|
||||
--served-model-name /path/to/indextts-2.5 \
|
||||
--task voice_clone --locale en \
|
||||
--dataset-path /path/to/seedtts_testset \
|
||||
--host 127.0.0.1 --port 8092 \
|
||||
--concurrency 4 8 16 32 \
|
||||
--num-prompts 500 --num-warmups 5 \
|
||||
--output-dir ./results/indextts2_5 \
|
||||
-- \
|
||||
--tokenizer /path/to/indextts-2.5/qwen0.6bemo4-merge \
|
||||
--seed 0 --metric-percentiles 50,95,99 --disable-tqdm --save-detailed
|
||||
```
|
||||
|
||||
The wrapper benchmarks an already-running server. For reproducible quality
|
||||
comparisons, add `--request-seed 42`; production-performance runs should omit
|
||||
it. The trailing `--seed 0` controls Seed-TTS row selection rather than model
|
||||
sampling.
|
||||
|
||||
### 4. Plot a sweep
|
||||
|
||||
```bash
|
||||
|
||||
@@ -84,12 +84,17 @@ def build_bench_args(
|
||||
result_filename: str | None,
|
||||
extra_cli_args: list[str],
|
||||
output_len: int | None = None,
|
||||
served_model_name: str | None = None,
|
||||
num_warmups: int = 2,
|
||||
request_seed: int | None = None,
|
||||
) -> list[str]:
|
||||
"""Build the ``vllm bench serve --omni`` command for one (task, concurrency) run."""
|
||||
dataset_name = _TASK_TO_DATASET[task]
|
||||
backend: str = model_cfg["backend"]
|
||||
endpoint: str = model_cfg["endpoint"]
|
||||
task_extra_body: dict[str, Any] = (model_cfg.get("task_extra_body") or {}).get(task) or {}
|
||||
task_extra_body: dict[str, Any] = dict((model_cfg.get("task_extra_body") or {}).get(task) or {})
|
||||
if request_seed is not None:
|
||||
task_extra_body["seed"] = request_seed
|
||||
|
||||
# Resolve dataset path
|
||||
if dataset_path:
|
||||
@@ -109,7 +114,7 @@ def build_bench_args(
|
||||
"--port",
|
||||
str(port),
|
||||
"--model",
|
||||
model,
|
||||
served_model_name or model,
|
||||
"--backend",
|
||||
backend,
|
||||
"--endpoint",
|
||||
@@ -119,7 +124,7 @@ def build_bench_args(
|
||||
"--num-prompts",
|
||||
str(num_prompts),
|
||||
"--num-warmups",
|
||||
"2",
|
||||
str(num_warmups),
|
||||
"--percentile-metrics",
|
||||
"ttft,e2el,audio_rtf,audio_ttfp,audio_duration,audio_underrun",
|
||||
]
|
||||
@@ -152,7 +157,8 @@ def build_bench_args(
|
||||
if result_filename:
|
||||
cmd += ["--result-filename", result_filename]
|
||||
|
||||
cmd += extra_cli_args
|
||||
passthrough = extra_cli_args[1:] if extra_cli_args[:1] == ["--"] else extra_cli_args
|
||||
cmd += passthrough
|
||||
return cmd
|
||||
|
||||
|
||||
@@ -225,6 +231,12 @@ def main() -> None:
|
||||
parser.add_argument(
|
||||
"--model", required=True, help="HuggingFace model ID (e.g. Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--served-model-name",
|
||||
default=None,
|
||||
help="Model name/path accepted by the running server. Use this when --model selects a registry entry "
|
||||
"but the server was launched from a local bundle path.",
|
||||
)
|
||||
parser.add_argument("--task", default="all", help="Task type: voice_clone | default_voice | voice_design | all")
|
||||
parser.add_argument("--locale", default="en", choices=["en", "zh"])
|
||||
parser.add_argument("--concurrency", type=int, nargs="+", default=[1, 4], metavar="N")
|
||||
@@ -236,6 +248,13 @@ def main() -> None:
|
||||
metavar="N",
|
||||
help="Number of prompts per run. If one value, applied to all concurrency levels.",
|
||||
)
|
||||
parser.add_argument("--num-warmups", type=int, default=2, help="Warmup requests before each measured run")
|
||||
parser.add_argument(
|
||||
"--request-seed",
|
||||
type=int,
|
||||
default=None,
|
||||
help="Optional model sampling seed added to every request body for reproducible quality runs",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dataset-path", default=None, help="Root of seed-tts-eval dataset (required for voice_clone/default_voice)"
|
||||
)
|
||||
@@ -256,6 +275,9 @@ def main() -> None:
|
||||
parser.add_argument("extra", nargs=argparse.REMAINDER, help="Extra args passed directly to vllm bench serve")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.num_warmups < 0:
|
||||
parser.error("--num-warmups cannot be negative")
|
||||
|
||||
model_configs = load_model_configs(Path(args.model_configs))
|
||||
if args.model not in model_configs:
|
||||
known = "\n ".join(model_configs.keys())
|
||||
@@ -308,6 +330,9 @@ def main() -> None:
|
||||
result_filename=result_filename,
|
||||
extra_cli_args=args.extra or [],
|
||||
output_len=args.output_len,
|
||||
served_model_name=args.served_model_name,
|
||||
num_warmups=args.num_warmups,
|
||||
request_seed=args.request_seed,
|
||||
)
|
||||
result = run_one_benchmark(cmd)
|
||||
if result is not None:
|
||||
|
||||
@@ -7,6 +7,17 @@
|
||||
# is tracked here.
|
||||
|
||||
models:
|
||||
IndexTeam/IndexTTS-2.5:
|
||||
supported_tasks: [voice_clone]
|
||||
backend: openai-audio-speech
|
||||
endpoint: /v1/audio/speech
|
||||
trust_remote_code: true
|
||||
task_extra_body:
|
||||
voice_clone:
|
||||
extra_params:
|
||||
lang: en
|
||||
text_normalization: true
|
||||
|
||||
# -CustomVoice checkpoints lack speaker_encoder weights, so voice_clone is
|
||||
# NOT supported (an attempt raises ValueError from _extract_speaker_embedding
|
||||
# at model runtime). Use -Base for voice_clone.
|
||||
|
||||
+19
-2
@@ -1,7 +1,24 @@
|
||||
# Target vllm version: v0.26.0 (releases/v0.26.0 branch).
|
||||
# Target vllm version: v0.27.0 (releases/v0.27.0 branch).
|
||||
# Keep VLLM_BASE_TAG aligned with the target vLLM release on every rebase.
|
||||
#
|
||||
# Release-boundary form: there is no precompiled-wheel pin here, because the
|
||||
# base image already ships exactly the target vLLM. Everything the runtime
|
||||
# needs — torch, flashinfer, nvJitLink, numpy — comes from that image as one
|
||||
# self-consistent set.
|
||||
#
|
||||
# This block reappears only when the rebase targets a vLLM commit that is NOT a
|
||||
# released tag. During the 0.27 rebase, targeting v0.27.0rc1 on top of the
|
||||
# v0.26.0 base image required reinstalling vLLM from wheels.vllm.ai and then
|
||||
# hand-repairing the fallout: pinning torch ahead of flashinfer (installing it
|
||||
# after bound flashinfer's TVM FFI runtime to the old torch and aborted engine
|
||||
# core init), registering libnvJitLink.so.13 with ldconfig, and re-pinning numpy
|
||||
# under numba's ceiling. All of it was compensation for a base image and a vLLM
|
||||
# that disagreed. At a real release boundary they agree, so none of it is
|
||||
# needed. If you pin an untagged commit again, restore the reinstall block —
|
||||
# agent/tasks/20_update_wheel_url.sh fails the run rather than letting the
|
||||
# Dockerfile silently ship the wrong vLLM.
|
||||
ARG VLLM_BASE_IMAGE=vllm/vllm-openai
|
||||
ARG VLLM_BASE_TAG=v0.26.0
|
||||
ARG VLLM_BASE_TAG=v0.27.0
|
||||
|
||||
# We use registry-based layer caching for the dependencies,
|
||||
# where the tag is determined based on the hash of the contents
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
ARG VLLM_ASCEND_IMAGE=quay.io/atlas-ci/vllm-ascend
|
||||
ARG VLLM_ASCEND_TAG=v0.26.0
|
||||
ARG VLLM_ASCEND_TAG=v0.27.0
|
||||
FROM ${VLLM_ASCEND_IMAGE}:${VLLM_ASCEND_TAG}
|
||||
|
||||
# WORKDIR /vllm-workspace/vllm
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
ARG VLLM_ASCEND_IMAGE=quay.io/atlas-ci/vllm-ascend
|
||||
ARG VLLM_ASCEND_TAG=v0.26.0-a3
|
||||
ARG VLLM_ASCEND_TAG=v0.27.0-a3
|
||||
FROM ${VLLM_ASCEND_IMAGE}:${VLLM_ASCEND_TAG}
|
||||
|
||||
# WORKDIR /vllm-workspace/vllm
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
ARG VLLM_ASCEND_IMAGE=quay.io/atlas-ci/vllm-ascend
|
||||
ARG VLLM_ASCEND_TAG=v0.26.0
|
||||
ARG VLLM_ASCEND_TAG=v0.27.0
|
||||
FROM ${VLLM_ASCEND_IMAGE}:${VLLM_ASCEND_TAG}
|
||||
|
||||
ARG APP_DIR=/vllm-workspace/vllm-omni
|
||||
@@ -45,6 +45,7 @@ RUN source /usr/local/Ascend/ascend-toolkit/set_env.sh && \
|
||||
"hyperpyyaml>=1.2.0" \
|
||||
"onnx>=1.16.0" \
|
||||
"librosa>=0.10.0" \
|
||||
"datasets>=3.0.0" \
|
||||
--index-url http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple \
|
||||
--trusted-host cache-service.nginx-pypi-cache.svc.cluster.local \
|
||||
--default-timeout=60 && \
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
ARG VLLM_ASCEND_IMAGE=quay.io/atlas-ci/vllm-ascend
|
||||
ARG VLLM_ASCEND_TAG=v0.26.0-a3
|
||||
ARG VLLM_ASCEND_TAG=v0.27.0-a3
|
||||
FROM ${VLLM_ASCEND_IMAGE}:${VLLM_ASCEND_TAG}
|
||||
|
||||
ARG APP_DIR=/vllm-workspace/vllm-omni
|
||||
@@ -46,6 +46,7 @@ RUN source /usr/local/Ascend/ascend-toolkit/set_env.sh && \
|
||||
"onnx>=1.16.0" \
|
||||
"librosa>=0.10.0" \
|
||||
"torchmetrics>=1.9.0" \
|
||||
"datasets>=3.0.0" \
|
||||
--index-url http://cache-service.nginx-pypi-cache.svc.cluster.local/pypi/simple \
|
||||
--trusted-host cache-service.nginx-pypi-cache.svc.cluster.local \
|
||||
--default-timeout=60 && \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
ARG BASE_IMAGE=vllm/vllm-openai-rocm:v0.26.0
|
||||
ARG BASE_IMAGE=vllm/vllm-openai-rocm:v0.27.0
|
||||
FROM ${BASE_IMAGE} AS base
|
||||
|
||||
# Declare a variable to know if we want to use the nightly build or the stable build.
|
||||
@@ -10,7 +10,7 @@ FROM ${BASE_IMAGE} AS base
|
||||
# we should swap over to use stable release ASAP.
|
||||
# We should avoid relying on custom commits.
|
||||
ARG USE_NIGHTLY_BUILD=0
|
||||
ARG VLLM_VERSION_OR_COMMIT_HASH=v0.26.0
|
||||
ARG VLLM_VERSION_OR_COMMIT_HASH=v0.27.0
|
||||
ARG ARG_PYTORCH_ROCM_ARCH
|
||||
ENV PYTORCH_ROCM_ARCH=${ARG_PYTORCH_ROCM_ARCH:-${PYTORCH_ROCM_ARCH}}
|
||||
|
||||
@@ -79,9 +79,16 @@ RUN printf '%s\n' \
|
||||
' os._exit(_exit_code)' \
|
||||
> ${COMMON_WORKDIR}/vllm-omni/conftest.py
|
||||
|
||||
# Some optional dependencies pull in the CPU ONNX Runtime distribution. The
|
||||
# CPU and ROCm wheels own the same import path and cannot coexist, so remove
|
||||
# the CPU wheel and reinstall the ROCm wheel after dependency resolution.
|
||||
RUN cd ${COMMON_WORKDIR}/vllm-omni && \
|
||||
uv pip install --python "$(python3 -c 'import sys; print(sys.executable)')" \
|
||||
--no-cache-dir ".[dev]" --no-build-isolation && \
|
||||
python3 -m pip uninstall -y onnxruntime && \
|
||||
python3 -m pip install --no-cache-dir --force-reinstall --no-deps \
|
||||
"onnxruntime-rocm>=1.22.2" && \
|
||||
python3 -c "import importlib.metadata as m; import onnxruntime as ort; assert 'ROCMExecutionProvider' in ort.get_available_providers(), ort.get_available_providers(); assert m.version('onnxruntime-rocm'); assert not any(d.metadata['Name'] == 'onnxruntime' for d in m.distributions())" && \
|
||||
python3 -c "from torchcodec.decoders import VideoDecoder"
|
||||
|
||||
RUN ln -sf /usr/bin/python3 /usr/bin/python
|
||||
|
||||
@@ -88,7 +88,7 @@ ENV UV_EXTRA_INDEX_URL=${PIP_EXTRA_INDEX_URL}
|
||||
ENV UV_INDEX_STRATEGY="unsafe-best-match"
|
||||
ENV UV_LINK_MODE="copy"
|
||||
|
||||
ARG VLLM_VERSION=v0.26.0
|
||||
ARG VLLM_VERSION=v0.27.0
|
||||
RUN git clone -b ${VLLM_VERSION} https://github.com/vllm-project/vllm
|
||||
WORKDIR /workspace/vllm
|
||||
|
||||
@@ -108,7 +108,7 @@ ENV VLLM_WORKER_MULTIPROC_METHOD=spawn
|
||||
|
||||
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||
uv pip uninstall triton triton-xpu && \
|
||||
uv pip install triton-xpu==3.7.1 && \
|
||||
uv pip install triton-xpu==3.7.2 && \
|
||||
uv pip install --no-build-isolation --no-deps .
|
||||
|
||||
CMD ["/bin/bash"]
|
||||
@@ -144,12 +144,13 @@ WORKDIR /workspace/vllm-omni
|
||||
COPY . .
|
||||
|
||||
ENV VLLM_OMNI_TARGET_DEVICE=xpu
|
||||
# Keep the upstream oneCCL packages paired with the XPU torch runtime.
|
||||
RUN --mount=type=cache,target=/root/.cache/uv \
|
||||
uv pip install --no-build-isolation \
|
||||
--extra-index-url https://mirrors.ustc.edu.cn/pypi/simple/ \
|
||||
".[dev]" && \
|
||||
uv pip uninstall triton oneccl oneccl-devel && \
|
||||
uv pip install triton-xpu==3.7.1 --reinstall
|
||||
uv pip uninstall triton && \
|
||||
uv pip install triton-xpu==3.7.2 --reinstall
|
||||
|
||||
FROM vllm-omni AS vllm-omni-openai
|
||||
|
||||
|
||||
+54
-28
@@ -40,30 +40,13 @@ nav:
|
||||
- Models:
|
||||
- models/supported_models.md
|
||||
- Features:
|
||||
- Sleep Mode: features/sleep_mode.md
|
||||
- Diffusion Features:
|
||||
- Overview: user_guide/diffusion_features.md
|
||||
- Feature Compatibility: user_guide/feature_compatibility.md
|
||||
- Regional Compilation: user_guide/diffusion/regional_compilation.md
|
||||
- Cache Acceleration:
|
||||
- TeaCache: user_guide/diffusion/cache_acceleration/teacache.md
|
||||
- Cache-DiT: user_guide/diffusion/cache_acceleration/cache_dit.md
|
||||
- Attention Backends: user_guide/diffusion/attention_backends.md
|
||||
- Frame Interpolation: user_guide/diffusion/frame_interpolation.md
|
||||
- Parallelism:
|
||||
- Overview: user_guide/diffusion/parallelism/overview.md
|
||||
- CFG Parallel: user_guide/diffusion/parallelism/cfg_parallel.md
|
||||
- Expert Parallel: user_guide/diffusion/parallelism/expert_parallel.md
|
||||
- Hybrid Sharded Data Parallel: user_guide/diffusion/parallelism/hsdp.md
|
||||
- Sequence Parallel: user_guide/diffusion/parallelism/sequence_parallel.md
|
||||
- Tensor Parallel: user_guide/diffusion/parallelism/tensor_parallel.md
|
||||
- VAE Parallelism: user_guide/diffusion/parallelism/vae_parallelism.md
|
||||
- CPU Offloading: user_guide/diffusion/cpu_offload.md
|
||||
- LoRA: user_guide/diffusion/lora.md
|
||||
- Custom Pipeline: features/custom_pipeline.md
|
||||
- Execution Modes: user_guide/diffusion/execution_modes.md
|
||||
- Overview: features/README.md
|
||||
- Runtime and Stage Execution:
|
||||
- Execution Modes and Streaming: user_guide/diffusion/execution_modes.md
|
||||
- Prefill-Decode Disaggregation (experimental): features/pd_disaggregation.md
|
||||
- Sleep Mode: features/sleep_mode.md
|
||||
- Quantization:
|
||||
- Quantization: user_guide/quantization/overview.md
|
||||
- Overview: user_guide/quantization/overview.md
|
||||
- Online Quantization: user_guide/quantization/online.md
|
||||
- Quantized KV Cache: user_guide/quantization/quantized_kvcache.md
|
||||
- FP8 W8A8: user_guide/quantization/fp8.md
|
||||
@@ -72,9 +55,43 @@ nav:
|
||||
- MXFP8 W8A8: user_guide/quantization/mxfp8.md
|
||||
- MXFP4 W4A4: user_guide/quantization/mxfp4.md
|
||||
- ModelOpt: user_guide/quantization/modelopt.md
|
||||
- GGUF: user_guide/quantization/gguf.md
|
||||
- AutoRound: user_guide/quantization/autoround.md
|
||||
- msModelSlim: user_guide/quantization/msmodelslim.md
|
||||
- Diffusion Acceleration:
|
||||
- Overview and Compatibility:
|
||||
- Overview: user_guide/diffusion_features.md
|
||||
- Feature Compatibility: user_guide/feature_compatibility.md
|
||||
- CPU Offloading:
|
||||
- Overview: user_guide/diffusion/cpu_offload.md
|
||||
- Model-Level: user_guide/diffusion/offloader/cpu_offload.md
|
||||
- Layerwise: user_guide/diffusion/offloader/layerwise_offload.md
|
||||
- Distributed Layerwise: user_guide/diffusion/offloader/distributed_layerwise_offload.md
|
||||
- Cache Acceleration:
|
||||
- TeaCache: user_guide/diffusion/cache_acceleration/teacache.md
|
||||
- Cache-DiT: user_guide/diffusion/cache_acceleration/cache_dit.md
|
||||
- Parallelism:
|
||||
- Overview: user_guide/diffusion/parallelism/overview.md
|
||||
- CFG Parallel: user_guide/diffusion/parallelism/cfg_parallel.md
|
||||
- Expert Parallel: user_guide/diffusion/parallelism/expert_parallel.md
|
||||
- Hybrid Sharded Data Parallel: user_guide/diffusion/parallelism/hsdp.md
|
||||
- Sequence Parallel: user_guide/diffusion/parallelism/sequence_parallel.md
|
||||
- Tensor Parallel: user_guide/diffusion/parallelism/tensor_parallel.md
|
||||
- VAE Parallelism: user_guide/diffusion/parallelism/vae_parallelism.md
|
||||
- Attention Backends:
|
||||
- Overview: user_guide/diffusion/attention_backends.md
|
||||
- Dense Backends: user_guide/diffusion/attention_backends/dense_backends.md
|
||||
- TRTLLM: user_guide/diffusion/attention_backends/trtllm.md
|
||||
- SageAttention: user_guide/diffusion/attention_backends/sage.md
|
||||
- Hugging Face Hub: user_guide/diffusion/attention_backends/huggingface_hub.md
|
||||
- RainFusion: user_guide/diffusion/attention_backends/rainfusion.md
|
||||
- Regional Compilation: user_guide/diffusion/regional_compilation.md
|
||||
- Frame Interpolation: user_guide/diffusion/frame_interpolation.md
|
||||
- Startup and Loading: user_guide/diffusion/startup_and_loading.md
|
||||
- LoRA: user_guide/diffusion/lora.md
|
||||
- Experimental:
|
||||
- Session State Manager: features/session_state_manager.md
|
||||
- Integrations:
|
||||
- Custom Diffusion Pipeline: features/custom_pipeline.md
|
||||
- ComfyUI: features/comfyui.md
|
||||
- Fault Tolerance:
|
||||
- Failure Modes: user_guide/fault_injection_reliability_matrix.md
|
||||
@@ -96,10 +113,12 @@ nav:
|
||||
- Feature Design:
|
||||
- Runtime and Stage Execution:
|
||||
- Disaggregated Inference: design/feature/disaggregated_inference.md
|
||||
- Host Weight Runtime: design/feature/host_weight_runtime.md
|
||||
- Async Chunk: design/feature/async_chunk.md
|
||||
- Async Diffusion Output: design/feature/async_diffusion_output.md
|
||||
- Async Omni Output Materialization: design/feature/omni_async_output_materialization.md
|
||||
- Automatic Prefix Caching: design/feature/prefix_caching.md
|
||||
- Realtime AR-Diffusion: design/feature/realtime_ar_diffusion.md
|
||||
- Communication:
|
||||
- OmniConnector Implementations:
|
||||
- Mooncake Store Connector: design/feature/omni_connectors/mooncake_store_connector.md
|
||||
@@ -108,6 +127,7 @@ nav:
|
||||
- Shared Memory Connector: design/feature/omni_connectors/shared_memory_connector.md
|
||||
- Yuanrong Store Connector: design/feature/omni_connectors/yuanrong_connector.md
|
||||
- Yuanrong Transfer Engine Connector: design/feature/omni_connectors/yuanrong_transfer_engine_connector.md
|
||||
- Quantization: design/feature/quantization.md
|
||||
- Diffusion Acceleration:
|
||||
- Parallelism:
|
||||
- CFG-Parallel: design/feature/cfg_parallel.md
|
||||
@@ -117,13 +137,17 @@ nav:
|
||||
- Sequence Parallel: design/feature/sequence_parallel.md
|
||||
- Tensor Parallel: design/feature/tensor_parallel.md
|
||||
- VAE Patch Parallelism: design/feature/vae_parallel.md
|
||||
- Attention Backends:
|
||||
- Attention Optimization:
|
||||
- Backend Selection: design/feature/attention_backend_selection.md
|
||||
- Skip-Softmax: design/feature/skip_softmax.md
|
||||
- Quantization: design/feature/quantization.md
|
||||
- CPU Offloading:
|
||||
- Overview: design/feature/offloader/README.md
|
||||
- Model-Level: design/feature/offloader/cpu_offload.md
|
||||
- Layerwise: design/feature/offloader/layerwise_offload.md
|
||||
- Distributed Layerwise: design/feature/offloader/distributed_layerwise_offload.md
|
||||
- Cache-DiT: design/feature/cache_dit.md
|
||||
- TeaCache: design/feature/teacache.md
|
||||
- Diffusion Continuous Batching: design/feature/diffusion_continuous_batching.md
|
||||
- Distributed Layerwise Offload: design/feature/distributed_layerwise_offload.md
|
||||
- Infrastructure and Performance:
|
||||
- Prometheus Metrics: design/metrics.md
|
||||
- Speech Generation Performance Optimizations: design/qwen3_omni_tts_performance_optimization.md
|
||||
@@ -146,6 +170,7 @@ nav:
|
||||
- Offloader: design/module/diffusion/offloader.md
|
||||
- Execution Platforms: design/module/execution_platforms.md
|
||||
- Cache Management: design/module/cache_management.md
|
||||
- Host Weight Runtime: design/module/host_weight_runtime.md
|
||||
- Quantization: design/module/quantization.md
|
||||
- Observability: design/module/observability.md
|
||||
- Profiling: design/module/profiling.md
|
||||
@@ -157,7 +182,8 @@ nav:
|
||||
- CLI Reference: cli
|
||||
- Community:
|
||||
- Governance: community/governance.md
|
||||
- community/*
|
||||
- Contact Us: community/contact_us.md
|
||||
- Community Meetings: community/meetings.md
|
||||
- Slack: https://slack.vllm.ai
|
||||
- Blog: https://blog.vllm.ai
|
||||
- Forum: https://discuss.vllm.ai
|
||||
@@ -114,10 +114,6 @@ Configuration classes.
|
||||
- [vllm_omni.model_executor.models.qwen3_tts.tokenizer_25hz.configuration_qwen3_tts_tokenizer_v1.Qwen3TTSTokenizerV1DecoderDiTConfig][]
|
||||
- [vllm_omni.model_executor.models.qwen3_tts.tokenizer_25hz.configuration_qwen3_tts_tokenizer_v1.Qwen3TTSTokenizerV1EncoderConfig][]
|
||||
- [vllm_omni.transformers_utils.configs.cosyvoice3.CosyVoice3Config][]
|
||||
- [vllm_omni.transformers_utils.configs.mammoth_moda2.Mammothmoda2Config][]
|
||||
- [vllm_omni.transformers_utils.configs.mammoth_moda2.Mammothmoda2Qwen2_5_VLConfig][]
|
||||
- [vllm_omni.transformers_utils.configs.mammoth_moda2.Mammothmoda2Qwen2_5_VLTextConfig][]
|
||||
- [vllm_omni.transformers_utils.configs.mammoth_moda2.Mammothmoda2Qwen2_5_VLVisionConfig][]
|
||||
- [vllm_omni.transformers_utils.configs.omnivoice.OmniVoiceConfig][]
|
||||
- [vllm_omni.transformers_utils.configs.voxcpm2.VoxCPM2Config][]
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 260 KiB After Width: | Height: | Size: 269 KiB |
@@ -1,5 +1,9 @@
|
||||
# Contact Us
|
||||
|
||||
- For technical questions and feature requests, please use GitHub [Issues](https://github.com/vllm-project/vllm-omni/issues)
|
||||
- For coordinating contributions and development and discussing with other users and developers, please join `sig-omni` channel in our [Slack](https://slack.vllm.ai/) or use the [vLLM Forum](https://discuss.vllm.ai/)
|
||||
- For security disclosures, please use GitHub's [Security Advisories](https://github.com/vllm-project/vllm-omni/security/advisories) feature
|
||||
- For bugs and feature requests, search or open a GitHub [issue](https://github.com/vllm-project/vllm-omni/issues).
|
||||
- For technical and usage questions, join the `sig-omni` channel in [vLLM Slack](https://slack.vllm.ai/) or use the [vLLM Forum](https://discuss.vllm.ai/).
|
||||
- For coordinating contributions and development, use `sig-omni`, the forum, or join a [community meeting](meetings.md).
|
||||
|
||||
## Security Disclosures
|
||||
|
||||
Do not share vulnerability details in public GitHub issues, pull requests, discussions, or Slack channels. To arrange a private report, send a direct message to one of the [lead maintainers](governance.md#lead-maintainers) in [vLLM Slack](https://slack.vllm.ai/). If you cannot send a direct message, you may post a detail-free request in `sig-omni` asking a lead maintainer to contact you privately; do not include any vulnerability details in that request.
|
||||
@@ -52,31 +52,11 @@ Committers have write access and merge rights. They typically have deep expertis
|
||||
- [@ZJY0516](https://github.com/ZJY0516): Diffusion attention backend, kernel fusion, and CustomOp
|
||||
- [@yuanheng-zhao](https://github.com/yuanheng-zhao): Diffusion cache, offload, and Omni Support
|
||||
|
||||
## Diffusion Workload Division
|
||||
## Reviewer Routing
|
||||
|
||||
This section breaks down diffusion-related responsibilities. If you have PRs touching these areas, please ping the listed owners for review.
|
||||
For path-based reviewer routing, consult [`.github/CODEOWNERS`](https://github.com/vllm-project/vllm-omni/blob/main/.github/CODEOWNERS). Detailed subsystem boundaries and safe-change guidance live in the [module design documents](../design/index.md#module-design-documents).
|
||||
|
||||
### Runtime-related
|
||||
|
||||
- Diffusion models: @RuixiangMa, @wtomin, @xuechendi
|
||||
|
||||
### Optimization
|
||||
|
||||
- Parallel: @RuixiangMa, @wtomin
|
||||
- Attention backend: @ZJY0516
|
||||
- Cache: @yuanheng-zhao, @RuixiangMa, @SamitHuang
|
||||
- Offload: @yuanheng-zhao
|
||||
- Intel GPU support: @xuechendi
|
||||
- Quantization: @lishunyang12, @david6666666
|
||||
- Kernel fusion / communication-computation: @ZJY0516
|
||||
|
||||
### Docs & Test
|
||||
|
||||
- Diffusion docs: @RuixiangMa, @wtomin
|
||||
|
||||
## Meetings
|
||||
|
||||
Committers hold **bi-weekly meetings** to discuss future directions and collaborations of the project.
|
||||
`CODEOWNERS` is operational routing metadata, not a governance or approval policy. Being listed does not grant committer status or merge rights, and it does not mean every listed reviewer must approve a change. The maintainer roster above is authoritative for project roles and merge rights.
|
||||
|
||||
## Committer Nomination Process
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Community Meetings
|
||||
|
||||
vLLM-Omni hosts developer-facing meetings for Chinese- and English-language audiences. Schedules and access details can change, so use these maintained documents as the source of truth:
|
||||
|
||||
- [Chinese-language meeting document](https://docs.google.com/document/d/1pdUBiS_7mdOUNDtdwy-9OUf7jsMWN324BIbps5olDME/edit?tab=t.0)
|
||||
- [English-language meeting document](https://docs.google.com/document/d/19AlD08T8uJ7wqfs8VtYCi0iGMTwlTYVVlAxFZ3S7OIg/edit?tab=t.0)
|
||||
|
||||
Each document contains the current schedule, access details, agendas, and past meeting notes. For broader vLLM community events, see the [vLLM events calendar](https://vllm.ai/events/).
|
||||
@@ -1 +0,0 @@
|
||||
# Meetups
|
||||
@@ -1,12 +0,0 @@
|
||||
# Volunteers for Bugfix and CI
|
||||
|
||||
We encourage you to check current docs and [issues](https://github.com/vllm-project/vllm-omni/issues) to find possible solutions for your questions. If non of these can solve it, please propose an issue to describe your questions about bug or CI problems for developing.
|
||||
|
||||
If you have urgent need for locating and solving bugfix or CI problems, please find community volunteers below.
|
||||
|
||||
| Dec 4-Dec 12 | Dec 15-Dec 19 | Dec 22-Dec 26 | Dec 29- Jan 2, 2026| Jan 5-Jan 9 | Jan 12-Jan 16 |
|
||||
|----------|----------|----------|----------|----------|----------|
|
||||
| <a href="https://github.com/congw729">Conw729</a> | <a href="https://github.com/yinpeiqi">yinpeiqi</a> | <a href="https://github.com/tzhouam">tzhouam</a> | <a href="https://github.com/SamitHuang">SamitHuang</a> | <a href="https://github.com/gcanlin">gcanlin</a> | <a href="https://github.com/natureofnature">natureofnature</a> |
|
||||
| <a href="https://github.com/david6666666">david6666666</a> | <a href="https://github.com/R2-Y">R2-Y</a> | <a href="https://github.com/hsliuustc0106">hsliuustc0106</a> | <a href="https://github.com/Gaohan123">Gaohan123</a> | <a href="https://github.com/ZJY0516">ZJY0516</a> | <a href="https://github.com/qibaoyuan">qibaoyuan</a> |
|
||||
|
||||
We kindly welcome more contributors to fix bugs and contribute new features!
|
||||
@@ -4,20 +4,17 @@ This section lists the most common options for running vLLM-Omni.
|
||||
|
||||
For options within a vLLM Engine, please refer to the [vLLM 0.26 configuration guide](https://docs.vllm.ai/en/v0.26.0/configuration/index.html).
|
||||
|
||||
Currently, the main options are maintained by stage configs for each model.
|
||||
Each model defines fixed topology in a registered `PipelineConfig` and runtime
|
||||
overrides in a deploy YAML.
|
||||
|
||||
For a specific example, see the [Qwen2.5-Omni deploy config](gh-file:vllm_omni/deploy/qwen2_5_omni.yaml). The matching frozen pipeline topology lives at [vllm_omni/model_executor/models/qwen2_5_omni/pipeline.py](gh-file:vllm_omni/model_executor/models/qwen2_5_omni/pipeline.py).
|
||||
|
||||
For introduction, please check [Introduction for stage config](./stage_configs.md)
|
||||
For an introduction, see [Pipeline and deploy configurations](./stage_configs.md).
|
||||
|
||||
## Memory Configuration
|
||||
|
||||
- **[GPU Memory Calculation and Configuration](./gpu_memory_utilization.md)** - Guide on how to calculate memory requirements and set up `gpu_memory_utilization` for optimal performance
|
||||
|
||||
## Multi-Stage Recipes
|
||||
|
||||
- **[Prefill-Decode Disaggregation](./pd_disaggregation.md)** - How to derive a PD-aware Qwen3-Omni stage config from the default config without introducing another bundled YAML
|
||||
|
||||
## Optimization Features
|
||||
|
||||
- **[Diffusion Features Overview](../user_guide/diffusion_features.md)** - Complete overview of all diffusion model features and supported models
|
||||
@@ -1,6 +1,6 @@
|
||||
# Composable parallel strategies
|
||||
|
||||
In vLLM-Omni, the `composable_parallel` system layers a declarative *parallel strategy* on top of the existing stage configs. A strategy YAML maps each pipeline stage (by its `model_stage` name) to a stack of axis declarations — one per parallelism dimension — that the engine translates into per-stage parallel sizing (`tensor_parallel_size`, `data_parallel_size`, `pipeline_parallel_size`, expert-parallel toggle, replica count) and, when relevant, an orchestrator-wide load-balancer policy.
|
||||
In vLLM-Omni, the `composable_parallel` system layers a declarative *parallel strategy* on top of the registered pipeline and deploy config. A strategy YAML maps each pipeline stage (by its `model_stage` name) to a stack of axis declarations — one per parallelism dimension — that the engine translates into per-stage parallel sizing (`tensor_parallel_size`, `data_parallel_size`, `pipeline_parallel_size`, expert-parallel toggle, replica count) and, when relevant, an orchestrator-wide load-balancer policy.
|
||||
|
||||
Strategies are intentionally narrow: each one only writes the axes it declares, leaving every other engine arg untouched. This makes a strategy file a small, reusable overlay you can swap independently of the deploy YAML (see `configuration/stage_configs.md`).
|
||||
|
||||
@@ -195,7 +195,7 @@ Because `omni_lb_policy` is read once at `AsyncOmniEngine` construction — not
|
||||
|
||||
Default: no default — required for every entry under `strategies:`.
|
||||
|
||||
Strategy keys MUST be `model_stage` *names* (strings), the same labels stage configs use for `engine_args.model_stage` (see [`model_stage` in `stage_configs.md`](stage_configs.md#engine_argsmodel_stage)). Integer `stage_id` values are not accepted; the resolver matches on `model_stage` exactly (`_resolve_stage` in `vllm_omni/config/composable_parallel/apply.py`).
|
||||
Strategy keys MUST be `model_stage` *names* (strings), the same labels defined by [`StagePipelineConfig.model_stage`](stage_configs.md#pipeline-configuration). Integer `stage_id` values are not accepted; the resolver matches on `model_stage` exactly (`_resolve_stage` in `vllm_omni/config/composable_parallel/apply.py`).
|
||||
|
||||
## Common pitfalls
|
||||
|
||||
|
||||
@@ -80,19 +80,15 @@ When multiple stages share the same GPU, you must ensure the sum of their `gpu_m
|
||||
|
||||
**Example: Two stages on GPU 0**
|
||||
```yaml
|
||||
stage_args:
|
||||
stages:
|
||||
- stage_id: 0
|
||||
runtime:
|
||||
devices: "0"
|
||||
engine_args:
|
||||
gpu_memory_utilization: 0.6 # Uses 60% of GPU 0
|
||||
devices: "0"
|
||||
gpu_memory_utilization: 0.6 # Uses 60% of GPU 0
|
||||
|
||||
- stage_id: 1
|
||||
runtime:
|
||||
devices: "0"
|
||||
engine_args:
|
||||
gpu_memory_utilization: 0.3 # Uses 30% of GPU 0
|
||||
# Total: 90% of GPU 0 (safe, leaves 10% buffer)
|
||||
devices: "0"
|
||||
gpu_memory_utilization: 0.3 # Uses 30% of GPU 0
|
||||
# Total: 90% of GPU 0 (safe, leaves 10% buffer)
|
||||
```
|
||||
|
||||
**Important:** If stages run on different GPUs, each can use up to 1.0 independently.
|
||||
@@ -103,14 +99,12 @@ When using `tensor_parallel_size > 1`, the model is split across multiple GPUs,
|
||||
|
||||
**Example: 2-way tensor parallelism**
|
||||
```yaml
|
||||
stage_args:
|
||||
stages:
|
||||
- stage_id: 0
|
||||
runtime:
|
||||
devices: "0,1" # Uses both GPUs
|
||||
engine_args:
|
||||
tensor_parallel_size: 2
|
||||
gpu_memory_utilization: 0.6 # 60% per GPU
|
||||
# Model is split, so each GPU uses ~30% of model memory
|
||||
devices: "0,1" # Uses both GPUs
|
||||
tensor_parallel_size: 2
|
||||
gpu_memory_utilization: 0.6 # 60% per GPU
|
||||
# Model is split, so each GPU uses ~30% of model memory
|
||||
```
|
||||
|
||||
## Examples
|
||||
@@ -118,27 +112,25 @@ stage_args:
|
||||
### Qwen3-Omni-MoE on 2x H100-80GB
|
||||
|
||||
```yaml
|
||||
stage_args:
|
||||
base_config: /path/to/vllm_omni/deploy/qwen3_omni_moe.yaml
|
||||
|
||||
stages:
|
||||
- stage_id: 0 # Thinker stage with TP=2
|
||||
runtime:
|
||||
devices: "0,1"
|
||||
engine_args:
|
||||
tensor_parallel_size: 2
|
||||
gpu_memory_utilization: 0.6 # 48GB per GPU
|
||||
devices: "0,1"
|
||||
tensor_parallel_size: 2
|
||||
gpu_memory_utilization: 0.6 # 48GB per GPU
|
||||
|
||||
- stage_id: 1 # Talker stage
|
||||
runtime:
|
||||
devices: "1"
|
||||
engine_args:
|
||||
gpu_memory_utilization: 0.3 # 24GB on GPU 1
|
||||
devices: "1"
|
||||
gpu_memory_utilization: 0.3 # 24GB on GPU 1
|
||||
|
||||
- stage_id: 2 # Code2Wav stage
|
||||
runtime:
|
||||
devices: "0"
|
||||
engine_args:
|
||||
gpu_memory_utilization: 0.1 # 8GB on GPU 0
|
||||
devices: "0"
|
||||
gpu_memory_utilization: 0.1 # 8GB on GPU 0
|
||||
```
|
||||
**Note:** In this configuration, stages 0 and 2 share GPU 0, but they run at different times in the pipeline, so their memory usage doesn't overlap.
|
||||
**Note:** Stage 0 uses GPUs 0 and 1, so the combined utilization is `0.7` on
|
||||
GPU 0 and `0.9` on GPU 1. Keep the sum of all resident stages below `1.0` on
|
||||
each device.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
|
||||
@@ -1,171 +0,0 @@
|
||||
# Prefill-Decode (PD) Disaggregation
|
||||
|
||||
PD disaggregation splits the Qwen3-Omni thinker into separate prefill and decode
|
||||
stages so prompt processing and token generation can run on different workers.
|
||||
|
||||
This is documented as a stage-config recipe instead of a bundled YAML because the
|
||||
deployment-specific values usually change per environment:
|
||||
|
||||
- GPU placement
|
||||
- `tensor_parallel_size`
|
||||
- connector backend and connector ports
|
||||
- connector IPs or bootstrap addresses
|
||||
|
||||
Start from the [default Qwen3-Omni stage config](gh-file:vllm_omni/deploy/qwen3_omni_moe.yaml)
|
||||
and copy it to your own file, for example `qwen3_omni_pd.yaml`. Then apply the
|
||||
changes below.
|
||||
|
||||
## Requirements
|
||||
|
||||
- 3+ GPUs for a basic layout: prefill, decode, and talker+code2wav
|
||||
- A KV connector supported by vLLM, such as `MooncakeConnector`
|
||||
- Matching `tensor_parallel_size` on the prefill and decode thinker stages
|
||||
|
||||
## 1. Split the thinker into prefill and decode stages
|
||||
|
||||
Replace the original thinker stage with two stages:
|
||||
|
||||
```yaml
|
||||
stage_args:
|
||||
- stage_id: 0
|
||||
stage_type: llm
|
||||
is_prefill_only: true
|
||||
runtime:
|
||||
devices: "0"
|
||||
engine_args:
|
||||
max_num_seqs: 16
|
||||
model_stage: thinker
|
||||
model_arch: Qwen3OmniMoeForConditionalGeneration
|
||||
worker_type: ar
|
||||
scheduler_cls: vllm_omni.core.sched.omni_ar_scheduler.OmniARScheduler
|
||||
gpu_memory_utilization: 0.9
|
||||
enforce_eager: true
|
||||
trust_remote_code: true
|
||||
engine_output_type: latent
|
||||
distributed_executor_backend: "mp"
|
||||
enable_prefix_caching: false
|
||||
max_num_batched_tokens: 32768
|
||||
hf_config_name: thinker_config
|
||||
tensor_parallel_size: 1
|
||||
kv_transfer_config:
|
||||
kv_connector: "MooncakeConnector"
|
||||
kv_role: "kv_producer"
|
||||
kv_rank: 0
|
||||
kv_parallel_size: 2
|
||||
kv_connector_extra_config:
|
||||
mooncake_bootstrap_port: 25201
|
||||
final_output: false
|
||||
is_comprehension: true
|
||||
default_sampling_params:
|
||||
temperature: 0.4
|
||||
top_p: 0.9
|
||||
top_k: 1
|
||||
max_tokens: 2048
|
||||
seed: 42
|
||||
detokenize: True
|
||||
repetition_penalty: 1.05
|
||||
|
||||
- stage_id: 1
|
||||
stage_type: llm
|
||||
is_decode_only: true
|
||||
runtime:
|
||||
devices: "1"
|
||||
engine_args:
|
||||
max_num_seqs: 64
|
||||
model_stage: thinker
|
||||
model_arch: Qwen3OmniMoeForConditionalGeneration
|
||||
worker_type: ar
|
||||
scheduler_cls: vllm_omni.core.sched.omni_ar_scheduler.OmniARScheduler
|
||||
gpu_memory_utilization: 0.9
|
||||
enforce_eager: true
|
||||
trust_remote_code: true
|
||||
engine_output_type: latent
|
||||
distributed_executor_backend: "mp"
|
||||
enable_prefix_caching: false
|
||||
max_num_batched_tokens: 32768
|
||||
hf_config_name: thinker_config
|
||||
tensor_parallel_size: 1
|
||||
kv_transfer_config:
|
||||
kv_connector: "MooncakeConnector"
|
||||
kv_role: "kv_consumer"
|
||||
kv_rank: 1
|
||||
kv_parallel_size: 2
|
||||
kv_connector_extra_config:
|
||||
mooncake_bootstrap_port: 25202
|
||||
engine_input_source: [0]
|
||||
final_output: true
|
||||
final_output_type: text
|
||||
is_comprehension: true
|
||||
default_sampling_params:
|
||||
temperature: 0.4
|
||||
top_p: 0.9
|
||||
top_k: 1
|
||||
max_tokens: 2048
|
||||
seed: 42
|
||||
detokenize: True
|
||||
repetition_penalty: 1.05
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
- `is_prefill_only: true` marks the thinker stage that only saves KV.
|
||||
- `is_decode_only: true` marks the thinker stage that resumes from remote KV.
|
||||
- `kv_transfer_config` is required on both stages.
|
||||
- The orchestrator forces the prefill stage to run with `max_tokens=1`, so the
|
||||
prefill side only processes the prompt and exports KV.
|
||||
|
||||
## 2. Shift the downstream stages by one index
|
||||
|
||||
After inserting the extra thinker stage, renumber the remaining stages:
|
||||
|
||||
```yaml
|
||||
- stage_id: 2
|
||||
runtime:
|
||||
devices: "2"
|
||||
engine_input_source: [1]
|
||||
sync_process_input_func: vllm_omni.model_executor.stage_input_processors.qwen3_omni.thinker2talker_token_only
|
||||
|
||||
- stage_id: 3
|
||||
runtime:
|
||||
devices: "2"
|
||||
engine_args:
|
||||
max_num_seqs: 1
|
||||
engine_input_source: [2]
|
||||
sync_process_input_func: vllm_omni.model_executor.stage_input_processors.qwen3_omni.talker2code2wav_token_only
|
||||
```
|
||||
|
||||
Compared with the default Qwen3-Omni config:
|
||||
|
||||
- the talker becomes stage `2` instead of stage `1`
|
||||
- the code2wav stage becomes stage `3` instead of stage `2`
|
||||
- the talker now reads from decode stage `1`
|
||||
|
||||
## 3. Add runtime edges for the four-stage pipeline
|
||||
|
||||
```yaml
|
||||
runtime:
|
||||
enabled: true
|
||||
edges:
|
||||
- from: 0
|
||||
to: 1
|
||||
- from: 1
|
||||
to: 2
|
||||
- from: 2
|
||||
to: 3
|
||||
```
|
||||
|
||||
## 4. Launch with your custom config
|
||||
|
||||
```bash
|
||||
vllm serve Qwen/Qwen3-Omni-30B-A3B-Instruct --omni --port 8091 \
|
||||
--deploy-config /path/to/qwen3_omni_pd.yaml
|
||||
```
|
||||
|
||||
## Operational Notes
|
||||
|
||||
- `MooncakeConnector` does not support heterogeneous TP sizes across the PD
|
||||
pair. Keep prefill and decode at the same `tensor_parallel_size`.
|
||||
- If the thinker requires TP=2, both thinker stages must use TP=2 and be given
|
||||
separate GPU sets, for example `"0,1"` for prefill and `"2,3"` for decode.
|
||||
- Choose connector ports and addresses that match your deployment. The values
|
||||
shown above are examples only.
|
||||
@@ -3,7 +3,46 @@
|
||||
In vLLM-Omni, a model's `PipelineConfig` defines its fixed stage topology, while a deploy configuration controls how those stages run.
|
||||
|
||||
!!! note
|
||||
Default deploy config YAMLs (for example, `vllm_omni/deploy/qwen2_5_omni.yaml`, `vllm_omni/deploy/qwen3_omni_moe.yaml`, and `vllm_omni/deploy/qwen3_tts.yaml`) are bundled and loaded automatically when `--deploy-config` is omitted. The model registry resolves the right pipeline and deploy YAML by `model_type`.
|
||||
Default deploy config YAMLs (for example, `vllm_omni/deploy/qwen2_5_omni.yaml`, `vllm_omni/deploy/qwen3_omni_moe.yaml`, and `vllm_omni/deploy/qwen3_tts.yaml`) are bundled and loaded automatically when `--deploy-config` is omitted. The resolved pipeline selects its default through `default_deploy_config_name`.
|
||||
|
||||
## Pipeline configuration
|
||||
|
||||
`PipelineConfig` and its `StagePipelineConfig` entries are Python definitions
|
||||
owned by the model implementation and registered in `OMNI_PIPELINES`. They
|
||||
describe fixed model topology and are not accepted in deploy YAMLs.
|
||||
|
||||
Common `PipelineConfig` fields include:
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `model_type` | Pipeline identifier used during model and config resolution. |
|
||||
| `default_deploy_config_name` | Bundled deploy YAML loaded when the user does not pass `deploy_config`. |
|
||||
| `model_arch` | Default Hugging Face architecture for the pipeline. |
|
||||
| `hf_architectures` | Architecture names used to identify checkpoints whose `model_type` is shared. |
|
||||
| `hf_config_predicate` | Optional predicate used to select between pipelines with otherwise identical HF metadata. |
|
||||
| `diffusers_class_name` | Diffusers `_class_name` used to identify Diffusers-style repositories. |
|
||||
| `stages` | Ordered tuple of fixed `StagePipelineConfig` definitions. |
|
||||
|
||||
Common `StagePipelineConfig` fields include:
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `stage_id` | Stable stage identifier. |
|
||||
| `model_stage` | Logical stage name used by runtime and strategy resolution. |
|
||||
| `execution_type` | `LLM_AR`, `LLM_GENERATION`, or `DIFFUSION`. |
|
||||
| `input_sources` | Upstream stage IDs that provide this stage's inputs. |
|
||||
| `final_output` / `final_output_type` | Whether the stage produces a user-visible output and its modality. |
|
||||
| `owns_tokenizer` | Whether this stage owns the pipeline tokenizer. |
|
||||
| `model_arch`, `hf_config_name` | Stage-specific model architecture and nested HF config selector. |
|
||||
| `engine_output_type` | Runtime output representation such as `text`, `latent`, or `audio`. |
|
||||
| `custom_process_input_func` | Processor applied to this stage's incoming payload. |
|
||||
| `custom_process_next_stage_input_func` | Processor used for full-payload handoff to the next stage. |
|
||||
| `async_chunk_process_next_stage_input_func` | Processor used for async chunk handoff. |
|
||||
| `sampling_constraints` | Model-owned sampling constraints that deploy defaults cannot override. |
|
||||
|
||||
To add or change topology, define and register a new pipeline variant. Use
|
||||
deploy YAML only for runtime placement, resource sizing, connectors, and other
|
||||
deployment overrides.
|
||||
|
||||
## Deploy configuration schema
|
||||
|
||||
@@ -13,42 +52,53 @@ The new deploy schema lives under `vllm_omni/deploy/` and is paired with a froze
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `base_config` | str (path) | optional | — | Overlay parent (relative or absolute). `stages:` / `platforms:` deep-merged by stage_id; other scalars overlay-wins. Intended for user-authored overlays; prod yamls stay flat. |
|
||||
| `async_chunk` | bool | optional | `true` | Enable chunked streaming between stages. Pin to `false` if the pipeline runs end-to-end. |
|
||||
| `session_mode` | str | optional | `"turn"` | Session behavior. Use `"duplex"` only with a pipeline that enables duplex control. |
|
||||
| `active_stream_window` | int | optional | `0` | Number of active downstream stream slots; `0` preserves all-stream cycling. |
|
||||
| `duplex_session` | dict | optional | runtime defaults | Full-duplex session lifecycle, buffering, replay, and capacity limits. |
|
||||
| `connectors` | dict | optional | `null` | Named connector specs (`{name, extra}`). Referenced by each stage's `input_connectors` / `output_connectors`. See [Connector schema](#connector-schema). |
|
||||
| `edges` | list | optional | `null` | Explicit edge list for the KV transfer graph. Auto-derived from stage inputs if omitted. |
|
||||
| `stages` | list | required | — | Per-stage engine args + wiring (see [Stage fields](#stage-fields)). |
|
||||
| `stages` | list | optional | `[]` | Per-stage runtime overrides matched by `stage_id`. Pipeline stages are still created from `PipelineConfig` when this list is empty. |
|
||||
| `platforms` | dict | optional | `null` | Keyed by `npu` / `rocm` / `xpu`, each contains a `stages:` list with per-platform overrides applied on top of the CUDA defaults. |
|
||||
| `pipeline` | str | optional | `null` | Override the auto-detected pipeline registry key (used for structural variants like `qwen2_5_omni_thinker_only`). |
|
||||
| `trust_remote_code` | bool | optional | `true` | **Pipeline-wide.** Trust HF remote code on model load; applies to every stage. |
|
||||
| `trust_remote_code` | bool \| null | optional | `null` | **Pipeline-wide.** Trust HF remote code on model load; applies to every stage when specified. |
|
||||
| `distributed_executor_backend` | str \| null | optional | `null` | **Pipeline-wide.** Distributed executor backend forwarded to vLLM (`"mp"`, `"ray"`, `"external_launcher"`). If omitted, vLLM auto-selects backend from runtime topology. |
|
||||
| `dtype` | str \| null | optional | `null` | **Pipeline-wide.** Model dtype for every stage. |
|
||||
| `quantization` | str \| null | optional | `null` | **Pipeline-wide.** Quantization method for every stage. |
|
||||
| `enable_prefix_caching` | bool | optional | `false` | **Pipeline-wide.** Prefix cache toggle applied to every stage. |
|
||||
| `enable_prefix_caching` | bool \| null | optional | `null` | **Pipeline-wide.** Prefix cache toggle applied to every stage when specified. |
|
||||
| `enable_chunked_prefill` | bool \| null | optional | `null` | **Pipeline-wide.** Chunked prefill toggle applied to every stage. |
|
||||
| `data_parallel_size` | int | optional | `1` | **Pipeline-wide.** DP degree for every stage. |
|
||||
| `pipeline_parallel_size` | int | optional | `1` | **Pipeline-wide.** PP degree for every stage. |
|
||||
| `data_parallel_size` | int \| null | optional | `null` | **Pipeline-wide.** DP degree for every stage. |
|
||||
| `pipeline_parallel_size` | int \| null | optional | `null` | **Pipeline-wide.** PP degree for every stage. |
|
||||
| `custom_voice_dir` | str \| null | optional | `null` | **Pipeline-wide.** Directory containing custom voice profiles for supported TTS models. |
|
||||
|
||||
Note: for diffusion path, `distributed_executor_backend` currently defaults to
|
||||
`mp`, and `ray` / `external_launcher` are not fully supported yet.
|
||||
For fields whose deploy default is `null`, the deploy layer contributes no
|
||||
override. The effective value may still come from a platform section, an
|
||||
explicit CLI or stage override, or the downstream vLLM engine default.
|
||||
|
||||
Note: for the diffusion path, an omitted `distributed_executor_backend` selects
|
||||
`uni` on a single GPU (in-process worker, no MessageQueue / `/dev/shm` output
|
||||
segments) and `mp` when `num_gpus > 1`. Set `mp` explicitly to keep a worker
|
||||
subprocess on one GPU. `ray` / `external_launcher` are not fully supported yet.
|
||||
|
||||
### Stage fields
|
||||
|
||||
Each entry under `stages:` accepts any `StageDeployConfig` field directly (no nested `engine_args:`). Only fields whose value legitimately varies across stages live here; pipeline-wide settings (trust_remote_code, distributed_executor_backend, dtype, quantization, prefix/chunked prefill, DP/PP sizes) are declared at the top level and applied to every stage. Unknown keys fall through to `engine_extras:` and are forwarded to the engine.
|
||||
Each entry under `stages:` accepts any `StageDeployConfig` field directly (no nested `engine_args:`). Only fields whose value legitimately varies across stages live here; pipeline-wide settings (trust_remote_code, distributed_executor_backend, dtype, quantization, prefix/chunked prefill, DP/PP sizes) are declared at the top level and applied to every stage. Unknown keys fall through to `engine_extras:` and are forwarded to the engine. Frequently used fields are listed below; the source-of-truth schema is `StageDeployConfig` in `vllm_omni/config/stage_config.py`.
|
||||
|
||||
| Field | Type | Required | Default | Description |
|
||||
|-------|------|----------|---------|-------------|
|
||||
| `stage_id` | int | required | — | Stage identity; matched against `PipelineConfig.stages[*].stage_id`. |
|
||||
| `max_num_seqs` | int | optional | `64` | Max concurrent sequences per stage. |
|
||||
| `gpu_memory_utilization` | float | optional | `0.9` | Per-stage memory budget. |
|
||||
| `tensor_parallel_size` | int | optional | `1` | TP degree for this stage. |
|
||||
| `enforce_eager` | bool | optional | `false` | Disable CUDA graphs. |
|
||||
| `max_num_batched_tokens` | int | optional | `32768` | Prefill budget. |
|
||||
| `max_model_len` | int \| null | optional | `null` | Per-stage context length (auto-sets `VLLM_ALLOW_LONG_MAX_MODEL_LEN=1` when larger than HF default). |
|
||||
| `max_num_seqs` | int \| null | optional | `null` | Max concurrent sequences per stage. |
|
||||
| `gpu_memory_utilization` | float \| null | optional | `null` | Per-stage total memory target; used for automatic KV-cache sizing. |
|
||||
| `kv_cache_memory_bytes` | int \| null | optional | `null` | Explicit per-rank KV-cache budget in bytes; overrides automatic sizing. |
|
||||
| `tensor_parallel_size` | int \| null | optional | `null` | TP degree for this stage. |
|
||||
| `enforce_eager` | bool \| null | optional | `null` | Disable CUDA graphs. |
|
||||
| `max_num_batched_tokens` | int \| null | optional | `null` | Per-stage prefill/token budget; also contributes to the native maximum in-flight token limit. |
|
||||
| `max_model_len` | int \| null | optional | `null` | Per-sequence context or KV length; `-1` enables native cache-capacity auto-fitting, while values above the HF default auto-set `VLLM_ALLOW_LONG_MAX_MODEL_LEN=1`. |
|
||||
| `async_scheduling` | bool \| null | optional | `null` | Per-stage async scheduling toggle. |
|
||||
| `devices` | str | optional | `"0"` | `CUDA_VISIBLE_DEVICES`-style device list. |
|
||||
| `devices` | str \| null | optional | `null` | Device list assigned to this stage. |
|
||||
| `output_connectors` | dict \| null | optional | `null` | Keyed by `to_stage_<n>`; values are names registered under top-level `connectors:`. |
|
||||
| `input_connectors` | dict \| null | optional | `null` | Keyed by `from_stage_<n>`; values are names registered under top-level `connectors:`. |
|
||||
| `default_sampling_params` | dict \| null | optional | `null` | Baseline sampling params. Deep-merged with pipeline `sampling_constraints` (pipeline wins). |
|
||||
| `engine_extras` | dict | optional | `{}` | Catch-all for keys not listed above; deep-merged across overlays. Also carries per-stage overrides of pipeline-wide settings (e.g. stage-specific `dtype`). |
|
||||
| `engine_extras` | dict | optional | `{}` | Catch-all for engine fields not listed above; deep-merged across overlays and forwarded to the stage engine. |
|
||||
|
||||
### Connector schema
|
||||
|
||||
@@ -60,7 +110,7 @@ connectors:
|
||||
name: <ConnectorClassName> # required — class registered in vllm_omni.distributed
|
||||
extra: # optional — forwarded to the connector's __init__
|
||||
<key>: <value>
|
||||
...
|
||||
# Additional connector-specific options
|
||||
```
|
||||
|
||||
| Connector class | Use case | `extra` keys |
|
||||
@@ -235,288 +285,3 @@ vllm serve Qwen/Qwen2.5-Omni-7B --omni --port 8091 --deploy-config /path/to/depl
|
||||
|
||||
!!! important
|
||||
We are actively iterating on the definition of deployment configurations, and we welcome feedback from users and developers.
|
||||
|
||||
## Legacy stage configuration reference
|
||||
|
||||
The remainder of this page documents the deprecated `stage_args` schema for models that have not migrated to deploy configurations. The following historical Qwen2.5-Omni configuration illustrates that schema; current Qwen2.5-Omni deployments should use `vllm_omni/deploy/qwen2_5_omni.yaml` instead.
|
||||
|
||||
```python
|
||||
# Historical stage configuration for Qwen2.5-Omni.
|
||||
stage_args:
|
||||
- stage_id: 0 # mark the unique id for each stage
|
||||
runtime: # The disaggregated configuration
|
||||
process: true # Run this stage in a separate process
|
||||
devices: "0" # Logical device index for this stage (mapped through CUDA_VISIBLE_DEVICES / ASCEND_RT_VISIBLE_DEVICES if set)
|
||||
engine_args: # Engine arguments for a certain engine
|
||||
model_stage: thinker
|
||||
max_num_seqs: 1
|
||||
model_arch: Qwen2_5OmniForConditionalGeneration # The model implementation registered in model_executor/models/registry.py
|
||||
worker_type: ar # The specific worker used
|
||||
scheduler_cls: vllm_omni.core.sched.omni_ar_scheduler.OmniARScheduler # The specific scehduler used
|
||||
gpu_memory_utilization: 0.8 # The gpu memory allocation for the stage within a single chip
|
||||
enforce_eager: true # Now we only support eager mode
|
||||
trust_remote_code: true # Needed by huggingface config parsing
|
||||
engine_output_type: latent # It claims that the stage will input latent hiddenstates besides token ids
|
||||
enable_prefix_caching: false # For request with hiddenstates output, the prefix caching is not supported now
|
||||
is_comprehension: true # If the stage is a text or multimodal comprehension module. If it is, the AsyncOmni will use its tokenizer as default
|
||||
final_output: true # If the stage has output as part of final outputs. If it is false, which means that the stage only works as a intermediate role.
|
||||
final_output_type: text # What is the final output type. It can be text and audio now.
|
||||
default_sampling_params: # sampling parameters for the stage. Their meaning aligns with vLLM.
|
||||
temperature: 0.0
|
||||
top_p: 1.0
|
||||
top_k: -1
|
||||
max_tokens: 2048
|
||||
seed: 42
|
||||
detokenize: True
|
||||
repetition_penalty: 1.1
|
||||
- stage_id: 1
|
||||
runtime:
|
||||
process: true
|
||||
devices: "1"
|
||||
engine_args:
|
||||
model_stage: talker
|
||||
max_num_seqs: 3
|
||||
model_arch: Qwen2_5OmniForConditionalGeneration
|
||||
worker_type: ar
|
||||
scheduler_cls: vllm_omni.core.sched.omni_ar_scheduler.OmniARScheduler
|
||||
gpu_memory_utilization: 0.8
|
||||
enforce_eager: true
|
||||
trust_remote_code: true
|
||||
enable_prefix_caching: false
|
||||
engine_output_type: latent
|
||||
engine_input_source: [0]
|
||||
default_sampling_params:
|
||||
temperature: 0.9
|
||||
top_p: 0.8
|
||||
top_k: 40
|
||||
max_tokens: 2048
|
||||
seed: 42
|
||||
detokenize: True
|
||||
repetition_penalty: 1.05
|
||||
stop_token_ids: [8294]
|
||||
- stage_id: 2
|
||||
runtime:
|
||||
process: true
|
||||
devices: "0" # Example: use a different GPU than the previous stage; use "0" if single GPU
|
||||
engine_args:
|
||||
model_stage: code2wav
|
||||
max_num_seqs: 1
|
||||
model_arch: Qwen2_5OmniForConditionalGeneration
|
||||
worker_type: generation
|
||||
scheduler_cls: vllm_omni.core.sched.omni_generation_scheduler.OmniGenerationScheduler
|
||||
gpu_memory_utilization: 0.15
|
||||
enforce_eager: true
|
||||
trust_remote_code: true
|
||||
enable_prefix_caching: false
|
||||
engine_output_type: audio
|
||||
engine_input_source: [1]
|
||||
final_output: true
|
||||
final_output_type: audio
|
||||
default_sampling_params:
|
||||
temperature: 0.0
|
||||
top_p: 1.0
|
||||
top_k: -1
|
||||
max_tokens: 2048
|
||||
seed: 42
|
||||
detokenize: True
|
||||
repetition_penalty: 1.1
|
||||
|
||||
# Top-level runtime config (concise): default windows and stage edges
|
||||
runtime:
|
||||
enabled: true
|
||||
|
||||
edges:
|
||||
- from: 0 # thinker → talker: trigger only after receiving full input (-1)
|
||||
to: 1
|
||||
- from: 1 # talker → code2wav: trigger only after receiving full input (-1)
|
||||
to: 2
|
||||
|
||||
```
|
||||
|
||||
## Legacy stage configuration arguments
|
||||
|
||||
Each stage in the `stage_args` list contains the following configuration options:
|
||||
|
||||
### `stage_id`
|
||||
|
||||
A unique identifier for each stage in the multi-stage pipeline. Stages are numbered sequentially starting from 0, and this ID is used to reference stages in inter-stage dependencies (e.g., `engine_input_source`).
|
||||
|
||||
### `prompt_expand_func` (Optional)
|
||||
|
||||
A custom Python function hook for the LLM stage (Stage 0) that expands a single incoming prompt object into multiple prompts. This is primarily used for multi-modal Classifier-Free Guidance (CFG), where it generates the necessary companion requests (like a negative text prompt) and tags them with internal roles (e.g., `cfg_text`). This ensures the upstream LLM generates the needed contextual hidden states for both the conditional and unconditional generations simultaneously.
|
||||
|
||||
### `cfg_kv_collect_func` (Optional)
|
||||
|
||||
A custom Python function hook for downstream diffusion stages (Stage 1+) to collect, map, and process the KV caches transferred from the companion requests fired by `prompt_expand_func`. It aggregates the hidden condition states cleanly (e.g., binding them as `cfg_text_past_key_values` and `cfg_text_kv_metadata`), allowing the diffusion runtime to perform CFG smoothly without redundantly evaluating text paths on the DiT workers.
|
||||
|
||||
### `runtime`
|
||||
|
||||
Configuration for disaggregated execution of the stage, controlling how the stage is deployed and executed.
|
||||
|
||||
#### `runtime.process`
|
||||
|
||||
Whether to run this stage in a separate process. When set to `true`, the stage will be executed in an isolated process, enabling better resource isolation and parallel execution across different stages. This is essential for multi-GPU deployments where different stages run on different devices.
|
||||
|
||||
Default: `true`
|
||||
|
||||
#### `runtime.devices`
|
||||
|
||||
Logical device indices for this stage, specified as a string. Values are **logical indices** (`0`, `1`, `2`, ...) — not physical GPU IDs — and are mapped through the platform's visibility env var (`CUDA_VISIBLE_DEVICES` on CUDA, `ASCEND_RT_VISIBLE_DEVICES` on NPU) before being applied via `torch.cuda.set_device()` (or the equivalent).
|
||||
|
||||
Example: if `CUDA_VISIBLE_DEVICES=0,2,4` is set in the environment, then `devices: "0"` selects physical GPU 0 (the first visible), `devices: "1"` selects physical GPU 2, and `devices: "0,1"` makes physical GPUs 0 and 2 available to the stage. If no visibility env var is set, logical and physical IDs coincide.
|
||||
|
||||
Default: `"0"`
|
||||
|
||||
#### `engine_args.max_num_seqs`
|
||||
|
||||
The maximum number of sequences for concurrent processing in this stage. For
|
||||
LLM stages, this controls the vLLM scheduler's maximum concurrent sequences.
|
||||
For diffusion stages, this controls scheduler wave capacity in both request
|
||||
batch mode and step batch mode. `max_num_seqs: 1` is the serial/conservative
|
||||
path; values above `1` allow compatible requests to batch when the selected
|
||||
diffusion pipeline supports that batching mode.
|
||||
|
||||
Default: `1`
|
||||
|
||||
#### `engine_args.request_batch_max_wait_ms`
|
||||
|
||||
The maximum time, in milliseconds, that a diffusion request-mode stage may wait
|
||||
before the first `schedule()` of a new scheduler wave so compatible requests can
|
||||
accumulate for request-level batching. This only applies to diffusion pipelines
|
||||
that support request-level batching with `step_execution` disabled.
|
||||
|
||||
Use this together with `max_num_seqs > 1` for bursty serving traffic. `0`
|
||||
disables admission waiting and preserves the lowest first-request latency.
|
||||
For diffusion execution and batching tuning, see
|
||||
[Diffusion Execution Modes](../user_guide/diffusion/execution_modes.md).
|
||||
|
||||
Default: `0.0`
|
||||
|
||||
### `engine_args`
|
||||
|
||||
Engine arguments for configuring the LLM engine, diffusion engine, or other engine types used by this stage.
|
||||
|
||||
#### `engine_args.model_stage`
|
||||
|
||||
The name identifier for this model stage within the multi-stage architecture. This is used internally to distinguish different stages of the same model (e.g., "thinker", "talker", "code2wav" in Qwen2.5-Omni).
|
||||
|
||||
#### `engine_args.model_arch`
|
||||
|
||||
The model architecture class name that is registered in `model_executor/models/registry.py`. This specifies which model implementation to use for this stage. The class must be registered in the model registry for vLLM-Omni to locate and instantiate it.
|
||||
|
||||
#### `engine_args.worker_cls`
|
||||
|
||||
The specific worker class to use for this stage. This determines how the model computations are executed. Examples include `vllm_omni.worker.gpu_ar_worker.GPUARWorker` for autoregressive stages and `vllm_omni.worker.gpu_generation_worker.GPUGenerationWorker` for diffusion-based stages.
|
||||
|
||||
#### `engine_args.scheduler_cls`
|
||||
|
||||
The scheduler class to use for this stage. The scheduler manages request queuing, batching, and execution order. Examples include `vllm_omni.core.sched.omni_ar_scheduler.OmniARScheduler` for standard stages and `vllm_omni.core.sched.omni_generation_scheduler.OmniGenerationScheduler` for diffusion stages.
|
||||
|
||||
#### `engine_args.gpu_memory_utilization`
|
||||
|
||||
The fraction of GPU memory to allocate for this stage within a single GPU chip. This is a value between 0.0 and 1.0, where 0.8 means 80% of the GPU memory will be used by this stage. This allows fine-grained control over memory allocation when multiple stages share the same GPU or when reserving memory for other operations.
|
||||
|
||||
Default: `0.8`
|
||||
|
||||
!!! tip "Memory Configuration Guide"
|
||||
For detailed information on how to calculate memory requirements and properly configure `gpu_memory_utilization`, see the [GPU Memory Calculation and Configuration Guide](./gpu_memory_utilization.md).
|
||||
|
||||
#### `engine_args.enforce_eager`
|
||||
|
||||
Whether to enforce eager execution mode. When set to `true`, the engine will run in eager mode without using CUDA graphs or other compilation optimizations. Currently, vLLM-Omni only supports eager mode.
|
||||
|
||||
Default: `true`
|
||||
|
||||
#### `engine_args.trust_remote_code`
|
||||
|
||||
Whether to trust remote code when loading models from Hugging Face. This is required for models that use custom code in their configuration files. Set to `true` when loading models that require custom model implementations.
|
||||
|
||||
Default: `true`
|
||||
|
||||
#### `engine_args.engine_output_type`
|
||||
|
||||
Specifies the type of output produced by this stage's engine. This determines what kind of data flows to downstream stages. Possible values include `latent` (hidden states), `text` (tokenized text), and `audio` (audio waveforms). When set to `latent`, the stage outputs latent hidden states in addition to token IDs, which are consumed by downstream stages.
|
||||
|
||||
Default: `latent`
|
||||
|
||||
#### `engine_args.enable_prefix_caching`
|
||||
|
||||
Whether to enable prefix caching for this stage. Prefix caching can improve performance by caching KV cache for common prompt prefixes. However, for requests that output hidden states (when `engine_output_type` is `latent`), prefix caching is not currently supported and should be set to `false`.
|
||||
|
||||
Default: `false`
|
||||
|
||||
### `is_comprehension`
|
||||
|
||||
Whether this stage is a text or multimodal comprehension module. When set to `true`, the stage acts as a comprehension module that processes input text or multimodal content. If this is the first comprehension stage, `AsyncOmni` will use its tokenizer as the default tokenizer for the entire pipeline.
|
||||
|
||||
Default: `true`
|
||||
|
||||
### `final_output`
|
||||
|
||||
Whether this stage produces output that is part of the final outputs returned to the user. When set to `false`, the stage only works as an intermediate stage, processing data that flows to downstream stages but not contributing directly to the final response.
|
||||
|
||||
Default: `true`
|
||||
|
||||
### `final_output_type`
|
||||
|
||||
The type of final output produced by this stage. This specifies what format the output will be in when returned to the user. Currently supported values are `text` (for text generation) and `audio` (for audio generation).
|
||||
|
||||
Default: `text`
|
||||
|
||||
### `default_sampling_params`
|
||||
|
||||
Default sampling parameters for this stage. These parameters control the generation behavior and align with vLLM's sampling parameter semantics. These defaults are used when no explicit sampling parameters are provided in the request.
|
||||
|
||||
#### `default_sampling_params.temperature`
|
||||
|
||||
Sampling temperature for controlling randomness. Lower values (e.g., 0.0) make the output more deterministic and focused, while higher values increase randomness.
|
||||
|
||||
Default: `0.0`
|
||||
|
||||
#### `default_sampling_params.top_p`
|
||||
|
||||
Nucleus sampling parameter. Only tokens with cumulative probability mass up to `top_p` are considered. This helps filter out low-probability tokens while maintaining diversity.
|
||||
|
||||
Default: `1.0`
|
||||
|
||||
#### `default_sampling_params.top_k`
|
||||
|
||||
Top-k sampling parameter. Only the top `k` most likely tokens are considered. Set to `-1` to disable top-k filtering and consider all tokens.
|
||||
|
||||
Default: `-1`
|
||||
|
||||
#### `default_sampling_params.max_tokens`
|
||||
|
||||
Maximum number of tokens to generate in this stage. This limits the length of the output sequence.
|
||||
|
||||
Default: `2048`
|
||||
|
||||
#### `default_sampling_params.seed`
|
||||
|
||||
Random seed for reproducible generation. When set, the random number generator will be initialized with this seed to ensure consistent outputs across runs.
|
||||
|
||||
Default: `42`
|
||||
|
||||
#### `default_sampling_params.detokenize`
|
||||
|
||||
Whether to detokenize the output tokens into text. When set to `true`, token IDs are converted back to readable text strings.
|
||||
|
||||
Default: `True`
|
||||
|
||||
#### `default_sampling_params.repetition_penalty`
|
||||
|
||||
Penalty applied to tokens that have already appeared in the generated sequence. Values greater than 1.0 discourage repetition, while values less than 1.0 encourage it. A value of 1.0 applies no penalty.
|
||||
|
||||
Default: `1.1`
|
||||
|
||||
### `tts_args` (TTS stages only)
|
||||
|
||||
Configuration for Text-to-Speech specific parameters. This section is only applicable to TTS model stages (e.g., `qwen3_tts`).
|
||||
|
||||
#### `tts_args.max_instructions_length`
|
||||
|
||||
Maximum character length for voice style/emotion instructions. Instructions exceeding this limit will be rejected with a validation error.
|
||||
|
||||
Default: `500`
|
||||
|
||||
This value can be overridden at runtime using the `--tts-max-instructions-length` CLI parameter when starting the server.
|
||||
@@ -46,7 +46,7 @@ class Omni:
|
||||
|
||||
Args:
|
||||
model: Model name or path
|
||||
stage_configs: Optional stage configurations
|
||||
deploy_config: Optional path to a deploy configuration
|
||||
**kwargs: Additional arguments passed to the engine
|
||||
|
||||
Example:
|
||||
|
||||
+189
-3
@@ -3,7 +3,7 @@
|
||||
Thank you for your interest in contributing to vLLM-Omni! This document provides guidelines and instructions for contributing.
|
||||
|
||||
!!! note
|
||||
We host weekly developer-facing online meetings to discuss milestones and updates **every Tuesday at 19:30 PDT**. Meeting link as well as the past meeting notes can be found [here](https://tinyurl.com/vllm-omni-meeting).
|
||||
vLLM-Omni hosts developer-facing meetings for Chinese- and English-language audiences. See [Community Meetings](../community/meetings.md) for current schedules, access details, agendas, and past notes.
|
||||
|
||||
## Getting Started
|
||||
|
||||
@@ -44,6 +44,149 @@ vLLM-Omni's `pre-commit` hooks will now run automatically every time you commit.
|
||||
pre-commit run --show-diff-on-failure --color=always --all-files # runs on all files (short for --all-files)
|
||||
```
|
||||
|
||||
!!! warning
|
||||
GitHub Actions `pre-commit` **skips** several local gates so a whole-tree
|
||||
`--all-files` run stays green while historical debt is cleaned up. The
|
||||
current `SKIP` list in
|
||||
[`.github/workflows/pre-commit.yml`](https://github.com/vllm-project/vllm-omni/blob/main/.github/workflows/pre-commit.yml)
|
||||
is `check-test-ci-coverage`, `markdownlint-cli2`, `shellcheck`,
|
||||
`check-spdx-header`, and `mypy-3.10`. Those hooks still run on **your
|
||||
commit** for changed files. A passing GitHub pre-commit check does not mean
|
||||
they passed locally. Hooks **not** on that list (forbidden imports,
|
||||
`torch.cuda`, TTS adapter ratchet, Buildkite schema, Ruff, typos, …) run in
|
||||
both places.
|
||||
|
||||
The hooks below are new relative to the previous Omni config (Ruff, typos,
|
||||
actionlint, YAML/whitespace, DCO sign-off, and the pickle-only checker were
|
||||
already there). `check-pickle-imports` is gone: pickle is now one rule inside
|
||||
`check-forbidden-imports`.
|
||||
|
||||
| Hook id | Enforces | GitHub Actions |
|
||||
| ------- | -------- | -------------- |
|
||||
| `markdownlint-cli2` | Markdown in `docs/`, `recipes/`, `README.md`, `CONTRIBUTING.md` (not `.claude/` / `.cursor/` / `CLAUDE.md`) | skipped |
|
||||
| `mypy-3.10` | Type-check changed `vllm_omni/` files (model trees excluded). `tests/` uses `--follow-imports skip` | skipped |
|
||||
| `mypy-3.11` / `3.12` / `3.13` | Same checker, extra Python versions | not installed; `pre-commit run --hook-stage manual mypy-3.12` |
|
||||
| `check-test-ci-coverage` | Every `tests/**/test_*.py` has a CI level mark and a hardware mark/helper | skipped |
|
||||
| `check-tts-adapter-migration` | `self._tts_model_type` branches in `serving_speech.py` must not increase | runs |
|
||||
| `shellcheck` | `*.sh` quoting / undefined vars | skipped |
|
||||
| `check-spdx-header` | Omni SPDX header on `.py` / `.pyi` / `.sh` / `.rs` / `.proto` | skipped |
|
||||
| `check-forbidden-imports` | pickle, stdlib `re`/`base64`, Triton, TileLang, Hugging Face Hub download/API | runs |
|
||||
| `check-torch-cuda-call` | Direct `torch.cuda.*` helpers outside platform adapters | runs |
|
||||
| `check-buildkite` | `.buildkite/*.yml` against the Buildkite schema | runs |
|
||||
|
||||
Related config (not a new hook id): Ruff `TID251` also bans `librosa` and several
|
||||
`torch.cuda.*` names; typos is pinned and ignores git-describe hashes (`+g` +
|
||||
hex) and NumPy `writeable`. Keep the `suggestion` hook last in
|
||||
`.pre-commit-config.yaml` so autofix output does not bury the SKIP tip.
|
||||
|
||||
#### SPDX headers
|
||||
|
||||
Source files must start with:
|
||||
|
||||
```text
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
```
|
||||
|
||||
Rust and proto files use `//` instead of `#`. Empty files are exempt. A stale
|
||||
`Copyright contributors to the vLLM project` line is **rewritten in place** to
|
||||
the Omni copyright; the hook then exits non-zero so you restage the rewrite.
|
||||
|
||||
#### Forbidden imports
|
||||
|
||||
Under `vllm_omni/`, do not use:
|
||||
|
||||
- stdlib `re` → `import regex as re`
|
||||
- stdlib `base64` → `import pybase64` (or `import pybase64 as base64`)
|
||||
- `pickle` / `cloudpickle` (also banned in most tests)
|
||||
- `from huggingface_hub import snapshot_download` / `hf_hub_download` / `HfApi`
|
||||
/ similar → `vllm.transformers_utils.repo_utils`
|
||||
- direct `triton` / `tilelang` → `vllm.triton_utils` / `vllm.tilelang_utils`
|
||||
|
||||
`examples/`, `tests/`, `benchmarks/`, `apps/`, `docs/`, `tools/`, `scripts/`,
|
||||
`.buildkite/`, and `.github/` may keep stdlib `re` and `base64`
|
||||
(`_NON_LIBRARY_DIRS`). Pickle is stricter: tests are not exempt unless the
|
||||
file is on the pickle allowlist.
|
||||
|
||||
#### `torch.cuda` call sites
|
||||
|
||||
Prefer `current_omni_platform` / `OmniPlatform`. Platform adapters under
|
||||
`vllm_omni/platforms/` are allowed; other files must not add new
|
||||
`torch.cuda.*` helpers (`device_count`, `synchronize`, `empty_cache`,
|
||||
`device()`, `manual_seed`, and similar). `import torch` is fine.
|
||||
|
||||
#### shellcheck
|
||||
|
||||
The hook does **not** download a binary. Install `shellcheck` with a signed
|
||||
package manager, then re-run:
|
||||
|
||||
- Debian/Ubuntu/WSL: `sudo apt-get install shellcheck`
|
||||
- Fedora: `sudo dnf install ShellCheck`
|
||||
- macOS: `brew install shellcheck`
|
||||
- Git Bash (MINGW): `scoop install shellcheck` so `shellcheck.exe` is on PATH.
|
||||
WSL is Linux: use `apt-get`, not a Windows `.exe`.
|
||||
|
||||
If no native binary is found, the wrapper prints those commands (and
|
||||
[the upstream install page](https://github.com/koalaman/shellcheck?tab=readme-ov-file#installing))
|
||||
and exits 1. AMD and other vendor scripts are **not** excluded.
|
||||
|
||||
#### mypy
|
||||
|
||||
`mypy-3.10` runs on commit for changed files. `[tool.mypy]` uses Python 3.12,
|
||||
`ignore_missing_imports = true`, and `follow_imports = "silent"`. Wrapper
|
||||
`tools/pre_commit/mypy.py` skips `vllm_omni/model_executor/models/` and
|
||||
`vllm_omni/diffusion/models/`, and type-checks `tests/` with
|
||||
`--follow-imports skip`. Extra versions:
|
||||
|
||||
```bash
|
||||
pre-commit run --hook-stage manual mypy-3.12
|
||||
```
|
||||
|
||||
#### Test CI marks
|
||||
|
||||
`check-test-ci-coverage` requires each collected test module under `tests/` to
|
||||
have at least one CI **level** mark (`core_model`, `advanced_model`,
|
||||
`full_model`, `local_model`, or `slow`) and a **hardware** mark (`cpu`, `cuda`,
|
||||
`H100`, …) or helper (`hardware_test(` / `hardware_marks(`). GitHub Actions
|
||||
skips this hook; local commit does not. See the
|
||||
[test writing guide](./ci/test_writing_guide.md).
|
||||
|
||||
#### TTS adapter ratchet
|
||||
|
||||
`check-tts-adapter-migration` counts `self._tts_model_type` comparisons in
|
||||
`vllm_omni/entrypoints/openai/serving_speech.py`. The count must stay at or
|
||||
below `MAX_MODEL_TYPE_BRANCHES` in
|
||||
[`tools/pre_commit/check_tts_adapter.py`](https://github.com/vllm-project/vllm-omni/blob/main/tools/pre_commit/check_tts_adapter.py).
|
||||
New per-model behavior belongs in
|
||||
`vllm_omni/entrypoints/openai/tts_adapters/`. Removing branches **must** lower
|
||||
the budget in the same change; raising it is a reviewable policy edit.
|
||||
|
||||
#### Markdownlint and Buildkite
|
||||
|
||||
`markdownlint-cli2` auto-fixes `docs/`, `recipes/`, and the root README /
|
||||
CONTRIBUTING (rules in `.markdownlint.yaml`). Skill files under `.claude/` and
|
||||
`.cursor/` are excluded.
|
||||
|
||||
`check-buildkite` validates `.buildkite/*.yml` against the official schema
|
||||
after the same expansion `upload_pipeline.py` uses. Omni-only keys such as
|
||||
`mirror_hardwares` are stripped or rendered first. A few files are skipped in
|
||||
`SKIP_FILES` inside `tools/pre_commit/check_buildkite.py`.
|
||||
|
||||
#### Extending allowlists and budgets
|
||||
|
||||
Prefer fixing the call site. Growing an allowlist or raising a budget is a
|
||||
policy change and needs review — do not edit these just to make the hook pass.
|
||||
|
||||
| Gate | File | What to edit |
|
||||
| ---- | ---- | ------------ |
|
||||
| pickle, `re`, `base64`, Hugging Face Hub, Triton/TileLang | [`tools/pre_commit/check_forbidden_imports.py`](https://github.com/vllm-project/vllm-omni/blob/main/tools/pre_commit/check_forbidden_imports.py) | `CHECK_IMPORTS[<rule>].allowed_files`. Use `allowed_dirs` only when a whole tree should stay exempt. |
|
||||
| `torch.cuda` | [`tools/pre_commit/check_torch_cuda.py`](https://github.com/vllm-project/vllm-omni/blob/main/tools/pre_commit/check_torch_cuda.py) | `ALLOWED_FILES`, or `ALLOWED_PREFIXES` for a platform adapter tree. |
|
||||
| TTS `_tts_model_type` branches | [`tools/pre_commit/check_tts_adapter.py`](https://github.com/vllm-project/vllm-omni/blob/main/tools/pre_commit/check_tts_adapter.py) | `MAX_MODEL_TYPE_BRANCHES` (down only, unless the PR justifies a raise). |
|
||||
| Buildkite skip list | [`tools/pre_commit/check_buildkite.py`](https://github.com/vllm-project/vllm-omni/blob/main/tools/pre_commit/check_buildkite.py) | `SKIP_FILES` for pipelines that cannot be expanded. |
|
||||
|
||||
To skip one hook for a single commit (discouraged): `SKIP=<hook-id> git commit`.
|
||||
To bypass every hook: `git commit --no-verify` (also discouraged).
|
||||
|
||||
### Documentation
|
||||
|
||||
MkDocs is a fast, simple and downright gorgeous static site generator that's geared towards building project documentation. Documentation source files are written in Markdown, and configured with a single YAML configuration file, `mkdocs.yml`.
|
||||
@@ -76,12 +219,53 @@ Please refer to the [test instructions](./ci/test_execution_guide.md) for detail
|
||||
!!! warning
|
||||
Currently, not all unit tests pass when run on CPU platforms. If you don't have access to a GPU platform to run unit tests locally, rely on the continuous integration system to run the tests for now.
|
||||
|
||||
### Using repository skills with coding agents
|
||||
|
||||
vLLM-Omni maintains [repository-scale skills](https://github.com/vllm-project/vllm-omni/tree/main/.claude/skills) for common coding, testing, performance, and review workflows. These skills capture repository-specific structure, validation requirements, and evidence standards that a general coding agent may not know.
|
||||
|
||||
If your coding agent discovers repository skills automatically, ask it to use the relevant skill by name. Otherwise, point it to the linked `SKILL.md` and ask it to read the file before changing code. Skills can be combined: use a domain skill for the implementation, `vllm-omni-test` for test and CI decisions, and `precheck-pr` before opening the pull request.
|
||||
|
||||
| Task | Repository skill |
|
||||
| --- | --- |
|
||||
| Add or extend a diffusion model | [`add-diffusion-model`](https://github.com/vllm-project/vllm-omni/blob/main/.claude/skills/add-diffusion-model/SKILL.md) |
|
||||
| Add or extend a text-to-speech model | [`add-tts-model`](https://github.com/vllm-project/vllm-omni/blob/main/.claude/skills/add-tts-model/SKILL.md) |
|
||||
| Add, select, or debug quantization | [`quantization`](https://github.com/vllm-project/vllm-omni/blob/main/.claude/skills/quantization/SKILL.md) |
|
||||
| Diagnose or optimize diffusion performance | [`diffusion-perf-opt`](https://github.com/vllm-project/vllm-omni/blob/main/.claude/skills/diffusion-perf-opt/SKILL.md) |
|
||||
| Upgrade an NPU model runner | [`vllm-omni-npu-model-runner-upgrade`](https://github.com/vllm-project/vllm-omni/blob/main/.claude/skills/vllm-omni-npu-upgrade/SKILL.md) |
|
||||
| Add a regression test, choose L1-L4 coverage, or wire Buildkite | [`vllm-omni-test`](https://github.com/vllm-project/vllm-omni/blob/main/.claude/skills/vllm-omni-test/SKILL.md) |
|
||||
| Self-check a branch before opening a pull request | [`precheck-pr`](https://github.com/vllm-project/vllm-omni/blob/main/.claude/skills/precheck-pr/SKILL.md) |
|
||||
| Perform a maintainer or reviewer review of an existing pull request or local branch | [`review-pr`](https://github.com/vllm-project/vllm-omni/blob/main/.claude/skills/review-pr/SKILL.md) |
|
||||
|
||||
Use the following workflow when collaborating with a coding agent:
|
||||
|
||||
1. **Ground the task.** Provide the issue, RFC, or design document that defines the expected behavior. Ask the agent to state its assumptions and identify the affected module or feature contracts before editing code.
|
||||
2. **Select the narrowest applicable skills.** Start with the domain skill that owns the change. Add `vllm-omni-test` whenever production behavior or tests change. For a bug fix, ask for the smallest reproducer and a regression test tied to the original symptom.
|
||||
3. **Require executable evidence.** Ask the agent to run the narrowest relevant checks and report the exact commands and results. It must identify tests it could not run because of unavailable hardware, model weights, credentials, or dependencies; an unrun check is not a pass.
|
||||
4. **Inspect the resulting diff.** Confirm that the implementation stays within the issue or RFC, does not overwrite unrelated work, and includes the required tests, documentation, and benchmark or accuracy evidence.
|
||||
5. **Run the pre-submit workflow.** Use `precheck-pr`, then run the applicable local tests and pre-commit hooks before opening the pull request.
|
||||
|
||||
For example:
|
||||
|
||||
```text
|
||||
Use add-diffusion-model and vllm-omni-test to implement the linked issue.
|
||||
Read the relevant design documents first, keep the change within the issue,
|
||||
and report every test command, result, and hardware validation gap.
|
||||
```
|
||||
|
||||
```text
|
||||
Use vllm-omni-test to turn this bug reproducer into the smallest deterministic
|
||||
regression test. Prefer L1 CPU coverage; if the failure requires real weights
|
||||
or serving, explain the required L2/L3 environment and provide the exact command.
|
||||
```
|
||||
|
||||
Repository skills guide the agent, but they do not replace contributor judgment, the accepted issue or RFC, required test evidence, or maintainer review. Review all generated changes before submitting them.
|
||||
|
||||
## Issues
|
||||
|
||||
If you encounter a bug or have a feature request, please search existing issues first to see if it has already been reported. If not, please file a new issue, providing as much relevant information as possible.
|
||||
|
||||
!!! important
|
||||
If you discover a security vulnerability, please report it by creating a GitHub issue with the `security` label.
|
||||
Do not report suspected security vulnerabilities through a public issue, pull request, discussion, or Slack channel. Follow the [security disclosure instructions](../community/contact_us.md#security-disclosures) to arrange a private report.
|
||||
|
||||
## Pull Requests & Code Reviews
|
||||
|
||||
@@ -121,12 +305,14 @@ Only specific types of PRs will be reviewed. The PR title is prefixed appropriat
|
||||
Before submitting a PR, run the [precheck-pr skill](https://github.com/vllm-project/vllm-omni/blob/main/.claude/skills/precheck-pr/SKILL.md) with the code agent for a self-review against project conventions:
|
||||
|
||||
The skill offers two modes:
|
||||
|
||||
- **Quick (~3 min):** catches showstoppers — PR title format, missing benchmark claims, rebase status
|
||||
- **Full (~10 min):** thorough maintainer-grade review — dead code scan, copy-paste detection, import hygiene
|
||||
|
||||
The precheck covers five PR types: Bug Fix, Performance, New Model, Diffusion Model, and General. Each type has a tailored checklist that validates evidence quality (repro steps, A/B benchmarks, registry entries, etc.). See the [precheck-pr skill](https://github.com/vllm-project/vllm-omni/blob/main/.claude/skills/precheck-pr/SKILL.md) for the full checklist.
|
||||
|
||||
### Local Test
|
||||
|
||||
Please run the L1 and L2 test cases locally first and attach the results before contacting us to add the "ready" label. Please refer to the [test instructions](./ci/test_execution_guide.md) for running the test cases.
|
||||
|
||||
### Automatic skip-ci (docs and pytest skip marks)
|
||||
@@ -148,7 +334,7 @@ These PR shapes all trigger skip-ci:
|
||||
Skip-ci does **not** apply when the diff also touches product code (for example `vllm_omni/`), or when test files change assertions, imports, fixtures, or other non-skip logic. If the diff cannot be resolved (non-PR branches outside `main`), CI runs as usual.
|
||||
|
||||
!!! note
|
||||
Skipping L2/L3 does **not** disable the Docker image build step. Nightly (L4) upload can still run when the PR has a `nightly-test` label or on scheduled `main` builds with `NIGHTLY=1`. Bootstrap child steps live in `bootstrap-upload-steps.yml`; the hook entry step runs `upload_pipeline.py --upload <platform>/bootstrap-upload-steps.yml`, which injects `if` by step `key` from skip-ci before upload. See [CI Settings — Diff-aware CI](./ci/ci_settings.md#diff-aware-ci) and [Test System Overview](./ci/test_system_overview.md).
|
||||
Skipping L2/L3 does **not** disable the Docker image build step. Nightly (L4) upload can still run when the PR has a `nightly-test` label or on scheduled `main` builds with `NIGHTLY=1`. Weekly (L5) upload can still run with `weekly-test`, `WEEKLY=1`, or `NON_CRITICAL=1`. Bootstrap child steps live in `bootstrap-upload-steps.yml`; the hook entry step runs `upload_pipeline.py --upload <platform>/bootstrap-upload-steps.yml`, which injects `if` by step `key` from skip-ci before upload. See [CI Settings — Diff-aware CI](./ci/ci_settings.md#diff-aware-ci) and [Test System Overview](./ci/test_system_overview.md).
|
||||
|
||||
### Code Quality
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ For CI levels (L1–L5) and triggers, see [Test System Overview](./test_system_o
|
||||
|
||||
Canonical layout (prefer these paths for new changes):
|
||||
|
||||
```
|
||||
```text
|
||||
.buildkite/
|
||||
├── common/ # Shared across platforms
|
||||
│ ├── scripts/
|
||||
@@ -48,7 +48,7 @@ Canonical layout (prefer these paths for new changes):
|
||||
└── scripts/
|
||||
```
|
||||
|
||||
**Placement rules**
|
||||
### Placement rules
|
||||
|
||||
| Rule | Detail |
|
||||
| ---- | ------ |
|
||||
@@ -81,7 +81,14 @@ There are still **legacy copies** at `.buildkite/*.yaml` (without the `cuda/` pr
|
||||
| L2 | `cuda/test-ready.yml` | `ready` label |
|
||||
| L3 | `cuda/test-merge.yml` | `merge-test` label / main merge |
|
||||
| L4 | `cuda/test-nightly.yml` | `nightly-test` label or `NIGHTLY=1` |
|
||||
| L5 | `cuda/test-weekly.yml` | `weekly-test` label or `WEEKLY=1` |
|
||||
| L5 | `cuda/test-weekly.yml` | `weekly-test` label, `WEEKLY=1`, or `NON_CRITICAL=1` (see step `if`s below) |
|
||||
|
||||
On scheduled `main` builds, `test-weekly.yml` is uploaded when **`WEEKLY=1` or `NON_CRITICAL=1`**. Inside that file:
|
||||
|
||||
- **Reliability** / **Perf Test** / **Simple · CPU Coverage Test** → `WEEKLY=1` (or PR label `weekly-test` for Reliability/Perf). Pipeline upload for scheduled env vars still requires `main`.
|
||||
- **E2E Tests** group (slow Omni/TTS/Diffusion sweeps) → `NON_CRITICAL=1`
|
||||
|
||||
**`--e2e`:** when uploading ready/merge on `main` with **`WEEKLY=1`**, bootstrap passes `--e2e` so only the **E2E Test** group is kept (same flag `run_cov_split.sh` uses to enable per-model coverage).
|
||||
|
||||
**Upload:** `upload_pipeline.py --upload` expands uploader-only keys before Buildkite upload.
|
||||
|
||||
@@ -112,6 +119,8 @@ There are still **legacy copies** at `.buildkite/*.yaml` (without the `cuda/` pr
|
||||
|
||||
**Test YAML:** `npu/test-npu-ready.yml` (L2), `test-npu-nightly.yml` (L4).
|
||||
|
||||
**L2 trigger:** PR label `ready` (CUDA/AMD L2). PR labels `ready` + `npu-test` trigger NPU CI only.
|
||||
|
||||
**Upload:** same as CUDA—`upload_pipeline.py --upload`.
|
||||
|
||||
**Hardware in YAML:** `mirror_hardwares` preset (string), expanded to `agents`, top-level `image`, and `plugins`. Presets: `a2b3_npu_1`, `a2b3_npu_4`, `a3_npu_2` in `common/ci_mirror_hardwares.yml`.
|
||||
@@ -204,15 +213,15 @@ Label triggers (`ready`, `merge-test`) are unchanged—diff-aware logic only red
|
||||
| Diff shape | Path | Default L2/L3 |
|
||||
| --- | --- | --- |
|
||||
| Product code / non-whitelisted paths | normal CI | all on |
|
||||
| Docs and/or qualifying skip-mark only | `skip_all` | all off (scheduled `main` NIGHTLY/WEEKLY exceptions below) |
|
||||
| Docs and/or qualifying skip-mark only | `skip_all` | all off (scheduled `main` NIGHTLY/WEEKLY/`NON_CRITICAL` exceptions below) |
|
||||
| Whitelisted CI YAML only | yaml-gated (`skip_l2_l3`) | per platform/level matrix |
|
||||
| Docs/skip-mark **+** whitelisted CI YAML | yaml-gated (`skip_l2_l3`) | same as CI-YAML-only (does **not** widen to normal CI) |
|
||||
| Non-qualifying skip-mark and no CI YAML | normal CI | all on |
|
||||
| Diff unavailable | normal CI | all on |
|
||||
|
||||
**`skip_all` exceptions (CUDA/NPU bootstrap only):** PR labels (`nightly-test`, `merge-test`, `npu-test`, `weekly-test`, …) do **not** revive jobs. On `main`, scheduled `NIGHTLY=1` still builds the image and uploads L4 plus L2/L3 (with `--e2e`); `WEEKLY=1` still builds the image and uploads L5 (CUDA).
|
||||
**`skip_all` exceptions (CUDA/NPU bootstrap only):** PR labels (`nightly-test`, `merge-test`, `weekly-test`, `ready`, …) do **not** revive jobs under `skip_all`. On `main`, scheduled `NIGHTLY=1` still builds the image and uploads L4; `WEEKLY=1` or `NON_CRITICAL=1` still builds the image and uploads L5 (CUDA). `WEEKLY=1` on `main` also uploads L2/L3 with `--e2e`.
|
||||
|
||||
**Yaml-gated nightly/weekly:** L4/L5 upload steps keep their normal label / `NIGHTLY` / `WEEKLY` conditions (for example PR `nightly-test` still uploads nightly). Only L2/L3 upload steps are matrix-gated.
|
||||
**Yaml-gated nightly/weekly:** L4/L5 upload steps keep their normal label / `NIGHTLY` / `WEEKLY` / `NON_CRITICAL` conditions (for example PR `nightly-test` still uploads nightly). Only L2/L3 upload steps are matrix-gated.
|
||||
|
||||
##### Whitelisted CI YAML → platform
|
||||
|
||||
@@ -285,12 +294,12 @@ CUDA **L2** (`.buildkite/cuda/test-ready.yml`) and **L3** (`.buildkite/cuda/test
|
||||
| `source_file_dependencies` | List of path **prefixes**. If any changed file equals a prefix or starts with `prefix/`, keep the step (or group); otherwise omit it. |
|
||||
| `mirror_hardwares` | Expand to `agents` + `plugins` (+ optional `image`) from `ci_mirror_hardwares.yml`. |
|
||||
|
||||
**Policy**
|
||||
### Policy
|
||||
|
||||
- **Always uploaded** (no key): groups outside **E2E Test**—Simple Test, Diffusion unit tests, Engine/Model Executor, Distributed, Custom Pipeline, Entrypoints (L2), LoRA / Entrypoints (L3).
|
||||
- **Diff-gated**: every **E2E Test** leaf job. List the smallest prefix set per step—pytest file(s), model code under `vllm_omni/model_executor/models/` or `vllm_omni/diffusion/models/`, plus `stage_input_processors/` and `vllm_omni/deploy/*.yaml` when applicable. A **group** may define the key instead; the whole group drops if no prefix matches.
|
||||
|
||||
**YAML examples**
|
||||
### YAML examples
|
||||
|
||||
```yaml
|
||||
- label: "Diffusion · Qwen Image Test"
|
||||
@@ -312,7 +321,7 @@ CUDA **L2** (`.buildkite/cuda/test-ready.yml`) and **L3** (`.buildkite/cuda/test
|
||||
mirror_hardwares: l4_4
|
||||
```
|
||||
|
||||
**Local dry-run**
|
||||
### Local dry-run
|
||||
|
||||
```bash
|
||||
python3 .buildkite/common/scripts/upload_pipeline.py .buildkite/cuda/test-ready.yml
|
||||
@@ -324,15 +333,109 @@ On PR builds, `upload_pipeline.py` logs `skip '…' (no changes under …)` for
|
||||
|
||||
### Labels and grouping
|
||||
|
||||
- Use **groups** for dashboard readability; keep **E2E Test** as the group name CUDA diff filtering expects for `--e2e` nightly runs on main.
|
||||
- Use **groups** for dashboard readability; keep **E2E Test** as the group name CUDA diff filtering expects for `--e2e` weekly runs on main (`WEEKLY=1`).
|
||||
- Prefix labels by model domain: **Omni ·**, **TTS ·**, **Diffusion ·**, **Simple ·**, etc., matching existing steps.
|
||||
|
||||
### Per-model coverage
|
||||
|
||||
Pilot (v1): one Merge-tier (L3) job in `.buildkite/cuda/test-merge.yml` uploads
|
||||
per-model, per-entry-mode coverage as Buildkite artifacts — "TTS · Qwen3-TTS Base
|
||||
Test". Coverage + artifact upload run only when bootstrap uploaded that job with
|
||||
`--e2e` (`WEEKLY=1` and `BUILDKITE_BRANCH=main`, via `run_cov_split.sh`); otherwise
|
||||
the same job runs plain pytest without `--cov`. It runs on a single GPU so the
|
||||
pilot is cheap to reproduce.
|
||||
|
||||
**L1 package coverage (CPU):** ready/merge Simple Test jobs run without `--cov`. Scheduled weekly on `main` with `WEEKLY=1` runs **Simple · CPU Coverage Test** in `.buildkite/cuda/test-weekly.yml` (`pytest -m 'core_model and cpu'` + Cobertura XML artifact).
|
||||
|
||||
**Naming convention**: `coverage-<model_id>-<mode>-<step_id>.xml.gz`, where
|
||||
`<model_id>` is the model's directory name under
|
||||
`vllm_omni/diffusion/models/<model_id>/` or
|
||||
`vllm_omni/model_executor/models/<model_id>/` (e.g. `z_image`, `qwen3_omni`),
|
||||
`<mode>` is `online` or `offline`, and `<step_id>` is `BUILDKITE_STEP_ID`
|
||||
(`local` outside Buildkite). `gunzip` before feeding a report to a Cobertura
|
||||
consumer.
|
||||
|
||||
Reports are gzipped because `--cov=vllm_omni` sets coverage's `source`, which
|
||||
makes it walk the package and emit one `<line>` element per statement for every
|
||||
file — including the ones a single model's tests never import. That inventory,
|
||||
not the coverage, is the size: a Bagel report is 7.1 MB, of which 96.5% is
|
||||
`<line>` elements and 77% belongs to the 840 of 1169 files that run never
|
||||
imported. A run covering zero lines produces the same 7 MB. gzip takes it to
|
||||
roughly 410 KB and changes nothing about the data.
|
||||
|
||||
`<step_id>` is what keeps two steps that cover the same model apart. Artifacts are
|
||||
scoped to the build, and a weekly build can carry ready/merge (with `--e2e`) and
|
||||
weekly tiers at once, so several same-model steps land in one namespace — `qwen3_tts` already has
|
||||
both a Base and a CustomVoice job, and `minicpmo_4_5` a base and a duplex one. Two
|
||||
uploads on one path do not fail loudly: an exact-name download can report the path
|
||||
as ambiguous, and a glob download fetches every match concurrently and renames each
|
||||
onto the same destination, so whichever finishes last wins. The step id remains the
|
||||
logical step identifier across retries, while Buildkite's default artifact lookup
|
||||
selects only the latest attempt — `BUILDKITE_JOB_ID` would instead give every
|
||||
attempt its own filename, leaving a failed attempt's partial report to be picked up
|
||||
alongside the real one. A step using `parallelism`/matrix would need
|
||||
`BUILDKITE_PARALLEL_JOB` added, since its jobs share a step id; neither pilot is
|
||||
one.
|
||||
|
||||
**Opting in a new model**: replace the job's combined `pytest` command with
|
||||
[`run_cov_split.sh`](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/common/scripts/run_cov_split.sh),
|
||||
which runs each mode, names the reports, uploads them, and fails the step if
|
||||
either half or the upload failed:
|
||||
|
||||
```yaml
|
||||
commands:
|
||||
- |
|
||||
.buildkite/common/scripts/run_cov_split.sh \
|
||||
--model-id <model_id> \
|
||||
--offline <offline test path> \
|
||||
--online <online test path> \
|
||||
-- <the job's existing pytest flags, e.g. -m '...' --run-level '...'>
|
||||
```
|
||||
|
||||
Everything after `--` is forwarded verbatim to both runs with quoting preserved,
|
||||
so an expression like `-m 'advanced_model and cuda'` survives intact and a job can
|
||||
pass anything else it needs. `--offline`/`--online` are repeatable and only one is
|
||||
required, so a job with tests in a single mode runs just that half. Runtime is
|
||||
bounded solely by the step's `timeout_in_minutes` — raise it, since the split
|
||||
loads the model once per mode.
|
||||
|
||||
Before splitting, confirm each half actually collects at least one test under the job's forwarded filters — pytest exits with code 5 ("no tests collected") if a half is empty, which the script reports as a failure, red-ing a job that used to pass as one combined invocation.
|
||||
|
||||
Also check the tests' `num_cards` against the job's `mirror_hardwares` preset.
|
||||
`cuda_marks` turns `num_cards > 1` into `skipif(device_count() < num_cards)`, so a
|
||||
test asking for more GPUs than the preset provides is silently skipped and its
|
||||
coverage artifact comes back empty. Splitting such a job produces a file that
|
||||
looks fine and measures nothing — "Diffusion · Z Image Test" is the current
|
||||
example (online tests want 4 cards, the job runs on `l4_1`), which is why it is
|
||||
not a coverage pilot.
|
||||
|
||||
Online-mode coverage depends on the `[tool.coverage.run]` `patch`/`sigterm`
|
||||
settings in `pyproject.toml`: online tests launch the server with
|
||||
`subprocess.Popen` and stop it with SIGTERM, and without those settings the XML
|
||||
reflects only the pytest parent process, not the server's code paths.
|
||||
|
||||
The upload depends on `buildkite-agent` being callable inside the container. The
|
||||
`kubernetes` presets (`h100_*`, `*_npu_*`) provide it; the `docker` ones (`l4_*`)
|
||||
only do because they set `mount-buildkite-agent: true`. A new docker preset that
|
||||
runs a coverage job needs the same.
|
||||
|
||||
List both `run_cov_split.sh` and `pyproject.toml` in every opted-in job's
|
||||
`source_file_dependencies` — both change what the job measures, so without them a
|
||||
change there is filtered out of normal PR builds and only surfaces in a later
|
||||
nightly. `tests/buildkite/test_upload_pipeline.py` covers the filter behavior with
|
||||
a synthetic job (it does not pin real merge labels).
|
||||
Editing only the surrounding CI YAML still does not schedule them, so a PR that
|
||||
touches just the wiring needs a full E2E run (or the commands run on a GPU host)
|
||||
to produce artifacts. When checking a new model's
|
||||
artifacts, compare `lines-covered` between the online and offline XML rather than
|
||||
just confirming both files exist.
|
||||
|
||||
### Validation checklist
|
||||
|
||||
| Check | Command / location |
|
||||
| ----- | ------------------ |
|
||||
| CUDA render | `python3 .buildkite/common/scripts/upload_pipeline.py .buildkite/cuda/test-<level>.yml` |
|
||||
| No leaked uploader keys | `… \| grep -E 'mirror_hardwares|source_file_dependencies'` → empty |
|
||||
| No leaked uploader keys | Pipe the render into `grep -E 'mirror_hardwares\|source_file_dependencies'` — expect empty |
|
||||
| Skip-ci / upload unit tests | `pytest tests/buildkite/` |
|
||||
| Local job replay (CUDA L2+) | `tools/run_ready_jobs.sh`, `tools/run_merge_jobs.sh`, `tools/nightly/run_nightly_jobs.sh` (read YAML from `cuda/`) |
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ When you open a PR against vLLM-Omni, several CI checks run automatically:
|
||||
|
||||
| Check | Platform | What it does |
|
||||
| ----- | -------- | ------------ |
|
||||
| **pre-commit** | GitHub Actions | Runs linting (Ruff), formatting, spell-checking (typos), and YAML validation. |
|
||||
| **pre-commit** | GitHub Actions | Runs Ruff, formatting, typos, YAML validation, forbidden imports, `torch.cuda`, TTS adapter ratchet, and Buildkite schema. Local-only gates (SPDX, shellcheck, markdownlint, mypy-3.10, test marks) are in the workflow `SKIP` env — see [Linting](../README.md#linting). |
|
||||
| **Build Wheel** | GitHub Actions | Builds Python wheels for Python 3.11 and 3.12 on Ubuntu. Skipped for docs-only or Markdown-only changes (controlled by `paths-ignore` in the workflow). |
|
||||
| **DCO** | GitHub | Verifies every commit has a `Signed-off-by` line. |
|
||||
| **docs/readthedocs.org:vllm-omni** | Read the Docs | Builds the MkDocs documentation site. |
|
||||
@@ -29,6 +29,13 @@ pre-commit run --all-files
|
||||
|
||||
Then commit the fixes and push.
|
||||
|
||||
A green GitHub pre-commit job can still miss SPDX, shellcheck, mypy-3.10,
|
||||
markdownlint, and test-mark coverage because CI skips those IDs. If your
|
||||
**local** commit hook fails, follow [Linting](../README.md#linting) for the
|
||||
full hook list (forbidden imports, `torch.cuda`, TTS adapter ratchet, and
|
||||
Buildkite schema still run in GHA). Do not grow allowlists or raise
|
||||
`MAX_MODEL_TYPE_BRANCHES` without review.
|
||||
|
||||
### DCO failures
|
||||
|
||||
Every commit must include a `Signed-off-by` line. If you forgot, amend your commits:
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
When you want to add L4-level ***performance test*** cases, add entries to JSON files under `tests/dfx/perf/tests/` and run them via `tests/dfx/perf/scripts/run_benchmark.py` (omni / TTS) or `run_diffusion_benchmark.py` (diffusion).
|
||||
|
||||
**Config file layout (in-tree examples)**
|
||||
#### Config file layout (in-tree examples)
|
||||
|
||||
| Model type | Runner | Example JSON files |
|
||||
| ---------- | ------ | ------------------ |
|
||||
| Omni | `run_benchmark.py` | `test_qwen3_omni_no_async_chunk.json`, `test_qwen3_omni_async_chunk.json`, `test_qwen3_omni_vllm_text.json`, `test_qwen3_omni_multi_replicas.json` |
|
||||
| Omni (nightly) | `run_benchmark.py` | `test_qwen3_omni_no_async_chunk.json`, `test_qwen3_omni_async_chunk.json` (`full_model` in `mark`) |
|
||||
| Omni (weekly) | `run_benchmark.py` | `test_qwen3_omni_vllm_text.json`, `test_qwen3_omni_multi_replicas.json` (`slow` in `mark`; **Perf Test** in `test-weekly.yml`) |
|
||||
| TTS | `run_benchmark.py` | `test_tts.json`, `test_voxcpm2.json`, `test_higgs_audio_v3.json` |
|
||||
| Diffusion | `run_diffusion_benchmark.py` | `test_qwen_image_vllm_omni.json`, `test_bagel_vllm_omni.json`, `test_wan22_i2v_vllm_omni.json`, `test_cosmos3_vllm_omni.json`, … |
|
||||
|
||||
**How runners pick cases**
|
||||
#### How runners pick cases
|
||||
|
||||
Without **`--test-config-file`**, each runner scans all `*.json` under `tests/dfx/perf/tests/` but only keeps its own model type:
|
||||
|
||||
@@ -17,9 +18,9 @@ Without **`--test-config-file`**, each runner scans all `*.json` under `tests/df
|
||||
|
||||
Diffusion cases are detected when the JSON has `server_type` (typically `"vllm-omni"`) or `"diffusion"` in the `mark` array. Omni / TTS JSON has neither.
|
||||
|
||||
**Running perf cases**
|
||||
#### Running perf cases
|
||||
|
||||
Pass **`--test-config-file`** to run one JSON file as-is, or omit it for the bulk scan above and filter with pytest **`-m`** on each case's JSON `mark` (for example `pytest … run_benchmark.py -m "full_model and tts and H100"`).
|
||||
Pass **`--test-config-file`** to run one JSON file as-is, or omit it for the bulk scan above and filter with pytest **`-m`** on each case's JSON `mark` (for example `pytest … run_benchmark.py -m "full_model and tts and H100"` or `-m "slow and omni and H100"` for weekly Omni configs).
|
||||
|
||||
```JSON
|
||||
{
|
||||
@@ -31,7 +32,7 @@ Pass **`--test-config-file`** to run one JSON file as-is, or omit it for the bul
|
||||
],
|
||||
"server_params": {
|
||||
"model": "Qwen/Qwen3-Omni-30B-A3B-Instruct",
|
||||
"stage_config_name": "qwen3_omni.yaml"
|
||||
"stage_config_name": "qwen3_omni_moe.yaml"
|
||||
},
|
||||
"benchmark_params": [
|
||||
{
|
||||
@@ -55,20 +56,22 @@ Pass **`--test-config-file`** to run one JSON file as-is, or omit it for the bul
|
||||
}
|
||||
```
|
||||
|
||||
**Parameter Explanation**
|
||||
#### Parameter Explanation
|
||||
|
||||
*Overview*
|
||||
##### Overview
|
||||
|
||||
| Field | Required | Description |
|
||||
| ---------------- | -------- | --------------------------------------------------------------- |
|
||||
| test_name | Yes | Unique identifier for the test case |
|
||||
| mark | No | Pytest marks for this case (see **`mark` field** below). Omit only for configs not meant to be filtered by `-m`. |
|
||||
| server_params | Yes | Server-side configuration parameters |
|
||||
| benchmark_params | Yes | Benchmark running parameters (supports multiple configurations) |
|
||||
| server_type | Diffusion only | When set (e.g. `"vllm-omni"`), routes the case to `run_diffusion_benchmark.py`. |
|
||||
| benchmark_endpoint | Diffusion only | API path for the benchmark client (e.g. `/v1/videos`, `/v1/images/generations`). |
|
||||
| Field | Required | Description |
|
||||
| ------------------ | -------------- | -------------------------------------------- |
|
||||
| test_name | Yes | Unique identifier for the test case |
|
||||
| mark | No | Pytest marks; see **`mark` field** below |
|
||||
| server_params | Yes | Server-side configuration parameters |
|
||||
| benchmark_params | Yes | Benchmark running parameters |
|
||||
| server_type | Diffusion only | Routes case to run_diffusion_benchmark.py |
|
||||
| benchmark_endpoint | Diffusion only | Benchmark API path |
|
||||
|
||||
**`mark` field**
|
||||
Omit `mark` only for configs not meant to be filtered by `-m`. `server_type` is typically `"vllm-omni"`. `benchmark_endpoint` examples: `/v1/videos`, `/v1/images/generations`.
|
||||
|
||||
#### `mark` field
|
||||
|
||||
Optional top-level field on each perf JSON **case object** (one per `test_name`). `run_benchmark.py` and `run_diffusion_benchmark.py` read it via `tests.dfx.conftest.resolve_pytest_marks` and attach the marks to the corresponding `pytest.param`, so you can filter locally with `-m`.
|
||||
|
||||
@@ -119,11 +122,11 @@ Multi-GPU diffusion (example: Cosmos3 with `cfg-parallel-size=2`):
|
||||
- Diffusion perf: include `"diffusion"` in the `mark` array
|
||||
- HunyuanImage local-weight cases: add `"local_model"` to the `mark` array
|
||||
|
||||
**Parametrization IDs**
|
||||
#### Parametrization IDs
|
||||
|
||||
Each `(server, benchmark index)` pair becomes one `pytest.param` with id `{test_name}-{suffix}`. The suffix comes from `benchmark_params[].name` when set (for example `test_tts-p0`, `test_omni-p1`); otherwise it is derived from fields like `task` / `eval_phase`.
|
||||
|
||||
**Benchmark result filenames**
|
||||
#### Benchmark result filenames
|
||||
|
||||
Result files use the **runtime** hardware label from `get_runtime_resource_label()` (detected GPU/NPU name on the machine that ran the job), **not** `mark.hardware_marks.res`. On the default H100 CI pool, `H100` is **omitted** from filenames (`resource_label_for_filename`).
|
||||
|
||||
@@ -132,7 +135,7 @@ Examples:
|
||||
- Omni/TTS: `result_{test_name}_{optional_hw}_{dataset}_....json` under `BENCHMARK_DIR`
|
||||
- Diffusion: one aggregate `diffusion_result_{config_stem}_{optional_hw}_{timestamp}.json` per source JSON file (array of all runs from that file)
|
||||
|
||||
**Local commands**
|
||||
#### Local commands
|
||||
|
||||
```bash
|
||||
# Bulk load + filter by JSON mark
|
||||
@@ -146,18 +149,19 @@ pytest -s -v tests/dfx/perf/scripts/run_benchmark.py \
|
||||
--test-config-file tests/dfx/perf/tests/test_qwen3_omni_async_chunk.json
|
||||
```
|
||||
|
||||
<!-- markdownlint-disable-next-line MD051 -->
|
||||
See also [Markers for Tests](#markers-for-tests) for registered hardware markers (`H100`, `L4`, `cuda`, `distributed_cuda`, …).
|
||||
|
||||
**`server_params` Configuration**
|
||||
#### `server_params` Configuration
|
||||
|
||||
*Basic Parameters*
|
||||
##### Basic Parameters
|
||||
|
||||
| Parameter | Required | Example | Description |
|
||||
| ----------------- | -------- | ---------------------------------- | ----------------------------- |
|
||||
| model | Yes | "Qwen/Qwen3-Omni-30B-A3B-Instruct" | Model name or path |
|
||||
| stage_config_name | Yes | "qwen3_omni.yaml" | Stage configuration file name |
|
||||
| Parameter | Required | Example | Description |
|
||||
| ----------------- | -------- | ------------------------- | ------------------------------ |
|
||||
| model | Yes | Qwen/Qwen3-Omni-30B-A3B… | Model name or path |
|
||||
| stage_config_name | Yes | qwen3_omni_moe.yaml | Deploy configuration file name |
|
||||
|
||||
*Dynamic Configuration (update/delete)*
|
||||
##### Dynamic Configuration (update/delete)
|
||||
|
||||
Supports incremental modifications based on the basic configuration:
|
||||
|
||||
@@ -166,38 +170,40 @@ Supports incremental modifications based on the basic configuration:
|
||||
| update | Update or add configuration items |
|
||||
| delete | Delete specified configuration items |
|
||||
|
||||
**Example**:
|
||||
##### Example
|
||||
|
||||
```
|
||||
```json
|
||||
"update": {
|
||||
"async_chunk": true, // Enable asynchronous chunk processing
|
||||
"stage_args": {
|
||||
"stages": {
|
||||
"0": {
|
||||
"engine_args.custom_process_next_stage_input_func": "vllm_omni.model_executor.stage_input_processors.qwen3_omni.thinker2talker_async_chunk"
|
||||
"max_num_seqs": 64
|
||||
}
|
||||
}
|
||||
},
|
||||
"delete": {
|
||||
"stage_args": {
|
||||
"2": ["custom_process_input_func"] // Delete this configuration for stage 2
|
||||
"stages": {
|
||||
"2": ["max_num_batched_tokens"] // Delete this deploy override for stage 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**`benchmark_params` Configuration**
|
||||
#### `benchmark_params` Configuration
|
||||
|
||||
You can add any benchmark running parameters you need here. For all optional parameters, refer to the [benchmark documentation](https://github.com/vllm-project/vllm-omni/blob/main/docs/cli/bench/serve.md). General modifications are as follows:
|
||||
|
||||
1. Change the --xxx-xx-xx running parameters to xxx_xx_xx format and fill them as keys in the JSON file.
|
||||
2. For boolean variables in the running parameters, modify them to forms such as ignore_eos: true/false and fill them into the JSON file.
|
||||
3. Optionally add a `baseline` object (see **Baseline thresholds** below). If you omit `baseline` or leave it empty, the performance test still runs but does not assert metric thresholds from this field.
|
||||
4. Set `"name"` on each `benchmark_params` entry for stable pytest ids and readable result keys.
|
||||
5. The qps and concurrency modes are recommended to be mutually exclusive. For detailed explanations, see the table below:
|
||||
1. Change the --xxx-xx-xx running parameters to xxx_xx_xx format and fill them as keys in the JSON file.
|
||||
2. For boolean variables in the running parameters, modify them to forms such as ignore_eos: true/false and fill them into the JSON file.
|
||||
3. Optionally add a `baseline` object (see **Baseline thresholds** below). If you omit `baseline` or leave it empty, the performance test still runs but does not assert metric thresholds from this field.
|
||||
4. Set `"name"` on each `benchmark_params` entry for stable pytest ids and readable result keys.
|
||||
5. The qps and concurrency modes are recommended to be mutually exclusive. For detailed explanations, see the table below:
|
||||
|
||||
| Parameter | Type | Required | Example/Values | Description |
|
||||
| --------------- | ----------- | -------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| name | string | No | `"1024x1024_steps4"` | Stable suffix for pytest param id and logs. |
|
||||
| num_prompts | int / array | Yes | 10,[10, 20, 30] | Number of requests. Supports single values or arrays. If a single value is used, it will be automatically expanded to match the number of qps or max_concurrency, e.g., [10,10,10]. If an array is used, its length must match the number of qps or max_concurrency. |
|
||||
| request_rate | float / array | No | 0.5, [0.5, 1, inf] | Queries per second. Supports single values or arrays. If a single value is used, it will be automatically expanded to match the number of num_prompts, e.g., [1,1,1]. If an array is used, its length must match the number of num_prompts. |
|
||||
| max_concurrency | int / array | No | 1, [1, 2, 3] | Maximum concurrent in-flight requests. Same array / expansion rules as `request_rate` (mutually exclusive with QPS mode). |
|
||||
| baseline | object | No | see below | Optional thresholds. **Hardware-nested only**: top-level keys must be `[hardware-resource]` pytest markers from `pyproject.toml` (`get_hardware_mark_list()`). Under each hardware key, metric names are free-form; values are scalars or sweep-aligned lists. Example: `{"H100": {"throughput_qps": […], "custom_stage_ms": 1.0}, "A3": {…}}`. Runtime filename aliases (`_RUNTIME_DEVICE_ALIASES`) are separate and do not expand this allowlist. |
|
||||
| Parameter | Type | Required | Example/Values | Description |
|
||||
| --------------- | ------------- | -------- | -------------------- | ------------------------------------ |
|
||||
| name | string | No | `"1024x1024_steps4"` | Stable suffix for pytest param id |
|
||||
| num_prompts | int / array | Yes | 10, [10, 20, 30] | Number of requests (scalar or sweep) |
|
||||
| request_rate | float / array | No | 0.5, [0.5, 1, inf] | Queries per second (QPS mode) |
|
||||
| max_concurrency | int / array | No | 1, [1, 2, 3] | Max in-flight requests |
|
||||
| baseline | object | No | see below | Optional hardware-nested thresholds |
|
||||
|
||||
`num_prompts`, `request_rate`, and `max_concurrency` accept scalars or arrays; single values expand to match sweep length. QPS and concurrency modes are mutually exclusive. `baseline` top-level keys must be hardware pytest markers from `pyproject.toml`; metric names and values are free-form (scalars or sweep-aligned lists). Omit `baseline` to run without threshold assertions.
|
||||
@@ -1,13 +1,20 @@
|
||||
# Test Execution Guide
|
||||
|
||||
## Setting Up the Test Environment
|
||||
|
||||
### Creating a Container
|
||||
|
||||
vLLM-Omni provides an official Docker image for deployment. These images are built upon vLLM Docker images and are available on [Docker Hub](https://hub.docker.com/r/vllm/vllm-omni/tags). The version of vLLM-Omni indicates which vLLM release it is based on.
|
||||
For a local test environment, you can follow the steps below to create a container:
|
||||
|
||||
## Installing Dependencies
|
||||
|
||||
### vLLM & vLLM-Omni
|
||||
|
||||
vLLM-Omni is built based on vLLM. You can follow [install guide](../../getting_started/installation/README.md) to build your local environment.
|
||||
|
||||
### Test Case Dependencies
|
||||
|
||||
When running test cases, you may need to install the following dependencies:
|
||||
|
||||
```bash
|
||||
@@ -16,6 +23,7 @@ apt-get install -y espeak-ng jq
|
||||
```
|
||||
|
||||
## Running Tests
|
||||
|
||||
Our test scripts use the pytest framework. First, please use `git clone https://github.com/vllm-project/vllm-omni.git` to download the vllm-omni source code. Then, in the root directory of vllm-omni, you can run the following commands in your local test environment to execute the corresponding test cases.
|
||||
|
||||
### CI job runners (L2–L4): logs, timing, and timeouts
|
||||
@@ -25,7 +33,7 @@ Our test scripts use the pytest framework. First, please use `git clone https://
|
||||
**Log layout** (default under `logs/ready_jobs`, `logs/merge_jobs`, or `logs/nightly_jobs`; override with `--log-dir`):
|
||||
|
||||
| Path | Description |
|
||||
|------|-------------|
|
||||
| ------ | ------------- |
|
||||
| `jobs/*.sh` | Generated per-step bash wrappers |
|
||||
| `jobs/.job_timeouts` | Job key → `timeout_in_minutes` from Buildkite YAML (when set) |
|
||||
| `<job_key>.log` | Tee output for each job |
|
||||
@@ -33,7 +41,7 @@ Our test scripts use the pytest framework. First, please use `git clone https://
|
||||
|
||||
**Timing:** while each job runs, stderr prints `finished in …` or `failed after …`. When all jobs finish, a summary is printed and written to `timing_summary.log`, for example:
|
||||
|
||||
```
|
||||
```text
|
||||
=== Job timing summary ===
|
||||
TTS_VoxCPM2_Test 25m 40s OK
|
||||
Omni_Qwen3-Omni_Test 8m 05s TIMED OUT
|
||||
@@ -114,7 +122,6 @@ Failed jobs: 1/2
|
||||
pytest -s -v -m "advanced_model and distributed_cuda and L4" --run-level=advanced_model
|
||||
```
|
||||
|
||||
|
||||
=== "L4 level"
|
||||
|
||||
**Recommended:** run CI-aligned nightly jobs from the repo root via [`tools/nightly/run_nightly_jobs.sh`](https://github.com/vllm-project/vllm-omni/blob/main/tools/nightly/run_nightly_jobs.sh). The script reads [`.buildkite/cuda/test-nightly.yml`](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/cuda/test-nightly.yml), generates per-step bash wrappers, runs pytest (perf jobs first, then aggregates perf JSON into Excel), and tees logs under `logs/nightly_jobs/` (see [CI job runners](#ci-job-runners-l2l4-logs-timing-and-timeouts); `generate_nightly_perf_excel` is included in the timing summary). Requires `bash`, `python3`, and PyYAML (`pip install pyyaml`).
|
||||
@@ -160,7 +167,7 @@ Failed jobs: 1/2
|
||||
pytest -sv tests/dfx/perf/scripts/run_benchmark.py --test-config-file tests/dfx/perf/tests/test_tts.json
|
||||
pytest -sv tests/dfx/perf/scripts/run_diffusion_benchmark.py --test-config-file tests/dfx/perf/tests/test_cosmos3_vllm_omni.json
|
||||
```
|
||||
Nightly **Perf Test** jobs in ``test-nightly.yml`` use ``--test-config-file`` only (no ``-m``). E2e L4 function tests still use ``full_model`` + ``--run-level full_model`` (see [test-nightly.yml](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/test-nightly.yml)). Example:
|
||||
Nightly **Perf Test** jobs in [``test-nightly.yml``](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/cuda/test-nightly.yml) use ``--test-config-file`` only (no ``-m``). Weekly **Perf Test** in [``test-weekly.yml``](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/cuda/test-weekly.yml) runs ``test_qwen3_omni_vllm_text.json`` and ``test_qwen3_omni_multi_replicas.json`` (JSON ``mark`` includes ``slow``). E2e L4 function tests use ``full_model`` + ``--run-level full_model``. Example:
|
||||
|
||||
=== "L5 level"
|
||||
|
||||
@@ -184,14 +191,15 @@ Failed jobs: 1/2
|
||||
# Reliability: HunyuanImage DiT (H100 × 4)
|
||||
pytest -s -v dfx/reliability/test_reliability_hunyuan_image.py -m slow
|
||||
|
||||
# Reliability: VoxCPM2 (L4)
|
||||
pytest -s -v dfx/reliability/test_reliability_voxcpm2.py -m slow
|
||||
|
||||
```
|
||||
|
||||
The latest L5 CI jobs (reliability + invalid-parameter weekly steps) are in [test-weekly.yml](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/cuda/test-weekly.yml).
|
||||
The latest L5 CI jobs are in [test-weekly.yml](https://github.com/vllm-project/vllm-omni/blob/main/.buildkite/cuda/test-weekly.yml):
|
||||
|
||||
- **Reliability** (+ invalid-parameter), **Perf Test** (Omni vLLM Text / Multi-Replica), and **Simple · CPU Coverage Test** → `WEEKLY=1` (or PR label `weekly-test` for Reliability/Perf). Scheduled upload of those env-gated steps still requires `main`.
|
||||
- **E2E Tests** (slow Omni / TTS / Diffusion sweeps) → `NON_CRITICAL=1` (pipeline upload also accepts `WEEKLY=1` / `weekly-test`; the group `if` still needs `NON_CRITICAL`)
|
||||
|
||||
You can find more information about markers in [Test Writing Guide — Markers for Tests](./test_writing_guide.md#markers-for-tests).
|
||||
|
||||
## Adding New Test Cases
|
||||
|
||||
Please refer to the [Test System Overview](./test_system_overview.md) and [Test Writing Guide](./test_writing_guide.md).
|
||||
@@ -12,8 +12,7 @@ Through five levels (L1-L5) and common (Common) specifications, the system clari
|
||||
<th>Level</th>
|
||||
<th>Scope & Focus</th>
|
||||
<th>Model Coverage Strategy</th>
|
||||
<th>Feature Coverage Strategy</th>
|
||||
<th>Interface Coverage Strategy</th>
|
||||
<th>Module Strategy</th>
|
||||
<th>Tags</th>
|
||||
<th>Time Cost</th>
|
||||
<th>Test Dir</th>
|
||||
@@ -31,7 +30,6 @@ Through five levels (L1-L5) and common (Common) specifications, the system clari
|
||||
<td>/</td>
|
||||
<td>/</td>
|
||||
<td>/</td>
|
||||
<td>/</td>
|
||||
<td><a href="https://github.com/vllm-project/vllm-omni/blob/main/.github/PULL_REQUEST_TEMPLATE.md">PR Checklist</a></td>
|
||||
<td>/</td>
|
||||
<td>/</td>
|
||||
@@ -43,7 +41,6 @@ Through five levels (L1-L5) and common (Common) specifications, the system clari
|
||||
<td>/</td>
|
||||
<td>/</td>
|
||||
<td>/</td>
|
||||
<td>/</td>
|
||||
<td><a href="./failures.md">CI Failures</a></td>
|
||||
<td>/</td>
|
||||
<td>/</td>
|
||||
@@ -53,7 +50,6 @@ Through five levels (L1-L5) and common (Common) specifications, the system clari
|
||||
<td>Unit tests for components like entrypoints, models</td>
|
||||
<td>/</td>
|
||||
<td>/</td>
|
||||
<td>/</td>
|
||||
<td><code>core_model and cpu</code></td>
|
||||
<td rowspan="2"><15min</td>
|
||||
<td>
|
||||
@@ -71,9 +67,8 @@ Through five levels (L1-L5) and common (Common) specifications, the system clari
|
||||
<tr>
|
||||
<td><strong>L2</strong><br>(E2E across models & GPU-required UT)</td>
|
||||
<td>Online (basic deployment scenarios):<br>dummy, normal inference function (output format, stream), some instance startup UT</td>
|
||||
<td>High-priority models + online basic scenarios; request success, non-empty output, format match (no Whisper/accuracy)</td>
|
||||
<td>High-priority features and component tests that require launching instances</td>
|
||||
<td>High-priority interfaces (using random lightweight models)</td>
|
||||
<td>Key models + online basic scenarios; request success, non-empty output, format match (no Whisper/accuracy)</td>
|
||||
<td>Key features and modules that require launching instances (prefer random weights)</td>
|
||||
<td><code>core_model and hardware_test(H100, L4, etc.) and omni/tts/diffusion</code></td>
|
||||
<td>
|
||||
<strong>Model E2E:</strong><br>
|
||||
@@ -95,9 +90,8 @@ Through five levels (L1-L5) and common (Common) specifications, the system clari
|
||||
<tr>
|
||||
<td><strong>L3</strong><br>(Important Perf & Integration & Accuracy)</td>
|
||||
<td>Online & Offline (multiple deployment scenarios):<br>real model, normal inference function, normal accuracy</td>
|
||||
<td>High/medium-priority models + key online/offline scenarios; real weights, Whisper/similarity, preset voice gender, basic accuracy</td>
|
||||
<td>Medium-priority features and component tests that require launching instances</td>
|
||||
<td>Medium-priority interfaces (using random lightweight models)</td>
|
||||
<td>Key models + key online/offline scenarios; real weights, Whisper/similarity, preset voice gender, basic accuracy</td>
|
||||
<td>Key features and modules that require launching instances (using real weights)</td>
|
||||
<td><code>advanced_model and hardware_test(H100, L4, etc.) and omni/tts/diffusion</code></td>
|
||||
<td><30min</td>
|
||||
<td>
|
||||
@@ -120,9 +114,8 @@ Through five levels (L1-L5) and common (Common) specifications, the system clari
|
||||
<tr>
|
||||
<td><strong>L4</strong><br>(Perf & Integration & Accuracy)</td>
|
||||
<td>Online: full functional scenarios + performance test + doc test + accuracy test</td>
|
||||
<td>High-priority models: function, performance, accuracy, and doc testing<br>Medium-priority models: function and doc testing</td>
|
||||
<td>Low-priority features and component tests that require launching instances</td>
|
||||
<td>Low-priority interfaces (using real weights)</td>
|
||||
<td>Key models: function, performance, accuracy, and doc testing</td>
|
||||
<td>Other features and modules that require launching instances (using real weights)</td>
|
||||
<td><code>full_model and hardware_test(H100, L4, etc.) and omni/tts/diffusion</code></td>
|
||||
<td><3 hour</td>
|
||||
<td>
|
||||
@@ -147,11 +140,10 @@ Through five levels (L1-L5) and common (Common) specifications, the system clari
|
||||
<td>GPU</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><strong>L5</strong><br>(Stability & Reliability)</td>
|
||||
<td>Online: long-term stability test + reliability test</td>
|
||||
<td>Long-term stability and reliability testing for high-priority models<br>Low-priority models: function and doc testing</td>
|
||||
<td><strong>L5</strong><br>(Stability & Reliability & selected Perf)</td>
|
||||
<td>Online: long-term stability + reliability; coverage test</td>
|
||||
<td>Long-term stability and reliability testing for key models<br>Non-critical scenario performance and accuracy testing for key models<br>Other models: function and doc testing</td>
|
||||
<td>/</td>
|
||||
<td>Invalid-parameter validation for high-priority interfaces</td>
|
||||
<td><code>slow and hardware_test(H100, L4, etc.) and omni/tts/diffusion</code></td>
|
||||
<td> Depends on reality </td>
|
||||
<td>
|
||||
@@ -178,8 +170,8 @@ For per-level test authoring (markers, examples), see [Test Writing Guide](./tes
|
||||
|
||||
Before entering specific testing levels, the project establishes two common specifications aimed at standardizing the development process and quickly locating issues.
|
||||
|
||||
1. ***PR Checklist ([`.github/PULL_REQUEST_TEMPLATE.md`](https://github.com/vllm-project/vllm-omni/blob/main/.github/PULL_REQUEST_TEMPLATE.md))***: This template defines the self-check items that must be completed before submitting a code review (Pull Request). It ensures that each code change meets basic requirements such as code style, dependency updates, and documentation synchronization before entering the automated testing pipeline, serving as the first manual line of defense for quality assurance.
|
||||
2. ***CI Failure Explanation ([CI Failures](./failures.md))***: This document archives and explains common failure patterns in the Continuous Integration (CI) pipeline, error log interpretation, and preliminary troubleshooting steps. It helps developers and testers quickly diagnose the causes of automated test failures, improving problem-solving efficiency.
|
||||
1. ***PR Checklist ([`.github/PULL_REQUEST_TEMPLATE.md`](https://github.com/vllm-project/vllm-omni/blob/main/.github/PULL_REQUEST_TEMPLATE.md))***: This template defines the self-check items that must be completed before submitting a code review (Pull Request). It ensures that each code change meets basic requirements such as code style, dependency updates, and documentation synchronization before entering the automated testing pipeline, serving as the first manual line of defense for quality assurance.
|
||||
2. ***CI Failure Explanation ([CI Failures](./failures.md))***: This document archives and explains common failure patterns in the Continuous Integration (CI) pipeline, error log interpretation, and preliminary troubleshooting steps. It helps developers and testers quickly diagnose the causes of automated test failures, improving problem-solving efficiency.
|
||||
|
||||
## Notes
|
||||
|
||||
|
||||
@@ -17,45 +17,46 @@ Summary:
|
||||
- **Reliability:** `tests/dfx/reliability/`
|
||||
- Do **not** add new top-level `tests/` directories unrelated to a component (or to `e2e` / `dfx` / `helpers` / `examples` / `buildkite`)
|
||||
|
||||
Deploy YAMLs: `vllm_omni/deploy/` via `tests.helpers.stage_config.get_deploy_config_path` (see [stage configs](../../configuration/stage_configs.md)).
|
||||
Deploy YAMLs: `vllm_omni/deploy/` via `tests.helpers.stage_config.get_deploy_config_path` (see [pipeline and deploy configs](../../configuration/stage_configs.md)).
|
||||
|
||||
## Markers for Tests
|
||||
|
||||
By adding markers before test functions, tests can later be executed uniformly by simply declaring the corresponding marker type.
|
||||
|
||||
### Current Markers
|
||||
|
||||
Defined in `pyproject.toml`:
|
||||
|
||||
| Marker | Description |
|
||||
| ------------------ | --------------------------------------------------------- |
|
||||
| `core_model` | L1&L2 tests (run in each PR) |
|
||||
| `advanced_model` | L3 tests (run on each merge to main) |
|
||||
| `full_model` | L4 tests (run nightly) |
|
||||
| `diffusion` | Diffusion model tests |
|
||||
| `omni` | Omni multimodal model tests |
|
||||
| `tts` | TTS model tests |
|
||||
| `cache` | Cache backend tests |
|
||||
| `parallel` | Parallelism/distributed tests |
|
||||
| `cpu` | Tests that run on CPU |
|
||||
| `gpu` | Tests that run on GPU * |
|
||||
| `cuda` | Tests that run on CUDA * |
|
||||
| `rocm` | Tests that run on AMD/ROCm * |
|
||||
| `xpu` | Tests that run on Intel XPU * |
|
||||
| `npu` | Tests that run on NPU/Ascend * |
|
||||
| `H100` | Tests that require H100 GPU * |
|
||||
| `L4` | Tests that require L4 GPU * |
|
||||
| `MI325` | Tests that require MI325 GPU (AMD/ROCm) * |
|
||||
| `A2` | Tests that require A2 NPU * |
|
||||
| `A3` | Tests that require A3 NPU * |
|
||||
| `distributed_cuda` | Tests that require multi cards on CUDA platform * |
|
||||
| `distributed_rocm` | Tests that require multi cards on ROCm platform * |
|
||||
| `distributed_npu` | Tests that require multi cards on NPU platform * |
|
||||
| `skipif_cuda` | Skip if the num of CUDA cards is less than the required * |
|
||||
| `skipif_rocm` | Skip if the num of ROCm cards is less than the required * |
|
||||
| `skipif_npu` | Skip if the num of NPU cards is less than the required * |
|
||||
| `slow` | Slow tests (may skip in quick CI) |
|
||||
| Marker | Description |
|
||||
| ------------------ | ------------------------------------------------------------------------------------------------------- |
|
||||
| `core_model` | L1&L2 tests (run in each PR) |
|
||||
| `advanced_model` | L3 tests (run on each merge to main) |
|
||||
| `full_model` | L4 tests (run nightly) |
|
||||
| `diffusion` | Diffusion model tests |
|
||||
| `omni` | Omni multimodal model tests |
|
||||
| `tts` | TTS model tests |
|
||||
| `cache` | Cache backend tests |
|
||||
| `parallel` | Parallelism/distributed tests |
|
||||
| `cpu` | Tests that run on CPU |
|
||||
| `gpu` | Tests that run on GPU * |
|
||||
| `cuda` | Tests that run on CUDA * |
|
||||
| `rocm` | Tests that run on AMD/ROCm * |
|
||||
| `xpu` | Tests that run on Intel XPU * |
|
||||
| `npu` | Tests that run on NPU/Ascend * |
|
||||
| `H100` | Tests that require H100 GPU * |
|
||||
| `L4` | Tests that require L4 GPU * |
|
||||
| `MI325` | Tests that require MI325 GPU (AMD/ROCm) * |
|
||||
| `A2` | Tests that require A2 NPU * |
|
||||
| `A3` | Tests that require A3 NPU * |
|
||||
| `distributed_cuda` | Tests that require multi cards on CUDA platform * |
|
||||
| `distributed_rocm` | Tests that require multi cards on ROCm platform * |
|
||||
| `distributed_npu` | Tests that require multi cards on NPU platform * |
|
||||
| `skipif_cuda` | Skip if the num of CUDA cards is less than the required * |
|
||||
| `skipif_rocm` | Skip if the num of ROCm cards is less than the required * |
|
||||
| `skipif_npu` | Skip if the num of NPU cards is less than the required * |
|
||||
| `slow` | Slow tests (may skip in quick CI) |
|
||||
| `benchmark` | Benchmark tests (decorator on runner test functions; perf JSON uses `full_model` + type marker instead) |
|
||||
| `local_model` | Tests requiring local / non-HF-hub model weights |
|
||||
| `local_model` | Tests requiring local / non-HF-hub model weights |
|
||||
|
||||
\* Means those markers are auto-added by `@hardware_test` (parametrization decorator) or `hardware_marks` (only returning the list of marks for flexibility).
|
||||
|
||||
@@ -81,13 +82,13 @@ This decorator is intended to make hardware-aware, cross-platform test authoring
|
||||
|
||||
1. **Applies platform and resource markers**
|
||||
Adds the appropriate pytest markers for each specified hardware platform (e.g., `cuda`, `rocm`, `xpu`, `npu`) and resource type (e.g., `L4`, `H100`, `MI325`, `B60`, `A2`, `A3`).
|
||||
```
|
||||
```python
|
||||
@pytest.mark.cuda
|
||||
@pytest.mark.L4
|
||||
```
|
||||
2. **Handles multi-card (distributed) scenarios**
|
||||
For tests requiring multiple cards, it automatically adds distributed markers such as `distributed_cuda`, `distributed_rocm`, or `distributed_npu`.
|
||||
```
|
||||
```python
|
||||
@pytest.mark.distributed_cuda(num_cards=num_cards)
|
||||
```
|
||||
3. **Supports flexible card requirements**
|
||||
@@ -97,11 +98,11 @@ This decorator is intended to make hardware-aware, cross-platform test authoring
|
||||
On CUDA, adds a skip marker (`skipif_cuda`) if the system does not have the required number of devices.
|
||||
Support for `skipif_rocm` and `skipif_npu` will be implemented later.
|
||||
|
||||
|
||||
5. **Works with pytest filtering**
|
||||
Allows tests to be filtered and selected at runtime using standard pytest marker expressions (e.g., `-m "distributed_cuda and L4"`).
|
||||
|
||||
##### Example usage for decorator
|
||||
|
||||
- Single call for multiple platforms:
|
||||
```python
|
||||
@hardware_test(
|
||||
@@ -220,6 +221,7 @@ If you want to add support for a new platform (e.g., "tpu" for a new accelerator
|
||||
```
|
||||
|
||||
**Summary**:
|
||||
|
||||
- Add pytest markers for your new platform/resources
|
||||
- Implement a marker function (`xxx_marks`)
|
||||
- Plug into `hardware_marks`
|
||||
@@ -237,47 +239,46 @@ L1 and L2 level testing form the foundation of the quality assurance system. L1
|
||||
|
||||
L2 level testing builds upon L1 by introducing GPU resources and verifying that the end-to-end (E2E) process of the model in basic deployment scenarios is smooth. For example, it uses dummy models to confirm that core interfaces like the inference pipeline, output format, and streaming response work properly. The common goal of these two levels is to provide developers with rapid feedback, discovering and fixing issues early in the development cycle.
|
||||
|
||||
|
||||
|
||||
#### 1.2 Testing Content and Scope
|
||||
|
||||
- ***L1 (Unit & Logic Testing)***:
|
||||
- - ***Scope***: Tests internal functions and methods of core components such as `entrypoints`, `models`.
|
||||
- ***Focus***: Branch coverage, exception handling, algorithm logic correctness. Does not involve external dependencies or the complete service stack.
|
||||
- ***Time Cost***: Execution time is controlled within ***15 minutes*** to ensure fast feedback.
|
||||
- ***L2 (Basic End-to-End Testing)***:
|
||||
- - ***Scope***: Covers two basic deployment scenarios: `online` (serving) and `offline` (inference).
|
||||
- ***Focus***: Uses `dummy` weights (via deploy YAML patching at `core_model`) or lightweight real models to verify that the entire chain from request input to result output works normally, including output data structure, streaming (stream) support, and **cheap payload checks** at `--run-level core_model` (see below). Also includes some unit tests that require launching independent service instances.
|
||||
- ***L2 response validation (`core_model`)***: Implemented in `tests/helpers/assertions.py` and invoked by `OpenAIClientHandler` based on `--run-level`. At L2 we require **request success** plus minimal output sanity—not full accuracy:
|
||||
- **Speech / TTS** (`assert_audio_speech_response`): decoded audio must be present and non-empty (or exceed `min_audio_bytes` when set in `request_config`); `response_format` must match the returned content-type (e.g. `wav`, `pcm`). Whisper transcript similarity, PCM HNR, and preset-voice gender checks run only at L3+.
|
||||
- **Diffusion** (`assert_diffusion_response`): at least one non-empty image, video, or audio artifact. Resolution/frame-count parity and other deep checks run only at L3+.
|
||||
- **Omni multimodal** (`assert_omni_response`): L2 asserts successful completion; keyword, transcript, and cross-modal similarity checks run only at L3+.
|
||||
- ***Characteristic***: Requires ***GPU*** resources to perform model computations.
|
||||
- ***L1 (Unit & Logic Testing)***:
|
||||
- ***Scope***: Tests internal functions and methods of core components such as `entrypoints`, `models`.
|
||||
- ***Focus***: Branch coverage, exception handling, algorithm logic correctness. Does not involve external dependencies or the complete service stack.
|
||||
- ***Time Cost***: Execution time is controlled within ***15 minutes*** to ensure fast feedback.
|
||||
- ***L2 (Basic End-to-End Testing)***:
|
||||
- ***Scope***: Covers two basic deployment scenarios: `online` (serving) and `offline` (inference).
|
||||
- ***Focus***: Uses `dummy` weights (via deploy YAML patching at `core_model`) or lightweight real models to verify that the entire chain from request input to result output works normally, including output data structure, streaming (stream) support, and **cheap payload checks** at `--run-level core_model` (see below). Also includes some unit tests that require launching independent service instances.
|
||||
- ***L2 response validation (`core_model`)***: Implemented in `tests/helpers/assertions.py` and invoked by `OpenAIClientHandler` based on `--run-level`. At L2 we require **request success** plus minimal output sanity—not full accuracy:
|
||||
- **Speech / TTS** (`assert_audio_speech_response`): decoded audio must be present and non-empty (or exceed `min_audio_bytes` when set in `request_config`); `response_format` must match the returned content-type (e.g. `wav`, `pcm`). Whisper transcript similarity, PCM HNR, and preset-voice gender checks run only at L3+.
|
||||
- **Diffusion** (`assert_diffusion_response`): at least one non-empty image, video, or audio artifact. Resolution/frame-count parity and other deep checks run only at L3+.
|
||||
- **Omni multimodal** (`assert_omni_response`): L2 asserts successful completion; keyword, transcript, and cross-modal similarity checks run only at L3+.
|
||||
- ***Characteristic***: Requires ***GPU*** resources to perform model computations.
|
||||
|
||||
#### 1.3 Test Directory and Execution Files
|
||||
|
||||
A clear directory structure is key to managing test cases efficiently. See the **Test Dir** column in [Test System Overview](./test_system_overview.md) for the canonical placement rules.
|
||||
|
||||
- ***L1 (component / unit)***: `tests/{component_name}/…` mirroring `vllm_omni/{component_name}/` (e.g. `tests/diffusion/`, `tests/entrypoints/`). Do **not** invent new top-level `tests/` folders unrelated to a component.
|
||||
- ***L2 (basic model E2E)***:
|
||||
- Online serving: `tests/e2e/online_serving/test_{model_name}.py`
|
||||
- Offline inference: `tests/e2e/offline_inference/test_{model_name}.py`
|
||||
- ***Feature-level integration*** (cross-cutting, not a single-model smoke): `tests/e2e/features/<feature>/` (e.g. `fullduplex/`, `custom_pipeline/`, `rlhf_test/`).
|
||||
- ***L1 (component / unit)***: `tests/{component_name}/…` mirroring `vllm_omni/{component_name}/` (e.g. `tests/diffusion/`, `tests/entrypoints/`). Do **not** invent new top-level `tests/` folders unrelated to a component.
|
||||
- ***L2 (basic model E2E)***:
|
||||
- Online serving: `tests/e2e/online_serving/test_{model_name}.py`
|
||||
- Offline inference: `tests/e2e/offline_inference/test_{model_name}.py`
|
||||
- ***Feature-level integration*** (cross-cutting, not a single-model smoke): `tests/e2e/features/<feature>/` (e.g. `fullduplex/`, `custom_pipeline/`, `rlhf_test/`).
|
||||
|
||||
#### 1.4 Execution Method and Example
|
||||
|
||||
- ***Trigger Timing***: **`PR with ready label`**. That is, when a developer adds a "ready for review" or similar label to a PR on platforms like GitHub, L1 and L2 tests are automatically triggered.
|
||||
- ***Diff-aware step skipping***: On L2, **E2E Test** jobs may be omitted at pipeline upload when the PR diff does not touch their [`source_file_dependencies`](ci_settings.md#step-filtering) prefixes; non-E2E groups still always upload. See [CI Settings — Diff-aware CI](ci_settings.md#diff-aware-ci).
|
||||
- ***Execution Environment***: L1 uses ***CPU*** environment; L2 requires ***GPU*** environment.
|
||||
- ***Script Example***:
|
||||
- ***Trigger Timing***: **`PR with ready label`**. That is, when a developer adds a "ready for review" or similar label to a PR on platforms like GitHub, L1 and L2 tests are automatically triggered.
|
||||
- ***Diff-aware step skipping***: On L2, **E2E Test** jobs may be omitted at pipeline upload when the PR diff does not touch their [`source_file_dependencies`](ci_settings.md#step-filtering) prefixes; non-E2E groups still always upload. See [CI Settings — Diff-aware CI](ci_settings.md#diff-aware-ci).
|
||||
- ***Execution Environment***: L1 uses ***CPU*** environment; L2 requires ***GPU*** environment.
|
||||
- ***Script Example***:
|
||||
|
||||
<details>
|
||||
<summary> L1 Test Examples</summary>
|
||||
|
||||
Examples from `tests/model_executor/models/qwen2_5_omni/test_audio_length.py`
|
||||
|
||||
```python
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
import pytest
|
||||
|
||||
@@ -331,6 +332,7 @@ def test_cap_and_align_mel_length_no_mismatch(repeats, code_len, max_mel_frames)
|
||||
if max_mel_frames is not None and int(max_mel_frames) > 0 and int(max_mel_frames) >= repeats:
|
||||
assert target_mel_len <= int(max_mel_frames)
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
@@ -338,7 +340,7 @@ def test_cap_and_align_mel_length_no_mismatch(repeats, code_len, max_mel_frames)
|
||||
You can refer to Test Examples in the L3 section to see example test cases that incorporate both L2 and L3 testing logic.
|
||||
</details>
|
||||
|
||||
- - ***Run Command***:
|
||||
- ***Run Command***:
|
||||
|
||||
`pytest -s -v /tests/e2e/online_serving/test_{model_name}.py`
|
||||
`pytest -s -v -m 'core_model and cpu' --run-level=core_model`
|
||||
@@ -351,36 +353,34 @@ L3 level testing executes after code is merged into the main branch. Its core pu
|
||||
|
||||
. It acts as the "quality gatekeeper" for the main branch, ensuring that no merge breaks the core capabilities of the model service. Testing needs to provide clear conclusions within a relatively short time (<30min), balancing test depth with feedback speed.
|
||||
|
||||
|
||||
|
||||
#### 2.2 Testing Content and Scope
|
||||
|
||||
- ***Deployment Scenarios***: Covers richer `online` and `offline` deployment configurations, which may include different hardware configurations, batch sizes, concurrency levels, etc.
|
||||
- ***Core Verification***:
|
||||
- 1. ***Inference Functionality***: Ensures real models can perform forward computation normally and return results.
|
||||
2. ***Accuracy Compliance***: Verifies that the model's evaluation metrics (e.g., accuracy) meet the expected baseline, preventing code changes from introducing accuracy issues.
|
||||
3. ***Important Performance***: Verifies whether performance (e.g., P99 latency, throughput) in core scenarios meets preset thresholds.
|
||||
- ***L3 response validation (`advanced_model`)***: At `--run-level advanced_model`, `tests/helpers/assertions.py` adds semantic checks on top of L2 payload gates (see L1 & L2 above):
|
||||
- **Speech / TTS** (`assert_audio_speech_response`): Whisper transcript of returned audio vs `request_config["input"]` (cosine similarity > 0.9 when input text is set); optional `min_audio_bytes` floor; PCM harmonic-to-noise ratio when `response_format` is `pcm`; **preset voice gender** via `_assert_preset_voice_gender_from_audio` when `voice` matches a known preset in `_PRESET_VOICE_GENDER_MAP` (pitch/F0-based classifier; skipped for unknown voices or `pcm` output).
|
||||
- **Omni multimodal** (`assert_omni_response`): non-empty text/audio outputs; `key_words` in transcript or text; text–audio similarity / containment; preset **`speaker`** gender check (same helper as TTS).
|
||||
- **Diffusion** (`assert_*_diffusion_response`): image/video dimension and frame-count parity with request parameters where configured.
|
||||
- **Accuracy suites**: pixel/video similarity and metric baselines under `/tests/e2e/accuracy/` (separate from inline helper assertions).
|
||||
- ***Deployment Scenarios***: Covers richer `online` and `offline` deployment configurations, which may include different hardware configurations, batch sizes, concurrency levels, etc.
|
||||
- ***Core Verification***:
|
||||
1. ***Inference Functionality***: Ensures real models can perform forward computation normally and return results.
|
||||
2. ***Accuracy Compliance***: Verifies that the model's evaluation metrics (e.g., accuracy) meet the expected baseline, preventing code changes from introducing accuracy issues.
|
||||
3. ***Important Performance***: Verifies whether performance (e.g., P99 latency, throughput) in core scenarios meets preset thresholds.
|
||||
- ***L3 response validation (`advanced_model`)***: At `--run-level advanced_model`, `tests/helpers/assertions.py` adds semantic checks on top of L2 payload gates (see L1 & L2 above):
|
||||
- **Speech / TTS** (`assert_audio_speech_response`): Whisper transcript of returned audio vs `request_config["input"]` (cosine similarity > 0.9 when input text is set); optional `min_audio_bytes` floor; PCM harmonic-to-noise ratio when `response_format` is `pcm`; **preset voice gender** via `_assert_preset_voice_gender_from_audio` when `voice` matches a known preset in `_PRESET_VOICE_GENDER_MAP` (pitch/F0-based classifier; skipped for unknown voices or `pcm` output).
|
||||
- **Omni multimodal** (`assert_omni_response`): non-empty text/audio outputs; `key_words` in transcript or text; text–audio similarity / containment; preset **`speaker`** gender check (same helper as TTS).
|
||||
- **Diffusion** (`assert_*_diffusion_response`): image/video dimension and frame-count parity with request parameters where configured.
|
||||
- **Accuracy suites**: pixel/video similarity and metric baselines under `/tests/e2e/accuracy/` (separate from inline helper assertions).
|
||||
|
||||
#### 2.3 Test Directory and Execution Files
|
||||
|
||||
- ***Functional / model E2E***:
|
||||
- Online serving: `tests/e2e/online_serving/test_{model_name}_expansion.py`
|
||||
- Offline inference: `tests/e2e/offline_inference/test_{model_name}_expansion.py`
|
||||
- Accuracy / similarity: `tests/e2e/accuracy/`
|
||||
- (`_expansion.py` holds broader scenario coverage than the L2 smoke file.)
|
||||
- ***Feature-level integration***: `tests/e2e/features/<feature>/` (not under a new top-level `tests/` directory).
|
||||
- ***Functional / model E2E***:
|
||||
- Online serving: `tests/e2e/online_serving/test_{model_name}_expansion.py`
|
||||
- Offline inference: `tests/e2e/offline_inference/test_{model_name}_expansion.py`
|
||||
- Accuracy / similarity: `tests/e2e/accuracy/`
|
||||
- (`_expansion.py` holds broader scenario coverage than the L2 smoke file.)
|
||||
- ***Feature-level integration***: `tests/e2e/features/<feature>/` (not under a new top-level `tests/` directory).
|
||||
|
||||
#### 2.4 Execution Method and Example
|
||||
|
||||
- ***Trigger Timing***: **`PR Merged`**. Automatically triggered after code review is approved and merged into the main branch (typically via `merge-test` label on the PR before merge).
|
||||
- ***Diff-aware step skipping***: Same [`source_file_dependencies`](ci_settings.md#step-filtering) mechanism as L2—**all E2E Test** leaf steps are diff-gated; other L3 groups always upload. See [CI Settings — Diff-aware CI](ci_settings.md#diff-aware-ci).
|
||||
- ***Execution Environment***: ***GPU*** servers.
|
||||
- ***Script Example***:
|
||||
- ***Trigger Timing***: **`PR Merged`**. Automatically triggered after code review is approved and merged into the main branch (typically via `merge-test` label on the PR before merge).
|
||||
- ***Diff-aware step skipping***: Same [`source_file_dependencies`](ci_settings.md#step-filtering) mechanism as L2—**all E2E Test** leaf steps are diff-gated; other L3 groups always upload. See [CI Settings — Diff-aware CI](ci_settings.md#diff-aware-ci).
|
||||
- ***Execution Environment***: ***GPU*** servers.
|
||||
- ***Script Example***:
|
||||
|
||||
???+ example "Test Examples"
|
||||
|
||||
@@ -496,9 +496,9 @@ L3 level testing executes after code is merged into the main branch. Its core pu
|
||||
|
||||
**Audio output debugging**: Deep validation may transcribe returned audio via `convert_audio_bytes_to_text` (Whisper). If an audio keyword or text–audio similarity assertion fails, set `VLLM_OMNI_KEEP_REQUEST_MEDIA=1` before running pytest to keep the intermediate WAV files for inspection (see [Test helper environment variables](test_system_overview.md#test-helper-environment-variables)).
|
||||
|
||||
- ***Run Command (L3 merge)***: `pytest -s -v /tests/e2e/online_serving/test_{model_name}.py -m advanced_model --run-level=advanced_model`
|
||||
- ***Run Command (L3 merge)***: `pytest -s -v /tests/e2e/online_serving/test_{model_name}.py -m advanced_model --run-level=advanced_model`
|
||||
|
||||
- ***Run Command (L4 nightly expansion)***: `pytest -s -v /tests/e2e/online_serving/test_{model_name}_expansion.py -m full_model --run-level=full_model`
|
||||
- ***Run Command (L4 nightly expansion)***: `pytest -s -v /tests/e2e/online_serving/test_{model_name}_expansion.py -m full_model --run-level=full_model`
|
||||
|
||||
### L4 Level Testing - Full Functionality, Performance, and Documentation Testing
|
||||
|
||||
@@ -506,27 +506,25 @@ L3 level testing executes after code is merged into the main branch. Its core pu
|
||||
|
||||
L4 level testing is a comprehensive quality audit before a version release. It expands upon L3, executing ***full*** functional scenarios, conducting systematic ***performance stress tests***, and simultaneously verifying the correctness of accompanying ***example documentation***. Its purpose is to perform deep validation of the system during off-peak nighttime hours, providing quality trend reports for daytime development and data support for release decisions.
|
||||
|
||||
|
||||
|
||||
#### 3.2 Testing Content and Scope
|
||||
|
||||
- ***Full Functionality Testing***: Executes all test cases defined in `test_{model_name}_expansion.py`, covering all implemented features, positive flows, boundary conditions, and exception handling.
|
||||
- ***Performance Testing***: Uses `tests/dfx/perf/tests/test_qwen3_omni_*.json` (Omni), `test_tts.json` / `test_voxcpm2.json` / `test_higgs_audio_v3.json` (TTS), and diffusion configs `tests/dfx/perf/tests/test_*_vllm_omni.json` (passed to `run_benchmark.py` or `run_diffusion_benchmark.py` via `--test-config-file` in nightly **Perf Test** steps) to drive throughput, latency, and memory benchmarks. Each JSON **case** may declare an optional top-level **`mark`** array: exactly one ``hardware_marks`` object plus pytest marker name strings (`full_model`, `omni` / `tts` / `diffusion`, …). Runners attach those marks to each parametrized `(server, benchmark index)` pair so **local** bulk runs can filter with `-m` (for example `-m "full_model and H100 and diffusion"`). Nightly CI perf jobs select workloads by **`--test-config-file`**, not `-m`. Details are in the Performance Tests example below.
|
||||
- ***Documentation Testing***: Verifies whether the example code provided to users is runnable and its results match the description.
|
||||
- ***Full Functionality Testing***: Executes all test cases defined in `test_{model_name}_expansion.py`, covering all implemented features, positive flows, boundary conditions, and exception handling.
|
||||
- ***Performance Testing***: JSON configs under `tests/dfx/perf/tests/` drive Omni, TTS, and diffusion serving benchmarks via `run_benchmark.py` or `run_diffusion_benchmark.py`, measuring throughput, latency, and related metrics under configured workloads.
|
||||
- ***Documentation Testing***: Verifies whether the example code provided to users is runnable and its results match the description.
|
||||
|
||||
#### 3.3 Test Directory and Execution Files
|
||||
|
||||
- ***Functional Testing***: Same directories as L3.
|
||||
- ***Performance Test Configuration***: `tests/dfx/perf/tests/test_qwen3_omni_*.json`, `test_tts.json`, `test_voxcpm2.json`, `test_higgs_audio_v3.json`, and diffusion configs `tests/dfx/perf/tests/test_*_vllm_omni.json` (e.g. `test_qwen_image_vllm_omni.json`, `test_cosmos3_vllm_omni.json`). Optional per-case `mark` for local `-m` filtering is documented in Section 3.4 Performance Tests.
|
||||
- ***Documentation Example Tests***:
|
||||
- `tests/examples/online_serving/test_{model_name}.py`
|
||||
- `tests/examples/offline_inference/test_{model_name}.py`
|
||||
- ***Functional Testing***: Same directories as L3.
|
||||
- ***Performance Test Configuration***: `tests/dfx/perf/tests/test_qwen3_omni_*.json`, `test_tts.json`, `test_voxcpm2.json`, `test_higgs_audio_v3.json`, and diffusion configs `tests/dfx/perf/tests/test_*_vllm_omni.json` (e.g. `test_qwen_image_vllm_omni.json`, `test_cosmos3_vllm_omni.json`). Optional per-case `mark` for local `-m` filtering is documented in Section 3.4 Performance Tests.
|
||||
- ***Documentation Example Tests***:
|
||||
- `tests/examples/online_serving/test_{model_name}.py`
|
||||
- `tests/examples/offline_inference/test_{model_name}.py`
|
||||
|
||||
#### 3.4 Execution Method and Example
|
||||
|
||||
- ***Trigger Timing***: **`Nightly`**, automatically executed every night.
|
||||
- ***Execution Environment***: ***GPU*** server clusters to meet the resource demands of performance testing.
|
||||
- ***Script Example***:
|
||||
- ***Trigger Timing***: **`Nightly`**, automatically executed every night.
|
||||
- ***Execution Environment***: ***GPU*** server clusters to meet the resource demands of performance testing.
|
||||
- ***Script Example***:
|
||||
|
||||
??? example "Test Examples: Documentation Example Tests"
|
||||
|
||||
@@ -540,7 +538,7 @@ L4 level testing is a comprehensive quality audit before a version release. It e
|
||||
|
||||
--8<-- "docs/contributing/ci/test_examples/l4_functionality_tests.inc.md"
|
||||
|
||||
- ***Run Command***: (Specific commands would depend on the performance testing tool and configuration defined in `nightly.json`).
|
||||
- ***Run Command***: (Specific commands would depend on the performance testing tool and configuration defined in `nightly.json`).
|
||||
|
||||
### L5 Level Testing - Stability and Reliability Testing
|
||||
|
||||
@@ -548,41 +546,43 @@ L4 level testing is a comprehensive quality audit before a version release. It e
|
||||
|
||||
L5 level testing focuses on the performance of model services under ***long-running*** and ***abnormal fault*** scenarios. It aims to uncover deep-seated issues that only manifest under sustained pressure or extreme conditions, such as memory leaks, resource contention, gradual performance degradation, and lack of fault tolerance mechanisms. This is the final, yet crucial, line of defense for ensuring service high availability and production environment robustness.
|
||||
|
||||
|
||||
|
||||
#### 4.2 Testing Content and Scope
|
||||
|
||||
- ***Long-term Stability (Stability) Testing***: Uses JSON under `tests/dfx/stability/tests/` (for example `test_qwen3_omni.json` and `test_wan22.json`) to run the service under moderate load for an extended period (e.g., over 12 hours), monitoring whether metrics like memory/VRAM usage, response time, and throughput degrade over time, and whether the service process remains stable.
|
||||
- ***Reliability Testing***: Uses pytest suites under `tests/dfx/reliability/` to inject controlled faults against a **live** `vllm_omni serve` instance (same **`omni_server` / `omni_server_function`** fixture style as E2E). Current suites emphasize **GPU memory pressure** (CUDA sidecar “memory hog”), **worker / runtime process kill** (`SIGKILL` on `VLLM::Worker` for Qwen3-Omni, `multiprocessing.spawn` for Wan2.2 video workers, or `vLLM-Omni::` for HunyuanImage DiT workers), **large multimodal chat**, **`/v1/videos`**, **`/v1/images/generations`**, or **`/v1/audio/speech`** jobs under OOM, **`/health` → 503** and **fast-fail / non-hanging concurrent** requests after kill, and **OpenAI-style 5xx error contracts** (e.g. text vs text+audio under OOM). **Post-fault recovery** checks exist where enabled (some cases may be `skip` while issues are tracked). See the Reliability `<details>` block in Section 4.4 for file-level responsibilities and CI markers (`slow`, `hardware_test`, POSIX-only kill).
|
||||
- ***Long-term Stability (Stability) Testing***: Uses JSON under `tests/dfx/stability/tests/` (for example `test_qwen3_omni.json` and `test_wan22.json`) to run the service under moderate load for an extended period (e.g., over 12 hours), monitoring whether metrics like memory/VRAM usage, response time, and throughput degrade over time, and whether the service process remains stable.
|
||||
- ***Reliability Testing***: Uses pytest suites under `tests/dfx/reliability/` to inject controlled faults against a **live** `vllm_omni serve` instance (same **`omni_server` / `omni_server_function`** fixture style as E2E). Current suites emphasize **GPU memory pressure** (CUDA sidecar “memory hog”), **worker / runtime process kill** (`SIGKILL` on `VLLM::Worker` for Qwen3-Omni, `multiprocessing.spawn` for Wan2.2 video workers, or `vLLM-Omni::` for HunyuanImage DiT workers), **large multimodal chat**, **`/v1/videos`**, **`/v1/images/generations`**, or **`/v1/audio/speech`** jobs under OOM, **`/health` → 503** and **fast-fail / non-hanging concurrent** requests after kill, and **OpenAI-style 5xx error contracts** (e.g. text vs text+audio under OOM). **Post-fault recovery** checks exist where enabled (some cases may be `skip` while issues are tracked). See Section 4.3 for file-level responsibilities and Section 4.4 Test Examples (Reliability) for CI markers (`slow`, `hardware_test`, POSIX-only kill).
|
||||
|
||||
#### 4.3 Test Directory and Execution Files
|
||||
|
||||
- ***Stability Test Configuration***: `tests/dfx/stability/tests/test_qwen3_omni.json`, `tests/dfx/stability/tests/test_wan22.json` (one JSON per model / runner family)
|
||||
- ***Reliability Test Suite*** (`tests/dfx/reliability/`):
|
||||
- `test_reliability_qwen3_omni.py` — Qwen3-Omni chat / multimodal reliability (GPU OOM, process kill, recovery, error contract under `--async-chunk` vs default).
|
||||
- `test_reliability_wan22.py` — Wan2.2 I2V video API reliability (`/v1/videos` under OOM and process kill, recovery).
|
||||
- `test_reliability_hunyuan_image.py` — HunyuanImage-3.0-Instruct DiT-only reliability (`/v1/images/generations` under OOM and process kill; deploy `hunyuan_image3_dit.yaml`, H100 × 4).
|
||||
- `test_reliability_voxcpm2.py` — VoxCPM2 TTS reliability (`/v1/audio/speech` under OOM and process kill; deploy `voxcpm2.yaml`, L4 × 1).
|
||||
- `helpers.py` — Shared primitives used by current suites: raw HTTP probes for `/v1/chat/completions` and `/health`, OpenAI-style error parsing, GPU OOM sidecar (`inject_gpu_oom` / `stop_gpu_oom_hogs`), and `pgrep`-based process-kill injector construction (`make_process_kill_fault_injector`).
|
||||
- `conftest.py` — `fault_injector` and `omni_server_after_fault` / `omni_server_after_fault_function` fixtures to run a callable **after** the server is ready.
|
||||
- `README.md` — Short local run commands for this directory.
|
||||
- ***Stability Test Configuration***: `tests/dfx/stability/tests/test_qwen3_omni.json`, `tests/dfx/stability/tests/test_wan22.json` (one JSON per model / runner family)
|
||||
- ***Reliability Test Suite*** (`tests/dfx/reliability/`):
|
||||
- `test_reliability_qwen3_omni.py` — Qwen3-Omni chat / multimodal reliability (GPU OOM, process kill, recovery, error contract under `--async-chunk` vs default).
|
||||
- `test_reliability_wan22.py` — Wan2.2 I2V video API reliability (`/v1/videos` under OOM and process kill, recovery).
|
||||
- `test_reliability_hunyuan_image.py` — HunyuanImage-3.0-Instruct DiT-only reliability (`/v1/images/generations` under OOM and process kill; deploy `hunyuan_image3_dit.yaml`, H100 × 4).
|
||||
- `helpers.py` — Shared primitives used by current suites: raw HTTP probes for `/v1/chat/completions` and `/health`, OpenAI-style error parsing, GPU OOM sidecar (`inject_gpu_oom` / `stop_gpu_oom_hogs`), and `pgrep`-based process-kill injector construction (`make_process_kill_fault_injector`).
|
||||
- `conftest.py` — `fault_injector` and `omni_server_after_fault` / `omni_server_after_fault_function` fixtures to run a callable **after** the server is ready.
|
||||
- `README.md` — Short local run commands for this directory.
|
||||
|
||||
#### 4.4 Execution Method and Example
|
||||
|
||||
- ***Trigger Timing***: **`Weekly`** (weekly) or **`Days before Release`** (several days before a major release). Due to long execution times, the frequency is lower.
|
||||
- ***Execution Environment***: ***GPU*** servers, requiring a stable and exclusive testing environment.
|
||||
- ***Script Example***:
|
||||
- ***Trigger Timing***: **`Weekly`** (weekly) or **`Days before Release`** (several days before a major release). Due to long execution times, the frequency is lower.
|
||||
- ***Run Command***:
|
||||
- ***Stability***: `pytest -s -v tests/dfx/stability/scripts/test_stability_qwen3_omni.py` or `pytest -s -v tests/dfx/stability/scripts/test_stability_wan22.py` (or add `test_stability_<model>.py` alongside a matching JSON config)
|
||||
- ***Reliability***: `pytest -s -v tests/dfx/reliability/test_reliability_<model>.py -m slow` (current suites: `qwen3_omni`, `wan22`, `hunyuan_image`).
|
||||
- ***Script Example***:
|
||||
|
||||
<details>
|
||||
<summary> Test Examples</summary>
|
||||
|
||||
When you want to add L5-level stability test cases, add or extend the appropriate JSON file under `tests/dfx/stability/tests/` (for example `test_qwen3_omni.json` for Omni bench traffic, or `test_wan22.json` for diffusion `/v1/videos` workloads). The following illustrates the Qwen3-Omni shape:
|
||||
##### Stability
|
||||
|
||||
When you want to add L5-level stability test cases, add or extend the appropriate JSON file under `tests/dfx/stability/tests/` (for example `test_qwen3_omni.json` for Omni bench traffic, or `test_wan22.json` for diffusion `/v1/videos` workloads). Pair the JSON with `tests/dfx/stability/scripts/test_stability_<model>.py`. The following illustrates the Qwen3-Omni shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"test_name": "test_qwen3_omni_stability",
|
||||
"server_params": {
|
||||
"model": "Qwen/Qwen3-Omni-30B-A3B-Instruct",
|
||||
"stage_config_name": "qwen3_omni.yaml"
|
||||
"stage_config_name": "qwen3_omni_moe.yaml"
|
||||
},
|
||||
"benchmark_params": [
|
||||
{
|
||||
@@ -601,112 +601,61 @@ When you want to add L5-level stability test cases, add or extend the appropriat
|
||||
}
|
||||
```
|
||||
|
||||
##### Parameter Explanation
|
||||
###### Parameter Explanation
|
||||
|
||||
***Overview***
|
||||
|
||||
| Field | Required | Description |
|
||||
| ---------------- | -------- | --------------------------------------------------------------------------- |
|
||||
| test_name | Yes | Unique identifier for the stability test case |
|
||||
| server_params | Yes | Server-side configuration parameters (model, stage configuration, etc.) |
|
||||
| server_params | Yes | Server-side configuration parameters (model, deploy configuration, etc.) |
|
||||
| benchmark_params | Yes | Stability benchmark running parameters (supports multiple configurations) |
|
||||
|
||||
##### server_params Configuration
|
||||
###### server_params Configuration
|
||||
|
||||
###### Basic Parameters
|
||||
Basic parameters:
|
||||
|
||||
| Parameter | Required | Example | Description |
|
||||
| ----------------- | -------- | ---------------------------------- | ----------------------------------- |
|
||||
| model | Yes | "Qwen/Qwen3-Omni-30B-A3B-Instruct" | Model name or path |
|
||||
| stage_config_name | Yes | "qwen3_omni.yaml" | Stage configuration file name |
|
||||
| stage_config_name | Yes | "qwen3_omni_moe.yaml" | Deploy configuration file name |
|
||||
|
||||
###### Dynamic Configuration (update/delete)
|
||||
|
||||
Supports incremental modifications based on the basic configuration:
|
||||
Dynamic configuration (`update` / `delete`) supports incremental modifications based on the basic configuration:
|
||||
|
||||
| Operation | Description |
|
||||
| --------- | ------------------------------------ |
|
||||
| update | Update or add configuration items |
|
||||
| delete | Delete specified configuration items |
|
||||
|
||||
***Example***:
|
||||
You can refer to Test Examples in L4 §3.4
|
||||
***Example***: You can refer to Test Examples in L4 §3.4.
|
||||
|
||||
##### benchmark_params Configuration
|
||||
###### benchmark_params Configuration
|
||||
|
||||
For stability testing, the key parameters are:
|
||||
|
||||
- **duration_sec**: Total duration (in seconds) during which benchmark traffic is sent. The stability benchmark will keep sending batches until this duration is reached.
|
||||
- **request_rate** / **max_concurrency**: Exactly one of them must be specified. They control how the traffic is generated for each batch:
|
||||
- `request_rate`: Number of requests per second. The benchmark will send `num_prompts_per_batch` requests at the given rate.
|
||||
- `max_concurrency`: Maximum number of concurrent requests. When this is used, `request_rate` is set to `inf` internally.
|
||||
- **num_prompts_per_batch**: Number of prompts sent in each batch. Multiple batches will be executed sequentially within `duration_sec`.
|
||||
- **duration_sec**: Total duration (in seconds) during which benchmark traffic is sent. The stability benchmark will keep sending batches until this duration is reached.
|
||||
- **request_rate** / **max_concurrency**: Exactly one of them must be specified. They control how the traffic is generated for each batch:
|
||||
- `request_rate`: Number of requests per second. The benchmark will send `num_prompts_per_batch` requests at the given rate.
|
||||
- `max_concurrency`: Maximum number of concurrent requests. When this is used, `request_rate` is set to `inf` internally.
|
||||
- **num_prompts_per_batch**: Number of prompts sent in each batch. Multiple batches will be executed sequentially within `duration_sec`.
|
||||
|
||||
All other optional parameters follow the same rules as in L4 §3.4.
|
||||
|
||||
</details>
|
||||
##### Reliability
|
||||
|
||||
<details>
|
||||
<summary> Reliability test suite (<code>tests/dfx/reliability</code>)</summary>
|
||||
Add pytest modules under `tests/dfx/reliability/` (for example `test_reliability_qwen3_omni.py`, `test_reliability_wan22.py`, `test_reliability_hunyuan_image.py`). Reuse `helpers.py` and `conftest.py` rather than duplicating OOM / process-kill / raw HTTP plumbing.
|
||||
|
||||
##### Purpose and relationship to stability
|
||||
|
||||
Reliability tests are **short fault-injection** integration runs (L5 **(b)** in `tests/dfx/reliability/README.md`). They complement **stability** JSON-driven long runs: instead of hours of steady traffic, they **perturb** the server (GPU OOM sidecar, fatal signals on selected processes) and check **failure mode** and **latency bounds** (e.g. chat or `/v1/videos` must not hang under concurrent fault-time load).
|
||||
|
||||
##### Directory layout
|
||||
|
||||
| Path | Responsibility |
|
||||
| ---- | -------------- |
|
||||
| `helpers.py` | Shared helpers used by current reliability suites: raw `POST`/`GET` probes (`/v1/chat/completions`, `/health`), OpenAI error parsing (`extract_openai_error_contract_from_bytes`), GPU OOM sidecar lifecycle (`inject_gpu_oom`, `stop_gpu_oom_hogs`), and process-kill injector builder (`make_process_kill_fault_injector`). |
|
||||
| `conftest.py` | Pytest fixtures: indirect `fault_injector`, `omni_server_after_fault` / `omni_server_after_fault_function` (run injector after server is ready, then yield server). |
|
||||
| `test_reliability_qwen3_omni.py` | Qwen3-Omni: OOM vs **text vs text+audio** error contract, large multimodal chat under OOM, concurrent pressure, **SIGKILL** on `VLLM::Worker`, `/health` → 503 + fast-fail + concurrent chat; optional OOM recovery scenario (may be skipped while tracked in issues). |
|
||||
| `test_reliability_wan22.py` | Wan2.2 I2V: large `/v1/videos` under OOM, **SIGKILL** on `multiprocessing.spawn` chain, health / fast-fail / concurrent video requests; optional recovery test (may be skipped). |
|
||||
| `test_reliability_hunyuan_image.py` | HunyuanImage DiT-only: large `/v1/images/generations` under OOM, **SIGKILL** on `vLLM-Omni::` workers and serve/tree targets, health / fast-fail / concurrent image requests; some OOM/recovery cases may be skipped while tracked in issues. |
|
||||
| `test_reliability_voxcpm2.py` | VoxCPM2: `/v1/audio/speech` under OOM (error contract), **SIGKILL** on `VLLM::` workers and serve/tree targets, health / fast-fail / concurrent speech requests; some OOM cases may be skipped while tracked in issues. |
|
||||
| `README.md` | Minimal run / collect examples. |
|
||||
|
||||
##### Parametrization and markers
|
||||
###### Parametrization and markers
|
||||
|
||||
- Each test module defines a **`RELIABILITY_SCENARIOS`** list (`test_name`, `server_params`: model, `stage_config_name` or diffusion `server_args`, etc.). **`create_reliability_omni_server_params()`** in `tests/dfx/conftest.py` resolves stage paths (including XPU substitutions where applicable) and builds **`OmniServerParams`** lists consumed by **`@pytest.mark.parametrize(..., indirect=True)`** on `omni_server` or `omni_server_function`.
|
||||
- Cases are tagged **`@pytest.mark.slow`** for weekly / selective CI. GPU-heavy suites use **`@hardware_test(res={"cuda": "H100"}, num_cards=...)`** or **`@hardware_test(res={"cuda": "L4"}, num_cards=1)`** (Qwen3-Omni **2**× H100; Wan2.2 **1**× H100; HunyuanImage DiT **4**× H100; VoxCPM2 **1**× L4).
|
||||
- Cases are tagged **`@pytest.mark.slow`** for weekly / selective CI. GPU-heavy suites use **`@hardware_test(res={"cuda": "H100"}, num_cards=...)`** (Qwen3-Omni **2**× H100; Wan2.2 **1**× H100; HunyuanImage DiT **4**× H100).
|
||||
- **Process-kill** tests use **`@pytest.mark.skipif(os.name == "nt", ...)`** because injection uses POSIX **`pgrep` / `kill`**.
|
||||
|
||||
##### CI trigger
|
||||
|
||||
Weekly Buildkite (`.buildkite/cuda/test-weekly.yml`) runs one step per model suite (trigger: `WEEKLY=1` or PR label `weekly-test`), for example:
|
||||
|
||||
| Buildkite step | Test file | CI hardware |
|
||||
| -------------- | --------- | ----------- |
|
||||
| Reliability Test - qwen3-omni | `test_reliability_qwen3_omni.py` | H100 × 2 (`mithril-h100-pool`) |
|
||||
| Reliability Test - wan22 | `test_reliability_wan22.py` | H100 × 2 (`mithril-h100-pool`) |
|
||||
| Reliability Test - hunyuan-image | `test_reliability_hunyuan_image.py` | H100 × 4 (`mithril-h100-pool`) |
|
||||
| Reliability Test - voxcpm2 | `test_reliability_voxcpm2.py` | L4 × 1 (`gpu_1_queue`) |
|
||||
|
||||
```bash
|
||||
pytest -s -v tests/dfx/reliability/test_reliability_qwen3_omni.py -m "slow"
|
||||
pytest -s -v tests/dfx/reliability/test_reliability_wan22.py -m "slow"
|
||||
pytest -s -v tests/dfx/reliability/test_reliability_hunyuan_image.py -m "slow"
|
||||
pytest -s -v tests/dfx/reliability/test_reliability_voxcpm2.py -m "slow"
|
||||
```
|
||||
|
||||
##### Local commands
|
||||
|
||||
```bash
|
||||
pytest --collect-only tests/dfx/reliability
|
||||
pytest -s -v tests/dfx/reliability/test_reliability_qwen3_omni.py -m slow
|
||||
pytest -s -v tests/dfx/reliability/test_reliability_wan22.py -m slow
|
||||
pytest -s -v tests/dfx/reliability/test_reliability_hunyuan_image.py -m slow
|
||||
pytest -s -v tests/dfx/reliability/test_reliability_voxcpm2.py -m slow
|
||||
```
|
||||
|
||||
##### Adding a new model suite
|
||||
###### Adding a new model suite
|
||||
|
||||
1. Add `test_reliability_<model>.py` under `tests/dfx/reliability/`.
|
||||
2. Define **`RELIABILITY_SCENARIOS`** and pass them through **`create_reliability_omni_server_params()`** with the correct deploy or e2e stage-config directory (same pattern as existing files).
|
||||
3. Reuse **`helpers`** for OOM / kill / raw HTTP; prefer **`assert_fault_exception()`** and **`resolve_oom_device_spec()`** from `tests/dfx/conftest.py` for consistent device selection vs stage YAML.
|
||||
2. Define **`RELIABILITY_SCENARIOS`** and pass them through **`create_reliability_omni_server_params()`** with the correct deploy or e2e deploy-config directory (same pattern as existing files).
|
||||
3. Reuse **`helpers`** for OOM / kill / raw HTTP; prefer **`assert_fault_exception()`** and **`resolve_oom_device_spec()`** from `tests/dfx/conftest.py` for consistent device selection vs deploy YAML.
|
||||
4. Register **`slow`** (and **`hardware_test`** if needed); extend **`.buildkite/cuda/test-weekly.yml`** when the suite should run in weekly L5.
|
||||
|
||||
</details>
|
||||
|
||||
- - ***Stability***: `pytest -s -v tests/dfx/stability/scripts/test_stability_qwen3_omni.py` or `pytest -s -v tests/dfx/stability/scripts/test_stability_wan22.py` (or add `test_stability_<model>.py` alongside a matching JSON config)
|
||||
- ***Reliability***: `pytest -s -v tests/dfx/reliability/test_reliability_<model>.py -m slow` (current suites: `qwen3_omni`, `wan22`, `hunyuan_image`, `voxcpm2`; add `test_reliability_<suite>.py` and a matching step in `.buildkite/cuda/test-weekly.yml` for new models)
|
||||
@@ -9,7 +9,7 @@ This guide walks through the process of adding a new multi-stage model to vLLM-O
|
||||
3. [Step-by-Step Implementation](#step-by-step-implementation)
|
||||
4. [Key Components](#key-components)
|
||||
5. [Model Registration](#model-registration)
|
||||
6. [Stage Configuration](#stage-configuration)
|
||||
6. [Pipeline and Deploy Configuration](#pipeline-and-deploy-configuration)
|
||||
7. [Stage Input Processors](#stage-input-processors)
|
||||
8. [Testing](#testing)
|
||||
9. [Adding a Model Recipe](#adding-a-model-recipe)
|
||||
@@ -316,18 +316,28 @@ _OMNI_MODELS = {
|
||||
|
||||
The registry uses lazy loading, so the model class is imported only when needed.
|
||||
|
||||
## Stage Configuration
|
||||
## Pipeline and Deploy Configuration
|
||||
|
||||
Create a YAML configuration file in `vllm_omni/deploy/`. For a complete example, see the [Qwen3-Omni configuration file](gh-file:vllm_omni/deploy/qwen3_omni_moe.yaml).
|
||||
Define fixed topology in `vllm_omni/model_executor/models/<model>/pipeline.py`
|
||||
with `PipelineConfig` and `StagePipelineConfig`, then register it in
|
||||
`vllm_omni/config/pipeline_registry.py`. For a complete example, see the
|
||||
[Qwen3-Omni pipeline](gh-file:vllm_omni/model_executor/models/qwen3_omni/pipeline.py).
|
||||
|
||||
### Key Configuration Fields
|
||||
### Pipeline topology fields
|
||||
|
||||
- **`model_stage`**: Which stage to run ("thinker", "talker", "code2wav", etc.)
|
||||
- **`model_arch`**: The model architecture name (must match registry)
|
||||
- **`engine_input_source`**: List of stage IDs that provide input to this stage
|
||||
- **`custom_process_input_func`**: Function to process inputs from previous stages
|
||||
- **`final_output`**: Whether this stage produces the final output (True/False)
|
||||
- **`final_output_type`**: Type of final output ("text", "audio", "image", etc.)
|
||||
- **`model_stage`**: Logical stage name ("thinker", "talker", "code2wav", etc.)
|
||||
- **`execution_type`**: Runtime family (`LLM_AR`, `LLM_GENERATION`, or `DIFFUSION`)
|
||||
- **`model_arch`**: Stage architecture name, when different from the pipeline default
|
||||
- **`input_sources`**: Upstream stage IDs that provide input to this stage
|
||||
- **`custom_process_input_func`**: Function that processes inputs from previous stages
|
||||
- **`final_output`**: Whether this stage produces user-facing output
|
||||
- **`final_output_type`**: Output modality ("text", "audio", "image", etc.)
|
||||
- **`owns_tokenizer`**: Whether this stage owns the pipeline tokenizer
|
||||
|
||||
Create the matching runtime defaults in `vllm_omni/deploy/<model>.yaml` and set
|
||||
`PipelineConfig.default_deploy_config_name` to that file. The deploy YAML owns
|
||||
GPU placement, memory sizing, parallelism, connectors, and sampling defaults;
|
||||
it must not redefine topology fields.
|
||||
|
||||
## Stage Input Processors
|
||||
|
||||
@@ -374,7 +384,7 @@ The stage transition process follows these steps:
|
||||
|
||||
2. **Transition Detection**: The orchestrator checks if there's a next stage and calls `process_engine_inputs()` on it
|
||||
|
||||
3. **Input Processing**: The stage input processor configured in stage YAML (under `vllm_omni/model_executor/stage_input_processors/`) handles the transition:
|
||||
3. **Input Processing**: The stage input processor registered by the pipeline (implemented under `vllm_omni/model_executor/stage_input_processors/`) handles the transition:
|
||||
```python
|
||||
def process_engine_inputs(
|
||||
self, stage_list: list[Any], prompt: OmniTokensPrompt | TextPrompt = None
|
||||
@@ -577,7 +587,7 @@ Adding a new model to vLLM-Omni involves:
|
||||
1. **Create model directory structure** with stage implementations
|
||||
2. **Implement unified model class** that orchestrates stages
|
||||
3. **Register model** in `registry.py`
|
||||
4. **Create stage configuration** YAML file
|
||||
4. **Define pipeline topology and deploy defaults** in `pipeline.py` and `vllm_omni/deploy/`
|
||||
5. **Implement stage input processors** for stage transitions
|
||||
6. **Write tests** to verify functionality
|
||||
7. **Add model recipe** to the [vllm-project/recipes](https://github.com/vllm-project/recipes) repository (see [Adding a Model Recipe](#adding-a-model-recipe) section)
|
||||
@@ -590,7 +600,8 @@ For a complete reference implementation, see:
|
||||
- **Thinker**: `vllm_omni/model_executor/models/qwen3_omni/qwen3_omni_moe_thinker.py`
|
||||
- **Talker**: `vllm_omni/model_executor/models/qwen3_omni/qwen3_omni_moe_talker.py`
|
||||
- **Code2Wav**: `vllm_omni/model_executor/models/qwen3_omni/qwen3_omni_code2wav.py`
|
||||
- **Stage config**: `vllm_omni/deploy/qwen3_omni_moe.yaml`
|
||||
- **Pipeline topology**: `vllm_omni/model_executor/models/qwen3_omni/pipeline.py`
|
||||
- **Deploy config**: `vllm_omni/deploy/qwen3_omni_moe.yaml`
|
||||
- **Input processors**: `vllm_omni/model_executor/stage_input_processors/qwen3_omni.py`
|
||||
- **Registry**: `vllm_omni/model_executor/models/registry.py`
|
||||
- **Testing**: `vllm_omni/tests/e2e/offline_inference/test_qwen3_omni.py`
|
||||
@@ -598,4 +609,4 @@ For a complete reference implementation, see:
|
||||
For more information, see:
|
||||
- [Architecture Overview](../../design/architecture_overview.md)
|
||||
- [Supported Models](../../models/supported_models.md)
|
||||
- [Stage Configuration Guide](../../configuration/stage_configs.md)
|
||||
- [Pipeline and Deploy Configuration Guide](../../configuration/stage_configs.md)
|
||||
@@ -20,7 +20,7 @@ pattern, refer to MOSS-TTS-Nano.
|
||||
4. [Step-by-Step Implementation](#step-by-step-implementation)
|
||||
5. [Key Components](#key-components)
|
||||
6. [Model Registration](#model-registration)
|
||||
7. [Stage Configuration](#stage-configuration)
|
||||
7. [Pipeline and Deploy Configuration](#pipeline-and-deploy-configuration)
|
||||
8. [Stage Input Processors](#stage-input-processors)
|
||||
9. [Online Serving Integration](#online-serving-integration)
|
||||
10. [Single-Stage Models](#single-stage-models)
|
||||
@@ -78,7 +78,7 @@ Profile before optimizing.
|
||||
new TTS model must pass all three levels:
|
||||
|
||||
| Layer | Catches | Tool |
|
||||
|-------|---------|------|
|
||||
| ------- | --------- | ------ |
|
||||
| Offline RTF / duration | Throughput regressions, missing audio, wrong sample rate | `end2end.py`, pytest e2e |
|
||||
| Browser streaming playback | Delta-vs-cumulative bugs, chunk boundary glitches, TTFP regressions | Gradio demo over `/v1/audio/speech?stream=true` |
|
||||
| Concurrent requests | Per-request state leaks, codec window round-robin gaps | `max_num_seqs>1` smoke with 4+ parallel prompts |
|
||||
@@ -94,10 +94,10 @@ the symptom is crosstalk or truncation under load, nothing in single-request tes
|
||||
vLLM-Omni supports TTS models as multi-stage pipelines where each stage runs independently
|
||||
and can be placed on different devices. Qwen3-TTS has two stages:
|
||||
|
||||
| Stage | Name | Input | Output |
|
||||
|-------|------|-------|--------|
|
||||
| 0 | Code Predictor (AR) | Text tokens | Discrete RVQ codec codes |
|
||||
| 1 | Code2Wav (Decoder) | RVQ codec codes | Audio waveform |
|
||||
| Stage | Name | Input | Output |
|
||||
| ----- | ------------------- | --------------- | ------------------------ |
|
||||
| 0 | Code Predictor (AR) | Text tokens | Discrete RVQ codec codes |
|
||||
| 1 | Code2Wav (Decoder) | RVQ codec codes | Audio waveform |
|
||||
|
||||
Each stage is a separate model class configured independently via YAML. The two stages
|
||||
are connected by the `async_chunk` framework, which enables inter-stage streaming for
|
||||
@@ -170,7 +170,7 @@ and Qwen3-Omni).
|
||||
|
||||
When adding a new TTS model, create the following structure:
|
||||
|
||||
```
|
||||
```text
|
||||
vllm_omni/model_executor/models/
|
||||
your_model_name/
|
||||
__init__.py
|
||||
@@ -201,7 +201,7 @@ it would not be picked up — the hub README is the documented surface.
|
||||
**Qwen3-TTS reference files:**
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| ------ | --------- |
|
||||
| `models/qwen3_tts/qwen3_tts.py` | Unified model class |
|
||||
| `models/qwen3_tts/qwen3_tts_code_predictor_vllm.py` | Stage 0 - optimized AR |
|
||||
| `models/qwen3_tts/qwen3_tts_code2wav.py` | Stage 1 - decoder |
|
||||
@@ -427,112 +427,93 @@ _OMNI_MODELS = {
|
||||
|
||||
The registry uses lazy loading - model classes are only imported when needed.
|
||||
|
||||
## Stage Configuration
|
||||
## Pipeline and Deploy Configuration
|
||||
|
||||
Each stage has a `worker_type` that determines how it is scheduled:
|
||||
Define fixed topology in `models/<model>/pipeline.py`. The execution type
|
||||
selects the scheduler and worker family:
|
||||
|
||||
- `worker_type: ar` - autoregressive stage, uses `OmniARScheduler` with PagedAttention
|
||||
- `worker_type: generation` - non-AR stage (e.g. decoder), uses `OmniGenerationScheduler`
|
||||
- `StageExecutionType.LLM_AR` uses the autoregressive runtime with PagedAttention.
|
||||
- `StageExecutionType.LLM_GENERATION` uses the generation runtime for stages such as audio decoders.
|
||||
|
||||
Key configuration fields:
|
||||
Key topology fields belong to `StagePipelineConfig`:
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| `model_stage` | Which stage to initialize (`ar_stage`, `decoder`, etc.) |
|
||||
| `model_arch` | Architecture name, must match `registry.py` |
|
||||
| `engine_input_source` | List of upstream stage IDs that provide input (e.g. `[0]`) |
|
||||
| `engine_output_type` | Output type: `latent` for intermediate, `audio` for final |
|
||||
| `custom_process_next_stage_input_func` | Async chunk processor function path (streaming only) |
|
||||
| `final_output` | Whether this stage produces the final user-facing output |
|
||||
| `final_output_type` | Type of final output (`audio`, `text`, etc.) |
|
||||
| `model_stage` | Logical stage name (`ar_stage`, `decoder`, etc.). |
|
||||
| `execution_type` | Runtime family for this stage. |
|
||||
| `input_sources` | Upstream stage IDs that provide input. |
|
||||
| `model_arch` | Stage-specific architecture name, when it differs from the pipeline default. |
|
||||
| `engine_output_type` | Output representation such as `latent` or `audio`. |
|
||||
| `custom_process_next_stage_input_func` | Processor for full-payload stage handoff. |
|
||||
| `async_chunk_process_next_stage_input_func` | Processor for streaming chunk handoff. |
|
||||
| `final_output` / `final_output_type` | Whether this stage produces user-facing output and its modality. |
|
||||
| `owns_tokenizer` | Whether this stage supplies the pipeline tokenizer. |
|
||||
|
||||
!!! note
|
||||
New in-tree models should define frozen topology in `models/<model>/pipeline.py`,
|
||||
register it in `vllm_omni/config/pipeline_registry.py`, and put deployment
|
||||
knobs in `vllm_omni/deploy/<model>.yaml`. Use `--deploy-config` to load a
|
||||
custom deployment YAML.
|
||||
For example, a two-stage TTS topology can be defined as:
|
||||
|
||||
### Batch mode
|
||||
```python
|
||||
from vllm_omni.config.stage_config import (
|
||||
PipelineConfig,
|
||||
StageExecutionType,
|
||||
StagePipelineConfig,
|
||||
)
|
||||
|
||||
```yaml
|
||||
# stage_configs/your_model_name.yaml
|
||||
_PROC = "vllm_omni.model_executor.stage_input_processors.your_model_name"
|
||||
|
||||
stage_args:
|
||||
- stage_id: 0
|
||||
stage_type: llm
|
||||
runtime:
|
||||
devices: "0"
|
||||
engine_args:
|
||||
model_stage: ar_stage
|
||||
max_num_seqs: 64
|
||||
model_arch: YourTTSModelForConditionalGeneration
|
||||
worker_type: ar
|
||||
scheduler_cls: vllm_omni.core.sched.omni_ar_scheduler.OmniARScheduler
|
||||
engine_output_type: latent
|
||||
default_sampling_params:
|
||||
temperature: 0.9
|
||||
top_k: 50
|
||||
max_tokens: 2048
|
||||
|
||||
- stage_id: 1
|
||||
stage_type: llm
|
||||
runtime:
|
||||
devices: "0"
|
||||
engine_args:
|
||||
model_stage: decoder
|
||||
model_arch: YourTTSModelForConditionalGeneration
|
||||
worker_type: generation
|
||||
scheduler_cls: vllm_omni.core.sched.omni_generation_scheduler.OmniGenerationScheduler
|
||||
engine_output_type: audio
|
||||
engine_input_source: [0]
|
||||
final_output: true
|
||||
final_output_type: audio
|
||||
YOUR_TTS_PIPELINE = PipelineConfig(
|
||||
model_type="your_model_name",
|
||||
default_deploy_config_name="your_model_name.yaml",
|
||||
model_arch="YourTTSModelForConditionalGeneration",
|
||||
stages=(
|
||||
StagePipelineConfig(
|
||||
stage_id=0,
|
||||
model_stage="ar_stage",
|
||||
execution_type=StageExecutionType.LLM_AR,
|
||||
input_sources=(),
|
||||
owns_tokenizer=True,
|
||||
engine_output_type="latent",
|
||||
custom_process_next_stage_input_func=f"{_PROC}.ar2decoder",
|
||||
async_chunk_process_next_stage_input_func=f"{_PROC}.ar2decoder_async_chunk",
|
||||
),
|
||||
StagePipelineConfig(
|
||||
stage_id=1,
|
||||
model_stage="decoder",
|
||||
execution_type=StageExecutionType.LLM_GENERATION,
|
||||
input_sources=(0,),
|
||||
model_arch="YourTTSDecoder",
|
||||
engine_output_type="audio",
|
||||
final_output=True,
|
||||
final_output_type="audio",
|
||||
),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
### Streaming mode (async_chunk)
|
||||
|
||||
Add `async_chunk: true` at the top level and specify `custom_process_next_stage_input_func`
|
||||
on Stage 0 to define how intermediate outputs are chunked and forwarded:
|
||||
Register the pipeline in `vllm_omni/config/pipeline_registry.py`. Runtime
|
||||
placement and sizing belong in `vllm_omni/deploy/your_model_name.yaml`:
|
||||
|
||||
```yaml
|
||||
# stage_configs/your_model_name_async_chunk.yaml
|
||||
|
||||
async_chunk: true
|
||||
|
||||
stage_args:
|
||||
stages:
|
||||
- stage_id: 0
|
||||
stage_type: llm
|
||||
runtime:
|
||||
devices: "0"
|
||||
engine_args:
|
||||
model_stage: ar_stage
|
||||
max_num_seqs: 64
|
||||
model_arch: YourTTSModelForConditionalGeneration
|
||||
worker_type: ar
|
||||
scheduler_cls: vllm_omni.core.sched.omni_ar_scheduler.OmniARScheduler
|
||||
engine_output_type: latent
|
||||
custom_process_next_stage_input_func: >
|
||||
vllm_omni.model_executor.stage_input_processors.your_model_name.ar2decoder_async_chunk
|
||||
devices: "0"
|
||||
max_num_seqs: 64
|
||||
default_sampling_params:
|
||||
temperature: 0.9
|
||||
top_k: 50
|
||||
max_tokens: 2048
|
||||
|
||||
- stage_id: 1
|
||||
stage_type: llm
|
||||
runtime:
|
||||
devices: "0"
|
||||
engine_args:
|
||||
model_stage: decoder
|
||||
model_arch: YourTTSModelForConditionalGeneration
|
||||
worker_type: generation
|
||||
scheduler_cls: vllm_omni.core.sched.omni_generation_scheduler.OmniGenerationScheduler
|
||||
engine_output_type: audio
|
||||
engine_input_source: [0]
|
||||
final_output: true
|
||||
final_output_type: audio
|
||||
devices: "0"
|
||||
max_num_seqs: 1
|
||||
```
|
||||
|
||||
Set `async_chunk: false` for end-to-end handoff. The registered pipeline
|
||||
selects the full-payload or async chunk processor; processor paths and topology
|
||||
must not be moved into the deploy YAML. Use `--deploy-config` to load a custom
|
||||
deployment overlay.
|
||||
|
||||
## Stage Input Processors
|
||||
|
||||
Stage input processors convert Stage 0 outputs into Stage 1 inputs. Create yours in
|
||||
@@ -547,9 +528,9 @@ Understanding what's available in stage outputs:
|
||||
- `stage_list[source_id].engine_outputs` - list of `EngineCoreOutput` objects
|
||||
- Each `EngineCoreOutput` has `outputs` - list of `RequestOutput` objects
|
||||
- Each `RequestOutput` has:
|
||||
- `token_ids` - generated token IDs
|
||||
- `multimodal_output` - dict with keys matching your model's `OmniOutput.multimodal_outputs`
|
||||
- `prompt_token_ids` - original prompt token IDs
|
||||
- `token_ids` - generated token IDs
|
||||
- `multimodal_output` - dict with keys matching your model's `OmniOutput.multimodal_outputs`
|
||||
- `prompt_token_ids` - original prompt token IDs
|
||||
|
||||
### Batch mode (non-streaming)
|
||||
|
||||
@@ -629,6 +610,7 @@ def ar2decoder_async_chunk(
|
||||
```
|
||||
|
||||
Key points:
|
||||
|
||||
- `transfer_manager` is the `OmniChunkTransferAdapter` that owns the chunk lifecycle
|
||||
- Each call appends one AR decode step's output; a chunk is emitted every `chunk_size` steps
|
||||
- The final (possibly partial) chunk is flushed when `is_finished` is true
|
||||
@@ -683,6 +665,7 @@ Create `vllm_omni/entrypoints/openai/tts_adapters/your_model.py`:
|
||||
|
||||
```python
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
"""YourModel serving adapter."""
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
@@ -821,7 +804,7 @@ directly from the model's own generator.
|
||||
|
||||
### Directory structure
|
||||
|
||||
```
|
||||
```text
|
||||
vllm_omni/model_executor/models/your_model_name/
|
||||
__init__.py
|
||||
modeling_your_model_name.py # unified class: load_weights + forward + streaming
|
||||
@@ -832,32 +815,40 @@ vllm_omni/deploy/your_model_name.yaml
|
||||
|
||||
No stage input processor is needed.
|
||||
|
||||
### Stage config
|
||||
### Pipeline and deploy config
|
||||
|
||||
Use a single stage with `worker_type: ar`. The `is_comprehension: true` field and the
|
||||
top-level `async_chunk: false` are required — omitting them causes silent
|
||||
misclassification in the serving layer. Set `max_num_seqs` to at least 4 for
|
||||
concurrent production use.
|
||||
Use a single `LLM_AR` stage that owns the tokenizer and produces final audio:
|
||||
|
||||
```python
|
||||
YOUR_TTS_PIPELINE = PipelineConfig(
|
||||
model_type="your_model_name",
|
||||
default_deploy_config_name="your_model_name.yaml",
|
||||
model_arch="YourModelForCausalLM",
|
||||
stages=(
|
||||
StagePipelineConfig(
|
||||
stage_id=0,
|
||||
model_stage="your_model_stage_key",
|
||||
execution_type=StageExecutionType.LLM_AR,
|
||||
input_sources=(),
|
||||
owns_tokenizer=True,
|
||||
engine_output_type="audio",
|
||||
final_output=True,
|
||||
final_output_type="audio",
|
||||
),
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
The deploy YAML controls runtime behavior. Set `max_num_seqs` to at least 4
|
||||
for concurrent production use:
|
||||
|
||||
```yaml
|
||||
# stage_configs/your_model_name.yaml
|
||||
async_chunk: false
|
||||
|
||||
stage_args:
|
||||
stages:
|
||||
- stage_id: 0
|
||||
stage_type: llm
|
||||
is_comprehension: true # required for serving_speech.py dispatch
|
||||
runtime:
|
||||
devices: "0"
|
||||
engine_args:
|
||||
model_stage: your_model_stage_key
|
||||
model_arch: YourModelForCausalLM
|
||||
worker_type: ar
|
||||
scheduler_cls: vllm_omni.core.sched.omni_ar_scheduler.OmniARScheduler
|
||||
engine_output_type: audio
|
||||
max_num_seqs: 4 # min 4 for concurrent requests; default 1 causes gaps
|
||||
final_output: true
|
||||
final_output_type: audio
|
||||
devices: "0"
|
||||
max_num_seqs: 4
|
||||
```
|
||||
|
||||
### Generator-based streaming pattern
|
||||
@@ -961,10 +952,17 @@ is correct. Stage the modified files and commit again — do not revert the chan
|
||||
Common failures and fixes:
|
||||
|
||||
| Check | Cause | Fix |
|
||||
|-------|-------|-----|
|
||||
| ------- | ------- | ----- |
|
||||
| `ruff F841` | Local variable assigned but never used | Remove the extraction or forward it to the model call |
|
||||
| `ruff E402` | Module-level import not at top of file | Move import to the top-level import block |
|
||||
| `ruff format` | Line length, spacing, or quote style | Accept the auto-fix, stage, and re-commit |
|
||||
| `check-spdx-header` | Missing header, or copyright still says `vLLM project` | Use `Copyright contributors to the vLLM-Omni project`; restage the rewrite |
|
||||
| `check-forbidden-imports` | Stdlib `re`/`base64`, pickle, Hugging Face Hub API, or direct Triton/TileLang | `import regex as re` and `pybase64`; do not grow the allowlist without review |
|
||||
| `check-torch-cuda-call` | New `torch.cuda.*` call site | Use `current_omni_platform`; do not grow `ALLOWED_FILES` without review |
|
||||
| `check-tts-adapter-migration` | New `_tts_model_type` branch in `serving_speech.py` | Put logic in `tts_adapters/`; lower `MAX_MODEL_TYPE_BRANCHES` when removing branches |
|
||||
| `check-test-ci-coverage` | Test file missing level or hardware mark | Add `core_model`/… plus `cpu`/`cuda`/`hardware_test(` |
|
||||
| `shellcheck` | Native `shellcheck` missing, or script warning | Install via apt/dnf/brew (or `shellcheck.exe` on Windows). See [Linting](../README.md#linting) |
|
||||
| `mypy-3.10` / `markdownlint-cli2` / `check-buildkite` | Types, docs markdown, or Buildkite YAML | See [Linting](../README.md#linting) |
|
||||
|
||||
### DCO sign-off
|
||||
|
||||
@@ -1019,7 +1017,7 @@ Adding a TTS model to vLLM-Omni involves:
|
||||
### Qwen3-TTS Reference Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| ------ | --------- |
|
||||
| `models/qwen3_tts/qwen3_tts.py` | Unified model class |
|
||||
| `models/qwen3_tts/qwen3_tts_code_predictor_vllm.py` | AR stage with vLLM fused ops |
|
||||
| `models/qwen3_tts/qwen3_tts_code2wav.py` | Decoder stage with `chunked_decode_streaming()` |
|
||||
@@ -1031,4 +1029,4 @@ For more information, see:
|
||||
|
||||
- [Architecture Overview](../../design/architecture_overview.md)
|
||||
- [Async Chunk Design](../../design/feature/async_chunk.md)
|
||||
- [Stage Configuration Guide](../../configuration/stage_configs.md)
|
||||
- [Pipeline and Deploy Configuration Guide](../../configuration/stage_configs.md)
|
||||
@@ -4,6 +4,9 @@
|
||||
> `experimental/ar_diffusion` contract. It follows the ownership and lifecycle
|
||||
> direction in [#5137](https://github.com/vllm-project/vllm-omni/issues/5137),
|
||||
> but it is not yet part of the stable module-design hierarchy.
|
||||
>
|
||||
> The end-to-end request, identity, failure, and memory contracts are documented
|
||||
> in [Realtime AR-Diffusion sessions](feature/realtime_ar_diffusion.md).
|
||||
|
||||
`ARDiffusionEngine` is an opt-in diffusion backend for pipelines that keep
|
||||
autoregressive attention KV across requests. The engine only selects
|
||||
@@ -51,14 +54,13 @@ time, and its inherited batch/step entry points also fail explicitly. Supporting
|
||||
those paths requires a batch-aware state-binding contract rather than silently
|
||||
bypassing `bind_ar_diffusion_state()`.
|
||||
|
||||
The current implementation retains one session per model instance. A request
|
||||
for a different `session_id` closes the resident session through the same LRU
|
||||
lifecycle used by explicit close and failure cleanup before allocating the new
|
||||
one. Self-attention and cross-attention memory are therefore sized for one
|
||||
resident session even if the pipeline declares a larger `session_capacity`.
|
||||
This prioritizes rollout throughput and prevents block-pool exhaustion before a
|
||||
count-based eviction can run. Multi-session residency can be added later with a
|
||||
memory-backed capacity calculation or allocation-pressure eviction.
|
||||
The implementation may retain multiple sessions per model instance. It selects
|
||||
the largest feasible capacity up to the pipeline's `session_capacity`, based on
|
||||
self-attention pages, cross-attention allocations, scratch, and declared
|
||||
model-owned state. One session is admitted whenever it fits actual free device
|
||||
memory; `gpu_memory_fraction` controls additional residency. Requests beyond
|
||||
that capacity evict the least-recently-used session through the same lifecycle
|
||||
hook used by explicit close and failure cleanup.
|
||||
|
||||
Scratch storage is also capability-driven. `frames_per_block` reserves space for
|
||||
an uncommitted current video block, while `max_scratch_tokens_per_branch`
|
||||
|
||||
@@ -335,8 +335,8 @@ The single resolution boundary is implemented by
|
||||
`StageConfigFactory.create_from_model()` and
|
||||
`VllmOmniConfig.from_pipeline_config()` in
|
||||
[`vllm_omni/config`](https://github.com/vllm-project/vllm-omni/tree/main/vllm_omni/config).
|
||||
The legacy `stage_args` YAML path remains only for models that have not yet
|
||||
migrated to `PipelineConfig` and `DeployConfig`.
|
||||
The legacy `stage_args` YAML path has been removed. Model topology now resolves
|
||||
through `PipelineConfig`, with runtime overrides supplied by `DeployConfig`.
|
||||
|
||||
In the typed path, each stage configuration derives from
|
||||
`BaseVllmOmniStageConfig` and is specialized as
|
||||
@@ -406,7 +406,7 @@ the source for configuration, compatibility, and implementation details.
|
||||
stage contract.
|
||||
* **Quantization and memory efficiency:** [Quantization](feature/quantization.md)
|
||||
resolves per-pipeline or per-component quantization configurations, while
|
||||
[Distributed Layerwise Offload](feature/distributed_layerwise_offload.md)
|
||||
[Distributed Layerwise Offload](feature/offloader/distributed_layerwise_offload.md)
|
||||
streams diffusion blocks from host memory within the existing parallel
|
||||
topology.
|
||||
|
||||
|
||||
@@ -211,38 +211,39 @@ In sequential mode, each stage must wait for the previous stage to complete enti
|
||||
|
||||
## Configuration
|
||||
|
||||
Enable async_chunk in stage configuration YAML:
|
||||
Enable async chunk mode in the deploy YAML:
|
||||
|
||||
```yaml
|
||||
async_chunk: true
|
||||
stage_args:
|
||||
- stage_id: 0
|
||||
engine_args:
|
||||
custom_process_next_stage_input_func: vllm_omni.model_executor.stage_input_processors.qwen3_omni.thinker2talker_async_chunk
|
||||
- stage_id: 1
|
||||
engine_args:
|
||||
custom_process_next_stage_input_func: vllm_omni.model_executor.stage_input_processors.qwen3_omni.talker2code2wav_async_chunk
|
||||
```
|
||||
|
||||
### Stage Configuration
|
||||
The registered `PipelineConfig` owns the async handoff processor functions.
|
||||
For Qwen3-Omni these are `thinker2talker_async_chunk` and
|
||||
`talker2code2wav_async_chunk`; deploy YAML only selects the mode and runtime
|
||||
sizing.
|
||||
|
||||
### Configuration ownership
|
||||
|
||||
- `async_chunk: bool`: Enable/disable async chunk mode
|
||||
- `custom_process_next_stage_input_func: str`: Path to custom chunk processing function; receives `(transfer_manager, pooling_output, request)`. For qwen3-omni: `thinker2talker_async_chunk`, `talker2code2wav_async_chunk`
|
||||
- `stage_connector_config: dict`: Connector configuration
|
||||
- `worker_type: str`: Model type, e.g. `"ar"` or `"generation"` (used by OmniChunkTransferAdapter for mode-specific payload handling)
|
||||
- `async_chunk_process_next_stage_input_func: str`: Pipeline-owned chunk processor path
|
||||
- `execution_type: StageExecutionType`: Pipeline-owned runtime family
|
||||
- `connectors: dict`: Deploy-owned connector definitions
|
||||
- `max_num_seqs: int`: Maximum number of sequences for concurrent processing in the stage
|
||||
|
||||
|
||||
### Connector Configuration
|
||||
|
||||
```yaml
|
||||
connectors:
|
||||
- from_stage: 0
|
||||
to_stage: 1
|
||||
spec:
|
||||
name: SharedMemoryConnector
|
||||
extra:
|
||||
stage_id: 0
|
||||
connector_of_shared_memory:
|
||||
name: SharedMemoryConnector
|
||||
|
||||
stages:
|
||||
- stage_id: 0
|
||||
output_connectors:
|
||||
to_stage_1: connector_of_shared_memory
|
||||
- stage_id: 1
|
||||
input_connectors:
|
||||
from_stage_0: connector_of_shared_memory
|
||||
```
|
||||
|
||||
### Code2Wav Batch Configuration
|
||||
@@ -250,13 +251,10 @@ connectors:
|
||||
For optimal performance with async_chunk, the code2wav stage should be configured with batching:
|
||||
|
||||
```yaml
|
||||
stage_args:
|
||||
stages:
|
||||
- stage_id: 2 # code2wav stage
|
||||
runtime:
|
||||
devices: "1"
|
||||
engine_args:
|
||||
model_stage: code2wav
|
||||
max_num_seqs: 64 # Enables batched audio generation
|
||||
devices: "1"
|
||||
max_num_seqs: 64 # Enables batched audio generation
|
||||
```
|
||||
|
||||
## Related Files
|
||||
|
||||
@@ -117,7 +117,22 @@ After (async D2H):
|
||||
|
||||
### Batch Split
|
||||
|
||||
When `execute_model_batch` returns a `COMPUTE_DONE` with a single `async_output_id` for the entire batch, the executor splits it into per-request `async_output_id`s (format `{batch_id}/{request_id}`) via `_batch_split_map`. When `OUTPUT_READY` arrives, the pump extracts per-request results from the batch output and resolves each request's output future independently.
|
||||
When `execute_model_batch` returns a `COMPUTE_DONE` with a single `async_output_id` for the entire batch, the executor splits it into per-request `async_output_id`s (format `{batch_id}/{request_id}`) via `_batch_split_map`. When `OUTPUT_READY` arrives, the pump extracts per-request results from the batch output and resolves each request's output future independently. If `OUTPUT_READY` arrives before `execute_batch` registers the split map, `execute_batch` directly adopts the early output.
|
||||
|
||||
### Reliability, Lifecycle & Timeout Behavior
|
||||
|
||||
1. **Drain Before Memory Release (`drain_async_outputs` / `_ASYNC_OUTPUT_DRAIN_TIMEOUT_S`)**:
|
||||
When workers transition into sleep states (`handle_sleep_task`) or invoke memory-releasing methods, `WorkerProc.drain_async_outputs()` blocks up to `_ASYNC_OUTPUT_DRAIN_TIMEOUT_S` (10.0s) until all in-flight background D2H/SHM packing tasks finish. This acts as a synchronization barrier preventing worker sleep cycles from releasing device tensors while the side CUDA stream is still actively reading them. Draining typically completes within 10–50 ms under normal operation.
|
||||
|
||||
2. **Timeout Diagnostics (`_async_output_timeout()`)**:
|
||||
The engine waits for `wait_output_ready()` with a timeout of `_async_output_timeout()` — 600.0s by default, overridable per run with the `VLLM_OMNI_ASYNC_OUTPUT_TIMEOUT` environment variable (a non-numeric or non-positive value is ignored with a warning and the default applies, since this resolves on the request path). If a timeout occurs, the executor logs detailed diagnostic bookkeeping (pending futures, cached outputs, and batch split maps) to identify whether the stall occurred in the worker, pump, or waiter. The packing itself takes milliseconds, but the wait is queued behind the step's GPU work, so its wall-clock duration tracks step time; the bound is generous because a hung engine is surfaced by the worker monitor and `check_health()`, not by this timeout.
|
||||
|
||||
3. **Queue Serialization & Atomic Future Resolution**:
|
||||
- `result_mq` writes are serialized with `_result_mq_lock` to protect the single-writer `MessageQueue` against concurrent writes from the worker main loop (`COMPUTE_DONE`) and background thread (`OUTPUT_READY`).
|
||||
- `ResultPumpThread` unpacks shared-memory payloads first, and then atomically resolves waiting futures or populates `_completed_outputs` under `_futures_lock`, avoiding race conditions with concurrent `wait_output_ready()` invocations.
|
||||
|
||||
4. **Storage-Aware IPC Packing**:
|
||||
`pack_diffusion_output_shm()` evaluates `max(view_bytes, storage_bytes)` against `_SHM_TENSOR_THRESHOLD` (1 MB) to ensure that per-request slices sharing a large batch storage are moved to POSIX shared memory rather than serialized through pickle over the MessageQueue inline buffer.
|
||||
|
||||
## Model Coverage
|
||||
|
||||
@@ -131,6 +146,7 @@ All models running in request-mode (`step_execution=False`, the default) automat
|
||||
|---|---|---|
|
||||
| **HunyuanImage-3.0** | Image | `False` |
|
||||
| **Qwen-Image** | Image | `True` |
|
||||
| **LTX-2.3** | Video / Audio | `False` |
|
||||
|
||||
Other models with `step_execution=False` are also supported but not yet verified.
|
||||
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
# Diffusion Attention Backend Selection
|
||||
|
||||
This document defines the selection and extension contract for diffusion
|
||||
attention backends. User-facing backend choices, installation, and tuning are
|
||||
in the [attention backend guides](../../user_guide/diffusion/attention_backends.md).
|
||||
|
||||
## Scope
|
||||
|
||||
The contract applies to DiT and other diffusion attention layers. It is
|
||||
separate from vLLM's autoregressive attention selector.
|
||||
|
||||
The selection path has four responsibilities:
|
||||
|
||||
1. normalize user configuration into `AttentionConfig` and `AttentionSpec`;
|
||||
2. resolve a spec for an attention role;
|
||||
3. ask the active platform to validate an explicit backend or choose a
|
||||
hardware default; and
|
||||
4. load the selected `AttentionBackend` class from the registry path.
|
||||
|
||||
## Resolution contract
|
||||
|
||||
`get_attn_backend_for_role()` resolves configuration in this order:
|
||||
|
||||
1. exact `per_role[role]`;
|
||||
2. category `per_role[role_category]`;
|
||||
3. `default`;
|
||||
4. platform default.
|
||||
|
||||
An explicit resolution returns both the backend class and its
|
||||
`AttentionSpec`. A platform-default resolution returns the class and `None`.
|
||||
Layers must therefore treat the spec as optional and must not infer that a
|
||||
missing spec means SDPA.
|
||||
|
||||
Class resolution is cached by backend name, head size, and whether TRTLLM may
|
||||
be selected automatically. Logging is cached separately by role and source so
|
||||
the startup record identifies why each role received its backend.
|
||||
|
||||
## Registry and platform boundary
|
||||
|
||||
`DiffusionAttentionBackendEnum` maps stable configuration names to default
|
||||
qualified class paths. `register_diffusion_backend()` may replace a path at
|
||||
runtime without changing the public enum value.
|
||||
|
||||
The active `OmniPlatform` owns compatibility policy through
|
||||
`get_diffusion_attn_backend_cls()`. It must:
|
||||
|
||||
- validate explicit selections and fail with an actionable error when the
|
||||
requested kernel cannot run;
|
||||
- choose only an available, compatible default when no backend is explicit;
|
||||
- account for head size and other platform-visible constraints; and
|
||||
- return a qualified class path implementing `AttentionBackend`.
|
||||
|
||||
The selector must not duplicate device capability or package-availability
|
||||
policy that belongs to the platform.
|
||||
|
||||
## Typed backend options
|
||||
|
||||
Backend-specific settings remain typed fields on `AttentionSpec` rather than
|
||||
unstructured keyword dictionaries:
|
||||
|
||||
- `quant` is consumed by FlashInfer and TRTLLM with backend-specific value
|
||||
validation;
|
||||
- `skip_softmax` is consumed by TRTLLM; and
|
||||
- `block_sparse` is consumed by block-sparse backends such as RainFusion; and
|
||||
- `fastvideo_vsa_topk` is consumed by FastVideo VSA.
|
||||
|
||||
A backend reads only the fields it owns and rejects incompatible values. New
|
||||
options should be added to a shared typed spec only when more than one backend
|
||||
shares their semantics; otherwise add a dedicated typed block.
|
||||
|
||||
## Model integration contract
|
||||
|
||||
Each diffusion attention call declares a stable role and, when appropriate, a
|
||||
broader category. Model-specific roles permit precise overrides; categories
|
||||
preserve common `self` or `cross` policies. A model also decides whether its
|
||||
path is compatible with automatic TRTLLM selection, because only the model
|
||||
knows whether masking and packing satisfy the kernel contract.
|
||||
|
||||
## Adding or changing a backend
|
||||
|
||||
An implementation change is complete only when it:
|
||||
|
||||
1. implements the `AttentionBackend` interface and exposes a stable enum name;
|
||||
2. adds platform validation and default routing where appropriate;
|
||||
3. defines and validates any typed configuration;
|
||||
4. tests explicit selection, default selection, and incompatible paths;
|
||||
5. documents installation, fallback behavior, and quality implications in the
|
||||
corresponding user guide; and
|
||||
6. updates the overview matrix without moving algorithm details back into the
|
||||
landing page.
|
||||
|
||||
## FastVideo VSA model metadata
|
||||
|
||||
FastVideo VSA support is scoped to `FastVideo/FastWan2.2-TI2V-5B-Diffusers`, whose text-to-video and image-to-video modes both use `Wan22Pipeline`. It operates on a flattened DiT sequence but partitions tokens in
|
||||
the original latent video grid. Wan integrations therefore attach the
|
||||
post-patch `(T, H, W)` shape as `vsa_dit_seq_shape` attention metadata. The
|
||||
backend validates that `T * H * W` equals the sequence length, derives the
|
||||
runtime block count, and selects the configured top-k key/value blocks for
|
||||
each query block.
|
||||
|
||||
Checkpoint-specific compensation remains model-owned. Wan layers pass an
|
||||
optional learned `gate_compress` projection through attention metadata when
|
||||
the checkpoint contains those weights. Checkpoints without the projection do
|
||||
not allocate or execute it. When top-k selects every block, native checkpoints
|
||||
route to SDPA, while FastVideo DMD checkpoints preserve the VSA all-block path
|
||||
to retain checkpoint semantics.
|
||||
@@ -59,19 +59,18 @@ This `metadata` must be passed through the control plane so `get()` can locate t
|
||||
|
||||
## Configuration Model
|
||||
|
||||
Define connectors in runtime:
|
||||
Define connectors at the top level of the deploy YAML:
|
||||
|
||||
```yaml
|
||||
runtime:
|
||||
connectors:
|
||||
connector_of_shared_memory:
|
||||
name: SharedMemoryConnector
|
||||
connectors:
|
||||
connector_of_shared_memory:
|
||||
name: SharedMemoryConnector
|
||||
```
|
||||
|
||||
Wire stages to connectors:
|
||||
|
||||
```yaml
|
||||
stage_args:
|
||||
stages:
|
||||
- stage_id: 0
|
||||
output_connectors:
|
||||
to_stage_1: connector_of_shared_memory
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
# Distributed Layerwise Offload
|
||||
|
||||
This document describes distributed layerwise offload (DLO) for diffusion
|
||||
models. DLO keeps only a small number of DiT blocks on the accelerator and
|
||||
streams the remaining blocks from host memory. The distributed backend can
|
||||
either shard those host-side weights across an existing parallel group or keep
|
||||
the standard loader's rank-local weights and avoid an additional collective.
|
||||
|
||||
For user-facing commands, see the
|
||||
[distributed layerwise offloading guide](../../user_guide/diffusion/cpu_offload.md)
|
||||
and the [Cosmos3 recipe](https://github.com/vllm-project/vllm-omni/blob/main/recipes/cosmos3/Cosmos3-DistOffload.md).
|
||||
|
||||
## Status
|
||||
|
||||
DLO is implemented for multi-device diffusion execution. The default
|
||||
AllGather path is the primary path for DP and SP deployments. The
|
||||
`--dlo-no-use-allgather` path is a rank-local compatibility mode: it is useful
|
||||
for standard-loader sharding, workstation bring-up, and systems where an
|
||||
additional DLO collective is undesirable, but it does not reduce host weight
|
||||
storage across ranks.
|
||||
|
||||
The compatibility matrix below describes the current implementation. The
|
||||
unit-level guards are covered, but not every parallelism combination has a
|
||||
full model-and-hardware end-to-end test.
|
||||
|
||||
## Design
|
||||
|
||||
### DLO consumes the existing parallel topology
|
||||
|
||||
DLO does not create a new DP, TP, or SP topology. It reads the configured
|
||||
`DiffusionParallelConfig` and attaches offload hooks to the DiT blocks after the
|
||||
standard distributed groups have been initialized.
|
||||
|
||||
The DLO weight-sharding group is selected as follows:
|
||||
|
||||
1. Use the existing DP group when `data_parallel_size > 1`.
|
||||
2. When DP is one and SP is greater than one, use the SP group.
|
||||
3. Otherwise, run rank-locally without a DLO process group.
|
||||
|
||||
TP is deliberately not used as DLO's AllGather group. HSDP has its own
|
||||
parameter-sharding lifecycle and is not allowed to be sharded a second time by
|
||||
DLO's AllGather path.
|
||||
|
||||
### AllGather path
|
||||
|
||||
With the default `dlo_use_allgather=True`, each rank stores approximately
|
||||
`1 / group_size` of each streamable block in pinned host memory. The next
|
||||
block's shard is copied to a device buffer and reconstructed with
|
||||
`all_gather_into_tensor` on a communication stream while the current block is
|
||||
executing.
|
||||
|
||||
```text
|
||||
Compute: [Block N] [Block N+1] [Block N+2]
|
||||
H2D: [shard N+1] [shard N+2]
|
||||
AllGather: [full N+1] [full N+2]
|
||||
Buffers: [current slot] [prefetch slot] [current slot]
|
||||
```
|
||||
|
||||

|
||||
|
||||
The backend uses two shared device buffers, so accelerator weight residency is
|
||||
bounded by the largest streamed blocks rather than the complete model.
|
||||
|
||||
When DP is greater than one, the engine can process one request per DP rank in
|
||||
the same denoising wave. Because AllGather is a collective, all participating
|
||||
requests must take the same execution path at every denoising step.
|
||||
|
||||
### Rank-local path without DLO AllGather
|
||||
|
||||
With `--dlo-no-use-allgather`, DLO forces its internal offload shard size to
|
||||
one. The regular model loader remains responsible for preparing each rank's
|
||||
weights, including TP-local tensors or HSDP-managed parameters. DLO then
|
||||
streams those rank-local tensors block by block using H2D copies only.
|
||||
|
||||
This mode means:
|
||||
|
||||
- DP still provides independent replicas, but DLO does not shard weights
|
||||
across DP ranks.
|
||||
- SP still performs its normal activation/attention collectives, but DLO does
|
||||
not shard weights across SP ranks.
|
||||
- TP/HSDP/SP collectives, if configured, are not disabled by this flag; only
|
||||
DLO's additional weight AllGather is disabled.
|
||||
- Pure DP deployments keep a full host-side model copy per rank, subject to
|
||||
shared OS page-cache behavior.
|
||||
- The scheduler does not require a synchronized DP request wave for DLO.
|
||||
|
||||
This path is intentionally not implemented by reusing the AllGather mmap
|
||||
loader. It relies on the standard loader so model-specific TP/HSDP transforms
|
||||
remain intact.
|
||||
|
||||
## Parallelism compatibility
|
||||
|
||||
| Parallelism | DLO + AllGather | DLO without AllGather |
|
||||
|---|---|---|
|
||||
| **DP** | Supported primary path. DLO shards host weights across the DP group and can run DP multi-concurrency. | Supported rank-local path. DP replicas remain independent; no DLO weight sharding or cross-DP DLO collective. |
|
||||
| **SP** | Supported in the implementation. With DP=1, DLO uses the SP group for host-weight sharding; SP still shards sequence/activation work. | SP remains active, but DLO keeps standard-loader rank-local weights and adds no SP weight collective. |
|
||||
| **TP > 1** | Unsupported in the DLO mmap path. TP-aware loader callbacks are bypassed, so the backend rejects this configuration when it enters that path. | Standard loading is retained and TP-local tensors can be streamed. This is the intended compatibility path, but it still needs broader model and hardware validation. |
|
||||
| **HSDP** | Rejected. HSDP has already sharded parameters, so DLO AllGather would double-shard them. | Accepted by configuration. HSDP owns parameter sharding and its own gathers; DLO only stages rank-local parameters. End-to-end coverage is limited. |
|
||||
|
||||
### Combined dimensions
|
||||
|
||||
- **DP + SP:** DLO uses the DP group for weight sharding when DP is greater
|
||||
than one; SP continues to use its own sequence-parallel group. If DP is one,
|
||||
the SP group becomes DLO's sharding group in AllGather mode.
|
||||
- **DP + TP/SP without AllGather:** standard model loading defines the
|
||||
rank-local tensor layout. DLO adds no cross-DP, cross-TP, or cross-SP weight
|
||||
collective.
|
||||
- **HSDP + SP:** the general parallel configuration permits HSDP over SP, but
|
||||
DLO must use `--dlo-no-use-allgather`. HSDP remains responsible for weight
|
||||
materialization and synchronization.
|
||||
- **HSDP + DP or TP:** rejected independently by the diffusion parallel
|
||||
configuration.
|
||||
|
||||
## Request and loading constraints
|
||||
|
||||
AllGather DP multi-concurrency requires:
|
||||
|
||||
- explicit `num_inference_steps`;
|
||||
- the same `num_inference_steps` for all requests in a wave; and
|
||||
- identical request arguments that affect the collective execution path.
|
||||
|
||||
The no-AllGather path does not impose these DLO-specific synchronized-wave
|
||||
requirements.
|
||||
|
||||
The mmap loader is used only by the supported DLO+AllGather path when the
|
||||
model has a compatible checkpoint layout. Online quantization is incompatible
|
||||
with that sharded mmap path; use `--dlo-no-use-allgather` or disable online
|
||||
quantization. Models that do not meet the mmap requirements use the regular
|
||||
loader path.
|
||||
|
||||
## Validation coverage
|
||||
|
||||
Current source-level validation includes:
|
||||
|
||||
- HSDP + DLO + AllGather rejection;
|
||||
- HSDP + DLO without AllGather acceptance at configuration level;
|
||||
- TP rejection in the DLO+AllGather mmap path;
|
||||
- resident-layer requests requiring no-AllGather;
|
||||
- DP request-wave validation for denoising-step compatibility;
|
||||
- sharding, double-buffer, AllGather-size, and heterogeneous-block regression
|
||||
tests.
|
||||
|
||||
The highest-value missing coverage is end-to-end numerical comparison against
|
||||
ordinary layerwise offload for DP+SP, TP+no-AllGather, and HSDP+SP+no-AllGather
|
||||
on the target CUDA/NCCL or CANN/HCCL hardware.
|
||||
|
||||
## Recommendations
|
||||
|
||||
- Use **DP + DLO AllGather** for the supported throughput and host-memory
|
||||
scaling path.
|
||||
- Use **SP + DLO AllGather** for long-sequence workloads when DP concurrency is
|
||||
not the goal.
|
||||
- Use **no-AllGather** to bring up TP or workstation PCIe configurations, with
|
||||
the expectation of higher host-memory use and lower validation confidence.
|
||||
- Prefer **HSDP alone** for production HSDP deployments until the combined
|
||||
HSDP + DLO no-AllGather path has broader end-to-end coverage.
|
||||
@@ -0,0 +1,386 @@
|
||||
# Host Weight Runtime
|
||||
|
||||
The Host Weight Runtime is a loader-facing feature for reusing immutable,
|
||||
runtime-ready model weights across workers on one host. It lets a model
|
||||
integration replace repeated checkpoint loading and transformation with an
|
||||
exact lookup of a previously published host representation, while keeping the
|
||||
canonical model source authoritative.
|
||||
|
||||
This feature is shared infrastructure. Diffusion, autoregressive, speech, and
|
||||
future model integrations may depend on the top-level
|
||||
`vllm_omni.host_weight_runtime` package without depending on one another's
|
||||
loader or execution stack. The internal component and filesystem contracts are
|
||||
specified in the [Host Weight Runtime module design](../module/host_weight_runtime.md).
|
||||
|
||||
## Status
|
||||
|
||||
The first implementation provides contracts and a CPU local-filesystem store.
|
||||
The initial diffusion consumer contract additionally defines typed,
|
||||
representation-independent final-layout identity/restoration mechanics plus a
|
||||
concrete BF16-with-preserved-FP32 policy for MiniMax H3. It remains
|
||||
library-only: no loader or DLO path selects, publishes, restores, or transports
|
||||
that artifact yet.
|
||||
|
||||
V1 includes:
|
||||
|
||||
- exact runtime-weight identity and immutable manifests;
|
||||
- coordinated local lookup and one-producer publication;
|
||||
- descriptor-backed safetensors mmap leases;
|
||||
- preferred and required resolution policy;
|
||||
- explicit, separately reported post-load publication;
|
||||
- validation, deny, quarantine, cleanup, and capacity controls; and
|
||||
- typed reports for every terminal resolution outcome.
|
||||
|
||||
V1 does not include:
|
||||
|
||||
- a public CLI, loader activation, or default-on model integration;
|
||||
- lease handoff to DLO or another transport consumer;
|
||||
- FP8, quantized, merged-adaptation, or additional model producers;
|
||||
- CUDA registration, pinned staging, H2D scheduling, or GPU kernels;
|
||||
- a remote artifact provider or cross-node coordination;
|
||||
- automatic eviction; or
|
||||
- a change to DLO AllGather or no-AllGather behavior.
|
||||
|
||||
## Motivation and use cases
|
||||
|
||||
Model loading can create the same final host representation repeatedly. This
|
||||
is especially expensive when loading performs checkpoint decoding, tensor
|
||||
renaming, TP slicing, quantization, packing, or scale construction before GPU
|
||||
transfer. Independent workers may then retain private CPU copies of identical
|
||||
runtime weights.
|
||||
|
||||
The Host Weight Runtime is useful when:
|
||||
|
||||
- multiple same-node workers request semantically identical final weights;
|
||||
- constructing those weights is materially more expensive than validating and
|
||||
mapping a local artifact;
|
||||
- the runtime layout can be identified exactly and reproduced deterministically;
|
||||
- the workers can share immutable file-backed pages through the OS page cache;
|
||||
and
|
||||
- canonical loading remains available when policy permits fallback.
|
||||
|
||||
Typical consumers include same-node diffusion replicas, DLO host-weight
|
||||
sources, and future transformed or quantized model loaders. Request routing and
|
||||
replica orchestration remain outside this feature.
|
||||
|
||||
This feature is not zero-copy GPU execution. A lease exposes stable CPU tensor
|
||||
views and mapped ranges. A separate transport still decides whether to use
|
||||
registered mmap, private pinned staging, synchronous copies, or asynchronous
|
||||
H2D transfer.
|
||||
|
||||
## Resolution behavior
|
||||
|
||||
The loader resolves the immutable canonical source and computes the exact
|
||||
requested identity before asking the runtime for a representation.
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
L["Loader resolves canonical source"] --> I["Compute exact WeightArtifactIdentity"]
|
||||
I --> M{"Runtime mode"}
|
||||
M -->|"disabled"| C["Canonical loader"]
|
||||
M -->|"preferred or required"| A{"Validated local artifact?"}
|
||||
A -->|"yes"| R["Return HostWeightLease"]
|
||||
A -->|"no"| X["Remote exact artifact (future)"]
|
||||
X --> P{"Registered producer available?"}
|
||||
P -->|"yes"| B["Build, validate, and publish atomically"]
|
||||
B --> R
|
||||
P -->|"no or recoverable failure"| F{"Policy permits fallback?"}
|
||||
F -->|"preferred"| C
|
||||
F -->|"required"| E["Fail startup"]
|
||||
P -->|"nonretryable failure"| E
|
||||
C --> W{"Post-load publication enabled?"}
|
||||
W -->|"yes"| B2["Publish final model through POST_LOAD_ONLY producer"]
|
||||
B2 --> CL["Close validated publication lease"]
|
||||
CL --> R2["Return separate publication report"]
|
||||
R2 --> D
|
||||
W -->|"no"| D["Keep canonical model"]
|
||||
```
|
||||
|
||||
The modes are:
|
||||
|
||||
| Mode | Observable behavior |
|
||||
| --- | --- |
|
||||
| `disabled` | Use canonical loading directly without probing storage, identity, credentials, or topology. |
|
||||
| `preferred` | Return an exact lease when available; otherwise use canonical fallback only for a miss, invalid cache entry, or typed retryable failure. |
|
||||
| `required` | Fail when an exact lease cannot be acquired. |
|
||||
|
||||
During pre-load resolution, an unsupported capability, semantic identity
|
||||
collision, producer failure, or publication failure is nonretryable and remains
|
||||
visible even in preferred mode. A post-load publication failure is likewise
|
||||
visible in its own report, but cannot revise the canonical-fallback outcome.
|
||||
Storage policy must never disguise a semantic or configuration error as a cache
|
||||
miss.
|
||||
|
||||
## Loader and restoration sequence
|
||||
|
||||
The model integration owns the end-to-end loading transaction. The runtime
|
||||
does not construct a model or invoke the canonical loader.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant L as Loader adapter
|
||||
participant R as HostWeightRuntime
|
||||
participant S as HostWeightStore
|
||||
participant P as WeightProducer
|
||||
participant X as WeightRestorer
|
||||
participant T as GPU transport
|
||||
|
||||
L->>L: Resolve canonical revision and exact identity
|
||||
L->>R: resolve(identity, producer)
|
||||
R->>S: lookup(exact identity)
|
||||
alt validated hit
|
||||
S-->>R: HostWeightLease
|
||||
R-->>L: lease and LOCAL_HIT report
|
||||
L->>X: plan_restore(model, lease)
|
||||
X-->>L: validation-only restore plan
|
||||
L->>X: commit() once
|
||||
else miss with allowed producer
|
||||
R->>S: get_or_build(identity, producer)
|
||||
S->>P: produce(store-scoped writer)
|
||||
P-->>S: final-layout tensors and metadata
|
||||
S-->>R: validated HostWeightLease
|
||||
R-->>L: lease and LOCAL_PRODUCTION report
|
||||
L->>X: plan_restore(model, lease)
|
||||
X-->>L: validation-only restore plan
|
||||
L->>X: commit() once
|
||||
else policy permits canonical fallback
|
||||
R-->>L: CANONICAL_FALLBACK
|
||||
L->>L: Run canonical loader
|
||||
opt explicit post-load publication enabled
|
||||
L->>R: publish_after_load(identity, POST_LOAD_ONLY producer)
|
||||
R->>S: get_or_build(identity, producer)
|
||||
S-->>R: validated HostWeightLease or typed failure
|
||||
R->>R: close publication lease
|
||||
R-->>L: separate publication report
|
||||
end
|
||||
else required or nonretryable failure
|
||||
R-->>L: FAILED report
|
||||
end
|
||||
L->>T: consume final CPU tensors and any lease
|
||||
T-->>L: transfer teardown complete
|
||||
L->>L: close lease when one was acquired
|
||||
```
|
||||
|
||||
`plan_restore()` must not mutate the model or lease. `commit() -> None` is the
|
||||
sole one-shot model mutation. If planning fails, canonical fallback may reuse
|
||||
the untouched model. If commit begins and fails, the partially hydrated model
|
||||
must be discarded and canonical fallback must construct a fresh model.
|
||||
|
||||
`publish_after_load()` is synchronous in V1 and accepts only a
|
||||
`POST_LOAD_ONLY` producer. Its report is separate from the terminal resolution,
|
||||
so a publication failure cannot rewrite a successful canonical fallback. A
|
||||
successful publication closes the store-returned lease inside the runtime and
|
||||
warms only future startups. It does not restore, rebind, or otherwise mutate the
|
||||
canonically loaded model serving the current startup.
|
||||
`allow_local_build` gates producers during pre-load resolution, while
|
||||
`allow_post_load_publish` independently gates this explicit post-load path.
|
||||
|
||||
## Exact representation identity
|
||||
|
||||
The store performs exact lookup. It never silently converts one representation
|
||||
into another or substitutes the first backing that responds.
|
||||
|
||||
Identity includes:
|
||||
|
||||
- immutable model revision and source fingerprint;
|
||||
- model component and ownership boundary;
|
||||
- representation name, dtype, and format metadata;
|
||||
- final tensor layout and semantic parallel coordinates;
|
||||
- static adaptation identity; and
|
||||
- producer implementation, manifest, and restorer schema versions.
|
||||
|
||||
The requested representation is selected by the loader. The store chooses
|
||||
where to obtain that exact representation: validated local artifact, future
|
||||
remote materialization, or a registered producer.
|
||||
|
||||
### Parallelism
|
||||
|
||||
Parallel coordinates are included only when they change bytes, shape, layout,
|
||||
or component ownership.
|
||||
|
||||
| Dimension | Identity and sharing rule |
|
||||
| --- | --- |
|
||||
| DP | Exclude DP rank for replicated weights so same-node replicas can acquire the same artifact. Include a coordinate only if DP changes weight ownership. |
|
||||
| TP | Include TP size and rank when each rank owns different tensor slices or packed layouts. Each distinct TP shard is a separate exact artifact. |
|
||||
| SP | Include SP size and backend when they change the weight layout. Exclude SP rank when all SP ranks consume identical bytes. |
|
||||
| PP | Encode component ownership or stage-local layout when PP changes which weights belong to the consumer. |
|
||||
| EP | Encode expert ownership and layout whenever ranks own different expert weights. |
|
||||
|
||||
The runtime does not infer these rules from process-group topology. The model
|
||||
adapter is responsible for constructing a correct identity.
|
||||
|
||||
### Quantization and adaptations
|
||||
|
||||
Runtime BF16, FP8, packed quantized weights, and future formats are distinct
|
||||
representations. Conversion is performed by an explicitly versioned producer,
|
||||
never by cache coercion. A producer must publish the final layout consumed by
|
||||
its matching restorer.
|
||||
|
||||
Dynamic LoRA overlays are not part of a reusable base-weight artifact. A
|
||||
statically merged adapter is cacheable only as a separate identity containing
|
||||
the adapter fingerprint and merge semantics.
|
||||
|
||||
### Initial diffusion final-layout contract
|
||||
|
||||
The shared diffusion contract covers complete final-layout DiT parameters and
|
||||
persistent buffers. Text encoders, VAEs, non-persistent derived state, and other
|
||||
pipeline components remain outside the artifact. One explicit representation
|
||||
policy selects allowed dtypes, tensor roles, physical layout identity, producer
|
||||
ABI, manifest schema, and restoration schema.
|
||||
|
||||
The contract is intentionally separate from loader activation:
|
||||
|
||||
- `FinalLayoutRequest` contains typed loader identity/configuration fingerprints,
|
||||
TP coordinate, and conservative SP semantics. It has no open metadata bag,
|
||||
DP coordinate, SP rank, device identity, DLO transfer mode, registration
|
||||
policy, or store path.
|
||||
- `FinalLayoutArtifactSpec` binds one `WeightRepresentation` and runtime-layout
|
||||
name to explicit producer/restorer schemas and a canonical, versioned
|
||||
implementation ABI descriptor. Compatibility never depends on reflective
|
||||
source inspection.
|
||||
- `PreparedWeightSource` snapshots immutable revisions or exact local file
|
||||
content plus a typed checkpoint-adapter identity before ordinary
|
||||
materialization. Source replacement before or during production fails
|
||||
publication. A hash-looking symlink basename is trusted only for an explicit
|
||||
Hugging Face Hub source whose repository ID and
|
||||
`models--.../snapshots/<revision> -> blobs/<hash>` topology validate; every
|
||||
local or otherwise unverified symlink target is content-hashed.
|
||||
- the tensor ownership digest records exact runtime names, kinds, shapes,
|
||||
semantic roles, dtypes, and strides from a CPU or meta model skeleton;
|
||||
- `FinalLayoutTensorRestorer` accepts only an exact lease identity, validates
|
||||
complete policy-defined coverage without mutation, and returns a one-shot
|
||||
commit plan;
|
||||
- each model declares one dtype-neutral `FinalLayoutModelContract` with an
|
||||
explicit implementation version and a post-commit validator; and
|
||||
- `FinalLayoutBF16Producer` accepts only the matching identity context and a
|
||||
finalized CPU model. It is `POST_LOAD_ONLY` and `SINGLE_PROCESS` per exact TP
|
||||
coordinate. Its BF16 policy preserves model-declared FP32 parameters and
|
||||
buffers and revalidates MiniMax H3 mixed-precision invariants.
|
||||
|
||||
Other representations reuse source identity, typed parallel identity, tensor
|
||||
ownership, and exact restoration only when their policy proves those semantics.
|
||||
For example, runtime FP8 needs a separate policy/producer for generated scales,
|
||||
quantization metadata, and Cutlass physical layouts; it is not enabled by
|
||||
changing a dtype string on the BF16 producer.
|
||||
|
||||
This stage makes no startup, sharing, or DLO performance claim. A following
|
||||
consumer PR owns disabled/preferred/required precedence, mixed-component loader
|
||||
transactions, warm-hit restoration, and transactional lease handoff. A TP2
|
||||
prewarm deployment will require a matching TP2 producer cohort to populate both
|
||||
TP-coordinate identities even though the store coordinates each artifact
|
||||
independently.
|
||||
|
||||
## Host sharing and GPU transport
|
||||
|
||||
Every process receives its own virtual mappings and `HostWeightLease`, but
|
||||
workers mapping the same local artifact can share physical file-backed pages
|
||||
through the OS page cache. This avoids independent private tensor allocations;
|
||||
it does not guarantee that process PSS reports exactly one model copy.
|
||||
|
||||
The ownership boundary is:
|
||||
|
||||
- the store owns immutable artifact files, publication, and lifecycle;
|
||||
- the kernel owns page-cache residency and placement;
|
||||
- the lease owns process-local mappings and the shared artifact lock; and
|
||||
- transport owns page registration, page locking, private staging, H2D copies,
|
||||
streams, device buffers, and lease release ordering.
|
||||
|
||||
DLO AllGather and no-AllGather remain transport and execution choices. A DLO
|
||||
integration may consume a lease, but the Host Weight Runtime does not choose a
|
||||
parallel collective or orchestrate DP requests. See the
|
||||
[DLO feature design](offloader/distributed_layerwise_offload.md).
|
||||
|
||||
## Locality and NUMA policy
|
||||
|
||||
The V1 backend is node-local. It accepts an allowlist of known local disk
|
||||
filesystems plus tmpfs/ramfs, records the detected kernel filesystem type, and
|
||||
rejects known remote or unknown filesystems. NFS, CIFS, Lustre, Ceph, and other
|
||||
cross-node mounts cannot silently satisfy the local backend because their
|
||||
page-cache and advisory-lock behavior does not provide the required node-local
|
||||
contract.
|
||||
|
||||
A NUMA-specific root creates a separate storage domain but does not by itself
|
||||
place page-cache pages on that NUMA node. A topology-aware integration must
|
||||
also pin workers, establish local first touch or prefault, perform transport
|
||||
registration in the same domain, and collect residency evidence.
|
||||
|
||||
Tmpfs artifacts consume host memory and may consume swap. They must be
|
||||
accounted as memory-backed storage rather than ordinary disk capacity.
|
||||
|
||||
## Concurrency and timeouts
|
||||
|
||||
One process per exact identity owns a build; other workers wait and then acquire
|
||||
leases for the published artifact. Publication is invisible until all payloads
|
||||
and metadata are validated, hashed, fsynced, and atomically renamed.
|
||||
|
||||
`coordination_timeout_seconds` bounds filesystem lock acquisition. It does not
|
||||
cancel synchronous validation, a producer that has already started, or atomic
|
||||
publication. A hung in-process producer therefore blocks its owning process and
|
||||
must be handled by external process supervision. Enforceable producer
|
||||
cancellation requires a future process-isolated producer contract.
|
||||
|
||||
Leases keep a shared artifact lock for their lifetime. A forked child may close
|
||||
its inherited descriptors but cannot unlock the parent process's lease. Cleanup
|
||||
uses a nonblocking exclusive lock and reports an active lease instead of
|
||||
removing live mappings.
|
||||
|
||||
## Failure and fallback contract
|
||||
|
||||
| Condition | Preferred mode | Required mode |
|
||||
| --- | --- | --- |
|
||||
| Exact local hit | Return lease | Return lease |
|
||||
| Local miss | Try later backing or canonical fallback | Try later backing or fail |
|
||||
| Invalid or denied artifact | Quarantine/rebuild when possible; otherwise canonical fallback | Quarantine/rebuild or fail |
|
||||
| Retryable lock, domain, or capacity failure | Canonical fallback | Fail |
|
||||
| Unsupported producer or backend | Fail | Fail |
|
||||
| Identity collision | Fail | Fail |
|
||||
| Pre-load producer or atomic publication failure | Fail | Fail |
|
||||
| Post-load publication failure after canonical fallback | Keep canonical model; report publication failure | Not reached through required resolution |
|
||||
| Restore planning failure | Canonical fallback may reuse untouched model | Fail |
|
||||
| Restore commit failure | Discard model; fallback requires a fresh instance | Fail |
|
||||
|
||||
Cache failures should normally reduce performance rather than availability,
|
||||
but only when the typed failure explicitly permits fallback. Canonical source,
|
||||
authentication, configuration, and semantic errors remain visible.
|
||||
|
||||
## Consumer integration requirements
|
||||
|
||||
A consumer PR must:
|
||||
|
||||
1. Resolve an immutable canonical model source before cache lookup.
|
||||
2. Construct the exact final representation identity, including relevant
|
||||
parallel, quantization, and adaptation semantics.
|
||||
3. Register a deterministic producer for that identity or support lookup-only
|
||||
operation.
|
||||
4. Provide a validation-only restorer with a one-shot commit.
|
||||
5. Keep GPU transport outside the producer, store, and restorer contracts.
|
||||
6. Handle preferred fallback and required failure without reusing a model after
|
||||
a failed restore commit.
|
||||
7. Retain the lease until every transport operation that may access mapped
|
||||
memory has completed.
|
||||
8. Emit and test the terminal resolution report and any separate post-load
|
||||
publication report.
|
||||
|
||||
Consumer validation must prove:
|
||||
|
||||
- output parity with canonical loading;
|
||||
- exact warm-hit work avoidance;
|
||||
- correct TP/SP/PP/EP ownership and layout identity;
|
||||
- correct BF16, FP8, quantized, or adaptation semantics;
|
||||
- shared-backing evidence when host-memory savings are claimed;
|
||||
- clean unmapping, unregistration, and artifact-lock release; and
|
||||
- startup, host-memory, and transport effects for the claimed deployment.
|
||||
|
||||
## Rollout
|
||||
|
||||
The rollout is intentionally staged:
|
||||
|
||||
1. Land the neutral contracts and local filesystem store.
|
||||
2. Add one model-specific producer/restorer integration with parity evidence.
|
||||
3. Connect eligible DLO or other transport paths without moving transport
|
||||
ownership into the runtime.
|
||||
4. Add additional final-layout and quantized producers independently.
|
||||
5. Introduce remote materialization only through the same local lease contract.
|
||||
|
||||
The architectural decisions and deferred work are tracked in
|
||||
[RFC #6414](https://github.com/vllm-project/vllm-omni/issues/6414).
|
||||
@@ -0,0 +1,80 @@
|
||||
# CPU Offloading
|
||||
|
||||
This document defines the shared architecture for diffusion CPU offloading.
|
||||
The three strategies have separate user and design pages:
|
||||
|
||||
| Strategy | User guide | Design contract |
|
||||
| --- | --- | --- |
|
||||
| Model-level | [Guide](../../../user_guide/diffusion/offloader/cpu_offload.md) | [Design](cpu_offload.md) |
|
||||
| Layerwise | [Guide](../../../user_guide/diffusion/offloader/layerwise_offload.md) | [Design](layerwise_offload.md) |
|
||||
| Distributed layerwise | [Guide](../../../user_guide/diffusion/offloader/distributed_layerwise_offload.md) | [Design](distributed_layerwise_offload.md) |
|
||||
|
||||
## Strategy selection
|
||||
|
||||
`OffloadConfig.from_od_config()` converts diffusion configuration into one
|
||||
`OffloadStrategy`. If callers set multiple flags, selection is deterministic:
|
||||
|
||||
1. `DISTRIBUTED_LAYERWISE`;
|
||||
2. `LAYERWISE`;
|
||||
3. `MODEL_LEVEL`; and
|
||||
4. `NONE`.
|
||||
|
||||
The factory logs when a higher-priority strategy disables another. It derives
|
||||
parallel and HSDP state from `DiffusionParallelConfig`; callers do not provide
|
||||
a separate offload group size.
|
||||
|
||||
`get_offload_backend()` then validates platform offload support, resolves the
|
||||
device, and creates exactly one backend. Returning `None` means offloading is
|
||||
disabled or unsupported and must not leave partially installed hooks.
|
||||
|
||||
## Shared lifecycle
|
||||
|
||||
Every backend implements `OffloadBackend`:
|
||||
|
||||
- `enable(pipeline)` discovers modules, establishes initial residency, and
|
||||
installs hooks;
|
||||
- `disable()` removes owned hooks and resources; and
|
||||
- `is_enabled()` reports lifecycle state.
|
||||
|
||||
`disable()` does not promise to restore the pipeline's original device
|
||||
placement. The caller owns any subsequent rematerialization.
|
||||
|
||||
Hooks are registered through `HookRegistry` and `ModelHook`; offload backends
|
||||
must use distinct hook names and remove only hooks they own.
|
||||
|
||||
## Discovery and topology
|
||||
|
||||
Pipeline component discovery prefers `SupportsComponentDiscovery` declarations:
|
||||
|
||||
- `_dit_modules`;
|
||||
- `_encoder_modules`;
|
||||
- `_vae_modules`; and
|
||||
- `_resident_modules`.
|
||||
|
||||
Dotted paths are supported. Legacy pipelines may use the fallback scan of
|
||||
well-known attribute names, but new integrations should declare components
|
||||
explicitly.
|
||||
|
||||
Ordinary layerwise offload obtains topology from declared
|
||||
`_layerwise_offload_blocks_attrs` (with a deprecated singular-name
|
||||
compatibility path). Distributed layerwise offload may instead use a pipeline
|
||||
`OffloadPlan`, then falls back to declared block attributes and its documented
|
||||
compatibility discovery. Discovery metadata describes structure only; the
|
||||
backend remains responsible for transfer, synchronization, and storage
|
||||
ownership.
|
||||
|
||||
## Cross-strategy invariants
|
||||
|
||||
- At most one strategy owns offload hooks for a pipeline.
|
||||
- A parameter has one authoritative host representation while offloaded.
|
||||
- Device storage is not freed until dependent compute or transfer work is
|
||||
complete.
|
||||
- Non-persistent and model-specific buffers remain correct after movement or
|
||||
checkpoint rematerialization.
|
||||
- Unsupported parallel or loading combinations fail before hooks mutate the
|
||||
model.
|
||||
- Platform streams, events, synchronization, and cache management go through
|
||||
the vLLM-Omni platform abstraction.
|
||||
|
||||
The diffusion [Offloader module design](../../module/diffusion/offloader.md)
|
||||
describes how these feature contracts fit into the larger diffusion runtime.
|
||||
@@ -0,0 +1,56 @@
|
||||
# Model-Level Offload
|
||||
|
||||
Model-level offload enforces mutual exclusion between pipeline component
|
||||
groups. For commands and model support, see the
|
||||
[model-level user guide](../../../user_guide/diffusion/offloader/cpu_offload.md).
|
||||
|
||||
## Generic hook path
|
||||
|
||||
`ModelLevelOffloadBackend.enable()` discovers DiTs, encoders, and VAEs. It
|
||||
makes encoders and VAEs device resident for initialization, then installs
|
||||
`SequentialOffloadHook` instances:
|
||||
|
||||
- each DiT hook offloads all encoders and other DiTs before loading itself;
|
||||
- each encoder hook offloads every DiT before loading itself; and
|
||||
- VAEs are not part of the mutual-exclusion hook set.
|
||||
|
||||
The hook moves parameters and buffers without recursively calling
|
||||
`module.to()`. This avoids recursion through modules that retain references to
|
||||
other transformer blocks. Host tensors are pinned when configured; DTensors
|
||||
are not pinned through the ordinary tensor path.
|
||||
|
||||
Before forward returns control to the model, the hook synchronizes the active
|
||||
platform so compute cannot race the transfer. XPU uses blocking device-to-host
|
||||
copies because its allocator cannot safely evict storage while an asynchronous
|
||||
copy is pending.
|
||||
|
||||
## Split-model delegation
|
||||
|
||||
If a pipeline provides callable `enable_omni_model_cpu_offload`, the backend
|
||||
delegates instead of installing generic encoder/DiT hooks. This supports models
|
||||
whose mutually exclusive components are nested inside one transformer, such
|
||||
as a reasoner and generator.
|
||||
|
||||
The delegated pipeline owns its internal contexts, but must preserve the same
|
||||
contract:
|
||||
|
||||
- only the executing component is device resident;
|
||||
- enable and disable are idempotent;
|
||||
- transfers use the supplied device, pinning, and HSDP settings; and
|
||||
- disabling removes all model-local offload hooks or contexts.
|
||||
|
||||
The delegation is currently duck typed. If another independent implementation
|
||||
is added, formalize the enable/disable pair as a protocol rather than expanding
|
||||
attribute-name heuristics.
|
||||
|
||||
## Extension invariants
|
||||
|
||||
- New ordinary pipelines declare both DiT and encoder groups through
|
||||
`SupportsComponentDiscovery`.
|
||||
- Models with multiple DiTs offload the inactive DiTs as well as encoders.
|
||||
- Empty or parameterless modules do not trigger transfers.
|
||||
- Hook removal does not move modules; callers must not assume original
|
||||
residency is restored.
|
||||
|
||||
Shared selection and lifecycle behavior is defined in the
|
||||
[CPU Offloading design](README.md).
|
||||
@@ -0,0 +1,308 @@
|
||||
# Distributed Layerwise Offload
|
||||
|
||||
This document describes distributed layerwise offload (DLO) for diffusion
|
||||
models. DLO keeps only a small number of DiT blocks on the accelerator and
|
||||
streams the remaining blocks from host memory. The distributed backend can
|
||||
either shard those host-side weights across an existing parallel group or keep
|
||||
complete rank-local block sources and avoid an additional collective.
|
||||
|
||||
For user-facing commands, see the
|
||||
[distributed layerwise offloading guide](../../../user_guide/diffusion/offloader/distributed_layerwise_offload.md)
|
||||
and the [Cosmos3 recipe](https://github.com/vllm-project/vllm-omni/blob/main/recipes/cosmos3/Cosmos3-DistOffload.md).
|
||||
|
||||
## Feature compatibility
|
||||
|
||||
Host-storage optimization and runtime compatibility are separate decisions.
|
||||
When direct checkpoint mmap is unavailable, DLO can still use tensors produced
|
||||
by the ordinary loader. "Compatibility path" below means that fallback is
|
||||
implemented but has less end-to-end coverage than the primary path.
|
||||
|
||||
Legend: ✅ supported, ⚠️ compatibility path or limited validation, ❌ unsupported.
|
||||
|
||||
| Feature | DLO + AllGather | DLO without AllGather |
|
||||
|---|---|---|
|
||||
| **DP** | ✅ Primary path; host weights are sharded across the DP group. | ✅ Each DP rank streams complete rank-local blocks. |
|
||||
| **SP** | ✅ When DP=1, DLO uses the SP group for weight sharding. | ✅ SP remains active without a DLO weight collective. |
|
||||
| **TP > 1** | ⚠️ Ordinary TP-aware loader only; no direct checkpoint mmap. | ⚠️ Ordinary TP-aware loader only; no direct checkpoint mmap. |
|
||||
| **HSDP** | ❌ Rejected to avoid double-sharding parameters. | ⚠️ Limited end-to-end coverage. |
|
||||
| **Per-tensor online FP8 linears** | ✅ Ordinary loader finalizes weights and scales before DLO sharding. | ✅ Ordinary loader retains complete rank-local tensors. |
|
||||
| **Other online quantization methods** | ❌ Rejected until runtime packing and scale layouts are validated. | ⚠️ Allowed through the ordinary loader; validation is method-specific. |
|
||||
| **Model-level or standard layerwise CPU offload** | ❌ Disabled because DLO takes priority. | ❌ Disabled because DLO takes priority. |
|
||||
| **Resident leading layers** | ❌ Rejected. | ✅ Requires eligible resident paths in the model's `OffloadPlan`. |
|
||||
|
||||
See [Parallelism compatibility](#parallelism-compatibility) and
|
||||
[Request and loading constraints](#request-and-loading-constraints) for the
|
||||
detailed contracts and validation boundaries.
|
||||
|
||||
## Status
|
||||
|
||||
DLO is implemented for multi-device diffusion execution. The default
|
||||
AllGather path is the primary path for DP and SP deployments. The
|
||||
`--dlo-no-use-allgather` path streams complete blocks independently and adds no
|
||||
DLO weight collective.
|
||||
|
||||
Host storage is selected separately from the transfer protocol. The loader can
|
||||
produce a direct-checkpoint mmap plan for a proven-compatible runtime layout;
|
||||
otherwise it uses the ordinary loader. Consequently, no-AllGather replicas on
|
||||
the same node can share immutable checkpoint pages when direct mmap is
|
||||
selected, while the ordinary-loader fallback still keeps a private runtime
|
||||
copy per process.
|
||||
|
||||
The Phase A shared-mmap support boundary is TP1. TP greater than one is an
|
||||
ordinary-loader compatibility path: DLO can consume the resulting TP-local
|
||||
tensors, but those configurations do not use checkpoint mmap and must not be
|
||||
used to claim shared-mmap host-memory savings.
|
||||
|
||||
The compatibility matrix below describes the current implementation. The
|
||||
unit-level guards are covered, but not every parallelism combination has a
|
||||
full model-and-hardware end-to-end test.
|
||||
|
||||
## Design
|
||||
|
||||
### DLO consumes the existing parallel topology
|
||||
|
||||
DLO does not create a new DP, TP, or SP topology. It reads the configured
|
||||
`DiffusionParallelConfig` and attaches offload hooks to the DiT blocks after the
|
||||
standard distributed groups have been initialized.
|
||||
|
||||
The DLO weight-sharding group is selected as follows:
|
||||
|
||||
1. Use the existing DP group when `data_parallel_size > 1`.
|
||||
2. When DP is one and SP is greater than one, use the SP group.
|
||||
3. Otherwise, run rank-locally without a DLO process group.
|
||||
|
||||
TP is deliberately not used as DLO's AllGather group. HSDP has its own
|
||||
parameter-sharding lifecycle and is not allowed to be sharded a second time by
|
||||
DLO's AllGather path.
|
||||
|
||||
### The loader owns host-weight planning
|
||||
|
||||
Before it decides whether ordinary weight materialization can be skipped, the
|
||||
diffusion loader builds one `HostWeightPlan`. A direct-checkpoint mmap plan is
|
||||
accepted only when preflight proves all of the following:
|
||||
|
||||
- every required DiT parameter and persistent buffer has exactly one source;
|
||||
- runtime names, checkpoint keys, shapes, and dtypes match;
|
||||
- the runtime topology is TP1 without HSDP or online quantization; and
|
||||
- every custom loader operation is represented by a loader-owned checkpoint
|
||||
adapter.
|
||||
|
||||
The exact plan object is handed to DLO. The backend does not rescan checkpoint
|
||||
files, repeat the capability decision, or reconstruct names from its block
|
||||
topology. If preflight fails, the loader materializes weights normally and DLO
|
||||
consumes those runtime tensors.
|
||||
|
||||
The plan owns only dedicated DiT component sources. If a pipeline also exposes
|
||||
ordinary sources for a text encoder or another non-DiT component, the loader
|
||||
still consumes those sources and includes their loaded names in its strict
|
||||
coverage check. Only the source prefixes covered by the plan skip ordinary
|
||||
materialization. A source that mixes DiT and non-DiT weights fails closed to
|
||||
the complete ordinary-loader path because it cannot be skipped safely as a
|
||||
unit.
|
||||
|
||||
This boundary keeps checkpoint semantics out of DLO and avoids model-pipeline
|
||||
flags such as `_supports_mmap_loading` or parameter attributes for mmap-only
|
||||
transforms. Model-specific direct-layout knowledge, when required, lives in a
|
||||
checkpoint adapter beside the ordinary loader.
|
||||
|
||||
### AllGather path
|
||||
|
||||
With the default `dlo_use_allgather=True`, each rank stores approximately
|
||||
`1 / group_size` of each streamable block in pinned host memory. The next
|
||||
block's shard is copied to a device buffer and reconstructed with
|
||||
`all_gather_into_tensor` on a communication stream while the current block is
|
||||
executing.
|
||||
|
||||
```text
|
||||
Compute: [Block N] [Block N+1] [Block N+2]
|
||||
H2D: [shard N+1] [shard N+2]
|
||||
AllGather: [full N+1] [full N+2]
|
||||
Buffers: [current slot] [prefetch slot] [current slot]
|
||||
```
|
||||
|
||||

|
||||
|
||||
The backend uses two shared device buffers, so accelerator weight residency is
|
||||
bounded by the largest streamed blocks rather than the complete model.
|
||||
|
||||
When direct checkpoint mmap is selected, the checkpoint mappings are only the
|
||||
source used to prepare each rank's persistent shard. They can be closed after
|
||||
shard preparation. Across the AllGather group, those private shards total
|
||||
approximately one runtime model copy.
|
||||
|
||||
An effective DLO group size of one performs no collective, even when
|
||||
`dlo_use_allgather=True`; it follows the rank-local transfer path described
|
||||
below.
|
||||
|
||||
When DP is greater than one, the engine can process one request per DP rank in
|
||||
the same denoising wave. Because AllGather is a collective, all participating
|
||||
requests must take the same execution path at every denoising step.
|
||||
|
||||
### Rank-local path without DLO AllGather
|
||||
|
||||
With `--dlo-no-use-allgather`, DLO forces its internal offload shard size to
|
||||
one and streams complete blocks using H2D copies only. The host backing may be
|
||||
either a loader-approved checkpoint mapping or ordinary runtime tensors.
|
||||
|
||||
For direct mmap, each process retains immutable safetensors views and uses two
|
||||
bounded pinned host staging slots. Processes on the same node that map the same
|
||||
files share physical checkpoint pages through the OS page cache. This removes
|
||||
the persistent private full-model copy per pure-DP process, but each process
|
||||
still packs and transfers every complete block. Sharing is node-local; each
|
||||
node has its own page cache.
|
||||
|
||||
When direct mmap preflight fails, the regular model loader remains responsible
|
||||
for preparing each rank's weights, including TP-local tensors or HSDP-managed
|
||||
parameters. In that fallback, each pure-DP process keeps a private full runtime
|
||||
copy.
|
||||
|
||||
This mode means:
|
||||
|
||||
- DP still provides independent replicas, but DLO does not shard weights
|
||||
across DP ranks.
|
||||
- SP still performs its normal activation/attention collectives, but DLO does
|
||||
not shard weights across SP ranks.
|
||||
- TP/HSDP/SP collectives, if configured, are not disabled by this flag; only
|
||||
DLO's additional weight AllGather is disabled.
|
||||
- Pure DP deployments share one checkpoint-backed copy per node when direct
|
||||
mmap is selected; the ordinary-loader fallback keeps one private runtime
|
||||
copy per rank.
|
||||
- The scheduler does not require a synchronized DP request wave for DLO.
|
||||
|
||||
## Parallelism compatibility
|
||||
|
||||
| Parallelism | DLO + AllGather | DLO without AllGather |
|
||||
|---|---|---|
|
||||
| **DP** | Supported primary path. DLO shards host weights across the DP group and can run DP multi-concurrency. | Supported rank-local path. Compatible TP1 replicas can share checkpoint pages on each node; fallback runtime tensors remain private. |
|
||||
| **SP** | Supported in the implementation. With DP=1, DLO uses the SP group for host-weight sharding; SP still shards sequence/activation work. | SP remains active, but DLO keeps standard-loader rank-local weights and adds no SP weight collective. |
|
||||
| **TP > 1** | Outside the Phase A shared-mmap support scope. The loader falls back before mutation, preserves TP-local layouts, and DLO may apply DP/SP host sharding to those ordinary runtime tensors. | Outside the Phase A shared-mmap support scope. The ordinary TP-aware loader produces rank-local tensors, which DLO streams without an additional weight collective; DP replicas retain private runtime storage. |
|
||||
| **HSDP** | Rejected. HSDP has already sharded parameters, so DLO AllGather would double-shard them. | Accepted by configuration. HSDP owns parameter sharding and its own gathers; DLO only stages rank-local parameters. End-to-end coverage is limited. |
|
||||
|
||||
### Combined dimensions
|
||||
|
||||
- **DP + SP:** DLO uses the DP group for weight sharding when DP is greater
|
||||
than one; SP continues to use its own sequence-parallel group. If DP is one,
|
||||
the SP group becomes DLO's sharding group in AllGather mode.
|
||||
- **DP + TP/SP without AllGather:** standard model loading defines the
|
||||
rank-local tensor layout. DLO adds no cross-DP, cross-TP, or cross-SP weight
|
||||
collective.
|
||||
- **HSDP + SP:** the general parallel configuration permits HSDP over SP, but
|
||||
DLO must use `--dlo-no-use-allgather`. HSDP remains responsible for weight
|
||||
materialization and synchronization.
|
||||
- **HSDP + DP or TP:** rejected independently by the diffusion parallel
|
||||
configuration.
|
||||
|
||||
## Request and loading constraints
|
||||
|
||||
AllGather DP multi-concurrency requires:
|
||||
|
||||
- explicit `num_inference_steps`;
|
||||
- the same `num_inference_steps` for all requests in a wave; and
|
||||
- identical request arguments that affect the collective execution path.
|
||||
|
||||
The no-AllGather path does not impose these DLO-specific synchronized-wave
|
||||
requirements.
|
||||
|
||||
Direct checkpoint mmap can back either transfer path. It is currently limited
|
||||
to proven TP1, non-HSDP, non-online-quantized layouts. Other layouts use the
|
||||
ordinary loader. Per-tensor online FP8 linears can use DLO AllGather after the
|
||||
ordinary loader finalizes their runtime weights and scales; DLO then shards and
|
||||
reconstructs those tensors with their recorded layouts. Other online methods
|
||||
must use `--dlo-no-use-allgather` or disable online quantization until their
|
||||
runtime layouts are validated.
|
||||
|
||||
A normalized runtime mmap cache, built through the ordinary loader, is the
|
||||
proposed general mechanism for sharing transformed TP or quantized layouts.
|
||||
That cache and its publication/lifecycle protocol are intentionally outside
|
||||
this phase; see [RFC #6195](https://github.com/vllm-project/vllm-omni/issues/6195).
|
||||
|
||||
## Validation coverage
|
||||
|
||||
Current source-level validation includes:
|
||||
|
||||
- HSDP + DLO + AllGather rejection;
|
||||
- HSDP + DLO without AllGather acceptance at configuration level;
|
||||
- loader preflight fallback for TP, HSDP, online quantization, unknown custom
|
||||
loaders, missing keys, and shape/dtype mismatches;
|
||||
- ordinary-loader fallback for per-tensor online FP8 linears followed by DLO
|
||||
sharding of finalized weights and scales;
|
||||
- exact loader-to-backend plan transfer and ordinary-loader fallback;
|
||||
- rank-local mmap source retention, bounded two-slot staging, and adapter
|
||||
transforms without parameter-side flags;
|
||||
- resident-layer requests requiring no-AllGather;
|
||||
- DP request-wave validation for denoising-step compatibility;
|
||||
- sharding, double-buffer, AllGather-size, and heterogeneous-block regression
|
||||
tests.
|
||||
|
||||
### B300 parallel-topology smoke matrix
|
||||
|
||||
A four-GPU B300 smoke test covered MiniMax-H3 FL2VA with the same prompt, seed,
|
||||
CUDNN attention backend, 256x256 output, two denoising steps, and
|
||||
`dlo_resident_layers=0`. The TP2 rows used DiT DP2xTP2 with the text encoder and
|
||||
VAEs at TP1. They validate the ordinary-loader fallback only, not direct mmap
|
||||
or shared-mmap host-memory savings.
|
||||
|
||||
| Configuration | Result | Warm E2E | Peak device memory | Host PSS |
|
||||
|---|---:|---:|---:|---:|
|
||||
| DP4xTP1 AllGather | Passed, 4 concurrent requests | 2.87 s / 4 requests | 13.84 GiB | 211.99 GiB |
|
||||
| DP4xTP1 no-AllGather | Passed, 1 request | 15.02 s | 13.23 GiB | 187.77 GiB |
|
||||
| DP2xTP2 AllGather | Passed, 2 concurrent requests | 4.16 s / 2 requests | 12.50 GiB | 211.97 GiB |
|
||||
| DP2xTP2 no-AllGather | Passed, 1 request | 3.51 s | 11.88 GiB | 314.01 GiB |
|
||||
|
||||
Within each topology, the AllGather and no-AllGather video and audio outputs
|
||||
were byte-identical. All four runs completed without an `ERROR` or traceback
|
||||
and released their device allocations. For DP4xTP1, no-AllGather direct mmap
|
||||
reduced total PSS by 24.22 GiB (11.4%) and `Private_Dirty` from 211.33 to
|
||||
125.32 GiB (40.7%) relative to AllGather. For DP2xTP2, preflight selected the
|
||||
ordinary loader as designed; no-AllGather PSS was 314.01 GiB, about 48% above
|
||||
AllGather, because DP replicas did not share checkpoint-backed runtime
|
||||
weights. This is a functional and memory smoke test, not a production-quality
|
||||
performance or output-quality benchmark.
|
||||
|
||||
### Host-memory measurement
|
||||
|
||||
A two-worker MiniMax-H3 FL2VA measurement on one L20X node compared the
|
||||
ordinary-loader fallback with direct mmap. Both runs used
|
||||
DP=2, TP=1, no DLO AllGather, BF16 weights, two denoising steps, and a
|
||||
256x256 four-second request. The ordinary-loader workers were sampled after
|
||||
initialization. The mmap workers were sampled after one completed request, so
|
||||
the checkpoint working set had been faulted into the page cache; this is the
|
||||
more conservative point for mmap.
|
||||
|
||||
The values below come from `/proc/<worker>/smaps_rollup` and include the whole
|
||||
worker, not only the DiT. The stable rank-to-rank difference comes from other
|
||||
pipeline components, so each worker should be compared with the same worker in
|
||||
the other storage mode.
|
||||
|
||||
| Worker | Ordinary RSS | mmap RSS | Ordinary PSS | mmap PSS | PSS reduction |
|
||||
|---|---:|---:|---:|---:|---:|
|
||||
| DP worker 0 | 168.27 GiB | 132.76 GiB | 167.84 GiB | 101.43 GiB | 66.40 GiB |
|
||||
| DP worker 1 | 116.19 GiB | 79.97 GiB | 115.73 GiB | 48.64 GiB | 67.09 GiB |
|
||||
| **Two-worker total** | — | — | **283.56 GiB** | **150.08 GiB** | **133.48 GiB (47.1%)** |
|
||||
|
||||
The direct-mmap workers each reported 62.45 GiB `Shared_Clean` but only
|
||||
31.20 GiB `Pss_File`, which is the proportional charge expected when the same
|
||||
resident checkpoint pages are mapped by two workers. `Private_Dirty` also fell
|
||||
from 167.53 to 70.24 GiB for worker 0 and from 115.40 to 17.44 GiB for worker
|
||||
1, a reduction of about 97–98 GiB per worker. RSS understates this benefit
|
||||
because it counts a shared physical page in every process that maps it; summed
|
||||
PSS is the appropriate node-memory comparison.
|
||||
|
||||
The highest-value missing coverage is broader end-to-end numerical and
|
||||
lifecycle comparison against ordinary layerwise offload for DP+SP,
|
||||
HSDP+SP+no-AllGather, and TP greater than one across additional models and
|
||||
target CUDA/NCCL or CANN/HCCL hardware. That broader TP coverage does not
|
||||
change the Phase A direct-mmap TP1 support boundary.
|
||||
|
||||
## Recommendations
|
||||
|
||||
- Use **DP + DLO AllGather** for the supported throughput and host-memory
|
||||
scaling path.
|
||||
- Use **SP + DLO AllGather** for long-sequence workloads when DP concurrency is
|
||||
not the goal.
|
||||
- Use **no-AllGather** when independent replica execution is required. TP1
|
||||
direct-mmap deployments can share checkpoint pages per node; other layouts
|
||||
retain the ordinary loader's private host memory behavior and are outside
|
||||
the Phase A shared-mmap support scope.
|
||||
- Prefer **HSDP alone** for production HSDP deployments until the combined
|
||||
HSDP + DLO no-AllGather path has broader end-to-end coverage.
|
||||
@@ -0,0 +1,57 @@
|
||||
# Layerwise Offload
|
||||
|
||||
Layerwise offload streams transformer blocks through one accelerator. For
|
||||
commands and model support, see the
|
||||
[layerwise user guide](../../../user_guide/diffusion/offloader/layerwise_offload.md).
|
||||
|
||||
## Hook ring
|
||||
|
||||
`LayerWiseOffloadBackend` discovers every streamable block and registers one
|
||||
`LayerwiseOffloadHook` per block. Hooks form a ring: each hook owns the pinned
|
||||
host representation of its registered block and a reference to the next block
|
||||
it must prefetch; the final hook prefetches the first block for the next
|
||||
denoising iteration.
|
||||
|
||||
During initialization, parameters and buffers are grouped by dtype and copied
|
||||
into contiguous pinned CPU tensors. Original tensor storage is replaced with
|
||||
an empty or meta placeholder while identity and module structure are retained.
|
||||
Metadata records names, offsets, shapes, and dtypes for rematerialization.
|
||||
|
||||
## Forward lifecycle
|
||||
|
||||
For each block:
|
||||
|
||||
1. the previous hook's completion event ensures this block is materialized;
|
||||
2. the copy stream asynchronously allocates and fills the next block's device
|
||||
tensors;
|
||||
3. parameter and buffer storage is rebound to views of those tensors;
|
||||
4. the current block computes on the normal stream; and
|
||||
5. its post-forward hook replaces device storage with placeholders after all
|
||||
dependent work is safe.
|
||||
|
||||
The copy stream waits on the compute stream before reusing storage, and the
|
||||
compute stream waits on the per-block prefetch event before forward. These
|
||||
dependencies, not incidental global synchronization, define correctness.
|
||||
|
||||
## Topology contract
|
||||
|
||||
A DiT declares ordered block-container attributes using
|
||||
`_layerwise_offload_blocks_attrs` or an `OffloadPlan`. Each resolved item must
|
||||
be an executable `nn.Module`; ordering must match forward execution. Multiple
|
||||
containers are concatenated in execution order.
|
||||
|
||||
Non-block DiT modules, encoders, VAEs, and declared resident modules are not
|
||||
streamed by this backend.
|
||||
|
||||
## Invariants and limitations
|
||||
|
||||
- Each offloaded tensor has one pinned host backing store.
|
||||
- Parameter identity is preserved when storage is rebound.
|
||||
- Blocks with heterogeneous shapes and dtypes use their recorded metadata;
|
||||
implementations must not assume identical blocks.
|
||||
- The ring is initialized before the first forward so block zero is available.
|
||||
- This backend is single-device; distributed weight reconstruction belongs to
|
||||
[Distributed Layerwise Offload](distributed_layerwise_offload.md).
|
||||
|
||||
Shared selection and lifecycle behavior is defined in the
|
||||
[CPU Offloading design](README.md).
|
||||
@@ -32,26 +32,25 @@ mooncake_master \
|
||||
|
||||
## Configuration
|
||||
|
||||
Define the connector in runtime:
|
||||
Define the connector at the top level of the deploy YAML:
|
||||
|
||||
```yaml
|
||||
runtime:
|
||||
connectors:
|
||||
connector_of_mooncake:
|
||||
name: MooncakeStoreConnector
|
||||
extra:
|
||||
host: "127.0.0.1"
|
||||
metadata_server: "http://<MASTER_IP>:8080/metadata"
|
||||
master: "<MASTER_IP>:50051"
|
||||
segment: 512000000
|
||||
localbuf: 64000000
|
||||
proto: "tcp"
|
||||
connectors:
|
||||
connector_of_mooncake:
|
||||
name: MooncakeStoreConnector
|
||||
extra:
|
||||
host: "127.0.0.1"
|
||||
metadata_server: "http://<MASTER_IP>:8080/metadata"
|
||||
master: "<MASTER_IP>:50051"
|
||||
segment: 512000000
|
||||
localbuf: 64000000
|
||||
proto: "tcp"
|
||||
```
|
||||
|
||||
Wire stages to the connector:
|
||||
|
||||
```yaml
|
||||
stage_args:
|
||||
stages:
|
||||
- stage_id: 0
|
||||
output_connectors:
|
||||
to_stage_1: connector_of_mooncake
|
||||
|
||||
@@ -21,26 +21,25 @@ InfiniBand/RoCE NICs).
|
||||
|
||||
## Configuration
|
||||
|
||||
Define the connector in runtime:
|
||||
Define the connector at the top level of the deploy YAML:
|
||||
|
||||
```yaml
|
||||
runtime:
|
||||
connectors:
|
||||
rdma_connector:
|
||||
name: MooncakeTransferEngineConnector
|
||||
extra:
|
||||
host: "auto" # Auto-detect local RDMA IP
|
||||
zmq_port: 50051 # ZMQ base port (see "Port Offset Scheme" below)
|
||||
protocol: "rdma" # "rdma" or "tcp"
|
||||
device_name: "" # RDMA device (e.g., "mlx5_0"), empty for auto-detect
|
||||
memory_pool_size: 4294967296 # 4 GB (CPU); use 2147483648 (2 GB) for GPU
|
||||
memory_pool_device: "cpu" # "cpu" for pinned memory (recommended), "cuda" for GPUDirect RDMA
|
||||
connectors:
|
||||
rdma_connector:
|
||||
name: MooncakeTransferEngineConnector
|
||||
extra:
|
||||
host: "auto" # Auto-detect local RDMA IP
|
||||
zmq_port: 50051 # ZMQ base port (see "Port Offset Scheme" below)
|
||||
protocol: "rdma" # "rdma" or "tcp"
|
||||
device_name: "" # RDMA device (e.g., "mlx5_0"), empty for auto-detect
|
||||
memory_pool_size: 4294967296 # 4 GB (CPU); use 2147483648 (2 GB) for GPU
|
||||
memory_pool_device: "cpu" # "cpu" for pinned memory (recommended), "cuda" for GPUDirect RDMA
|
||||
```
|
||||
|
||||
Wire stages to the connector:
|
||||
|
||||
```yaml
|
||||
stage_args:
|
||||
stages:
|
||||
- stage_id: 0
|
||||
output_connectors:
|
||||
to_stage_1: rdma_connector
|
||||
@@ -415,7 +414,7 @@ A receiver connector:
|
||||
- allocates receive buffers from its own pool
|
||||
- requests metadata or transfer service from the sender
|
||||
|
||||
The role is not inferred dynamically. It is injected by the stage configuration layer:
|
||||
The role is not inferred dynamically. It is injected from the deploy connector wiring:
|
||||
|
||||
- incoming edge for a stage -> `role="receiver"`
|
||||
- outgoing edge for a stage -> `role="sender"`
|
||||
|
||||
@@ -13,10 +13,9 @@ segment name is returned in metadata.
|
||||
## Configuration
|
||||
|
||||
```yaml
|
||||
runtime:
|
||||
connectors:
|
||||
connector_of_shared_memory:
|
||||
name: SharedMemoryConnector
|
||||
connectors:
|
||||
connector_of_shared_memory:
|
||||
name: SharedMemoryConnector
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
@@ -65,23 +65,22 @@ dscli stop --worker_address "${WORKER_IP}:31501"
|
||||
|
||||
## Configuration
|
||||
|
||||
Define the connector in runtime:
|
||||
Define the connector at the top level of the deploy YAML:
|
||||
|
||||
```yaml
|
||||
runtime:
|
||||
connectors:
|
||||
connector_of_yuanrong:
|
||||
name: YuanrongConnector
|
||||
extra:
|
||||
host: "127.0.0.1"
|
||||
port: 31501
|
||||
get_sub_timeout_ms: 1000
|
||||
connectors:
|
||||
connector_of_yuanrong:
|
||||
name: YuanrongConnector
|
||||
extra:
|
||||
host: "127.0.0.1"
|
||||
port: 31501
|
||||
get_sub_timeout_ms: 1000
|
||||
```
|
||||
|
||||
Wire stages to the connector:
|
||||
|
||||
```yaml
|
||||
stage_args:
|
||||
stages:
|
||||
- stage_id: 0
|
||||
output_connectors:
|
||||
to_stage_1: connector_of_yuanrong
|
||||
|
||||
@@ -94,26 +94,23 @@ For Ascend P2P, configure the connector with `protocol: "ascend"` and an NPU
|
||||
memory pool:
|
||||
|
||||
```yaml
|
||||
runtime:
|
||||
enabled: true
|
||||
defaults:
|
||||
connectors:
|
||||
yuanrong_te_connector:
|
||||
name: YuanrongTransferEngineConnector
|
||||
extra:
|
||||
host: "auto"
|
||||
zmq_port: 50051
|
||||
rpc_port: "auto"
|
||||
protocol: "ascend"
|
||||
device_name: "auto"
|
||||
memory_pool_size: 1073741824
|
||||
memory_pool_device: "npu"
|
||||
|
||||
edges:
|
||||
- from: 0
|
||||
to: 1
|
||||
window_size: -1
|
||||
max_inflight: 1
|
||||
connectors:
|
||||
yuanrong_te_connector:
|
||||
name: YuanrongTransferEngineConnector
|
||||
extra:
|
||||
host: "auto"
|
||||
zmq_port: 50051
|
||||
rpc_port: "auto"
|
||||
protocol: "ascend"
|
||||
device_name: "auto"
|
||||
memory_pool_size: 1073741824
|
||||
memory_pool_device: "npu"
|
||||
edges:
|
||||
- from: 0
|
||||
to: 1
|
||||
window_size: -1
|
||||
```
|
||||
|
||||
Important fields:
|
||||
@@ -141,31 +138,27 @@ For AR 4-way TP sending KV cache to DiT 4-way TP, set the stage TP topology in
|
||||
both stage `omni_kv_config` blocks:
|
||||
|
||||
```yaml
|
||||
stage_args:
|
||||
stages:
|
||||
- stage_id: 0
|
||||
runtime:
|
||||
devices: "0,1,2,3"
|
||||
engine_args:
|
||||
tensor_parallel_size: 4
|
||||
omni_kv_config:
|
||||
need_send_cache: true
|
||||
rank_mapping:
|
||||
from_tp: 4
|
||||
to_tp: 4
|
||||
devices: "0,1,2,3"
|
||||
tensor_parallel_size: 4
|
||||
omni_kv_config:
|
||||
need_send_cache: true
|
||||
rank_mapping:
|
||||
from_tp: 4
|
||||
to_tp: 4
|
||||
output_connectors:
|
||||
to_stage_1: yuanrong_te_connector
|
||||
|
||||
- stage_id: 1
|
||||
runtime:
|
||||
devices: "4,5,6,7"
|
||||
engine_args:
|
||||
parallel_config:
|
||||
tensor_parallel_size: 4
|
||||
omni_kv_config:
|
||||
need_recv_cache: true
|
||||
rank_mapping:
|
||||
from_tp: 4
|
||||
to_tp: 4
|
||||
devices: "4,5,6,7"
|
||||
parallel_config:
|
||||
tensor_parallel_size: 4
|
||||
omni_kv_config:
|
||||
need_recv_cache: true
|
||||
rank_mapping:
|
||||
from_tp: 4
|
||||
to_tp: 4
|
||||
input_connectors:
|
||||
from_stage_0: yuanrong_te_connector
|
||||
```
|
||||
|
||||
@@ -41,7 +41,7 @@ With this in mind, consider the set of blocks in a 2D layout, where the row repr
|
||||
|
||||
### Example
|
||||
!!! note "Note 3"
|
||||
Prefix caching in vLLM-Omni currently is only supported on AutoRegressive stages with one kv-cache group. It can be enabled/disabled per-stage via the `enable_prefix_caching` parameter in the model's stage config.
|
||||
Prefix caching in vLLM-Omni currently is only supported on AutoRegressive stages with one kv-cache group. Configure it with the pipeline-wide `enable_prefix_caching` field in the deploy config.
|
||||
|
||||
The way in which vLLM-Omni ties into vLLM's prefix caching is best understood by example. Say that we have the following:
|
||||
|
||||
|
||||
@@ -76,6 +76,12 @@ equivalent. `auto-round` and `auto_round` use the Omni INC/AutoRound adapter.
|
||||
ModelOpt checkpoint metadata is detected from its method, producer metadata, or
|
||||
`quant_algo`, then mapped to the corresponding vLLM ModelOpt configuration.
|
||||
|
||||
Unless the input is a per-component dictionary, the resolved configuration is
|
||||
passed unchanged to every quantization-aware component constructed by the
|
||||
pipeline. It affects only layers supported by that component's quantization
|
||||
method; it does not rewrite arbitrary `torch.nn` modules. A per-component
|
||||
dictionary narrows this global scope through runtime layer-prefix routing.
|
||||
|
||||
The factory uses Omni-specific overrides for methods whose diffusion behavior
|
||||
or platform dispatch is not provided by the vLLM registry. The current override
|
||||
set includes INT8, BitsAndBytes, MXFP8, MXFP4, MXFP4 dual-scale, and INC/
|
||||
@@ -154,9 +160,11 @@ quantizable vLLM layers. Each method configuration is responsible for:
|
||||
Model code must keep precision-sensitive or unsupported modules unquantized.
|
||||
The shared `safe_quant_config()` helper is used by model integrations for
|
||||
normalization and modulation layers where a generic FP8 configuration would be
|
||||
unsafe. Text encoders, audio/vision encoders, VAEs, schedulers, and tokenizers
|
||||
are not implicitly quantized just because the main transformer is quantized;
|
||||
they require explicit component routing and method support.
|
||||
unsafe. Encoders exposed through the quantization factory receive a global
|
||||
configuration just like the main transformer, but only their supported vLLM
|
||||
quantizable layers are affected. Ordinary `torch.nn` encoder layers, VAEs,
|
||||
schedulers, and tokenizers are not rewritten automatically. A component map can
|
||||
select a narrower scope, but it cannot add quantization support to a layer.
|
||||
|
||||
Weight quantization and quantized KV cache are separate paths. The former is
|
||||
resolved through `quantization_config`; runtime attention/KV-cache quantization
|
||||
@@ -182,12 +190,15 @@ configured parallelism strategy:
|
||||
- `WeightsMapper` transformations must be applied before matching ignored-layer
|
||||
lists or component prefixes.
|
||||
|
||||
Distributed layerwise offload has an additional boundary: its sharded mmap
|
||||
AllGather path is not compatible with online quantization because the path
|
||||
expects already materialized checkpoint weights. Use the rank-local
|
||||
`--dlo-no-use-allgather` path or a compatible pre-quantized checkpoint when
|
||||
combining these features. See the [DLO design document](distributed_layerwise_offload.md)
|
||||
for the full compatibility matrix.
|
||||
Distributed layerwise offload has an additional boundary: direct checkpoint
|
||||
mmap cannot prepare online-quantized tensors because it bypasses the ordinary
|
||||
loader that creates their runtime weights and scales. Per-tensor online FP8
|
||||
linears can still use DLO AllGather through the ordinary loader: each rank first
|
||||
finalizes the FP8 tensors, then DLO shards those runtime tensors for
|
||||
reconstruction during prefetch. Other online methods remain limited to
|
||||
`--dlo-no-use-allgather` until their packing and scale layouts are validated.
|
||||
See the [DLO design document](offloader/distributed_layerwise_offload.md) for
|
||||
the full compatibility matrix.
|
||||
|
||||
## Adding a quantization backend
|
||||
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
# Realtime AR-Diffusion sessions
|
||||
|
||||
> **Status:** experimental. This document describes the internal execution
|
||||
> contract implemented under `vllm_omni.experimental.ar_diffusion`. It does not
|
||||
> define a public HTTP or WebSocket schema.
|
||||
|
||||
## Scope
|
||||
|
||||
Realtime AR-Diffusion serves world models that generate one autoregressive
|
||||
latent block per request while retaining model state across requests. The
|
||||
generic runtime owns identity, event ordering, session lifecycle, routing, and
|
||||
KV allocation. A model adapter owns model-specific controls and conditioning.
|
||||
|
||||
LingBot World v2 is the first single-KV-branch integration. DreamZero uses the
|
||||
same runner capability with two logical CFG branches.
|
||||
|
||||
## Identities
|
||||
|
||||
Four identifiers have distinct lifetimes:
|
||||
|
||||
| Identifier | Lifetime | Owner | Contract |
|
||||
| --- | --- | --- | --- |
|
||||
| `session_id` | One persistent world | Session manager | Selects runner KV and model-owned state. |
|
||||
| `event_id` | One control/prompt update | Transport adapter | Unique and monotonically increasing within a session, including across reset. |
|
||||
| `chunk_index` | One committed AR block position | Session | Contiguous from zero; reset starts again at zero. |
|
||||
| `request_id` | One chunk execution | Session | Correlates the tick with its returned metadata. |
|
||||
|
||||
`AsyncOmni` keeps its normal UUID-suffixed engine routing ID. The tick
|
||||
`request_id` remains inside the immutable AR-Diffusion snapshot and the
|
||||
standard output metadata, while caller-visible `OmniRequestOutput.request_id`
|
||||
continues to use AsyncOmni's existing external-ID contract. Protocol identity
|
||||
therefore does not require a private entrypoint override.
|
||||
|
||||
## Request lifecycle
|
||||
|
||||
1. `ARDiffusionSession.accept_event()` validates and queues an immutable
|
||||
`ARDiffusionSessionEvent`. Prompt and opaque control tracks may be updated in
|
||||
the same event.
|
||||
2. `ARDiffusionSession.next_chunk()` serializes chunk execution and calls
|
||||
`_build_tick_locked()`. The resulting `ARDiffusionTickRequest` is a snapshot
|
||||
of the current prompt, reduced controls, ordered event IDs, and chunk index.
|
||||
3. `ARDiffusionOmniTickConsumer.execute_tick()` copies the stage sampling
|
||||
parameters, stores the typed tick in
|
||||
`sampling_params.extra_args["ar_diffusion_tick"]`, constructs the normal Omni
|
||||
prompt through its `prompt_provider`, and invokes `AsyncOmni.generate()`.
|
||||
4. `AsyncOmni` allocates its normal unique engine routing ID and submits one
|
||||
`OmniDiffusionRequest` through the orchestrator.
|
||||
5. `ARDiffusionModelRunner._request_session()` parses the typed tick.
|
||||
`_get_or_create_session()` obtains runner-owned paged KV, and
|
||||
`bind_ar_diffusion_state()` exposes it to the pipeline only for the duration
|
||||
of `execute_model()`.
|
||||
6. The model pipeline validates the tick and generates exactly one latent
|
||||
block. LingBot interprets camera controls in
|
||||
`LingBotCameraControlReducer` and
|
||||
`LingBotWorldCausalDMDPipeline.forward()`; the generic runtime does not parse
|
||||
camera or action schemas.
|
||||
7. The pipeline returns one `DiffusionOutput` with the generated payload and an
|
||||
`ARDiffusionChunkMetadata` mapping under `metadata["ar_diffusion"]`.
|
||||
`AsyncOmni` exposes it as
|
||||
`OmniRequestOutput.multimodal_output["metadata"]["ar_diffusion"]`.
|
||||
8. The consumer parses the standard envelope. The session commits its reducer
|
||||
state, prompt, controls, event IDs, and next chunk index only when returned
|
||||
metadata exactly equals the submitted tick snapshot.
|
||||
|
||||
The metadata envelope is:
|
||||
|
||||
```json
|
||||
{
|
||||
"metadata": {
|
||||
"ar_diffusion": {
|
||||
"session_id": "world-7",
|
||||
"request_id": "ar-world-7-3-...",
|
||||
"chunk_index": 3,
|
||||
"applied_event_ids": [10, 11]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Transaction and failure semantics
|
||||
|
||||
Accepted events are not acknowledged as applied until the model output and
|
||||
metadata are validated. Reducer `prepare()` is speculative; reducer `commit()`
|
||||
and the session snapshot form one logical commit. A model, metadata, or reducer
|
||||
failure leaves the chunk index and queued events uncommitted and transitions the
|
||||
session to `FAILED`.
|
||||
|
||||
After a tick failure, worker state is closed because a forward may have
|
||||
partially modified or already released KV. The same chunk is not retried in
|
||||
place. A caller must explicitly reset the session, starting again at chunk
|
||||
zero, or close it.
|
||||
|
||||
Explicit close follows this state machine:
|
||||
|
||||
```text
|
||||
ACTIVE or FAILED
|
||||
|
|
||||
v
|
||||
CLOSING ---- worker cleanup succeeds ----> CLOSED
|
||||
|
|
||||
+------- worker cleanup fails --------> CLEANUP_FAILED
|
||||
|
|
||||
+-- close retry --> CLOSING
|
||||
```
|
||||
|
||||
`CLEANUP_FAILED` is a local tombstone. The session manager retains it, rejects
|
||||
creation of the same `session_id`, and rejects reset. Only an idempotent close
|
||||
retry that succeeds removes the session. Transport disconnect uses the same
|
||||
path.
|
||||
|
||||
## KV ownership and capacity
|
||||
|
||||
`ARDiffusionKVCacheSpec` is the pipeline-owned immutable geometry contract. It
|
||||
declares:
|
||||
|
||||
- TP-local self-attention geometry, AR block size, sink, and recent window;
|
||||
- logical KV branches and their worker-local slots;
|
||||
- fixed-length cross-attention caches;
|
||||
- scratch tokens required by an uncommitted forward;
|
||||
- persistent model-owned CUDA bytes per resident session; and
|
||||
- the requested resident-session capacity.
|
||||
|
||||
The runner computes:
|
||||
|
||||
```text
|
||||
required(capacity) =
|
||||
scratch
|
||||
+ managed_self_attention_pages(capacity)
|
||||
+ capacity * cross_attention_bytes_per_session
|
||||
+ capacity * model_owned_state_bytes_per_session
|
||||
```
|
||||
|
||||
`gpu_memory_fraction` is a soft expansion budget:
|
||||
|
||||
```text
|
||||
configured_budget = available_device_bytes * gpu_memory_fraction
|
||||
effective_budget = max(configured_budget, required(1))
|
||||
```
|
||||
|
||||
If `required(1)` exceeds actual available device memory, initialization fails.
|
||||
Otherwise the runner always admits one viable session and uses the configured
|
||||
fraction to select additional resident sessions up to the model-declared cap.
|
||||
All model-owned reservations are deducted before the paged self-attention pool
|
||||
is allocated.
|
||||
|
||||
LingBot reports its persistent full-horizon image-condition tensor. DreamZero
|
||||
reports the measured 603 MiB per-session Wan VAE causal-convolution state.
|
||||
|
||||
## Concurrency and routing limits
|
||||
|
||||
The current runner executes one request at a time:
|
||||
|
||||
- `max_num_seqs` must be one;
|
||||
- request batching and diffusion step execution are rejected;
|
||||
- one AR block is generated per engine request; and
|
||||
- an AR-Diffusion stage must have exactly one replica.
|
||||
|
||||
The single-replica restriction is intentional. Multi-replica support requires
|
||||
session-affine routing so every tick, reset, and close reaches the worker that
|
||||
owns the session. Random or round-robin routing is not correct.
|
||||
|
||||
Multiple resident sessions may share one runner. Capacity selection accounts
|
||||
for all persistent pools, and the runner performs LRU eviction through the same
|
||||
model lifecycle hook used by explicit close.
|
||||
|
||||
## Model boundary
|
||||
|
||||
The generic runtime transports controls as opaque
|
||||
`ARDiffusionControlInput(track, schema, data)` values. Model adapters validate
|
||||
and reduce those values. This keeps target/velocity, key state, pose,
|
||||
intrinsics, and other model-specific conventions out of the session protocol.
|
||||
|
||||
For LingBot World v2:
|
||||
|
||||
- `lingbot_world/actions.py` parses key-state and trajectory controls;
|
||||
- `lingbot_world/camera.py` loads or constructs camera trajectories and Plücker embeddings;
|
||||
- `lingbot_world/transformer.py` implements checkpoint-compatible causal attention; and
|
||||
- `lingbot_world/pipeline.py` constructs conditioning, owns small non-KV session state, and
|
||||
produces one block plus the standard metadata envelope.
|
||||
|
||||
## Non-goals
|
||||
|
||||
This contract does not currently provide:
|
||||
|
||||
- a public HTTP or WebSocket request schema (the structured-interaction
|
||||
frontend is tracked separately in
|
||||
[#5527](https://github.com/vllm-project/vllm-omni/pull/5527));
|
||||
- camera/action semantics shared by every world model;
|
||||
- session migration or replication across workers;
|
||||
- retry of an ambiguous partially executed chunk;
|
||||
- cross-stage KV transfer; or
|
||||
- stateful streaming VAE decode.
|
||||
|
||||
Those features can be layered on top without adding LingBot-specific identity
|
||||
or lifecycle fields to the generic runtime.
|
||||
|
||||
## Required regression coverage
|
||||
|
||||
CPU contract tests cover:
|
||||
|
||||
- separation of tick correlation IDs from internal engine routing IDs;
|
||||
- event ordering, metadata equality, and reducer fail-closed commit;
|
||||
- close/disconnect failure tombstones and cleanup retry;
|
||||
- capacity one under the default fraction for shipped LingBot geometry;
|
||||
- capacity expansion under a tuned fraction;
|
||||
- DreamZero model-owned state accounting;
|
||||
- runner session reuse, reset, close, LRU eviction, and forward cleanup; and
|
||||
- LingBot model registration, imports, camera/action reduction, and one-block
|
||||
output metadata.
|
||||
|
||||
GPU validation must additionally exercise real model loading, action input,
|
||||
prompt switching, rolling-window replacement, reset, close, finite output
|
||||
latents, and exact metadata/request identity.
|
||||
Loaded 100 of 1270 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user