[ci] xpu: trigger pr-test-xpu on multimodal_gen changes (#36100)

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Ma Mingfei <mingfei.ma@intel.com>
This commit is contained in:
ashwini rathi
2026-08-27 14:50:26 +08:00
committed by GitHub
co-authored by Claude Opus 4.7 Ma Mingfei
parent adcf73d7f7
commit 72bf8c4d53
5 changed files with 363 additions and 4 deletions
+95 -3
View File
@@ -28,7 +28,9 @@ jobs:
check-changes:
runs-on: ubuntu-latest
outputs:
main_package: ${{ steps.filter.outputs.main_package || steps.run-mode.outputs.run_all_tests }}
changes_exist: ${{ steps.filter.outputs.main_package == 'true' || steps.filter.outputs.multimodal_gen == 'true' || steps.run-mode.outputs.run_all_tests == 'true' }}
main_package: ${{ steps.filter.outputs.main_package == 'true' || steps.run-mode.outputs.run_all_tests == 'true' }}
multimodal_gen: ${{ steps.filter.outputs.multimodal_gen == 'true' || steps.run-mode.outputs.run_all_tests == 'true' }}
steps:
- name: Checkout code
uses: actions/checkout@v4
@@ -60,11 +62,16 @@ jobs:
- "python/sglang/kernels/aot/**/!(*.md|THIRDPARTYNOTICES.txt|LICENSE)"
- ".github/workflows/pr-test-xpu.yml"
- "docker/xpu.Dockerfile"
multimodal_gen:
- "python/sglang/multimodal_gen/**/!(*.md|*.ipynb)"
- "python/pyproject_xpu.toml"
- ".github/workflows/pr-test-xpu.yml"
- "docker/xpu.Dockerfile"
# ==================== PR Gate ==================== #
pr-gate:
needs: check-changes
if: needs.check-changes.outputs.main_package == 'true'
if: needs.check-changes.outputs.changes_exist == 'true'
uses: ./.github/workflows/pr-gate.yml
secrets: inherit
@@ -249,15 +256,96 @@ jobs:
docker rmi -f "${CI_SGLANG_XPU_IMAGE}" || true
fi
# ==================== Multimodal Gen ==================== #
multimodal-gen-test-1-gpu-xpu:
needs: [check-changes, pr-gate]
if: needs.check-changes.outputs.multimodal_gen == 'true'
runs-on: bmg-multigen-models
env:
DOCKERHUB_INTEL_USERNAME: ${{ secrets.DOCKERHUB_INTEL_USERNAME }}
DOCKERHUB_INTEL_TOKEN: ${{ secrets.DOCKERHUB_INTEL_TOKEN }}
steps:
- name: Reset workspace ownership
run: |
docker run --rm -v "${{ github.workspace }}:/w" busybox:latest \
chown -R "$(id -u):$(id -g)" /w || true
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
ref: ${{ inputs.ref || github.ref }}
- name: Start CI container
run: |
export HF_TOKEN="$(cat ~/huggingface_token.txt)"
bash scripts/ci/xpu/xpu_ci_start_container.sh
env:
GITHUB_WORKSPACE: ${{ github.workspace }}
- name: Install Dependency
timeout-minutes: 60
run: |
docker exec ci_sglang_xpu /opt/venv/bin/python3 -m pip install --upgrade pip
docker exec ci_sglang_xpu /opt/venv/bin/python3 -m pip install pytest expecttest ray huggingface_hub tabulate "lmcache>=0.3.9"
docker exec ci_sglang_xpu /opt/venv/bin/python3 -m pip uninstall -y flashinfer-python sgl-kernel sglang
docker exec ci_sglang_xpu cp /sglang-checkout/python/pyproject_xpu.toml /sglang-checkout/python/pyproject.toml
# Fetch tags so setuptools_scm resolves a real version instead of
# falling back to 0.0.0 on a shallow/tag-less checkout.
docker exec -w /sglang-checkout ci_sglang_xpu git fetch origin '+refs/tags/*:refs/tags/*' --force
docker exec -w /sglang-checkout/python ci_sglang_xpu /opt/venv/bin/python3 -m pip install --no-cache-dir . --extra-index-url https://download.pytorch.org/whl/xpu
docker exec ci_sglang_xpu /opt/venv/bin/python3 -m pip install --no-cache-dir --no-deps xgrammar==0.1.33
docker exec ci_sglang_xpu /bin/bash -c '/opt/venv/bin/hf auth login --token ${HF_TOKEN}'
- name: Run diffusion server tests (1-GPU)
timeout-minutes: 60
run: |
docker exec ci_sglang_xpu bash -c "source /opt/venv/bin/activate && cd /sglang-checkout/python && python3 sglang/multimodal_gen/test/run_suite.py --suite 1-gpu-xpu"
- name: Cleanup container
if: always()
run: |
docker run --rm -v "${{ github.workspace }}:/w" busybox:latest \
chown -R "$(id -u):$(id -g)" /w || true
rm -rf \
python/build \
python/dist \
python/sglang.egg-info \
python/sglang/*.egg-info \
test/result.jsonl \
test/results \
test/.pytest_cache \
.pytest_cache || true
find . -type d -name "__pycache__" -prune -exec rm -rf {} + || true
find . -type f -name "*.pyc" -delete || true
# SIGTERM sglang and drain GPU context before `docker rm -f`;
# SIGKILL leaves the xe/GuC exec queue registered and triggers a
# GT reset (+ devcoredump) on B580.
if docker ps --format '{{.Names}}' | grep -qx ci_sglang_xpu; then
docker exec ci_sglang_xpu bash -c '
pkill -TERM -f "sglang|run_suite|python3.*test_" 2>/dev/null || true
for _ in $(seq 1 30); do
pgrep -f "sglang::|sglang.launch_server" >/dev/null || break
sleep 1
done
pkill -KILL -f "sglang|run_suite" 2>/dev/null || true
' || true
fi
docker rm -f ci_sglang_xpu || true
if [[ -n "${CI_SGLANG_XPU_IMAGE:-}" ]]; then
docker rmi -f "${CI_SGLANG_XPU_IMAGE}" || true
fi
finish:
if: always()
needs: [stage-a-test-1-gpu-xpu, stage-b-test-1-gpu-xpu, pr-gate]
needs: [stage-a-test-1-gpu-xpu, stage-b-test-1-gpu-xpu, multimodal-gen-test-1-gpu-xpu, pr-gate]
runs-on: ubuntu-latest
steps:
- name: Check job status
run: |
stage_a="${{ needs.stage-a-test-1-gpu-xpu.result }}"
stage_b="${{ needs.stage-b-test-1-gpu-xpu.result }}"
multimodal_gen="${{ needs.multimodal-gen-test-1-gpu-xpu.result }}"
if [ "$stage_a" != "success" ] && [ "$stage_a" != "skipped" ]; then
echo "stage-a failed with result: $stage_a"
exit 1
@@ -266,5 +354,9 @@ jobs:
echo "stage-b failed with result: $stage_b"
exit 1
fi
if [ "$multimodal_gen" != "success" ] && [ "$multimodal_gen" != "skipped" ]; then
echo "multimodal-gen failed with result: $multimodal_gen"
exit 1
fi
echo "All jobs completed successfully"
exit 0
@@ -1223,8 +1223,11 @@ class DenoisingStage(PipelineStage, RolloutDenoisingMixin):
image_kwargs = self.prepare_extra_func_kwargs(
getattr(self.transformer, "forward", self.transformer),
{
# Pass None (not []) so T2V paths whose transformer has no
# image_embedder skip the branch; diffusers guards on
# `is not None` only.
# TODO: make sure on-device
"encoder_hidden_states_image": image_embeds,
"encoder_hidden_states_image": image_embeds if image_embeds else None,
},
)
@@ -1233,6 +1233,40 @@ ONE_GPU_5090_CASES.append(_make_5090_flux_layerwise_cpu_offload_case())
ONE_GPU_5090_CASES.append(_make_5090_h3_consumer_budget_case())
# Intel Arc Pro B60 has 24 GiB of XPU memory, so only sub-~5B-parameter
# checkpoints fit fully resident. Larger cases in ONE_GPU_CASES (FLUX.1-dev,
# FLUX.2-dev, Qwen-Image, Hunyuan3D, SANA-Video, image-edit families) OOM on
# 24 GiB, and the FP8/NVFP4 quant paths are CUDA-only.
ONE_GPU_XPU_CASE_IDS = (
"zimage_image_t2i",
"flux_2_klein_image_t2i",
"flux_2_klein_base_image_t2i",
"wan2_1_t2v_1.3b",
)
def _select_xpu_cases(case_ids: tuple[str, ...]) -> list[DiffusionTestCase]:
cases_by_id = {case.id: case for case in ONE_GPU_CASES}
missing = [case_id for case_id in case_ids if case_id not in cases_by_id]
if missing:
raise RuntimeError(f"Unknown XPU diffusion case(s): {missing}")
return [cases_by_id[case_id] for case_id in case_ids]
# Consistency GT images are H100-generated; XPU output diverges at the
# pixel level (different attention kernels + fp reductions on Xe2) so
# SSIM/PSNR against the H100 golden always fails. test_server_1_gpu.py
# parametrizes directly from ONE_GPU_CASES, so mutate those entries in
# place -- overriding only via ONE_GPU_XPU_CASES would be ignored.
if current_platform.is_xpu():
_xpu_ids = set(ONE_GPU_XPU_CASE_IDS)
for _i, _case in enumerate(ONE_GPU_CASES):
if _case.id in _xpu_ids and _case.run_consistency_check:
ONE_GPU_CASES[_i] = replace(_case, run_consistency_check=False)
ONE_GPU_XPU_CASES = _select_xpu_cases(ONE_GPU_XPU_CASE_IDS)
# Nested unit/ tests verified to pass on AMD/ROCm as-is (no code change).
# Enabled incrementally and AMD-only: the CUDA `multimodal-gen-unit-test`
# lane keeps the flat glob below. Files that still need fixes/skips are added
@@ -1300,6 +1334,9 @@ PARAMETRIZED_CASE_GROUPS = {
"1-gpu-5090": [
("test_server_1_gpu_5090.py", ONE_GPU_5090_CASES),
],
"1-gpu-xpu": [
("test_server_1_gpu.py", ONE_GPU_XPU_CASES),
],
"2-gpu": [
("test_server_2_gpu.py", TWO_GPU_CASES),
],
@@ -0,0 +1,222 @@
{
"metadata": {
"model": "Diffusion Server",
"hardware": "CI Intel Arc Pro B60 (24 GiB) pool: bmg-multigen-models",
"description": "Reference numbers seeded from XPU multimodal_gen CI run 32736878259 job 97461821112 (PR #36100).",
"last_updated": "2026-08-24"
},
"tolerances": {
"long_term": {
"e2e": 0.30,
"denoise_stage": 0.20,
"non_denoise_stage": 0.60,
"denoise_step": 0.35,
"denoise_agg": 0.25,
"load_peak_vram": 0.05,
"runtime_peak_vram": 0.05
},
"pr_test": {
"e2e": 0.40,
"denoise_stage": 0.35,
"non_denoise_stage": 0.90,
"denoise_step": 0.45,
"denoise_agg": 0.30,
"load_peak_vram": 0.05,
"runtime_peak_vram": 0.05
}
},
"improvement_reporting": {
"threshold": 0.2
},
"sampling": {
"step_fractions": [
0.0,
0.2,
0.4,
0.6,
0.8,
1.0
]
},
"scenarios": {
"zimage_image_t2i": {
"estimated_full_test_time_s": 65.1,
"stages_ms": {
"InputValidationStage": 0.03,
"TextEncodingStage": 87.64,
"LatentPreparationStage": 0.21,
"TimestepPreparationStage": 136.9,
"DenoisingStage": 8361.1,
"DecodingStage": 8.39
},
"denoise_step_ms": {
"0": 99.57,
"1": 927.61,
"2": 926.72,
"3": 928.32,
"4": 929.29,
"5": 928.8,
"6": 925.2,
"7": 927.22,
"8": 931.28
},
"expected_e2e_ms": 9312.75,
"expected_avg_denoise_ms": 836.0,
"expected_median_denoise_ms": 927.61
},
"flux_2_klein_image_t2i": {
"estimated_full_test_time_s": 106.8,
"stages_ms": {
"InputValidationStage": 0.04,
"TextEncodingStage": 37.83,
"ImageVAEEncodingStage": 0.0,
"LatentPreparationStage": 0.33,
"TimestepPreparationStage": 351.26,
"DenoisingStage": 2518.52,
"DecodingStage": 9.13
},
"denoise_step_ms": {
"0": 83.44,
"1": 16.73,
"2": 18.04,
"3": 17.11
},
"expected_e2e_ms": 3509.48,
"expected_avg_denoise_ms": 33.83,
"expected_median_denoise_ms": 17.58
},
"flux_2_klein_base_image_t2i": {
"stages_ms": {
"InputValidationStage": 0.03,
"TextEncodingStage": 36.3,
"ImageVAEEncodingStage": 0.0,
"LatentPreparationStage": 0.28,
"TimestepPreparationStage": 355.5,
"DenoisingStage": 55237.43,
"DecodingStage": 11.09
},
"denoise_step_ms": {
"0": 106.73,
"1": 34.25,
"2": 34.59,
"3": 34.59,
"4": 35.08,
"5": 34.24,
"6": 34.03,
"7": 34.47,
"8": 34.17,
"9": 44.04,
"10": 34.83,
"11": 34.64,
"12": 35.38,
"13": 34.32,
"14": 35.51,
"15": 36.16,
"16": 35.32,
"17": 34.75,
"18": 35.28,
"19": 50.88,
"20": 35.41,
"21": 35.36,
"22": 34.53,
"23": 35.42,
"24": 34.75,
"25": 34.78,
"26": 34.95,
"27": 34.84,
"28": 35.38,
"29": 34.7,
"30": 34.42,
"31": 35.01,
"32": 34.98,
"33": 34.61,
"34": 34.78,
"35": 34.76,
"36": 34.61,
"37": 37.59,
"38": 35.0,
"39": 34.6,
"40": 35.52,
"41": 35.14,
"42": 34.84,
"43": 35.16,
"44": 33.86,
"45": 34.52,
"46": 34.94,
"47": 33.84,
"48": 35.14,
"49": 34.75
},
"expected_e2e_ms": 56248.35,
"expected_avg_denoise_ms": 36.83,
"expected_median_denoise_ms": 34.84
},
"wan2_1_t2v_1.3b": {
"estimated_full_test_time_s": 331.5,
"stages_ms": {
"InputValidationStage": 0.04,
"TextEncodingStage": 704.97,
"LatentPreparationStage": 0.89,
"TimestepPreparationStage": 2.71,
"DenoisingStage": 114601.91,
"DecodingStage": 73.74,
"per_frame_generation": null
},
"denoise_step_ms": {
"0": 208.34,
"1": 80.0,
"2": 84.33,
"3": 85.37,
"4": 92.98,
"5": 85.51,
"6": 84.71,
"7": 85.0,
"8": 84.82,
"9": 85.45,
"10": 85.89,
"11": 86.33,
"12": 85.68,
"13": 86.51,
"14": 94.06,
"15": 86.65,
"16": 86.39,
"17": 86.15,
"18": 86.54,
"19": 86.88,
"20": 87.36,
"21": 85.66,
"22": 86.22,
"23": 85.45,
"24": 94.66,
"25": 86.44,
"26": 86.3,
"27": 86.35,
"28": 85.29,
"29": 86.31,
"30": 85.8,
"31": 86.12,
"32": 86.03,
"33": 86.42,
"34": 91.27,
"35": 85.84,
"36": 86.3,
"37": 85.04,
"38": 84.99,
"39": 85.46,
"40": 85.72,
"41": 84.76,
"42": 88.92,
"43": 85.58,
"44": 86.57,
"45": 85.42,
"46": 87.03,
"47": 85.65,
"48": 86.77,
"49": 84.42
},
"expected_e2e_ms": 116299.31,
"expected_avg_denoise_ms": 88.83,
"expected_median_denoise_ms": 86.07
}
}
}
@@ -853,6 +853,7 @@ PERF_BASELINE_FILE_BY_PLATFORM = {
"h100": "h100.json",
"b200": "b200.json",
"5090": "5090.json",
"xpu_b60": "xpu_b60.json",
}
PERF_BASELINE_PLATFORM_ALIASES = {
"sm90": "h100",
@@ -864,6 +865,8 @@ PERF_BASELINE_PLATFORM_ALIASES = {
"sm120": "5090",
"rtx5090": "5090",
"5090": "5090",
"xpu": "xpu_b60",
"bmg": "xpu_b60",
}
@@ -883,6 +886,8 @@ def get_perf_baseline_platform() -> str:
override = os.getenv(PERF_BASELINE_PLATFORM_ENV)
if override:
return _normalize_perf_baseline_platform(override)
if current_platform.is_xpu():
return "xpu_b60"
if current_platform.is_sm120():
return "5090"
if current_platform.is_blackwell():