chore: import upstream snapshot with attribution
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
PR Test (NPU) / check-changes (push) Has been cancelled
PR Test (NPU) / pr-gate (push) Has been cancelled
PR Test (NPU) / set-image-config (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-1-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (0) (push) Has been cancelled
PR Test (NPU) / stage-b-test-2-npu-a2 (1) (push) Has been cancelled
PR Test (NPU) / stage-b-test-4-npu-a3 (push) Has been cancelled
PR Test (NPU) / stage-b-test-16-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-1-npu-a3 (push) Has been cancelled
PR Test (NPU) / multimodal-gen-test-2-npu-a3 (push) Has been cancelled
PR Test (Arm64) / pr-gate (push) Has been cancelled
PR Test (Arm64) / check-changes (push) Has been cancelled
PR Test (Arm64) / build-test (push) Has been cancelled
PR Test (sgl-router) / gate (push) Has been cancelled
PR Test (sgl-router) / tier-1 — lint (push) Has been cancelled
PR Test (sgl-router) / tier-2 — build + test (push) Has been cancelled
PR Test (sgl-router) / tier-3 — docker (placeholder) (push) Has been cancelled
PR Test (sgl-router) / tier-3 — k8s integration (push) Has been cancelled
PR Test (sgl-router) / tier-3 — e2e (push) Has been cancelled
PR Test (sgl-router) / finish (push) Has been cancelled
PR Test (NPU) / single-node-poc (map[name:qwen3_6_27b_w8a8_1p_in64k_out1k_50ms runner:linux-aarch64-a3-2 test_case:test/registered/ascend/performance/qwen3_6_27b/test_npu_qwen3_6_27b_w8a8_1p_in64k_out1k_50ms.py test_type:perf]) (push) Has been cancelled
PR Test (NPU) / pr-test-npu-finish (push) Has been cancelled
PR Test (Xeon) / pr-gate (push) Has been cancelled
PR Test (Xeon) / check-changes (push) Has been cancelled
PR Test (Xeon) / build-test (, xeon-gnr, base-b-test-cpu) (push) Has been cancelled
PR Test (XPU) / check-changes (push) Has been cancelled
PR Test (XPU) / pr-gate (push) Has been cancelled
PR Test (XPU) / stage-a-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / wait-for-stage-a (push) Has been cancelled
PR Test (XPU) / stage-b-test-1-gpu-xpu (push) Has been cancelled
PR Test (XPU) / finish (push) Has been cancelled
CI Model Inventory / build-inventory (push) Has been cancelled
Lint / lint (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Compilation Check (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Manual Policy (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark - Request Processing (push) Has been cancelled
PR Benchmark (SMG Components) / Benchmark Summary (push) Has been cancelled
PR Test (SMG) / build-wheel (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on windows (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (x86_64 - auto) (push) Has been cancelled
PR Test (SMG) / python-unit-tests (push) Has been cancelled
PR Test (SMG) / unit-tests (push) Has been cancelled
PR Test (SMG) / benchmarks (push) Has been cancelled
PR Test (SMG) / chat-completions (push) Has been cancelled
PR Test (SMG) / chat-completions-4gpu (push) Has been cancelled
PR Test (SMG) / e2e (push) Has been cancelled
PR Test (SMG) / docker-build-test (push) Has been cancelled
PR Test (SMG) / k8s-integration (push) Has been cancelled
PR Test (SMG) / finish (push) Has been cancelled
PR Test (SMG) / summarize-benchmarks (push) Has been cancelled
Release SGLang Model Gateway Docker Image / publish (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on macos (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - auto) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (aarch64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / build on linux (x86_64 - musllinux_1_1) (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Build SDist (push) Has been cancelled
Release SGLang Model Gateway to PyPI / Upload to PyPI (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (aarch64, 12.9, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu129-matrix (x86_64, 12.9, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu129 (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (aarch64, 13.0, 3.10, arm-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / build-cu130-matrix (x86_64, 13.0, 3.10, x64-kernel-build-node) (push) Has been cancelled
Release SGLang Kernels / release-cu130 (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 700) (push) Has been cancelled
Release SGLang Kernels / build-rocm-matrix (3.10, 720) (push) Has been cancelled
Release SGLang Kernels / release-rocm700 (push) Has been cancelled
Release SGLang Kernels / release-rocm720 (push) Has been cancelled
Release SGLang Kernels / build-musa43 (43, 3.10) (push) Has been cancelled
Release SGLang Kernels / release-musa43 (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,703 @@
|
||||
{
|
||||
"metadata": {
|
||||
"model": "Diffusion Server",
|
||||
"hardware": "Ascend A3",
|
||||
"description": "Reference numbers captured from the CI diffusion server baseline run"
|
||||
},
|
||||
"scenarios": {
|
||||
"flux_image_t2i_npu": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 0.06,
|
||||
"TextEncodingStage": 468.6,
|
||||
"TimestepPreparationStage": 41.44,
|
||||
"LatentPreparationStage": 0.28,
|
||||
"DenoisingStage": 19973.94,
|
||||
"DecodingStage": 8.58
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 100.15,
|
||||
"1": 95.5,
|
||||
"2": 334.93,
|
||||
"3": 413.4,
|
||||
"4": 413.43,
|
||||
"5": 413.33,
|
||||
"6": 413.6,
|
||||
"7": 413.2,
|
||||
"8": 413.4,
|
||||
"9": 413.15,
|
||||
"10": 413.24,
|
||||
"11": 413.37,
|
||||
"12": 413.63,
|
||||
"13": 413.39,
|
||||
"14": 413.49,
|
||||
"15": 413.69,
|
||||
"16": 413.61,
|
||||
"17": 413.38,
|
||||
"18": 413.32,
|
||||
"19": 413.3,
|
||||
"20": 413.45,
|
||||
"21": 413.49,
|
||||
"22": 413.31,
|
||||
"23": 413.14,
|
||||
"24": 413.46,
|
||||
"25": 413.31,
|
||||
"26": 413.61,
|
||||
"27": 413.58,
|
||||
"28": 413.52,
|
||||
"29": 413.37,
|
||||
"30": 413.46,
|
||||
"31": 413.83,
|
||||
"32": 413.23,
|
||||
"33": 413.49,
|
||||
"34": 413.45,
|
||||
"35": 413.41,
|
||||
"36": 413.4,
|
||||
"37": 413.46,
|
||||
"38": 413.38,
|
||||
"39": 413.43,
|
||||
"40": 413.52,
|
||||
"41": 413.56,
|
||||
"42": 413.63,
|
||||
"43": 413.46,
|
||||
"44": 413.47,
|
||||
"45": 413.38,
|
||||
"46": 413.57,
|
||||
"47": 413.37,
|
||||
"48": 413.19,
|
||||
"49": 413.38
|
||||
},
|
||||
"expected_e2e_ms": 20670.75,
|
||||
"expected_avg_denoise_ms": 399.24,
|
||||
"expected_median_denoise_ms": 413.41
|
||||
},
|
||||
"flux_2_image_t2i_2npu": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 0.08,
|
||||
"TextEncodingStage": 192.4,
|
||||
"ImageVAEEncodingStage": 0.01,
|
||||
"LatentPreparationStage": 0.97,
|
||||
"TimestepPreparationStage": 34.65,
|
||||
"DenoisingStage": 45390.41,
|
||||
"DecodingStage": 5.32
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 84.23,
|
||||
"1": 80.0,
|
||||
"2": 874.6,
|
||||
"3": 918.81,
|
||||
"4": 900.4,
|
||||
"5": 910.67,
|
||||
"6": 903.36,
|
||||
"7": 904.97,
|
||||
"8": 906.84,
|
||||
"9": 906.39,
|
||||
"10": 904.99,
|
||||
"11": 909.96,
|
||||
"12": 901.67,
|
||||
"13": 908.8,
|
||||
"14": 902.93,
|
||||
"15": 906.17,
|
||||
"16": 906.67,
|
||||
"17": 905.89,
|
||||
"18": 906.9,
|
||||
"19": 907.1,
|
||||
"20": 905.31,
|
||||
"21": 907.93,
|
||||
"22": 903.68,
|
||||
"23": 904.49,
|
||||
"24": 905.73,
|
||||
"25": 907.66,
|
||||
"26": 906.71,
|
||||
"27": 912.69,
|
||||
"28": 901.4,
|
||||
"29": 909.9,
|
||||
"30": 901.72,
|
||||
"31": 904.35,
|
||||
"32": 905.61,
|
||||
"33": 905.97,
|
||||
"34": 906.5,
|
||||
"35": 921.45,
|
||||
"36": 892.58,
|
||||
"37": 909.03,
|
||||
"38": 903.82,
|
||||
"39": 906.25,
|
||||
"40": 905.18,
|
||||
"41": 905.06,
|
||||
"42": 906.21,
|
||||
"43": 911.62,
|
||||
"44": 901.04,
|
||||
"45": 909.09,
|
||||
"46": 904.29,
|
||||
"47": 905.16,
|
||||
"48": 907.35,
|
||||
"49": 905.65
|
||||
},
|
||||
"expected_e2e_ms": 46557.7,
|
||||
"expected_avg_denoise_ms": 872.7,
|
||||
"expected_median_denoise_ms": 905.81
|
||||
},
|
||||
"wan2_1_t2v_1.3b_1_npu": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 0.06,
|
||||
"TextEncodingStage": 2386.55,
|
||||
"LatentPreparationStage": 0.2,
|
||||
"TimestepPreparationStage": 3.03,
|
||||
"DenoisingStage": 26240.89,
|
||||
"DecodingStage": 720.28,
|
||||
"per_frame_generation": null
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 330.0,
|
||||
"1": 303.37,
|
||||
"2": 548.94,
|
||||
"3": 542.02,
|
||||
"4": 537.7,
|
||||
"5": 537.26,
|
||||
"6": 537.78,
|
||||
"7": 537.27,
|
||||
"8": 537.72,
|
||||
"9": 537.65,
|
||||
"10": 537.49,
|
||||
"11": 537.41,
|
||||
"12": 537.31,
|
||||
"13": 537.43,
|
||||
"14": 537.41,
|
||||
"15": 537.51,
|
||||
"16": 537.54,
|
||||
"17": 537.56,
|
||||
"18": 538.09,
|
||||
"19": 537.09,
|
||||
"20": 537.72,
|
||||
"21": 537.56,
|
||||
"22": 537.85,
|
||||
"23": 537.54,
|
||||
"24": 537.67,
|
||||
"25": 537.66,
|
||||
"26": 537.25,
|
||||
"27": 537.71,
|
||||
"28": 537.77,
|
||||
"29": 537.16,
|
||||
"30": 537.6,
|
||||
"31": 537.58,
|
||||
"32": 537.6,
|
||||
"33": 537.51,
|
||||
"34": 537.78,
|
||||
"35": 537.43,
|
||||
"36": 537.52,
|
||||
"37": 537.59,
|
||||
"38": 537.46,
|
||||
"39": 537.77,
|
||||
"40": 537.41,
|
||||
"41": 538.11,
|
||||
"42": 537.41,
|
||||
"43": 537.18,
|
||||
"44": 537.64,
|
||||
"45": 537.32,
|
||||
"46": 537.52,
|
||||
"47": 537.52,
|
||||
"48": 537.29,
|
||||
"49": 547.88
|
||||
},
|
||||
"expected_e2e_ms": 29360.56,
|
||||
"expected_avg_denoise_ms": 524.67,
|
||||
"expected_median_denoise_ms": 537.54,
|
||||
"estimated_full_test_time_s": 157.8
|
||||
},
|
||||
"wan2_2_t2v_14b_w8a8_2npu": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 0.09,
|
||||
"TextEncodingStage": 2789.3,
|
||||
"LatentPreparationStage": 0.28,
|
||||
"TimestepPreparationStage": 3.19,
|
||||
"DenoisingStage": 187650.19,
|
||||
"DecodingStage": 3491.88,
|
||||
"per_frame_generation": null
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 1415.84,
|
||||
"1": 4801.54,
|
||||
"2": 4781.57,
|
||||
"3": 4770.19,
|
||||
"4": 4808.86,
|
||||
"5": 4737.55,
|
||||
"6": 4774.02,
|
||||
"7": 4774.85,
|
||||
"8": 4773.25,
|
||||
"9": 4775.33,
|
||||
"10": 4771.31,
|
||||
"11": 4773.07,
|
||||
"12": 4773.18,
|
||||
"13": 4772.77,
|
||||
"14": 4773.68,
|
||||
"15": 4771.91,
|
||||
"16": 4776.16,
|
||||
"17": 4773.88,
|
||||
"18": 4769.87,
|
||||
"19": 4772.1,
|
||||
"20": 4774.55,
|
||||
"21": 4772.54,
|
||||
"22": 4772.39,
|
||||
"23": 4776.14,
|
||||
"24": 4772.84,
|
||||
"25": 4772.82,
|
||||
"26": 4789.34,
|
||||
"27": 4792.58,
|
||||
"28": 4807.52,
|
||||
"29": 4740.66,
|
||||
"30": 4773.46,
|
||||
"31": 4774.19,
|
||||
"32": 4772.8,
|
||||
"33": 4774.84,
|
||||
"34": 4772.52,
|
||||
"35": 4773.77,
|
||||
"36": 4775.43,
|
||||
"37": 4771.58,
|
||||
"38": 4772.68,
|
||||
"39": 4769.1
|
||||
},
|
||||
"expected_e2e_ms": 193947.19,
|
||||
"expected_avg_denoise_ms": 4691.07,
|
||||
"expected_median_denoise_ms": 4773.22
|
||||
},
|
||||
"qwen_image_t2i_2npu": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 0.07,
|
||||
"TextEncodingStage": 629.24,
|
||||
"LatentPreparationStage": 0.69,
|
||||
"TimestepPreparationStage": 35.29,
|
||||
"DenoisingStage": 30529.83,
|
||||
"DecodingStage": 428.21
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 477.43,
|
||||
"1": 511.96,
|
||||
"2": 607.78,
|
||||
"3": 615.12,
|
||||
"4": 616.29,
|
||||
"5": 614.61,
|
||||
"6": 623.04,
|
||||
"7": 607.12,
|
||||
"8": 615.32,
|
||||
"9": 615.47,
|
||||
"10": 616.93,
|
||||
"11": 623.26,
|
||||
"12": 607.12,
|
||||
"13": 615.48,
|
||||
"14": 615.07,
|
||||
"15": 614.83,
|
||||
"16": 623.18,
|
||||
"17": 609.0,
|
||||
"18": 614.8,
|
||||
"19": 623.08,
|
||||
"20": 607.64,
|
||||
"21": 614.2,
|
||||
"22": 615.58,
|
||||
"23": 615.43,
|
||||
"24": 623.59,
|
||||
"25": 606.57,
|
||||
"26": 616.02,
|
||||
"27": 615.48,
|
||||
"28": 615.76,
|
||||
"29": 623.13,
|
||||
"30": 608.73,
|
||||
"31": 615.04,
|
||||
"32": 616.08,
|
||||
"33": 616.59,
|
||||
"34": 623.77,
|
||||
"35": 608.0,
|
||||
"36": 616.1,
|
||||
"37": 615.79,
|
||||
"38": 615.34,
|
||||
"39": 617.43,
|
||||
"40": 610.99,
|
||||
"41": 614.22,
|
||||
"42": 623.27,
|
||||
"43": 606.98,
|
||||
"44": 615.87,
|
||||
"45": 615.99,
|
||||
"46": 614.66,
|
||||
"47": 622.93,
|
||||
"48": 607.97,
|
||||
"49": 614.69
|
||||
},
|
||||
"expected_e2e_ms": 34362.34,
|
||||
"expected_avg_denoise_ms": 610.41,
|
||||
"expected_median_denoise_ms": 615.39
|
||||
},
|
||||
"ernie_image_t2i_1npu": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 0.07,
|
||||
"PromptEnhancementStage": 8787.2,
|
||||
"TextEncodingStage": 35.87,
|
||||
"TimestepPreparationStage": 32.74,
|
||||
"LatentPreparationStage": 0.2,
|
||||
"DenoisingStage": 47471.93,
|
||||
"DecodingStage": 42.24
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 93.3,
|
||||
"1": 229.78,
|
||||
"2": 982.46,
|
||||
"3": 984.1,
|
||||
"4": 982.02,
|
||||
"5": 982.42,
|
||||
"6": 982.01,
|
||||
"7": 982.12,
|
||||
"8": 981.92,
|
||||
"9": 982.08,
|
||||
"10": 982.39,
|
||||
"11": 982.14,
|
||||
"12": 982.37,
|
||||
"13": 982.06,
|
||||
"14": 982.0,
|
||||
"15": 982.53,
|
||||
"16": 981.83,
|
||||
"17": 982.41,
|
||||
"18": 981.97,
|
||||
"19": 981.93,
|
||||
"20": 982.14,
|
||||
"21": 981.71,
|
||||
"22": 982.36,
|
||||
"23": 981.97,
|
||||
"24": 981.92,
|
||||
"25": 982.12,
|
||||
"26": 981.87,
|
||||
"27": 982.38,
|
||||
"28": 981.92,
|
||||
"29": 981.95,
|
||||
"30": 982.28,
|
||||
"31": 981.94,
|
||||
"32": 981.95,
|
||||
"33": 982.2,
|
||||
"34": 981.71,
|
||||
"35": 982.29,
|
||||
"36": 981.84,
|
||||
"37": 982.2,
|
||||
"38": 981.98,
|
||||
"39": 981.93,
|
||||
"40": 982.3,
|
||||
"41": 982.27,
|
||||
"42": 982.15,
|
||||
"43": 981.96,
|
||||
"44": 981.82,
|
||||
"45": 982.11,
|
||||
"46": 981.79,
|
||||
"47": 982.17,
|
||||
"48": 982.01,
|
||||
"49": 981.89
|
||||
},
|
||||
"expected_e2e_ms": 56379.07,
|
||||
"expected_avg_denoise_ms": 949.3,
|
||||
"expected_median_denoise_ms": 982.02
|
||||
},
|
||||
"glm_image_t2i_1npu": {
|
||||
"stages_ms": {
|
||||
"GlmImageAR": 69299.14,
|
||||
"GlmImageBeforeDenoisingStage": 94.01,
|
||||
"DenoisingStage": 24325.65,
|
||||
"DecodingStage": 290.05
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 548.52,
|
||||
"1": 819.64,
|
||||
"2": 819.1,
|
||||
"3": 819.05,
|
||||
"4": 819.51,
|
||||
"5": 819.38,
|
||||
"6": 818.79,
|
||||
"7": 819.04,
|
||||
"8": 818.91,
|
||||
"9": 819.87,
|
||||
"10": 819.65,
|
||||
"11": 825.78,
|
||||
"12": 812.68,
|
||||
"13": 819.45,
|
||||
"14": 820.37,
|
||||
"15": 820.32,
|
||||
"16": 819.2,
|
||||
"17": 821.85,
|
||||
"18": 817.57,
|
||||
"19": 819.32,
|
||||
"20": 819.99,
|
||||
"21": 819.73,
|
||||
"22": 819.84,
|
||||
"23": 819.79,
|
||||
"24": 820.7,
|
||||
"25": 819.27,
|
||||
"26": 819.59,
|
||||
"27": 820.06,
|
||||
"28": 819.45,
|
||||
"29": 820.13
|
||||
},
|
||||
"expected_e2e_ms": 94017.76,
|
||||
"expected_avg_denoise_ms": 810.55,
|
||||
"expected_median_denoise_ms": 819.55
|
||||
},
|
||||
"z_image_t2i_1npu": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 0.08,
|
||||
"TextEncodingStage": 246.13,
|
||||
"LatentPreparationStage": 0.23,
|
||||
"TimestepPreparationStage": 29.16,
|
||||
"DenoisingStage": 36649.71,
|
||||
"DecodingStage": 6.28
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 732.97,
|
||||
"1": 732.49,
|
||||
"2": 732.47,
|
||||
"3": 732.93,
|
||||
"4": 732.5,
|
||||
"5": 732.51,
|
||||
"6": 732.18,
|
||||
"7": 733.07,
|
||||
"8": 733.17,
|
||||
"9": 734.29,
|
||||
"10": 734.49,
|
||||
"11": 735.74,
|
||||
"12": 733.51,
|
||||
"13": 732.76,
|
||||
"14": 733.39,
|
||||
"15": 732.44,
|
||||
"16": 731.72,
|
||||
"17": 731.76,
|
||||
"18": 732.76,
|
||||
"19": 731.88,
|
||||
"20": 732.23,
|
||||
"21": 731.63,
|
||||
"22": 731.59,
|
||||
"23": 732.4,
|
||||
"24": 732.18,
|
||||
"25": 732.54,
|
||||
"26": 732.08,
|
||||
"27": 732.09,
|
||||
"28": 732.08,
|
||||
"29": 732.44,
|
||||
"30": 732.18,
|
||||
"31": 731.93,
|
||||
"32": 732.05,
|
||||
"33": 732.32,
|
||||
"34": 733.97,
|
||||
"35": 736.5,
|
||||
"36": 735.63,
|
||||
"37": 733.37,
|
||||
"38": 734.09,
|
||||
"39": 732.9,
|
||||
"40": 732.78,
|
||||
"41": 732.26,
|
||||
"42": 731.74,
|
||||
"43": 732.48,
|
||||
"44": 732.14,
|
||||
"45": 732.64,
|
||||
"46": 733.53,
|
||||
"47": 733.48,
|
||||
"48": 732.59,
|
||||
"49": 732.1
|
||||
},
|
||||
"expected_e2e_ms": 36940.12,
|
||||
"expected_avg_denoise_ms": 732.82,
|
||||
"expected_median_denoise_ms": 732.5
|
||||
},
|
||||
"flux_2_klein_4b_t2i_1npu": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 0.07,
|
||||
"TextEncodingStage": 232.96,
|
||||
"ImageVAEEncodingStage": 0.01,
|
||||
"LatentPreparationStage": 0.57,
|
||||
"TimestepPreparationStage": 29.26,
|
||||
"DenoisingStage": 992.79,
|
||||
"DecodingStage": 10.76
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 37.78,
|
||||
"1": 35.77,
|
||||
"2": 34.34,
|
||||
"3": 34.91
|
||||
},
|
||||
"expected_e2e_ms": 1317.11,
|
||||
"expected_avg_denoise_ms": 35.7,
|
||||
"expected_median_denoise_ms": 35.34
|
||||
},
|
||||
"joyai_image_edit_ti2i_1npu": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 20.04,
|
||||
"ImageEncodingStage": 1239.81,
|
||||
"ImageVAEEncodingStage": 370.97,
|
||||
"LatentPreparationStage": 0.33,
|
||||
"TimestepPreparationStage": 34.12,
|
||||
"DenoisingStage": 105471.23,
|
||||
"DecodingStage": 2762.97
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 229.17,
|
||||
"1": 2429.69,
|
||||
"2": 2706.14,
|
||||
"3": 2707.12,
|
||||
"4": 2702.84,
|
||||
"5": 2704.71,
|
||||
"6": 2704.96,
|
||||
"7": 2706.45,
|
||||
"8": 2705.75,
|
||||
"9": 2703.3,
|
||||
"10": 2705.13,
|
||||
"11": 2704.95,
|
||||
"12": 2704.57,
|
||||
"13": 2705.43,
|
||||
"14": 2702.58,
|
||||
"15": 2705.44,
|
||||
"16": 2705.74,
|
||||
"17": 2706.63,
|
||||
"18": 2705.73,
|
||||
"19": 2703.79,
|
||||
"20": 2704.97,
|
||||
"21": 2707.3,
|
||||
"22": 2705.92,
|
||||
"23": 2708.38,
|
||||
"24": 2703.5,
|
||||
"25": 2704.63,
|
||||
"26": 2706.51,
|
||||
"27": 2704.44,
|
||||
"28": 2706.82,
|
||||
"29": 2704.59,
|
||||
"30": 2704.36,
|
||||
"31": 2707.21,
|
||||
"32": 2704.87,
|
||||
"33": 2708.24,
|
||||
"34": 2703.86,
|
||||
"35": 2704.19,
|
||||
"36": 2706.7,
|
||||
"37": 2705.72,
|
||||
"38": 2706.74,
|
||||
"39": 2704.96
|
||||
},
|
||||
"expected_e2e_ms": 109909.47,
|
||||
"expected_avg_denoise_ms": 2636.6,
|
||||
"expected_median_denoise_ms": 2705.05
|
||||
},
|
||||
"mova_360p_ti2va_2npu": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 19.09,
|
||||
"TextEncodingStage": 512.61,
|
||||
"ImageVAEEncodingStage": 588.51,
|
||||
"MOVALatentPreparationStage": 0.34,
|
||||
"MOVATimestepPreparationStage": 0.52,
|
||||
"MOVADenoisingStage": 91033.05,
|
||||
"MOVADecodingStage": 586.86
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 1816.84,
|
||||
"1": 1818.1,
|
||||
"2": 1819.39,
|
||||
"3": 1817.58,
|
||||
"4": 1820.35,
|
||||
"5": 1816.92,
|
||||
"6": 1811.79,
|
||||
"7": 1826.0,
|
||||
"8": 1816.3,
|
||||
"9": 1817.59,
|
||||
"10": 1816.24,
|
||||
"11": 1815.25,
|
||||
"12": 1815.69,
|
||||
"13": 1817.23,
|
||||
"14": 1817.59,
|
||||
"15": 1820.19,
|
||||
"16": 1820.93,
|
||||
"17": 1823.82,
|
||||
"18": 1848.39,
|
||||
"19": 1819.37,
|
||||
"20": 1818.51,
|
||||
"21": 1815.18,
|
||||
"22": 1821.84,
|
||||
"23": 1816.08,
|
||||
"24": 1817.98,
|
||||
"25": 1817.91,
|
||||
"26": 1818.12,
|
||||
"27": 1816.79,
|
||||
"28": 1815.43,
|
||||
"29": 1818.44,
|
||||
"30": 1817.64,
|
||||
"31": 1818.73,
|
||||
"32": 1814.81,
|
||||
"33": 1818.24,
|
||||
"34": 1817.88,
|
||||
"35": 1816.15,
|
||||
"36": 1818.26,
|
||||
"37": 1814.76,
|
||||
"38": 1816.17,
|
||||
"39": 1817.48,
|
||||
"40": 1817.83,
|
||||
"41": 1817.71,
|
||||
"42": 1811.81,
|
||||
"43": 1820.49,
|
||||
"44": 1817.3,
|
||||
"45": 1814.35,
|
||||
"46": 1820.92,
|
||||
"47": 1824.75,
|
||||
"48": 1822.46,
|
||||
"49": 1822.08
|
||||
},
|
||||
"expected_e2e_ms": 92840.23,
|
||||
"expected_avg_denoise_ms": 1818.63,
|
||||
"expected_median_denoise_ms": 1817.77,
|
||||
"estimated_full_test_time_s": 175.6
|
||||
},
|
||||
"ltx_2_ti2va_2npu": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 3.8,
|
||||
"TextEncodingStage": 1029.19,
|
||||
"LTX2TextConnectorStage": 56.3,
|
||||
"LTX2SigmaPreparationStage": 0.19,
|
||||
"TimestepPreparationStage": 33.52,
|
||||
"LTX2AVLatentPreparationStage": 0.45,
|
||||
"LTX2ImageEncodingStage": 93.32,
|
||||
"LTX2AVDenoisingStage": 29672.06,
|
||||
"LTX2AVDecodingStage": 560.9
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 544.81,
|
||||
"1": 746.36,
|
||||
"2": 746.01,
|
||||
"3": 774.46,
|
||||
"4": 717.7,
|
||||
"5": 749.83,
|
||||
"6": 746.58,
|
||||
"7": 784.74,
|
||||
"8": 708.78,
|
||||
"9": 746.72,
|
||||
"10": 746.38,
|
||||
"11": 784.14,
|
||||
"12": 708.74,
|
||||
"13": 746.85,
|
||||
"14": 746.57,
|
||||
"15": 751.14,
|
||||
"16": 742.59,
|
||||
"17": 747.19,
|
||||
"18": 746.26,
|
||||
"19": 750.58,
|
||||
"20": 742.55,
|
||||
"21": 746.34,
|
||||
"22": 760.44,
|
||||
"23": 736.36,
|
||||
"24": 741.97,
|
||||
"25": 746.3,
|
||||
"26": 782.28,
|
||||
"27": 714.3,
|
||||
"28": 741.96,
|
||||
"29": 746.25,
|
||||
"30": 784.82,
|
||||
"31": 711.85,
|
||||
"32": 742.0,
|
||||
"33": 746.24,
|
||||
"34": 746.13,
|
||||
"35": 750.84,
|
||||
"36": 741.81,
|
||||
"37": 746.2,
|
||||
"38": 746.08,
|
||||
"39": 752.12
|
||||
},
|
||||
"expected_e2e_ms": 31484.37,
|
||||
"expected_avg_denoise_ms": 741.58,
|
||||
"expected_median_denoise_ms": 746.28
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
"""
|
||||
Config-driven diffusion performance test with pytest parametrization.
|
||||
|
||||
|
||||
If the actual run is significantly better than the baseline, the improved cases with their updated baseline will be printed
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from sglang.multimodal_gen.test.server.ascend.testcase_configs_npu import ONE_NPU_CASES
|
||||
from sglang.multimodal_gen.test.server.common.case_fixtures import (
|
||||
diffusion_case_fixture,
|
||||
)
|
||||
from sglang.multimodal_gen.test.server.test_server_common import ( # noqa: F401
|
||||
DiffusionServerBase,
|
||||
diffusion_server,
|
||||
)
|
||||
|
||||
|
||||
class TestDiffusionServerOneNpu(DiffusionServerBase):
|
||||
"""Performance tests for 1-NPU diffusion cases."""
|
||||
|
||||
case = diffusion_case_fixture(ONE_NPU_CASES)
|
||||
@@ -0,0 +1,23 @@
|
||||
"""
|
||||
Config-driven diffusion performance test with pytest parametrization.
|
||||
|
||||
|
||||
If the actual run is significantly better than the baseline, the improved cases with their updated baseline will be printed
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from sglang.multimodal_gen.test.server.ascend.testcase_configs_npu import TWO_NPU_CASES
|
||||
from sglang.multimodal_gen.test.server.common.case_fixtures import (
|
||||
diffusion_case_fixture,
|
||||
)
|
||||
from sglang.multimodal_gen.test.server.test_server_common import ( # noqa: F401
|
||||
DiffusionServerBase,
|
||||
diffusion_server,
|
||||
)
|
||||
|
||||
|
||||
class TestDiffusionServerTwoNpu(DiffusionServerBase):
|
||||
"""Performance tests for 2-NPU diffusion cases."""
|
||||
|
||||
case = diffusion_case_fixture(TWO_NPU_CASES)
|
||||
@@ -0,0 +1,200 @@
|
||||
import os
|
||||
|
||||
from sglang.multimodal_gen.test.server.testcase_configs import (
|
||||
T2V_PROMPT,
|
||||
DiffusionSamplingParams,
|
||||
DiffusionServerArgs,
|
||||
DiffusionTestCase,
|
||||
T2I_sampling_params,
|
||||
TI2V_sampling_params,
|
||||
)
|
||||
|
||||
MODELSCOPE_MODEL_WEIGHTS_DIR = "/root/.cache/modelscope/hub/models/"
|
||||
|
||||
|
||||
def use_modelscope(name: str):
|
||||
return os.path.join(MODELSCOPE_MODEL_WEIGHTS_DIR, name)
|
||||
|
||||
|
||||
COSMOS3_NANO_WEIGHTS_PATH = use_modelscope("nv-community/Cosmos3-Nano")
|
||||
ERNIE_IMAGE_WEIGHTS_PATH = use_modelscope("PaddlePaddle/ERNIE-Image")
|
||||
FLUX_1_DEV_WEIGHTS_PATH = use_modelscope("black-forest-labs/FLUX.1-dev")
|
||||
FLUX_2_DEV_WEIGHTS_PATH = use_modelscope("black-forest-labs/FLUX.2-dev")
|
||||
FLUX_2_KLEIN_4B_WEIGHTS_PATH = use_modelscope("black-forest-labs/FLUX.2-klein-4B")
|
||||
GLM_IMAGE_WEIGHTS_PATH = use_modelscope("ZhipuAI/GLM-Image")
|
||||
JOYAI_IMAGE_EDIT_WEIGHTS_PATH = use_modelscope(
|
||||
"jd-opensource/JoyAI-Image-Edit-Diffusers"
|
||||
)
|
||||
LTX_2_WEIGHTS_PATH = use_modelscope("Lightricks/LTX-2")
|
||||
MOVA_360_WEIGHTS_PATH = use_modelscope("openmoss/MOVA-360p")
|
||||
QWEN_IMAGE_WEIGHTS_PATH = use_modelscope("Qwen/Qwen-Image")
|
||||
WAN2_1_T2V_1_3B_DIFFUSERS_WEIGHTS_PATH = use_modelscope(
|
||||
"Wan-AI/Wan2.1-T2V-1.3B-Diffusers"
|
||||
)
|
||||
WAN2_2_T2V_A14B_DIFFUSERS_W8A8_WEIGHTS_PATH = use_modelscope(
|
||||
"Eco-Tech/Wan2.2-T2V-A14B-Diffusers-w8a8"
|
||||
)
|
||||
Z_IMAGE_WEIGHTS_PATH = use_modelscope("Tongyi-MAI/Z-Image")
|
||||
|
||||
EXTRAS_DISABLE_WARMUP = ["--warmup-mode", "request"]
|
||||
|
||||
ONE_NPU_CASES: list[DiffusionTestCase] = [
|
||||
# === Text to Image (T2I) ===
|
||||
DiffusionTestCase(
|
||||
"ernie_image_t2i_1npu",
|
||||
DiffusionServerArgs(
|
||||
model_path=ERNIE_IMAGE_WEIGHTS_PATH,
|
||||
extras=EXTRAS_DISABLE_WARMUP,
|
||||
),
|
||||
T2I_sampling_params,
|
||||
run_consistency_check=False,
|
||||
),
|
||||
DiffusionTestCase(
|
||||
"glm_image_t2i_1npu",
|
||||
DiffusionServerArgs(
|
||||
model_path=GLM_IMAGE_WEIGHTS_PATH,
|
||||
extras=EXTRAS_DISABLE_WARMUP,
|
||||
),
|
||||
T2I_sampling_params,
|
||||
run_consistency_check=False,
|
||||
),
|
||||
DiffusionTestCase(
|
||||
"flux_image_t2i_npu",
|
||||
DiffusionServerArgs(
|
||||
model_path=FLUX_1_DEV_WEIGHTS_PATH,
|
||||
extras=EXTRAS_DISABLE_WARMUP,
|
||||
),
|
||||
T2I_sampling_params,
|
||||
),
|
||||
DiffusionTestCase(
|
||||
"flux_2_klein_4b_t2i_1npu",
|
||||
DiffusionServerArgs(
|
||||
model_path=FLUX_2_KLEIN_4B_WEIGHTS_PATH,
|
||||
extras=EXTRAS_DISABLE_WARMUP,
|
||||
),
|
||||
T2I_sampling_params,
|
||||
run_consistency_check=False,
|
||||
),
|
||||
DiffusionTestCase(
|
||||
"z_image_t2i_1npu",
|
||||
DiffusionServerArgs(
|
||||
model_path=Z_IMAGE_WEIGHTS_PATH,
|
||||
extras=EXTRAS_DISABLE_WARMUP,
|
||||
),
|
||||
T2I_sampling_params,
|
||||
run_consistency_check=False,
|
||||
),
|
||||
# === Text to Video (T2V) ===
|
||||
DiffusionTestCase(
|
||||
"wan2_1_t2v_1.3b_1_npu",
|
||||
DiffusionServerArgs(
|
||||
model_path=WAN2_1_T2V_1_3B_DIFFUSERS_WEIGHTS_PATH,
|
||||
extras=EXTRAS_DISABLE_WARMUP,
|
||||
),
|
||||
DiffusionSamplingParams(
|
||||
prompt=T2V_PROMPT,
|
||||
),
|
||||
),
|
||||
# === Text+Image to Image (TI2I)
|
||||
DiffusionTestCase(
|
||||
"joyai_image_edit_ti2i_1npu",
|
||||
DiffusionServerArgs(
|
||||
model_path=JOYAI_IMAGE_EDIT_WEIGHTS_PATH,
|
||||
extras=EXTRAS_DISABLE_WARMUP,
|
||||
),
|
||||
run_consistency_check=False,
|
||||
run_component_accuracy_check=False,
|
||||
),
|
||||
]
|
||||
|
||||
TWO_NPU_CASES: list[DiffusionTestCase] = [
|
||||
# === Text to Image (T2I) ===
|
||||
DiffusionTestCase(
|
||||
"flux_2_image_t2i_2npu",
|
||||
DiffusionServerArgs(
|
||||
model_path=FLUX_2_DEV_WEIGHTS_PATH,
|
||||
num_gpus=2,
|
||||
tp_size=2,
|
||||
extras=EXTRAS_DISABLE_WARMUP,
|
||||
),
|
||||
T2I_sampling_params,
|
||||
),
|
||||
DiffusionTestCase(
|
||||
"qwen_image_t2i_2npu",
|
||||
DiffusionServerArgs(
|
||||
model_path=QWEN_IMAGE_WEIGHTS_PATH,
|
||||
num_gpus=2,
|
||||
# test ring attn
|
||||
ulysses_degree=1,
|
||||
ring_degree=2,
|
||||
extras=EXTRAS_DISABLE_WARMUP,
|
||||
),
|
||||
T2I_sampling_params,
|
||||
),
|
||||
# === Text to Video (T2V) ===
|
||||
DiffusionTestCase(
|
||||
"wan2_2_t2v_14b_w8a8_2npu",
|
||||
DiffusionServerArgs(
|
||||
model_path=WAN2_2_T2V_A14B_DIFFUSERS_W8A8_WEIGHTS_PATH,
|
||||
num_gpus=2,
|
||||
tp_size=1,
|
||||
ulysses_degree=2,
|
||||
extras=EXTRAS_DISABLE_WARMUP,
|
||||
),
|
||||
DiffusionSamplingParams(
|
||||
prompt=T2V_PROMPT,
|
||||
),
|
||||
),
|
||||
# === Text+Image to Video+Audio (TI2V)
|
||||
DiffusionTestCase(
|
||||
"ltx_2_ti2va_2npu",
|
||||
DiffusionServerArgs(
|
||||
model_path=LTX_2_WEIGHTS_PATH,
|
||||
num_gpus=2,
|
||||
ulysses_degree=2,
|
||||
extras=EXTRAS_DISABLE_WARMUP,
|
||||
),
|
||||
TI2V_sampling_params,
|
||||
run_consistency_check=False,
|
||||
),
|
||||
DiffusionTestCase(
|
||||
"mova_360p_ti2va_2npu",
|
||||
DiffusionServerArgs(
|
||||
model_path=MOVA_360_WEIGHTS_PATH,
|
||||
num_gpus=2,
|
||||
tp_size=2,
|
||||
dit_layerwise_offload=True,
|
||||
extras=EXTRAS_DISABLE_WARMUP,
|
||||
),
|
||||
run_consistency_check=False,
|
||||
),
|
||||
]
|
||||
|
||||
DEFAULT_EST_TIME_SECONDS = 300.0
|
||||
STARTUP_OVERHEAD_SECONDS = 120.0
|
||||
DEFAULT_STANDALONE_EST_TIME_SECONDS = 300.0
|
||||
|
||||
SUITES = {
|
||||
"1-npu": [
|
||||
"ascend/test_server_1_npu.py",
|
||||
# add new 1-npu test files here
|
||||
],
|
||||
"2-npu": [
|
||||
"ascend/test_server_2_npu.py",
|
||||
# add new 2-npu test files here
|
||||
],
|
||||
}
|
||||
|
||||
PARAMETRIZED_CASE_GROUPS = {
|
||||
"1-npu": [
|
||||
("ascend/test_server_1_npu.py", ONE_NPU_CASES),
|
||||
],
|
||||
"2-npu": [
|
||||
("ascend/test_server_2_npu.py", TWO_NPU_CASES),
|
||||
],
|
||||
}
|
||||
|
||||
FILE_SUITES = {}
|
||||
STANDALONE_FILES = {}
|
||||
COMPONENT_ACCURACY_SUITES = {}
|
||||
_UPDATE_WEIGHTS_FROM_DISK_TEST_FILE = None
|
||||
@@ -0,0 +1 @@
|
||||
"""Common server test helpers."""
|
||||
@@ -0,0 +1,16 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Sequence
|
||||
|
||||
import pytest
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from sglang.multimodal_gen.test.server.testcase_configs import DiffusionTestCase
|
||||
|
||||
|
||||
def diffusion_case_fixture(cases: Sequence[DiffusionTestCase]):
|
||||
@pytest.fixture(params=cases, ids=lambda case: case.id)
|
||||
def case(self, request) -> DiffusionTestCase:
|
||||
return request.param
|
||||
|
||||
return case
|
||||
@@ -0,0 +1,216 @@
|
||||
"""
|
||||
This file upload the media generated in diffusion-nightly-test to a slack channel of SGLang
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import tempfile
|
||||
from datetime import datetime
|
||||
from typing import List, Union
|
||||
from urllib.parse import urlparse
|
||||
from urllib.request import urlopen
|
||||
|
||||
from sglang.multimodal_gen.runtime.utils.perf_logger import get_git_commit_hash
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
import inspect
|
||||
|
||||
try:
|
||||
import sglang.multimodal_gen.test.server.testcase_configs as configs
|
||||
from sglang.multimodal_gen.test.server.testcase_configs import DiffusionTestCase
|
||||
|
||||
ALL_CASES = []
|
||||
for name, value in inspect.getmembers(configs):
|
||||
if name.endswith("_CASES") or "_CASES_" in name:
|
||||
if (
|
||||
isinstance(value, list)
|
||||
and len(value) > 0
|
||||
and isinstance(value[0], DiffusionTestCase)
|
||||
):
|
||||
ALL_CASES.extend(value)
|
||||
elif isinstance(value, list) and len(value) == 0:
|
||||
# Assume empty list with matching name is a valid case list container
|
||||
pass
|
||||
|
||||
# Deduplicate cases by ID
|
||||
seen_ids = set()
|
||||
unique_cases = []
|
||||
for c in ALL_CASES:
|
||||
if c.id not in seen_ids:
|
||||
seen_ids.add(c.id)
|
||||
unique_cases.append(c)
|
||||
ALL_CASES = unique_cases
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to import test cases: {e}")
|
||||
ALL_CASES = []
|
||||
|
||||
|
||||
def _get_status_message(run_id, current_case_id, thread_messages=None):
|
||||
date_str = datetime.now().strftime("%d/%m")
|
||||
base_header = f"""🧵 for nightly test of {date_str}
|
||||
*Git Revision:* {get_git_commit_hash()}
|
||||
*GitHub Run ID:* {run_id}
|
||||
*Total Tasks:* {len(ALL_CASES)}
|
||||
"""
|
||||
|
||||
if not ALL_CASES:
|
||||
return base_header
|
||||
|
||||
default_emoji_for_case_in_progress = "⏳"
|
||||
status_map = {c.id: default_emoji_for_case_in_progress for c in ALL_CASES}
|
||||
|
||||
if thread_messages:
|
||||
for msg in thread_messages:
|
||||
text = msg.get("text", "")
|
||||
# Look for case_id in the message (format: *Case ID:* `case_id`)
|
||||
for c in ALL_CASES:
|
||||
if f"*Case ID:* `{c.id}`" in text:
|
||||
status_map[c.id] = "✅"
|
||||
|
||||
if current_case_id:
|
||||
status_map[current_case_id] = "✅"
|
||||
|
||||
lines = [base_header, "", "*Tasks Status:*"]
|
||||
|
||||
# Calculate padding
|
||||
max_len = max(len(c.id) for c in ALL_CASES) if ALL_CASES else 10
|
||||
max_len = max(max_len, len("Case ID"))
|
||||
|
||||
# Build markdown table inside a code block
|
||||
table_lines = ["```"]
|
||||
table_lines.append(f"| {'Case ID'.ljust(max_len)} | Status |")
|
||||
table_lines.append(f"| {'-' * max_len} | :----: |")
|
||||
|
||||
for c in ALL_CASES:
|
||||
mark = status_map.get(c.id, default_emoji_for_case_in_progress)
|
||||
table_lines.append(f"| {c.id.ljust(max_len)} | {mark} |")
|
||||
|
||||
table_lines.append("```")
|
||||
|
||||
lines.extend(table_lines)
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def upload_file_to_slack(
|
||||
case_id: str = None,
|
||||
model: str = None,
|
||||
prompt: str = None,
|
||||
file_path: str = None,
|
||||
origin_file_path: Union[str, List[str]] = None,
|
||||
) -> bool:
|
||||
temp_paths = []
|
||||
try:
|
||||
from slack_sdk import WebClient
|
||||
|
||||
run_id = os.getenv("GITHUB_RUN_ID", "local")
|
||||
|
||||
token = os.environ.get("SGLANG_DIFFUSION_SLACK_TOKEN")
|
||||
if not token:
|
||||
logger.info("Slack upload failed: no token")
|
||||
return False
|
||||
|
||||
if not file_path or not os.path.exists(file_path):
|
||||
logger.info("Slack upload failed: no file path")
|
||||
return False
|
||||
|
||||
origin_paths = []
|
||||
if isinstance(origin_file_path, str):
|
||||
if origin_file_path:
|
||||
origin_paths.append(origin_file_path)
|
||||
elif isinstance(origin_file_path, list):
|
||||
origin_paths = [p for p in origin_file_path if p]
|
||||
|
||||
final_origin_paths = []
|
||||
for path in origin_paths:
|
||||
if path.startswith(("http", "https")):
|
||||
try:
|
||||
suffix = os.path.splitext(urlparse(path).path)[1] or ".tmp"
|
||||
with tempfile.NamedTemporaryFile(delete=False, suffix=suffix) as tf:
|
||||
with urlopen(path, timeout=30) as response:
|
||||
tf.write(response.read())
|
||||
temp_paths.append(tf.name)
|
||||
final_origin_paths.append(tf.name)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to download {path}: {e}")
|
||||
else:
|
||||
final_origin_paths.append(path)
|
||||
|
||||
uploads = []
|
||||
for i, path in enumerate(final_origin_paths):
|
||||
if os.path.exists(path):
|
||||
title = (
|
||||
"Original Image"
|
||||
if len(final_origin_paths) == 1
|
||||
else f"Original Image {i+1}"
|
||||
)
|
||||
uploads.append({"file": path, "title": title})
|
||||
|
||||
uploads.append({"file": file_path, "title": "Generated Image"})
|
||||
|
||||
message = (
|
||||
f"*Case ID:* `{case_id}`\n" f"*Model:* `{model}`\n" f"*Prompt:* {prompt}"
|
||||
)
|
||||
|
||||
client = WebClient(token=token, timeout=60)
|
||||
channel_id = "C0A02NDF7UY"
|
||||
thread_ts = None
|
||||
|
||||
parent_msg_text = None
|
||||
try:
|
||||
history = client.conversations_history(channel=channel_id, limit=100)
|
||||
for msg in history.get("messages", []):
|
||||
if f"*GitHub Run ID:* {run_id}" in msg.get("text", ""):
|
||||
# Use thread_ts if it exists (msg is a reply), otherwise use ts (msg is a parent)
|
||||
thread_ts = msg.get("thread_ts") or msg.get("ts")
|
||||
parent_msg_text = msg.get("text", "")
|
||||
logger.info(f"Found thread_ts: {thread_ts}")
|
||||
break
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to search slack history: {e}")
|
||||
|
||||
if not thread_ts:
|
||||
try:
|
||||
text = _get_status_message(run_id, case_id)
|
||||
response = client.chat_postMessage(channel=channel_id, text=text)
|
||||
thread_ts = response["ts"]
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to create parent thread: {e}")
|
||||
|
||||
# Upload first to ensure it's in history
|
||||
client.files_upload_v2(
|
||||
channel=channel_id,
|
||||
file_uploads=uploads,
|
||||
initial_comment=message,
|
||||
thread_ts=thread_ts,
|
||||
)
|
||||
|
||||
# Then update status based on thread replies
|
||||
if thread_ts:
|
||||
try:
|
||||
replies = client.conversations_replies(
|
||||
channel=channel_id, ts=thread_ts, limit=200
|
||||
)
|
||||
messages = replies.get("messages", [])
|
||||
new_text = _get_status_message(run_id, case_id, messages)
|
||||
|
||||
# Only update if changed significantly (ignoring timestamp diffs if any)
|
||||
# But here we just check text content
|
||||
if new_text != parent_msg_text:
|
||||
client.chat_update(channel=channel_id, ts=thread_ts, text=new_text)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to update parent message: {e}")
|
||||
|
||||
logger.info(f"File uploaded successfully: {os.path.basename(file_path)}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.info(f"Slack upload failed: {e}")
|
||||
return False
|
||||
finally:
|
||||
for p in temp_paths:
|
||||
if os.path.exists(p):
|
||||
os.remove(p)
|
||||
@@ -0,0 +1,13 @@
|
||||
cache_config:
|
||||
max_warmup_steps: 2
|
||||
warmup_interval: 2
|
||||
max_cached_steps: -1
|
||||
max_continuous_cached_steps: 2
|
||||
Fn_compute_blocks: 1
|
||||
Bn_compute_blocks: 0
|
||||
residual_diff_threshold: 0.12
|
||||
enable_taylorseer: true
|
||||
taylorseer_order: 1
|
||||
num_inference_steps: 8
|
||||
steps_computation_mask: "medium"
|
||||
steps_computation_policy: dynamic
|
||||
@@ -0,0 +1,165 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
print("[CONFTEST] Loading conftest.py at import time")
|
||||
|
||||
|
||||
def pytest_configure(config):
|
||||
"""
|
||||
Create the perf results StashKey once and store it in config.
|
||||
This hook runs once per test session, before module double-import issues.
|
||||
"""
|
||||
if not hasattr(config, "_diffusion_perf_key"):
|
||||
config._diffusion_perf_key = pytest.StashKey[list]()
|
||||
print(f"[CONFTEST] Created perf_results_key: {config._diffusion_perf_key}")
|
||||
|
||||
|
||||
def add_perf_results(config, results: list):
|
||||
"""Add performance results to the shared stash."""
|
||||
# Get the shared key from config (created once in pytest_configure)
|
||||
key = config._diffusion_perf_key
|
||||
existing = config.stash.get(key, [])
|
||||
existing.extend(results)
|
||||
config.stash[key] = existing
|
||||
print(f"[CONFTEST] Added {len(results)} results, total now: {len(existing)}")
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def perf_config(request):
|
||||
"""Provide access to pytest config for storing perf results."""
|
||||
return request.config
|
||||
|
||||
|
||||
def _write_github_step_summary(content: str):
|
||||
"""Write content to GitHub Step Summary if available."""
|
||||
summary_file = os.environ.get("GITHUB_STEP_SUMMARY")
|
||||
if summary_file:
|
||||
with open(summary_file, "a") as f:
|
||||
f.write(content)
|
||||
|
||||
|
||||
def _write_results_json(results: list, output_path: str = "diffusion-results.json"):
|
||||
"""Write performance results to JSON file for CI artifact collection."""
|
||||
try:
|
||||
with open(output_path, "w") as f:
|
||||
json.dump(results, f, indent=2)
|
||||
print(f"[CONFTEST] Wrote results to {output_path}")
|
||||
except Exception as e:
|
||||
print(f"[CONFTEST] Failed to write results JSON: {e}")
|
||||
|
||||
|
||||
def _generate_diffusion_markdown_report(results: list) -> str:
|
||||
"""Generate a markdown report for diffusion performance results."""
|
||||
if not results:
|
||||
return ""
|
||||
|
||||
gpu_config = os.environ.get("GPU_CONFIG", "")
|
||||
header = "## Diffusion Performance Summary"
|
||||
if gpu_config:
|
||||
header += f" [{gpu_config}]"
|
||||
header += "\n\n"
|
||||
|
||||
# Main performance table
|
||||
markdown = header
|
||||
markdown += "| Test Suite | Test Name | Modality | E2E (ms) | Avg Denoise (ms) | Median Denoise (ms) |\n"
|
||||
markdown += "| ---------- | --------- | -------- | -------- | ---------------- | ------------------- |\n"
|
||||
|
||||
for entry in sorted(results, key=lambda x: (x["class_name"], x["test_name"])):
|
||||
modality = entry.get("modality", "image")
|
||||
markdown += (
|
||||
f"| {entry['class_name']} | {entry['test_name']} | {modality} | "
|
||||
f"{entry['e2e_ms']:.2f} | {entry['avg_denoise_ms']:.2f} | "
|
||||
f"{entry['median_denoise_ms']:.2f} |\n"
|
||||
)
|
||||
|
||||
# Video-specific metrics table (if any video tests)
|
||||
video_results = [r for r in results if r.get("modality") == "video"]
|
||||
if video_results:
|
||||
markdown += "\n### Video Generation Metrics\n\n"
|
||||
markdown += "| Test Name | FPS | Total Frames | Avg Frame Time (ms) |\n"
|
||||
markdown += "| --------- | --- | ------------ | ------------------- |\n"
|
||||
for entry in video_results:
|
||||
fps = entry.get("frames_per_second", "N/A")
|
||||
frames = entry.get("total_frames", "N/A")
|
||||
avg_frame = entry.get("avg_frame_time_ms", "N/A")
|
||||
if isinstance(fps, float):
|
||||
fps = f"{fps:.2f}"
|
||||
if isinstance(avg_frame, float):
|
||||
avg_frame = f"{avg_frame:.2f}"
|
||||
markdown += f"| {entry['test_name']} | {fps} | {frames} | {avg_frame} |\n"
|
||||
|
||||
return markdown
|
||||
|
||||
|
||||
def pytest_sessionfinish(session):
|
||||
"""
|
||||
This hook is called by pytest at the end of the entire test session.
|
||||
It prints a consolidated summary of all performance results.
|
||||
"""
|
||||
# Get results from stash using the shared key from config
|
||||
key = session.config._diffusion_perf_key
|
||||
results = session.config.stash.get(key, [])
|
||||
print(f"\n[DEBUG] pytest_sessionfinish called, has {len(results)} entries")
|
||||
if not results:
|
||||
print("[DEBUG] No results collected, skipping summary output")
|
||||
return
|
||||
|
||||
sorted_results = sorted(results, key=lambda x: (x["class_name"], x["test_name"]))
|
||||
|
||||
# Print to stdout (existing behavior)
|
||||
print("\n\n" + "=" * 35 + " Performance Summary " + "=" * 35)
|
||||
print(
|
||||
f"{'Test Suite':<30} | {'Test Name':<20} | {'E2E (ms)':>12} | {'Avg Denoise (ms)':>18} | {'Median Denoise (ms)':>20}"
|
||||
)
|
||||
print(
|
||||
"-" * 30
|
||||
+ "-+-"
|
||||
+ "-" * 20
|
||||
+ "-+-"
|
||||
+ "-" * 12
|
||||
+ "-+-"
|
||||
+ "-" * 18
|
||||
+ "-+-"
|
||||
+ "-" * 20
|
||||
)
|
||||
|
||||
for entry in sorted_results:
|
||||
print(
|
||||
f"{entry['class_name']:<30} | {entry['test_name']:<20} | {entry['e2e_ms']:>12.2f} | "
|
||||
f"{entry['avg_denoise_ms']:>18.2f} | {entry['median_denoise_ms']:>20.2f}"
|
||||
)
|
||||
|
||||
print("=" * 91)
|
||||
|
||||
print("\n\n" + "=" * 36 + " Detailed Reports " + "=" * 37)
|
||||
for entry in sorted_results:
|
||||
print(f"\n--- Details for {entry['class_name']} / {entry['test_name']} ---")
|
||||
stage_report = ", ".join(
|
||||
f"{name}:{duration:.2f}ms"
|
||||
for name, duration in entry.get("stage_metrics", {}).items()
|
||||
)
|
||||
if stage_report:
|
||||
print(f" Stages: {stage_report}")
|
||||
|
||||
sampled_steps = entry.get("sampled_steps") or {}
|
||||
if sampled_steps:
|
||||
step_report = ", ".join(
|
||||
f"{idx}:{duration:.2f}ms"
|
||||
for idx, duration in sorted(sampled_steps.items())
|
||||
)
|
||||
print(f" Sampled Steps: {step_report}")
|
||||
print("=" * 91)
|
||||
|
||||
print("\n\n" + "=" * 34 + " Performance Data JSON " + "=" * 34)
|
||||
print(json.dumps(sorted_results, indent=2, sort_keys=True))
|
||||
print("=" * 91)
|
||||
|
||||
# Write to GitHub Step Summary (new behavior for CI monitoring)
|
||||
markdown_report = _generate_diffusion_markdown_report(sorted_results)
|
||||
if markdown_report:
|
||||
_write_github_step_summary(markdown_report)
|
||||
|
||||
# Write results to JSON file for CI artifact collection
|
||||
_write_results_json(sorted_results)
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"cases": {
|
||||
"zimage_image_t2i": {
|
||||
"clip_threshold": 0.92,
|
||||
"ssim_threshold": 0.86,
|
||||
"psnr_threshold": 19.5,
|
||||
"mean_abs_diff_threshold": 8.5
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"cases": {}
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
{
|
||||
"_comment": "Some cases use lower thresholds; raise them if quality/perf improves later.",
|
||||
"cases": {
|
||||
"qwen_image_t2i": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.83,
|
||||
"psnr_threshold": 16.0,
|
||||
"mean_abs_diff_threshold": 13.3
|
||||
},
|
||||
"flux_image_t2i": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.95,
|
||||
"psnr_threshold": 24.0,
|
||||
"mean_abs_diff_threshold": 5.5
|
||||
},
|
||||
"flux1_modelopt_fp8_t2i": {
|
||||
"clip_threshold": 0.96,
|
||||
"ssim_threshold": 0.94,
|
||||
"psnr_threshold": 28.0,
|
||||
"mean_abs_diff_threshold": 6.3
|
||||
},
|
||||
"ideogram4_nvfp4_t2i": {
|
||||
"clip_threshold": 0.98,
|
||||
"ssim_threshold": 0.95,
|
||||
"psnr_threshold": 18.0,
|
||||
"mean_abs_diff_threshold": 4.0
|
||||
},
|
||||
"qwen_image_2512_modelopt_nvfp4_t2i": {
|
||||
"clip_threshold": 0.95,
|
||||
"ssim_threshold": 0.88,
|
||||
"psnr_threshold": 23.0,
|
||||
"mean_abs_diff_threshold": 9.0
|
||||
},
|
||||
"flux_2_klein_image_t2i": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.83,
|
||||
"psnr_threshold": 17.0,
|
||||
"mean_abs_diff_threshold": 12.5
|
||||
},
|
||||
"zimage_image_t2i": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.86,
|
||||
"psnr_threshold": 19.9,
|
||||
"mean_abs_diff_threshold": 8.5
|
||||
},
|
||||
"zimage_image_t2i_multi_lora": {
|
||||
"clip_threshold": 0.98,
|
||||
"ssim_threshold": 0.95,
|
||||
"psnr_threshold": 19.9,
|
||||
"mean_abs_diff_threshold": 4.0
|
||||
},
|
||||
"qwen_image_t2i_cache_dit_enabled": {
|
||||
"clip_threshold": 0.98,
|
||||
"ssim_threshold": 0.78,
|
||||
"psnr_threshold": 13.5,
|
||||
"mean_abs_diff_threshold": 17.2
|
||||
},
|
||||
"qwen_image_t2i_2_gpus": {
|
||||
"clip_threshold": 0.98,
|
||||
"ssim_threshold": 0.79,
|
||||
"psnr_threshold": 15.7,
|
||||
"mean_abs_diff_threshold": 17.2
|
||||
},
|
||||
"flux_2_image_t2i": {
|
||||
"clip_threshold": 0.98,
|
||||
"ssim_threshold": 0.95,
|
||||
"psnr_threshold": 14.9,
|
||||
"mean_abs_diff_threshold": 4.0
|
||||
},
|
||||
"flux_2_ti2i": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.88,
|
||||
"psnr_threshold": 19.5,
|
||||
"mean_abs_diff_threshold": 13.5
|
||||
},
|
||||
"zimage_image_t2i_fp8": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.95,
|
||||
"psnr_threshold": 30.0,
|
||||
"mean_abs_diff_threshold": 4.0
|
||||
},
|
||||
"qwen_image_edit_2509_ti2i": {
|
||||
"clip_threshold": 0.91,
|
||||
"ssim_threshold": 0.68,
|
||||
"psnr_threshold": 11.3,
|
||||
"mean_abs_diff_threshold": 26.4
|
||||
},
|
||||
"qwen_image_edit_ti2i": {
|
||||
"clip_threshold": 0.96,
|
||||
"ssim_threshold": 0.94,
|
||||
"psnr_threshold": 25.4,
|
||||
"mean_abs_diff_threshold": 10.0
|
||||
},
|
||||
"qwen_image_edit_2511_ti2i": {
|
||||
"clip_threshold": 0.96,
|
||||
"ssim_threshold": 0.83,
|
||||
"psnr_threshold": 20.5,
|
||||
"mean_abs_diff_threshold": 17.0
|
||||
},
|
||||
"qwen_image_layered_i2i": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.95,
|
||||
"psnr_threshold": 30.0,
|
||||
"mean_abs_diff_threshold": 4.2
|
||||
},
|
||||
"wan2_1_t2v_1_3b_lora_1gpu": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.94,
|
||||
"psnr_threshold": 30.0,
|
||||
"mean_abs_diff_threshold": 4.0
|
||||
},
|
||||
"wan2_1_t2v_1.3b": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.85,
|
||||
"psnr_threshold": 25.0,
|
||||
"mean_abs_diff_threshold": 8.0
|
||||
},
|
||||
"cosmos3_nano_t2v": {
|
||||
"clip_threshold": 0.91,
|
||||
"ssim_threshold": 0.89,
|
||||
"psnr_threshold": 24.0,
|
||||
"mean_abs_diff_threshold": 9.9
|
||||
},
|
||||
"ltx_2_two_stage_t2v": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.89,
|
||||
"psnr_threshold": 30.0,
|
||||
"mean_abs_diff_threshold": 5.9
|
||||
},
|
||||
"ltx_2.3_one_stage_ti2v": {
|
||||
"clip_threshold": 0.87,
|
||||
"ssim_threshold": 0.78,
|
||||
"psnr_threshold": 20.5,
|
||||
"mean_abs_diff_threshold": 11.0
|
||||
},
|
||||
"ltx_2.3_two_stage_t2v_2gpus": {
|
||||
"clip_threshold": 0.94,
|
||||
"ssim_threshold": 0.45,
|
||||
"psnr_threshold": 16.0,
|
||||
"mean_abs_diff_threshold": 27.5
|
||||
},
|
||||
"wan2_1_t2v_1.3b_teacache_enabled": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.92,
|
||||
"psnr_threshold": 30.0,
|
||||
"mean_abs_diff_threshold": 5.5
|
||||
},
|
||||
"wan2_1_t2v_1.3b_upscaling_4x": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.94,
|
||||
"psnr_threshold": 30.0,
|
||||
"mean_abs_diff_threshold": 4.6
|
||||
},
|
||||
"wan2_2_ti2v_5b": {
|
||||
"clip_threshold": 0.94,
|
||||
"ssim_threshold": 0.88,
|
||||
"psnr_threshold": 27.1,
|
||||
"mean_abs_diff_threshold": 7.2
|
||||
},
|
||||
"fastwan2_2_ti2v_5b": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.92,
|
||||
"psnr_threshold": 30.0,
|
||||
"mean_abs_diff_threshold": 4.7
|
||||
},
|
||||
"turbo_wan2_1_t2v_1.3b": {
|
||||
"clip_threshold": 0.90,
|
||||
"ssim_threshold": 0.52,
|
||||
"psnr_threshold": 9.5,
|
||||
"mean_abs_diff_threshold": 46.0
|
||||
},
|
||||
"fsdp-inference": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.95,
|
||||
"psnr_threshold": 30.0,
|
||||
"mean_abs_diff_threshold": 4.0
|
||||
},
|
||||
"zimage_image_t2i_2_gpus_non_square": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.95,
|
||||
"psnr_threshold": 30.0,
|
||||
"mean_abs_diff_threshold": 4.0
|
||||
},
|
||||
"flux_2_image_t2i_2_gpus": {
|
||||
"clip_threshold": 0.98,
|
||||
"ssim_threshold": 0.95,
|
||||
"psnr_threshold": 19,
|
||||
"mean_abs_diff_threshold": 4.0
|
||||
},
|
||||
"flux_2_image_t2i_upscaling_4x": {
|
||||
"clip_threshold": 0.98,
|
||||
"ssim_threshold": 0.95,
|
||||
"psnr_threshold": 30.0,
|
||||
"mean_abs_diff_threshold": 4.0
|
||||
},
|
||||
"flux_2_t2i_customized_vae_path": {
|
||||
"clip_threshold": 0.98,
|
||||
"ssim_threshold": 0.95,
|
||||
"psnr_threshold": 28.0,
|
||||
"mean_abs_diff_threshold": 4.0
|
||||
},
|
||||
"flux_2_ti2i_multi_image_cache_dit": {
|
||||
"clip_threshold": 0.94,
|
||||
"ssim_threshold": 0.90,
|
||||
"psnr_threshold": 22.0,
|
||||
"mean_abs_diff_threshold": 9.0
|
||||
},
|
||||
"zimage_image_t2i_2_gpus": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.95,
|
||||
"psnr_threshold": 30.0,
|
||||
"mean_abs_diff_threshold": 4.0
|
||||
},
|
||||
"flux_image_t2i_2_gpus": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.95,
|
||||
"psnr_threshold": 25.8,
|
||||
"mean_abs_diff_threshold": 4.0
|
||||
},
|
||||
"wan2_2_t2v_a14b_teacache_2gpu": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.90,
|
||||
"psnr_threshold": 29.1,
|
||||
"mean_abs_diff_threshold": 6.8
|
||||
},
|
||||
"wan2_1_t2v_14b_2gpu": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.91,
|
||||
"psnr_threshold": 30.0,
|
||||
"mean_abs_diff_threshold": 5.6
|
||||
},
|
||||
"wan2_1_i2v_14b_lora_2gpu": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.90,
|
||||
"psnr_threshold": 30.0,
|
||||
"mean_abs_diff_threshold": 5.3
|
||||
},
|
||||
"wan2_2_t2v_a14b_2gpu": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.90,
|
||||
"psnr_threshold": 29.1,
|
||||
"mean_abs_diff_threshold": 6.8
|
||||
},
|
||||
"wan2_2_t2v_a14b_lora_2gpu": {
|
||||
"clip_threshold": 0.98,
|
||||
"ssim_threshold": 0.95,
|
||||
"psnr_threshold": 22.2,
|
||||
"mean_abs_diff_threshold": 4.0
|
||||
},
|
||||
"wan2_1_i2v_14b_480P_2gpu": {
|
||||
"clip_threshold": 0.92,
|
||||
"ssim_threshold": 0.75,
|
||||
"psnr_threshold": 21.4,
|
||||
"mean_abs_diff_threshold": 9.7
|
||||
},
|
||||
"wan2_1_i2v_14b_720P_2gpu": {
|
||||
"clip_threshold": 0.97,
|
||||
"ssim_threshold": 0.90,
|
||||
"psnr_threshold": 30.0,
|
||||
"mean_abs_diff_threshold": 5.5
|
||||
},
|
||||
"ltx_2_3_hq_pipeline": {
|
||||
"clip_threshold": 0.995,
|
||||
"ssim_threshold": 0.995,
|
||||
"psnr_threshold": 50.0,
|
||||
"mean_abs_diff_threshold": 0.5
|
||||
},
|
||||
"ltx_2_3_two_stage_ti2v_2gpus": {
|
||||
"clip_threshold": 0.55,
|
||||
"ssim_threshold": 0.29,
|
||||
"psnr_threshold": 11.7,
|
||||
"mean_abs_diff_threshold": 47.0
|
||||
},
|
||||
"joy_echo_t2v_2gpu": {
|
||||
"clip_threshold": 0.78,
|
||||
"ssim_threshold": 0.48,
|
||||
"psnr_threshold": 13.0,
|
||||
"mean_abs_diff_threshold": 45.0
|
||||
}
|
||||
},
|
||||
"default_clip_threshold_image": 0.92,
|
||||
"default_clip_threshold_video": 0.90,
|
||||
"default_ssim_threshold_image": 0.95,
|
||||
"default_psnr_threshold_image": 28.0,
|
||||
"default_mean_abs_diff_threshold_image": 8.0,
|
||||
"default_ssim_threshold_video": 0.92,
|
||||
"default_psnr_threshold_video": 24.0,
|
||||
"default_mean_abs_diff_threshold_video": 10.0
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,564 @@
|
||||
{
|
||||
"metadata": {
|
||||
"model": "Diffusion Server",
|
||||
"hardware": "CI S5000 pool",
|
||||
"description": "Reference numbers captured from the CI diffusion server baseline run"
|
||||
},
|
||||
"scenarios": {
|
||||
"zimage_image_t2i_musa": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 0.08,
|
||||
"TextEncodingStage": 3761.4,
|
||||
"LatentPreparationStage": 4.06,
|
||||
"TimestepPreparationStage": 21.94,
|
||||
"DenoisingStage": 4873.8,
|
||||
"DecodingStage": 252.49
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 3281.35,
|
||||
"2": 209.69,
|
||||
"3": 199.26,
|
||||
"5": 200.42,
|
||||
"6": 207.8,
|
||||
"8": 205.19
|
||||
},
|
||||
"expected_e2e_ms": 12161.85,
|
||||
"expected_avg_denoise_ms": 540.67,
|
||||
"expected_median_denoise_ms": 205.19,
|
||||
"estimated_full_test_time_s": 64.6
|
||||
},
|
||||
"qwen_image_layered_i2i_musa": {
|
||||
"stages_ms": {
|
||||
"QwenImageLayeredBeforeDenoisingStage": 287.12,
|
||||
"TimestepPreparationStage": 0.01,
|
||||
"DenoisingStage": 79962.68,
|
||||
"DecodingStage": 232.86
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 1377.49,
|
||||
"1": 1608.67,
|
||||
"2": 1606.57,
|
||||
"3": 1601.06,
|
||||
"4": 1606.65,
|
||||
"5": 1605.0,
|
||||
"6": 1596.31,
|
||||
"7": 1609.13,
|
||||
"8": 1599.48,
|
||||
"9": 1601.81,
|
||||
"10": 1606.7,
|
||||
"11": 1601.7,
|
||||
"12": 1607.68,
|
||||
"13": 1606.42,
|
||||
"14": 1599.13,
|
||||
"15": 1611.78,
|
||||
"16": 1598.31,
|
||||
"17": 1600.97,
|
||||
"18": 1611.38,
|
||||
"19": 1598.6,
|
||||
"20": 1599.72,
|
||||
"21": 1608.24,
|
||||
"22": 1599.4,
|
||||
"23": 1613.52,
|
||||
"24": 1600.56,
|
||||
"25": 1605.91,
|
||||
"26": 1605.47,
|
||||
"27": 1598.85,
|
||||
"28": 1607.93,
|
||||
"29": 1603.65,
|
||||
"30": 1598.64,
|
||||
"31": 1607.1,
|
||||
"32": 1595.55,
|
||||
"33": 1608.09,
|
||||
"34": 1606.47,
|
||||
"35": 1596.18,
|
||||
"36": 1599.88,
|
||||
"37": 1607.12,
|
||||
"38": 1595.63,
|
||||
"39": 1612.07,
|
||||
"40": 1596.19,
|
||||
"41": 1602.35,
|
||||
"42": 1604.17,
|
||||
"43": 1598.26,
|
||||
"44": 1602.67,
|
||||
"45": 1611.54,
|
||||
"46": 1599.01,
|
||||
"47": 1619.72,
|
||||
"48": 1593.45,
|
||||
"49": 1602.33
|
||||
},
|
||||
"expected_e2e_ms": 80490.53,
|
||||
"expected_avg_denoise_ms": 1599.09,
|
||||
"expected_median_denoise_ms": 1602.51,
|
||||
"estimated_full_test_time_s": 159.4
|
||||
},
|
||||
"fast_hunyuan_video_musa": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 0.08,
|
||||
"TextEncodingStage": 4146.14,
|
||||
"TimestepPreparationStage": 18.33,
|
||||
"LatentPreparationStage": 2.42,
|
||||
"DenoisingStage": 17236.59,
|
||||
"DecodingStage": 7019.29
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 5462.17,
|
||||
"1": 2338.96,
|
||||
"2": 2355.67,
|
||||
"3": 2353.45,
|
||||
"4": 2359.64,
|
||||
"5": 2363.04
|
||||
},
|
||||
"expected_e2e_ms": 32799.37,
|
||||
"expected_avg_denoise_ms": 2872.16,
|
||||
"expected_median_denoise_ms": 2357.66,
|
||||
"estimated_full_test_time_s": 111.3
|
||||
},
|
||||
"qwen_image_t2i_musa": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 0.09,
|
||||
"TextEncodingStage": 658.4,
|
||||
"LatentPreparationStage": 0.33,
|
||||
"TimestepPreparationStage": 24.39,
|
||||
"DenoisingStage": 36196.6,
|
||||
"DecodingStage": 40.44
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 666.68,
|
||||
"1": 732.33,
|
||||
"2": 721.29,
|
||||
"3": 729.27,
|
||||
"4": 725.05,
|
||||
"5": 721.71,
|
||||
"6": 722.22,
|
||||
"7": 725.93,
|
||||
"8": 724.94,
|
||||
"9": 724.14,
|
||||
"10": 730.43,
|
||||
"11": 719.92,
|
||||
"12": 726.24,
|
||||
"13": 722.04,
|
||||
"14": 727.68,
|
||||
"15": 720.31,
|
||||
"16": 721.75,
|
||||
"17": 725.65,
|
||||
"18": 720.23,
|
||||
"19": 724.12,
|
||||
"20": 726.35,
|
||||
"21": 723.27,
|
||||
"22": 731.58,
|
||||
"23": 724.97,
|
||||
"24": 721.48,
|
||||
"25": 722.0,
|
||||
"26": 722.37,
|
||||
"27": 719.81,
|
||||
"28": 721.64,
|
||||
"29": 724.81,
|
||||
"30": 723.9,
|
||||
"31": 725.42,
|
||||
"32": 719.86,
|
||||
"33": 728.04,
|
||||
"34": 728.55,
|
||||
"35": 723.13,
|
||||
"36": 722.0,
|
||||
"37": 730.11,
|
||||
"38": 724.06,
|
||||
"39": 728.35,
|
||||
"40": 728.04,
|
||||
"41": 726.62,
|
||||
"42": 728.47,
|
||||
"43": 728.11,
|
||||
"44": 728.59,
|
||||
"45": 721.5,
|
||||
"46": 724.59,
|
||||
"47": 729.26,
|
||||
"48": 726.05,
|
||||
"49": 721.13
|
||||
},
|
||||
"expected_e2e_ms": 37190.98,
|
||||
"expected_avg_denoise_ms": 723.72,
|
||||
"expected_median_denoise_ms": 724.7,
|
||||
"estimated_full_test_time_s": 137.0
|
||||
},
|
||||
"qwen_image_2512_t2i_musa": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 0.07,
|
||||
"TextEncodingStage": 849.1,
|
||||
"LatentPreparationStage": 0.26,
|
||||
"TimestepPreparationStage": 21.95,
|
||||
"DenoisingStage": 31935.97,
|
||||
"DecodingStage": 98.62
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 553.87,
|
||||
"1": 639.78,
|
||||
"2": 640.39,
|
||||
"3": 638.78,
|
||||
"4": 640.13,
|
||||
"5": 639.69,
|
||||
"6": 640.19,
|
||||
"7": 639.67,
|
||||
"8": 638.95,
|
||||
"9": 640.06,
|
||||
"10": 639.8,
|
||||
"11": 640.81,
|
||||
"12": 638.7,
|
||||
"13": 640.16,
|
||||
"14": 639.76,
|
||||
"15": 640.17,
|
||||
"16": 639.26,
|
||||
"17": 640.33,
|
||||
"18": 639.91,
|
||||
"19": 640.47,
|
||||
"20": 640.1,
|
||||
"21": 639.81,
|
||||
"22": 639.05,
|
||||
"23": 639.7,
|
||||
"24": 640.02,
|
||||
"25": 640.67,
|
||||
"26": 639.04,
|
||||
"27": 640.21,
|
||||
"28": 639.78,
|
||||
"29": 643.32,
|
||||
"30": 640.2,
|
||||
"31": 639.54,
|
||||
"32": 640.14,
|
||||
"33": 640.14,
|
||||
"34": 639.54,
|
||||
"35": 639.22,
|
||||
"36": 639.94,
|
||||
"37": 639.87,
|
||||
"38": 639.41,
|
||||
"39": 639.6,
|
||||
"40": 638.5,
|
||||
"41": 639.5,
|
||||
"42": 639.35,
|
||||
"43": 641.43,
|
||||
"44": 638.73,
|
||||
"45": 639.74,
|
||||
"46": 639.72,
|
||||
"47": 639.72,
|
||||
"48": 638.64,
|
||||
"49": 638.72
|
||||
},
|
||||
"expected_e2e_ms": 32915.75,
|
||||
"expected_avg_denoise_ms": 638.55,
|
||||
"expected_median_denoise_ms": 640.05,
|
||||
"estimated_full_test_time_s": 137.8
|
||||
},
|
||||
"wan2_1_t2v_1.3b_musa": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 0.06,
|
||||
"TextEncodingStage": 1381.91,
|
||||
"LatentPreparationStage": 0.18,
|
||||
"TimestepPreparationStage": 3.99,
|
||||
"DenoisingStage": 23679.86,
|
||||
"DecodingStage": 1059.53,
|
||||
"per_frame_generation": null
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 331.71,
|
||||
"1": 478.93,
|
||||
"2": 481.37,
|
||||
"3": 483.42,
|
||||
"4": 476.27,
|
||||
"5": 488.73,
|
||||
"6": 486.79,
|
||||
"7": 467.89,
|
||||
"8": 465.47,
|
||||
"9": 472.81,
|
||||
"10": 478.41,
|
||||
"11": 488.84,
|
||||
"12": 474.68,
|
||||
"13": 468.48,
|
||||
"14": 483.79,
|
||||
"15": 476.05,
|
||||
"16": 483.77,
|
||||
"17": 476.04,
|
||||
"18": 484.27,
|
||||
"19": 486.43,
|
||||
"20": 483.04,
|
||||
"21": 473.76,
|
||||
"22": 464.09,
|
||||
"23": 474.14,
|
||||
"24": 470.76,
|
||||
"25": 487.99,
|
||||
"26": 477.77,
|
||||
"27": 465.76,
|
||||
"28": 483.96,
|
||||
"29": 484.14,
|
||||
"30": 471.99,
|
||||
"31": 483.41,
|
||||
"32": 486.66,
|
||||
"33": 467.07,
|
||||
"34": 478.04,
|
||||
"35": 476.9,
|
||||
"36": 462.4,
|
||||
"37": 476.53,
|
||||
"38": 485.65,
|
||||
"39": 478.89,
|
||||
"40": 465.22,
|
||||
"41": 472.03,
|
||||
"42": 479.65,
|
||||
"43": 479.74,
|
||||
"44": 479.48,
|
||||
"45": 474.19,
|
||||
"46": 464.47,
|
||||
"47": 463.09,
|
||||
"48": 463.77,
|
||||
"49": 463.49
|
||||
},
|
||||
"expected_e2e_ms": 26134.51,
|
||||
"expected_avg_denoise_ms": 473.44,
|
||||
"expected_median_denoise_ms": 476.72,
|
||||
"estimated_full_test_time_s": 101.5
|
||||
},
|
||||
"wan2_2_t2v_a14b_2gpu_musa": {
|
||||
"stages_ms": {
|
||||
"per_frame_generation": null,
|
||||
"TimestepPreparationStage": 4.8,
|
||||
"DenoisingStage": 281769.53,
|
||||
"DecodingStage": 1728.76,
|
||||
"InputValidationStage": 0.13,
|
||||
"TextEncodingStage": 1098.56,
|
||||
"LatentPreparationStage": 0.33
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 6262.73,
|
||||
"1": 7103.05,
|
||||
"2": 7039.74,
|
||||
"3": 7052.97,
|
||||
"4": 7046.74,
|
||||
"5": 7059.9,
|
||||
"6": 7048.75,
|
||||
"7": 7054.99,
|
||||
"8": 7052.75,
|
||||
"9": 7059.59,
|
||||
"10": 7056.92,
|
||||
"11": 7053.61,
|
||||
"12": 7063.48,
|
||||
"13": 7045.34,
|
||||
"14": 7051.22,
|
||||
"15": 7051.25,
|
||||
"16": 7048.83,
|
||||
"17": 7053.91,
|
||||
"18": 7060.47,
|
||||
"19": 7056.4,
|
||||
"20": 7055.39,
|
||||
"21": 7052.72,
|
||||
"22": 7054.84,
|
||||
"23": 7058.17,
|
||||
"24": 7052.26,
|
||||
"25": 7057.8,
|
||||
"26": 7362.31,
|
||||
"27": 7053.57,
|
||||
"28": 7044.42,
|
||||
"29": 7044.03,
|
||||
"30": 7056.59,
|
||||
"31": 7045.81,
|
||||
"32": 7051.59,
|
||||
"33": 7048.66,
|
||||
"34": 7050.84,
|
||||
"35": 7048.57,
|
||||
"36": 7056.21,
|
||||
"37": 7056.08,
|
||||
"38": 7053.32,
|
||||
"39": 7047.35
|
||||
},
|
||||
"expected_e2e_ms": 285727.55,
|
||||
"expected_avg_denoise_ms": 7043.96,
|
||||
"expected_median_denoise_ms": 7056.07
|
||||
},
|
||||
"wan2_1_i2v_14b_480P_2gpu_musa": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 10.35,
|
||||
"TextEncodingStage": 1098.55,
|
||||
"ImageEncodingStage": 730.6,
|
||||
"ImageVAEEncodingStage": 1188.4,
|
||||
"LatentPreparationStage": 0.5,
|
||||
"TimestepPreparationStage": 7.99,
|
||||
"DenoisingStage": 134355.99,
|
||||
"DecodingStage": 1200.0,
|
||||
"per_frame_generation": null
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 2441.69,
|
||||
"1": 2711.82,
|
||||
"2": 2701.26,
|
||||
"3": 2692.91,
|
||||
"4": 2686.94,
|
||||
"5": 2685.35,
|
||||
"6": 2689.45,
|
||||
"7": 2685.49,
|
||||
"8": 2687.74,
|
||||
"9": 2690.0,
|
||||
"10": 2691.31,
|
||||
"11": 2691.65,
|
||||
"12": 2698.52,
|
||||
"13": 2689.37,
|
||||
"14": 2690.18,
|
||||
"15": 2691.48,
|
||||
"16": 2695.74,
|
||||
"17": 2691.77,
|
||||
"18": 2689.77,
|
||||
"19": 2690.6,
|
||||
"20": 2686.84,
|
||||
"21": 2694.9,
|
||||
"22": 2689.56,
|
||||
"23": 2696.38,
|
||||
"24": 2689.13,
|
||||
"25": 2686.38,
|
||||
"26": 2689.53,
|
||||
"27": 2695.91,
|
||||
"28": 2691.9,
|
||||
"29": 2691.55,
|
||||
"30": 2700.09,
|
||||
"31": 2691.45,
|
||||
"32": 2696.8,
|
||||
"33": 2689.42,
|
||||
"34": 2695.87,
|
||||
"35": 2690.31,
|
||||
"36": 2687.65,
|
||||
"37": 2697.62,
|
||||
"38": 2683.46,
|
||||
"39": 2692.41,
|
||||
"40": 2699.33,
|
||||
"41": 2695.25,
|
||||
"42": 2691.16,
|
||||
"43": 2687.13,
|
||||
"44": 2692.92,
|
||||
"45": 2690.4,
|
||||
"46": 2696.53,
|
||||
"47": 2689.51,
|
||||
"48": 2692.06,
|
||||
"49": 2680.93
|
||||
},
|
||||
"expected_e2e_ms": 138624.98,
|
||||
"expected_avg_denoise_ms": 2686.91,
|
||||
"expected_median_denoise_ms": 2691.24
|
||||
},
|
||||
"qwen_image_edit_t2i_musa": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 35.9,
|
||||
"ImageEncodingStage": 7483.38,
|
||||
"ImageVAEEncodingStage": 160.82,
|
||||
"LatentPreparationStage": 3.0,
|
||||
"TimestepPreparationStage": 19.02,
|
||||
"DenoisingStage": 84367.86,
|
||||
"DecodingStage": 36.82
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 7612.62,
|
||||
"1": 1567.7,
|
||||
"2": 1559.81,
|
||||
"3": 1570.75,
|
||||
"4": 1568.7,
|
||||
"5": 1572.44,
|
||||
"6": 1565.71,
|
||||
"7": 1559.33,
|
||||
"8": 1567.63,
|
||||
"9": 1566.83,
|
||||
"10": 1560.77,
|
||||
"11": 1561.03,
|
||||
"12": 1565.61,
|
||||
"13": 1560.43,
|
||||
"14": 1562.47,
|
||||
"15": 1562.22,
|
||||
"16": 1564.1,
|
||||
"17": 1571.28,
|
||||
"18": 1563.26,
|
||||
"19": 1561.37,
|
||||
"20": 1559.04,
|
||||
"21": 1556.07,
|
||||
"22": 1577.83,
|
||||
"23": 1564.54,
|
||||
"24": 1564.28,
|
||||
"25": 1573.79,
|
||||
"26": 1572.94,
|
||||
"27": 1568.81,
|
||||
"28": 1568.73,
|
||||
"29": 1571.71,
|
||||
"30": 1557.83,
|
||||
"31": 1568.7,
|
||||
"32": 1570.3,
|
||||
"33": 1567.36,
|
||||
"34": 1566.47,
|
||||
"35": 1567.2,
|
||||
"36": 1560.98,
|
||||
"37": 1563.43,
|
||||
"38": 1570.74,
|
||||
"39": 1568.01,
|
||||
"40": 1560.57,
|
||||
"41": 1572.64,
|
||||
"42": 1564.01,
|
||||
"43": 1566.34,
|
||||
"44": 1569.09,
|
||||
"45": 1573.18,
|
||||
"46": 1566.5,
|
||||
"47": 1567.04,
|
||||
"48": 1570.02,
|
||||
"49": 1559.91
|
||||
},
|
||||
"expected_e2e_ms": 92355.9,
|
||||
"expected_avg_denoise_ms": 1687.04,
|
||||
"expected_median_denoise_ms": 1566.67,
|
||||
"estimated_full_test_time_s": 217.0
|
||||
},
|
||||
"qwen_image_edit_2509_ti2i_musa": {
|
||||
"stages_ms": {
|
||||
"InputValidationStage": 125.7,
|
||||
"ImageEncodingStage": 1018.93,
|
||||
"ImageVAEEncodingStage": 311.41,
|
||||
"LatentPreparationStage": 0.24,
|
||||
"TimestepPreparationStage": 33.39,
|
||||
"DenoisingStage": 88792.03,
|
||||
"DecodingStage": 320.64
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 1914.75,
|
||||
"1": 2230.29,
|
||||
"2": 2216.93,
|
||||
"3": 2231.22,
|
||||
"4": 2230.63,
|
||||
"5": 2222.13,
|
||||
"6": 2224.43,
|
||||
"7": 2235.47,
|
||||
"8": 2220.55,
|
||||
"9": 2239.83,
|
||||
"10": 2239.29,
|
||||
"11": 2216.95,
|
||||
"12": 2221.39,
|
||||
"13": 2229.65,
|
||||
"14": 2231.94,
|
||||
"15": 2222.23,
|
||||
"16": 2230.03,
|
||||
"17": 2236.55,
|
||||
"18": 2217.18,
|
||||
"19": 2231.48,
|
||||
"20": 2236.88,
|
||||
"21": 2226.74,
|
||||
"22": 2224.26,
|
||||
"23": 2231.1,
|
||||
"24": 2214.29,
|
||||
"25": 2224.57,
|
||||
"26": 2233.64,
|
||||
"27": 2217.0,
|
||||
"28": 2226.08,
|
||||
"29": 2229.47,
|
||||
"30": 2230.21,
|
||||
"31": 2224.45,
|
||||
"32": 2230.89,
|
||||
"33": 2232.82,
|
||||
"34": 2219.97,
|
||||
"35": 2228.74,
|
||||
"36": 2231.6,
|
||||
"37": 2225.25,
|
||||
"38": 2223.72,
|
||||
"39": 2228.41
|
||||
},
|
||||
"expected_e2e_ms": 90612.84,
|
||||
"expected_avg_denoise_ms": 2219.58,
|
||||
"expected_median_denoise_ms": 2228.58,
|
||||
"estimated_full_test_time_s": 220.8
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
"""
|
||||
Test runner for multimodal_gen MUSA suites that manages partitioned execution.
|
||||
|
||||
Usage:
|
||||
python3 -m sglang.multimodal_gen.test.server.musa.run_suite --suite <suite_name>
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import tabulate
|
||||
|
||||
TEST_ROOT = Path(__file__).resolve().parents[2]
|
||||
if str(TEST_ROOT) not in sys.path:
|
||||
sys.path.insert(0, str(TEST_ROOT))
|
||||
|
||||
from runner.pytest_runner import ( # noqa: E402
|
||||
collect_test_items,
|
||||
partition_items_by_index,
|
||||
run_pytest,
|
||||
)
|
||||
|
||||
SUITES = {
|
||||
"1-gpu-musa": [
|
||||
"test_server_1_gpu_musa.py",
|
||||
],
|
||||
"1-gpu-musa-nightly": [
|
||||
"test_server_1_gpu_musa_nightly.py",
|
||||
],
|
||||
"2-gpu-musa": [
|
||||
"test_server_2_gpu_musa.py",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description="Run multimodal_gen MUSA test suite")
|
||||
parser.add_argument(
|
||||
"--suite",
|
||||
type=str,
|
||||
required=True,
|
||||
choices=list(SUITES.keys()),
|
||||
help="The test suite to run (valid names are defined in SUITES)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--partition-id",
|
||||
type=int,
|
||||
default=0,
|
||||
help="Index of the current partition (for parallel execution)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--total-partitions",
|
||||
type=int,
|
||||
default=1,
|
||||
help="Total number of partitions",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--base-dir",
|
||||
type=str,
|
||||
default=None,
|
||||
help=(
|
||||
"Base directory for tests relative to multimodal_gen/test. "
|
||||
"Defaults to server/musa."
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"-k",
|
||||
"--filter",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Pytest filter expression (passed to pytest -k)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--continue-on-error",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Continue running remaining tests even if one fails.",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def _resolve_suite_files(
|
||||
suite: str, test_root_dir: Path, musa_dir: Path, base_dir: str | None
|
||||
) -> tuple[Path, list[str]]:
|
||||
target_dir = test_root_dir / base_dir if base_dir else musa_dir
|
||||
suite_files_rel = SUITES[suite]
|
||||
if target_dir == musa_dir:
|
||||
return target_dir, suite_files_rel
|
||||
|
||||
musa_rel = musa_dir.relative_to(target_dir)
|
||||
return target_dir, [str(musa_rel / rel_path) for rel_path in suite_files_rel]
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
||||
musa_dir = Path(__file__).resolve().parent
|
||||
test_root_dir = musa_dir.parent.parent
|
||||
target_dir, suite_files_rel = _resolve_suite_files(
|
||||
args.suite, test_root_dir, musa_dir, args.base_dir
|
||||
)
|
||||
|
||||
if not target_dir.exists():
|
||||
print(f"Error: Target directory {target_dir} does not exist.")
|
||||
sys.exit(1)
|
||||
|
||||
suite_files_abs = []
|
||||
for rel_path in suite_files_rel:
|
||||
abs_path = target_dir / rel_path
|
||||
if not abs_path.exists():
|
||||
print(f"Warning: Test file {rel_path} not found in {target_dir}. Skipping.")
|
||||
continue
|
||||
suite_files_abs.append(str(abs_path))
|
||||
|
||||
if not suite_files_abs:
|
||||
print(f"No valid test files found for suite '{args.suite}'.")
|
||||
sys.exit(0)
|
||||
|
||||
all_test_items = collect_test_items(suite_files_abs, filter_expr=args.filter)
|
||||
if not all_test_items:
|
||||
print(f"No test items found for suite '{args.suite}'.")
|
||||
sys.exit(0)
|
||||
|
||||
my_items = partition_items_by_index(
|
||||
all_test_items, args.partition_id, args.total_partitions
|
||||
)
|
||||
|
||||
partition_info = (
|
||||
f"{args.partition_id + 1}/{args.total_partitions} "
|
||||
f"(0-based id={args.partition_id})"
|
||||
)
|
||||
rows = [[args.suite, partition_info]]
|
||||
msg = (
|
||||
tabulate.tabulate(rows, headers=["Suite", "Partition"], tablefmt="psql") + "\n"
|
||||
)
|
||||
msg += f"Enabled {len(my_items)} test(s):\n"
|
||||
for item in my_items:
|
||||
msg += f" - {item}\n"
|
||||
print(msg, flush=True)
|
||||
print(
|
||||
f"Suite: {args.suite} | Partition: {args.partition_id}/{args.total_partitions}"
|
||||
)
|
||||
print(f"Selected {len(suite_files_abs)} files:")
|
||||
for file_path in suite_files_abs:
|
||||
print(f" - {os.path.basename(file_path)}")
|
||||
|
||||
if not my_items:
|
||||
print("No items assigned to this partition. Exiting success.")
|
||||
sys.exit(0)
|
||||
|
||||
print(f"Running {len(my_items)} items in this shard: {', '.join(my_items)}")
|
||||
exit_code, _, _ = run_pytest(my_items, exitfirst=not args.continue_on_error)
|
||||
|
||||
msg = (
|
||||
"\n"
|
||||
+ tabulate.tabulate(rows, headers=["Suite", "Partition"], tablefmt="psql")
|
||||
+ "\n"
|
||||
)
|
||||
msg += f"Executed {len(my_items)} test(s):\n"
|
||||
for item in my_items:
|
||||
msg += f" - {item}\n"
|
||||
print(msg, flush=True)
|
||||
|
||||
sys.exit(exit_code)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,22 @@
|
||||
"""
|
||||
MUSA-specific 1-GPU diffusion performance tests.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from sglang.multimodal_gen.test.server.common.case_fixtures import (
|
||||
diffusion_case_fixture,
|
||||
)
|
||||
from sglang.multimodal_gen.test.server.musa.testcase_configs_musa import (
|
||||
ONE_GPU_MUSA_CASES,
|
||||
)
|
||||
from sglang.multimodal_gen.test.server.test_server_common import ( # noqa: F401
|
||||
DiffusionServerBase,
|
||||
diffusion_server,
|
||||
)
|
||||
|
||||
|
||||
class TestDiffusionServerOneGpuMusa(DiffusionServerBase):
|
||||
"""Performance tests for 1-GPU diffusion cases on MUSA."""
|
||||
|
||||
case = diffusion_case_fixture(ONE_GPU_MUSA_CASES)
|
||||
@@ -0,0 +1,22 @@
|
||||
"""
|
||||
MUSA-specific 1-GPU diffusion performance tests for nightly suite.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from sglang.multimodal_gen.test.server.common.case_fixtures import (
|
||||
diffusion_case_fixture,
|
||||
)
|
||||
from sglang.multimodal_gen.test.server.musa.testcase_configs_musa import (
|
||||
ONE_GPU_NIGHTLY_MUSA_CASES,
|
||||
)
|
||||
from sglang.multimodal_gen.test.server.test_server_common import ( # noqa: F401
|
||||
DiffusionServerBase,
|
||||
diffusion_server,
|
||||
)
|
||||
|
||||
|
||||
class TestDiffusionServerOneGpuMusaNightly(DiffusionServerBase):
|
||||
"""Performance tests for 1-GPU diffusion cases on MUSA (nightly-only)."""
|
||||
|
||||
case = diffusion_case_fixture(ONE_GPU_NIGHTLY_MUSA_CASES)
|
||||
@@ -0,0 +1,22 @@
|
||||
"""
|
||||
MUSA-specific 2-GPU diffusion performance tests.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from sglang.multimodal_gen.test.server.common.case_fixtures import (
|
||||
diffusion_case_fixture,
|
||||
)
|
||||
from sglang.multimodal_gen.test.server.musa.testcase_configs_musa import (
|
||||
TWO_GPU_MUSA_CASES,
|
||||
)
|
||||
from sglang.multimodal_gen.test.server.test_server_common import ( # noqa: F401
|
||||
DiffusionServerBase,
|
||||
diffusion_server,
|
||||
)
|
||||
|
||||
|
||||
class TestDiffusionServerTwoGpuMusa(DiffusionServerBase):
|
||||
"""Performance tests for 2-GPU diffusion cases on MUSA."""
|
||||
|
||||
case = diffusion_case_fixture(TWO_GPU_MUSA_CASES)
|
||||
@@ -0,0 +1,134 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import replace
|
||||
from functools import lru_cache
|
||||
|
||||
from sglang.multimodal_gen.test.server.testcase_configs import (
|
||||
T2V_PROMPT,
|
||||
DiffusionSamplingParams,
|
||||
DiffusionServerArgs,
|
||||
DiffusionTestCase,
|
||||
MULTI_FRAME_I2I_sampling_params,
|
||||
MULTI_IMAGE_TI2I_sampling_params,
|
||||
T2I_sampling_params,
|
||||
T2V_sampling_params,
|
||||
TI2I_sampling_params,
|
||||
TI2V_sampling_params,
|
||||
)
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def hf_cached_model(repo_id: str) -> str:
|
||||
"""Resolve an HF repo id to the local cache snapshot prepared on MUSA runners."""
|
||||
from huggingface_hub import snapshot_download
|
||||
|
||||
return snapshot_download(repo_id, local_files_only=True)
|
||||
|
||||
|
||||
MUSA_TI2I_sampling_params = replace(
|
||||
TI2I_sampling_params,
|
||||
image_path="/hf-cache/hub/musa-test-assets/TI2I_Qwen_Image_Edit_Input.jpg",
|
||||
)
|
||||
|
||||
ONE_GPU_MUSA_CASES: list[DiffusionTestCase] = [
|
||||
DiffusionTestCase(
|
||||
"qwen_image_t2i_musa",
|
||||
DiffusionServerArgs(
|
||||
model_path=hf_cached_model("Qwen/Qwen-Image"),
|
||||
modality="image",
|
||||
),
|
||||
T2I_sampling_params,
|
||||
run_consistency_check=False,
|
||||
),
|
||||
DiffusionTestCase(
|
||||
"wan2_1_t2v_1.3b_musa",
|
||||
DiffusionServerArgs(
|
||||
model_path=hf_cached_model("Wan-AI/Wan2.1-T2V-1.3B-Diffusers"),
|
||||
modality="video",
|
||||
custom_validator="video",
|
||||
),
|
||||
DiffusionSamplingParams(
|
||||
prompt=T2V_PROMPT,
|
||||
),
|
||||
run_consistency_check=False,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
NIGHTLY_1_GPU_MUSA_CASES: list[DiffusionTestCase] = [
|
||||
DiffusionTestCase(
|
||||
"zimage_image_t2i_musa",
|
||||
DiffusionServerArgs(
|
||||
model_path=hf_cached_model("Tongyi-MAI/Z-Image-Turbo"),
|
||||
modality="image",
|
||||
),
|
||||
T2I_sampling_params,
|
||||
run_consistency_check=False,
|
||||
),
|
||||
DiffusionTestCase(
|
||||
"qwen_image_layered_i2i_musa",
|
||||
DiffusionServerArgs(
|
||||
model_path=hf_cached_model("Qwen/Qwen-Image-Layered"),
|
||||
modality="image",
|
||||
),
|
||||
MULTI_FRAME_I2I_sampling_params,
|
||||
run_consistency_check=False,
|
||||
),
|
||||
DiffusionTestCase(
|
||||
"fast_hunyuan_video_musa",
|
||||
DiffusionServerArgs(
|
||||
model_path=hf_cached_model("FastVideo/FastHunyuan-diffusers"),
|
||||
modality="video",
|
||||
custom_validator="video",
|
||||
),
|
||||
T2V_sampling_params,
|
||||
run_consistency_check=False,
|
||||
),
|
||||
DiffusionTestCase(
|
||||
"qwen_image_2512_t2i_musa",
|
||||
DiffusionServerArgs(
|
||||
model_path=hf_cached_model("Qwen/Qwen-Image-2512"),
|
||||
modality="image",
|
||||
),
|
||||
T2I_sampling_params,
|
||||
run_consistency_check=False,
|
||||
),
|
||||
DiffusionTestCase(
|
||||
"qwen_image_edit_t2i_musa",
|
||||
DiffusionServerArgs(
|
||||
model_path=hf_cached_model("Qwen/Qwen-Image-Edit"),
|
||||
modality="image",
|
||||
),
|
||||
MUSA_TI2I_sampling_params,
|
||||
run_consistency_check=False,
|
||||
),
|
||||
DiffusionTestCase(
|
||||
"qwen_image_edit_2509_ti2i_musa",
|
||||
DiffusionServerArgs(
|
||||
model_path=hf_cached_model("Qwen/Qwen-Image-Edit-2509"),
|
||||
modality="image",
|
||||
),
|
||||
MULTI_IMAGE_TI2I_sampling_params,
|
||||
run_consistency_check=False,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
ONE_GPU_NIGHTLY_MUSA_CASES: list[DiffusionTestCase] = (
|
||||
ONE_GPU_MUSA_CASES + NIGHTLY_1_GPU_MUSA_CASES
|
||||
)
|
||||
|
||||
|
||||
TWO_GPU_MUSA_CASES: list[DiffusionTestCase] = [
|
||||
DiffusionTestCase(
|
||||
"wan2_1_i2v_14b_480P_2gpu_musa",
|
||||
DiffusionServerArgs(
|
||||
model_path=hf_cached_model("Wan-AI/Wan2.1-I2V-14B-480P-Diffusers"),
|
||||
modality="video",
|
||||
custom_validator="video",
|
||||
num_gpus=2,
|
||||
),
|
||||
TI2V_sampling_params,
|
||||
run_consistency_check=False,
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,106 @@
|
||||
{
|
||||
"metadata": {
|
||||
"model": "Diffusion Server",
|
||||
"hardware": "CI RTX 5090 pool",
|
||||
"description": "Reference numbers captured from real 5090 CI runner history (PR 29791 run 28492141274, job 84450974283).",
|
||||
"last_updated": "2026-07-01"
|
||||
},
|
||||
"tolerances": {
|
||||
"long_term": {
|
||||
"e2e": 0.15,
|
||||
"denoise_stage": 0.1,
|
||||
"non_denoise_stage": 0.5,
|
||||
"denoise_step": 0.25,
|
||||
"denoise_agg": 0.15
|
||||
},
|
||||
"pr_test": {
|
||||
"e2e": 0.25,
|
||||
"denoise_stage": 0.25,
|
||||
"non_denoise_stage": 0.8,
|
||||
"denoise_step": 0.3,
|
||||
"denoise_agg": 0.2
|
||||
}
|
||||
},
|
||||
"improvement_reporting": {
|
||||
"threshold": 0.2
|
||||
},
|
||||
"sampling": {
|
||||
"step_fractions": [
|
||||
0.0,
|
||||
0.2,
|
||||
0.4,
|
||||
0.6,
|
||||
0.8,
|
||||
1.0
|
||||
]
|
||||
},
|
||||
"scenarios": {
|
||||
"flux_2_klein_base_image_t2i": {
|
||||
"stages_ms": {
|
||||
"DecodingStage": 18.19,
|
||||
"DenoisingStage": 18213.48,
|
||||
"ImageVAEEncodingStage": 0.01,
|
||||
"InputValidationStage": 0.08,
|
||||
"LatentPreparationStage": 4.87,
|
||||
"TextEncodingStage": 104.46,
|
||||
"TimestepPreparationStage": 142.18
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 219.58,
|
||||
"10": 359.79,
|
||||
"20": 361.55,
|
||||
"29": 361.99,
|
||||
"39": 362.57,
|
||||
"49": 362.89
|
||||
},
|
||||
"expected_e2e_ms": 18641.09,
|
||||
"expected_avg_denoise_ms": 357.93,
|
||||
"expected_median_denoise_ms": 361.8,
|
||||
"estimated_full_test_time_s": 94.0
|
||||
},
|
||||
"wan2_1_t2v_1.3b": {
|
||||
"stages_ms": {
|
||||
"DecodingStage": 1202.43,
|
||||
"DenoisingStage": 21452.59,
|
||||
"InputValidationStage": 0.09,
|
||||
"LatentPreparationStage": 0.23,
|
||||
"TextEncodingStage": 1210.22,
|
||||
"TimestepPreparationStage": 3.91
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 480.39,
|
||||
"10": 426.11,
|
||||
"20": 427.32,
|
||||
"29": 428.09,
|
||||
"39": 428.04,
|
||||
"49": 422.31
|
||||
},
|
||||
"expected_e2e_ms": 23877.73,
|
||||
"expected_avg_denoise_ms": 428.74,
|
||||
"expected_median_denoise_ms": 427.94,
|
||||
"estimated_full_test_time_s": 160.9
|
||||
},
|
||||
"zimage_image_t2i": {
|
||||
"stages_ms": {
|
||||
"DecodingStage": 7.11,
|
||||
"DenoisingStage": 2229.48,
|
||||
"InputValidationStage": 0.04,
|
||||
"LatentPreparationStage": 0.17,
|
||||
"TextEncodingStage": 252.73,
|
||||
"TimestepPreparationStage": 38.57
|
||||
},
|
||||
"denoise_step_ms": {
|
||||
"0": 39.34,
|
||||
"2": 277.35,
|
||||
"3": 267.94,
|
||||
"5": 279.01,
|
||||
"6": 273.01,
|
||||
"8": 275.12
|
||||
},
|
||||
"expected_e2e_ms": 2533.95,
|
||||
"expected_avg_denoise_ms": 246.97,
|
||||
"expected_median_denoise_ms": 273.01,
|
||||
"estimated_full_test_time_s": 329.8
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"metadata": {
|
||||
"model": "Diffusion Server",
|
||||
"hardware": "CI B200 pool",
|
||||
"description": "Reference estimates for B200-only diffusion cases, split out from the shared diffusion baseline file.",
|
||||
"last_updated": "2026-07-01"
|
||||
},
|
||||
"tolerances": {
|
||||
"long_term": {
|
||||
"e2e": 0.15,
|
||||
"denoise_stage": 0.1,
|
||||
"non_denoise_stage": 0.5,
|
||||
"denoise_step": 0.25,
|
||||
"denoise_agg": 0.15
|
||||
},
|
||||
"pr_test": {
|
||||
"e2e": 0.25,
|
||||
"denoise_stage": 0.25,
|
||||
"non_denoise_stage": 0.8,
|
||||
"denoise_step": 0.3,
|
||||
"denoise_agg": 0.2
|
||||
}
|
||||
},
|
||||
"improvement_reporting": {
|
||||
"threshold": 0.2
|
||||
},
|
||||
"sampling": {
|
||||
"step_fractions": [
|
||||
0.0,
|
||||
0.2,
|
||||
0.4,
|
||||
0.6,
|
||||
0.8,
|
||||
1.0
|
||||
]
|
||||
},
|
||||
"scenarios": {
|
||||
"flux1_modelopt_nvfp4_t2i": {
|
||||
"stages_ms": {},
|
||||
"denoise_step_ms": {},
|
||||
"expected_e2e_ms": 0.0,
|
||||
"expected_avg_denoise_ms": 0.0,
|
||||
"expected_median_denoise_ms": 0.0,
|
||||
"estimated_full_test_time_s": 71.2
|
||||
},
|
||||
"flux2_modelopt_nvfp4_t2i": {
|
||||
"stages_ms": {},
|
||||
"denoise_step_ms": {},
|
||||
"expected_e2e_ms": 0.0,
|
||||
"expected_avg_denoise_ms": 0.0,
|
||||
"expected_median_denoise_ms": 0.0,
|
||||
"estimated_full_test_time_s": 592.3
|
||||
},
|
||||
"qwen_image_2512_modelopt_nvfp4_t2i": {
|
||||
"stages_ms": {},
|
||||
"denoise_step_ms": {},
|
||||
"expected_e2e_ms": 0.0,
|
||||
"expected_avg_denoise_ms": 0.0,
|
||||
"expected_median_denoise_ms": 0.0,
|
||||
"estimated_full_test_time_s": 120.0
|
||||
},
|
||||
"wan22_modelopt_nvfp4_t2v": {
|
||||
"stages_ms": {},
|
||||
"denoise_step_ms": {},
|
||||
"expected_e2e_ms": 0.0,
|
||||
"expected_avg_denoise_ms": 0.0,
|
||||
"expected_median_denoise_ms": 0.0,
|
||||
"estimated_full_test_time_s": 181.8
|
||||
},
|
||||
"ideogram4_nvfp4_t2i": {
|
||||
"stages_ms": {},
|
||||
"denoise_step_ms": {},
|
||||
"expected_e2e_ms": 0.0,
|
||||
"expected_avg_denoise_ms": 0.0,
|
||||
"expected_median_denoise_ms": 0.0,
|
||||
"estimated_full_test_time_s": 300.0
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,403 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import statistics
|
||||
import tempfile
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import imageio
|
||||
import msgspec.msgpack
|
||||
import numpy as np
|
||||
import pytest
|
||||
from openai import Client
|
||||
|
||||
from sglang.multimodal_gen.runtime.utils.realtime_video import (
|
||||
RAW_RGB_CONTENT_TYPE,
|
||||
RAW_RGB_DELTA_GZIP_CONTENT_TYPE,
|
||||
RAW_RGBA_DELTA_GZIP_CONTENT_TYPE,
|
||||
restore_delta_gzip_raw_rgb_payload,
|
||||
)
|
||||
from sglang.multimodal_gen.test.server.testcase_configs import DiffusionSamplingParams
|
||||
from sglang.multimodal_gen.test.test_utils import is_image_url
|
||||
|
||||
_REALTIME_WS_TIMEOUT_SECS = float(
|
||||
os.environ.get("SGLANG_TEST_REALTIME_WS_TIMEOUT_SECS", "1200")
|
||||
)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RealtimeChunkStats:
|
||||
chunk_index: int
|
||||
request_id: str | None
|
||||
content_type: str
|
||||
num_frames: int
|
||||
raw_bytes: int
|
||||
ws_payload_bytes: int
|
||||
request_prepare_ms: float
|
||||
scheduler_forward_ms: float
|
||||
raw_payload_build_ms: float
|
||||
raw_write_ms: float
|
||||
ws_write_ms: float
|
||||
chunk_total_ms: float
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class RealtimeCollectionResult:
|
||||
frames: list[np.ndarray]
|
||||
chunk_stats: list[RealtimeChunkStats]
|
||||
|
||||
|
||||
_REALTIME_CHUNK_STATS_BY_CASE: dict[str, list[RealtimeChunkStats]] = {}
|
||||
_REALTIME_KEY_FRAMES_BY_CASE: dict[str, list[np.ndarray]] = {}
|
||||
|
||||
|
||||
def realtime_ws_url(client: Client) -> str:
|
||||
base_url = str(client.base_url).rstrip("/")
|
||||
if base_url.startswith("https://"):
|
||||
return "wss://" + base_url[len("https://") :] + "/realtime_video/generate"
|
||||
if base_url.startswith("http://"):
|
||||
return "ws://" + base_url[len("http://") :] + "/realtime_video/generate"
|
||||
raise ValueError(f"Unsupported realtime client base_url: {base_url}")
|
||||
|
||||
|
||||
def prepare_realtime_first_frame(
|
||||
image_path: Path | str | list[Path | str] | None,
|
||||
) -> bytes | str | None:
|
||||
if image_path is None:
|
||||
return None
|
||||
if isinstance(image_path, list):
|
||||
image_path = image_path[0]
|
||||
if isinstance(image_path, str) and is_image_url(image_path):
|
||||
return image_path
|
||||
path = Path(image_path)
|
||||
if not path.exists():
|
||||
raise FileNotFoundError(f"Realtime first frame file missing: {path}")
|
||||
return path.read_bytes()
|
||||
|
||||
|
||||
def build_realtime_init_payload(
|
||||
*,
|
||||
model_path: str,
|
||||
sampling_params: DiffusionSamplingParams,
|
||||
output_size: str,
|
||||
first_frame: bytes | str | None,
|
||||
) -> dict[str, Any]:
|
||||
payload: dict[str, Any] = {
|
||||
"type": "init",
|
||||
"model": model_path,
|
||||
"prompt": sampling_params.prompt,
|
||||
"size": output_size,
|
||||
"seconds": sampling_params.seconds,
|
||||
"first_frame": first_frame,
|
||||
}
|
||||
optional_fields = {
|
||||
"fps": sampling_params.fps,
|
||||
"num_frames": sampling_params.num_frames,
|
||||
"realtime_output_format": sampling_params.realtime_output_format,
|
||||
}
|
||||
payload.update({k: v for k, v in optional_fields.items() if v is not None})
|
||||
payload.update(dict(sampling_params.extras))
|
||||
return {k: v for k, v in payload.items() if v is not None}
|
||||
|
||||
|
||||
def build_realtime_event_payload(event: dict[str, Any]) -> dict[str, Any]:
|
||||
payload = dict(event)
|
||||
payload.pop("after_chunk", None)
|
||||
payload.setdefault("type", "event")
|
||||
if "kind" not in payload:
|
||||
raise ValueError("realtime event config must include kind")
|
||||
return payload
|
||||
|
||||
|
||||
def parse_realtime_chunk_stats(header: dict[str, Any]) -> RealtimeChunkStats:
|
||||
if header.get("type") != "chunk_stats":
|
||||
raise ValueError(f"Unexpected realtime chunk stats message: {header}")
|
||||
return RealtimeChunkStats(
|
||||
chunk_index=int(header["chunk_index"]),
|
||||
request_id=header.get("request_id"),
|
||||
content_type=str(header.get("content_type", "")),
|
||||
num_frames=int(header.get("num_frames", 0)),
|
||||
raw_bytes=int(header.get("raw_bytes", 0)),
|
||||
ws_payload_bytes=int(header.get("ws_payload_bytes", 0)),
|
||||
request_prepare_ms=float(header.get("request_prepare_ms", 0.0)),
|
||||
scheduler_forward_ms=float(header.get("scheduler_forward_ms", 0.0)),
|
||||
raw_payload_build_ms=float(header.get("raw_payload_build_ms", 0.0)),
|
||||
raw_write_ms=float(header.get("raw_write_ms", 0.0)),
|
||||
ws_write_ms=float(header.get("ws_write_ms", 0.0)),
|
||||
chunk_total_ms=float(header.get("chunk_total_ms", 0.0)),
|
||||
)
|
||||
|
||||
|
||||
def summarize_realtime_perf_stats(
|
||||
chunk_stats: list[RealtimeChunkStats],
|
||||
*,
|
||||
ignore_initial_chunks: int = 0,
|
||||
) -> dict[str, float]:
|
||||
if not chunk_stats:
|
||||
return {}
|
||||
if ignore_initial_chunks < 0:
|
||||
raise ValueError("ignore_initial_chunks must be non-negative")
|
||||
if ignore_initial_chunks >= len(chunk_stats):
|
||||
raise ValueError(
|
||||
"ignore_initial_chunks must leave at least one realtime chunk to guard"
|
||||
)
|
||||
|
||||
ignored_stats = chunk_stats[:ignore_initial_chunks]
|
||||
guarded_stats = chunk_stats[ignore_initial_chunks:]
|
||||
|
||||
metrics = {
|
||||
"request_prepare_ms": [s.request_prepare_ms for s in guarded_stats],
|
||||
"scheduler_forward_ms": [s.scheduler_forward_ms for s in guarded_stats],
|
||||
"raw_payload_build_ms": [s.raw_payload_build_ms for s in guarded_stats],
|
||||
"raw_write_ms": [s.raw_write_ms for s in guarded_stats],
|
||||
"ws_write_ms": [s.ws_write_ms for s in guarded_stats],
|
||||
"chunk_total_ms": [s.chunk_total_ms for s in guarded_stats],
|
||||
"ws_payload_mb": [s.ws_payload_bytes / (1024 * 1024) for s in guarded_stats],
|
||||
}
|
||||
summary: dict[str, float] = {
|
||||
"num_chunks": float(len(chunk_stats)),
|
||||
"total_frames": float(sum(s.num_frames for s in chunk_stats)),
|
||||
"ignored_initial_chunks": float(ignore_initial_chunks),
|
||||
"guarded_chunks": float(len(guarded_stats)),
|
||||
}
|
||||
if ignored_stats:
|
||||
summary["ignored_max_chunk_total_ms"] = max(
|
||||
s.chunk_total_ms for s in ignored_stats
|
||||
)
|
||||
summary["ignored_max_scheduler_forward_ms"] = max(
|
||||
s.scheduler_forward_ms for s in ignored_stats
|
||||
)
|
||||
for name, values in metrics.items():
|
||||
sorted_values = sorted(values)
|
||||
p95_idx = min(len(sorted_values) - 1, int(len(sorted_values) * 0.95))
|
||||
summary[f"avg_{name}"] = statistics.fmean(values)
|
||||
summary[f"p95_{name}"] = sorted_values[p95_idx]
|
||||
summary[f"max_{name}"] = max(values)
|
||||
return summary
|
||||
|
||||
|
||||
def validate_realtime_perf_stats(
|
||||
case_id: str,
|
||||
chunk_stats: list[RealtimeChunkStats],
|
||||
thresholds: dict[str, float],
|
||||
*,
|
||||
ignore_initial_chunks: int = 0,
|
||||
) -> None:
|
||||
if not thresholds:
|
||||
return
|
||||
summary = summarize_realtime_perf_stats(
|
||||
chunk_stats, ignore_initial_chunks=ignore_initial_chunks
|
||||
)
|
||||
if not summary:
|
||||
pytest.fail(f"{case_id}: no realtime chunk stats were received")
|
||||
|
||||
failures = []
|
||||
for metric_name, threshold in thresholds.items():
|
||||
if metric_name not in summary:
|
||||
raise ValueError(
|
||||
f"{case_id}: unknown realtime perf metric {metric_name!r}; "
|
||||
f"available metrics: {sorted(summary)}"
|
||||
)
|
||||
actual = summary[metric_name]
|
||||
if actual > threshold:
|
||||
failures.append(
|
||||
f"{metric_name}: actual={actual:.2f}, limit={threshold:.2f}"
|
||||
)
|
||||
|
||||
if failures:
|
||||
pytest.fail(
|
||||
f"Realtime performance guard failed for {case_id}:\n"
|
||||
+ "\n".join(f" - {failure}" for failure in failures)
|
||||
)
|
||||
|
||||
|
||||
def record_realtime_perf_stats(
|
||||
case_id: str, chunk_stats: list[RealtimeChunkStats]
|
||||
) -> None:
|
||||
_REALTIME_CHUNK_STATS_BY_CASE[case_id] = list(chunk_stats)
|
||||
|
||||
|
||||
def pop_realtime_perf_stats(case_id: str) -> list[RealtimeChunkStats]:
|
||||
return _REALTIME_CHUNK_STATS_BY_CASE.pop(case_id, [])
|
||||
|
||||
|
||||
def select_realtime_key_frames(frames: list[np.ndarray]) -> list[np.ndarray]:
|
||||
if not frames:
|
||||
return []
|
||||
key_indices = [0, len(frames) // 2, len(frames) - 1]
|
||||
return [frames[idx].copy() for idx in key_indices]
|
||||
|
||||
|
||||
def record_realtime_key_frames(case_id: str, frames: list[np.ndarray]) -> None:
|
||||
_REALTIME_KEY_FRAMES_BY_CASE[case_id] = select_realtime_key_frames(frames)
|
||||
|
||||
|
||||
def pop_realtime_key_frames(case_id: str) -> list[np.ndarray] | None:
|
||||
return _REALTIME_KEY_FRAMES_BY_CASE.pop(case_id, None)
|
||||
|
||||
|
||||
def decode_realtime_raw_rgb_frames(
|
||||
header: dict[str, Any],
|
||||
payload: bytes,
|
||||
previous_frame: bytes | None = None,
|
||||
) -> list[np.ndarray]:
|
||||
content_type = header.get("content_type")
|
||||
if content_type not in (
|
||||
RAW_RGB_CONTENT_TYPE,
|
||||
RAW_RGB_DELTA_GZIP_CONTENT_TYPE,
|
||||
RAW_RGBA_DELTA_GZIP_CONTENT_TYPE,
|
||||
):
|
||||
raise ValueError(f"Unsupported realtime frame content type: {content_type}")
|
||||
|
||||
width = int(header["width"])
|
||||
height = int(header["height"])
|
||||
channels = int(header["channels"])
|
||||
num_frames = int(header["num_frames"])
|
||||
bytes_per_frame = int(header["bytes_per_frame"])
|
||||
expected_size = num_frames * bytes_per_frame
|
||||
if content_type in (
|
||||
RAW_RGB_DELTA_GZIP_CONTENT_TYPE,
|
||||
RAW_RGBA_DELTA_GZIP_CONTENT_TYPE,
|
||||
):
|
||||
if header.get("delta_reference") != "previous-frame":
|
||||
previous_frame = None
|
||||
payload = restore_delta_gzip_raw_rgb_payload(
|
||||
payload,
|
||||
bytes_per_frame=bytes_per_frame,
|
||||
num_frames=num_frames,
|
||||
reference_frame=previous_frame,
|
||||
)
|
||||
if len(payload) != expected_size:
|
||||
raise ValueError(
|
||||
f"Realtime payload size mismatch: expected {expected_size}, got {len(payload)}"
|
||||
)
|
||||
|
||||
frames = []
|
||||
for frame_idx in range(num_frames):
|
||||
offset = frame_idx * bytes_per_frame
|
||||
frame = np.frombuffer(
|
||||
payload[offset : offset + bytes_per_frame], dtype=np.uint8
|
||||
)
|
||||
frame = frame.reshape(height, width, channels)
|
||||
if channels > 3:
|
||||
frame = frame[:, :, :3]
|
||||
frames.append(frame.copy())
|
||||
return frames
|
||||
|
||||
|
||||
def encode_realtime_frames_to_mp4(frames: list[np.ndarray], fps: int) -> bytes:
|
||||
if not frames:
|
||||
raise ValueError("Cannot encode empty realtime frame list")
|
||||
|
||||
with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmp:
|
||||
output_path = tmp.name
|
||||
try:
|
||||
imageio.mimsave(
|
||||
output_path,
|
||||
frames,
|
||||
fps=fps,
|
||||
format="mp4",
|
||||
codec="libx264",
|
||||
quality=5,
|
||||
)
|
||||
return Path(output_path).read_bytes()
|
||||
finally:
|
||||
try:
|
||||
os.remove(output_path)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
async def collect_realtime_frames(
|
||||
*,
|
||||
ws_url: str,
|
||||
init_payload: dict[str, Any],
|
||||
events: list[dict[str, Any]],
|
||||
num_chunks: int,
|
||||
) -> list[np.ndarray]:
|
||||
return (
|
||||
await collect_realtime_output(
|
||||
ws_url=ws_url,
|
||||
init_payload=init_payload,
|
||||
events=events,
|
||||
num_chunks=num_chunks,
|
||||
)
|
||||
).frames
|
||||
|
||||
|
||||
async def collect_realtime_output(
|
||||
*,
|
||||
ws_url: str,
|
||||
init_payload: dict[str, Any],
|
||||
events: list[dict[str, Any]],
|
||||
num_chunks: int,
|
||||
require_chunk_stats: bool = False,
|
||||
) -> RealtimeCollectionResult:
|
||||
try:
|
||||
import websockets
|
||||
except ImportError:
|
||||
pytest.skip("websockets is required for realtime consistency checks")
|
||||
|
||||
frames: list[np.ndarray] = []
|
||||
chunk_stats: list[RealtimeChunkStats] = []
|
||||
sent_event_indices: set[int] = set()
|
||||
|
||||
async def send_events_for_boundary(ws, completed_chunk: int) -> None:
|
||||
for event_idx, event in enumerate(events):
|
||||
if event_idx in sent_event_indices:
|
||||
continue
|
||||
if int(event.get("after_chunk", 0)) != completed_chunk:
|
||||
continue
|
||||
await ws.send(msgspec.msgpack.encode(build_realtime_event_payload(event)))
|
||||
sent_event_indices.add(event_idx)
|
||||
|
||||
async with websockets.connect(ws_url, max_size=None, ping_interval=None) as ws:
|
||||
await ws.send(msgspec.msgpack.encode(init_payload))
|
||||
await send_events_for_boundary(ws, -1)
|
||||
|
||||
received_chunks: set[int] = set()
|
||||
previous_frame: bytes | None = None
|
||||
while len(received_chunks) < num_chunks or (
|
||||
require_chunk_stats and len(chunk_stats) < len(received_chunks)
|
||||
):
|
||||
header_payload = await asyncio.wait_for(
|
||||
ws.recv(), timeout=_REALTIME_WS_TIMEOUT_SECS
|
||||
)
|
||||
header = msgspec.msgpack.decode(header_payload)
|
||||
message_type = header.get("type")
|
||||
if message_type == "error":
|
||||
pytest.fail(f"Realtime generation failed: {header.get('content')}")
|
||||
if message_type == "chunk_stats":
|
||||
chunk_stats.append(parse_realtime_chunk_stats(header))
|
||||
continue
|
||||
if message_type == "frame_batch":
|
||||
raw_payload = header.pop("payload", None)
|
||||
header["type"] = "frame_batch_header"
|
||||
elif message_type == "frame_batch_header":
|
||||
raw_payload = await asyncio.wait_for(
|
||||
ws.recv(), timeout=_REALTIME_WS_TIMEOUT_SECS
|
||||
)
|
||||
else:
|
||||
raise ValueError(f"Unexpected realtime message: {header}")
|
||||
if not isinstance(raw_payload, bytes):
|
||||
raise ValueError("Realtime frame payload must be bytes")
|
||||
|
||||
chunk_frames = decode_realtime_raw_rgb_frames(
|
||||
header,
|
||||
raw_payload,
|
||||
previous_frame,
|
||||
)
|
||||
frames.extend(chunk_frames)
|
||||
if chunk_frames:
|
||||
previous_frame = chunk_frames[-1].tobytes()
|
||||
chunk_index = int(header["chunk_index"])
|
||||
if header.get("is_final_frame_batch", True):
|
||||
received_chunks.add(chunk_index)
|
||||
await send_events_for_boundary(ws, chunk_index)
|
||||
|
||||
return RealtimeCollectionResult(frames=frames, chunk_stats=chunk_stats)
|
||||
@@ -0,0 +1,233 @@
|
||||
"""
|
||||
Test request logging for diffusion models.
|
||||
|
||||
Tests the --log-requests CLI flags for diffusion model serving,
|
||||
verifying that request logs are correctly written to stdout and files.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from openai import OpenAI
|
||||
|
||||
from sglang.multimodal_gen.test.server.test_server_utils import ServerManager
|
||||
from sglang.multimodal_gen.test.test_utils import get_dynamic_server_port
|
||||
|
||||
# Test models and prompts
|
||||
IMAGE_MODEL = "Efficient-Large-Model/Sana_600M_512px_diffusers"
|
||||
IMAGE_PROMPT = "A beautiful sunset over mountains, oil painting style"
|
||||
VIDEO_MODEL = "Wan-AI/Wan2.1-T2V-1.3B-Diffusers"
|
||||
VIDEO_PROMPT = "A cat playing with a ball"
|
||||
|
||||
# Timeout settings
|
||||
BASE_TIMEOUT = float(os.environ.get("SGLANG_TEST_OPENAI_REQUEST_TIMEOUT_SECS", "600"))
|
||||
POLL_INTERVAL = 1.0
|
||||
|
||||
|
||||
def _start_server(model: str, log_format: str):
|
||||
"""Start server with request logging enabled."""
|
||||
temp_dir = tempfile.mkdtemp()
|
||||
port = get_dynamic_server_port()
|
||||
extra_args = (
|
||||
f"--log-requests "
|
||||
f"--log-requests-level 2 "
|
||||
f"--log-requests-format {log_format} "
|
||||
f"--log-requests-target stdout {temp_dir} "
|
||||
f"--strict-ports"
|
||||
)
|
||||
wait_deadline = float(os.environ.get("SGLANG_TEST_WAIT_SECS", "1200"))
|
||||
manager = ServerManager(
|
||||
model=model,
|
||||
port=port,
|
||||
wait_deadline=wait_deadline,
|
||||
extra_args=extra_args,
|
||||
)
|
||||
ctx = manager.start()
|
||||
ctx.temp_dir = temp_dir
|
||||
return ctx
|
||||
|
||||
|
||||
def _cleanup_server(ctx):
|
||||
"""Cleanup server and temp directory."""
|
||||
ctx.cleanup()
|
||||
shutil.rmtree(ctx.temp_dir, ignore_errors=True)
|
||||
|
||||
|
||||
def _create_client(ctx) -> OpenAI:
|
||||
"""Create OpenAI client for the server."""
|
||||
return OpenAI(
|
||||
api_key="test",
|
||||
base_url=f"http://localhost:{ctx.port}/v1",
|
||||
timeout=BASE_TIMEOUT,
|
||||
)
|
||||
|
||||
|
||||
def _wait_for_video_completion(client: OpenAI, video_id: str, timeout: float):
|
||||
"""Poll video job until completion."""
|
||||
deadline = time.time() + timeout
|
||||
while time.time() < deadline:
|
||||
page = client.videos.list()
|
||||
item = next((v for v in page.data if v.id == video_id), None)
|
||||
status = getattr(item, "status", None) if item else None
|
||||
|
||||
if status == "completed":
|
||||
return True
|
||||
if status in ("failed", "cancelled", "deleted"):
|
||||
pytest.fail(f"Video job {video_id} ended with status={status}")
|
||||
|
||||
time.sleep(POLL_INTERVAL)
|
||||
|
||||
pytest.fail(f"Video job {video_id} did not complete in {timeout}s")
|
||||
|
||||
|
||||
def _verify_json_logs(content: str):
|
||||
"""Verify JSON logs contain request.received and request.finished events."""
|
||||
has_received = False
|
||||
has_finished = False
|
||||
|
||||
for line in content.splitlines():
|
||||
idx = line.find("{")
|
||||
if idx == -1:
|
||||
continue
|
||||
try:
|
||||
data = json.loads(line[idx:])
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
|
||||
if data.get("event") == "request.received":
|
||||
has_received = True
|
||||
elif data.get("event") == "request.finished":
|
||||
has_finished = True
|
||||
|
||||
assert has_received, "request.received event not found"
|
||||
assert has_finished, "request.finished event not found"
|
||||
|
||||
|
||||
def _verify_text_logs(content: str, prompt: str):
|
||||
"""Verify text logs contain Receive, prompt, and Finish markers."""
|
||||
assert "Receive:" in content, "'Receive:' not found"
|
||||
assert prompt in content, f"Prompt '{prompt}' not found"
|
||||
assert "Finish:" in content, "'Finish:' not found"
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def image_text_server():
|
||||
"""Server with text-format logging for image model."""
|
||||
ctx = _start_server(IMAGE_MODEL, "text")
|
||||
yield ctx
|
||||
_cleanup_server(ctx)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def image_json_server():
|
||||
"""Server with JSON-format logging for image model."""
|
||||
ctx = _start_server(IMAGE_MODEL, "json")
|
||||
yield ctx
|
||||
_cleanup_server(ctx)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def video_text_server():
|
||||
"""Server with text-format logging for video model."""
|
||||
ctx = _start_server(VIDEO_MODEL, "text")
|
||||
yield ctx
|
||||
_cleanup_server(ctx)
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def video_json_server():
|
||||
"""Server with JSON-format logging for video model."""
|
||||
ctx = _start_server(VIDEO_MODEL, "json")
|
||||
yield ctx
|
||||
_cleanup_server(ctx)
|
||||
|
||||
|
||||
class TestImageRequestLoggerText:
|
||||
"""Test text-format request logging for image models."""
|
||||
|
||||
def test_request_logging(self, image_text_server):
|
||||
ctx = image_text_server
|
||||
client = _create_client(ctx)
|
||||
|
||||
# Image generation is synchronous, waits for completion
|
||||
client.images.generate(prompt=IMAGE_PROMPT, size="256x256", n=1)
|
||||
|
||||
# Verify stdout and file logs
|
||||
stdout = ctx.log_tail(lines=500)
|
||||
_verify_text_logs(stdout, IMAGE_PROMPT[:30])
|
||||
|
||||
logs = list(Path(ctx.temp_dir).glob("*.log"))
|
||||
assert logs, "No log files found"
|
||||
_verify_text_logs("".join(f.read_text() for f in logs), IMAGE_PROMPT[:30])
|
||||
|
||||
|
||||
class TestImageRequestLoggerJson:
|
||||
"""Test JSON-format request logging for image models."""
|
||||
|
||||
def test_request_logging(self, image_json_server):
|
||||
ctx = image_json_server
|
||||
client = _create_client(ctx)
|
||||
|
||||
# Image generation is synchronous, waits for completion
|
||||
client.images.generate(prompt=IMAGE_PROMPT, size="256x256", n=1)
|
||||
|
||||
# Verify stdout and file logs
|
||||
stdout = ctx.log_tail(lines=500)
|
||||
_verify_json_logs(stdout)
|
||||
|
||||
logs = list(Path(ctx.temp_dir).glob("*.log"))
|
||||
assert logs, "No log files found"
|
||||
_verify_json_logs("".join(f.read_text() for f in logs))
|
||||
|
||||
|
||||
class TestVideoRequestLoggerText:
|
||||
"""Test text-format request logging for video models."""
|
||||
|
||||
def test_request_logging(self, video_text_server):
|
||||
ctx = video_text_server
|
||||
client = _create_client(ctx)
|
||||
|
||||
# Video generation is async - create job and poll until completion
|
||||
job = client.videos.create(
|
||||
prompt=VIDEO_PROMPT,
|
||||
size="832x480",
|
||||
extra_body={"num_frames": 5, "num_inference_steps": 10},
|
||||
)
|
||||
_wait_for_video_completion(client, job.id, BASE_TIMEOUT * 2)
|
||||
|
||||
# Verify stdout and file logs
|
||||
stdout = ctx.log_tail(lines=500)
|
||||
_verify_text_logs(stdout, VIDEO_PROMPT[:20])
|
||||
|
||||
logs = list(Path(ctx.temp_dir).glob("*.log"))
|
||||
assert logs, "No log files found"
|
||||
_verify_text_logs("".join(f.read_text() for f in logs), VIDEO_PROMPT[:20])
|
||||
|
||||
|
||||
class TestVideoRequestLoggerJson:
|
||||
"""Test JSON-format request logging for video models."""
|
||||
|
||||
def test_request_logging(self, video_json_server):
|
||||
ctx = video_json_server
|
||||
client = _create_client(ctx)
|
||||
|
||||
# Video generation is async - create job and poll until completion
|
||||
job = client.videos.create(
|
||||
prompt=VIDEO_PROMPT,
|
||||
size="832x480",
|
||||
extra_body={"num_frames": 5, "num_inference_steps": 10},
|
||||
)
|
||||
_wait_for_video_completion(client, job.id, BASE_TIMEOUT * 2)
|
||||
|
||||
# Verify stdout and file logs
|
||||
stdout = ctx.log_tail(lines=500)
|
||||
_verify_json_logs(stdout)
|
||||
|
||||
logs = list(Path(ctx.temp_dir).glob("*.log"))
|
||||
assert logs, "No log files found"
|
||||
_verify_json_logs("".join(f.read_text() for f in logs))
|
||||
@@ -0,0 +1,23 @@
|
||||
"""
|
||||
Config-driven diffusion performance test with pytest parametrization.
|
||||
|
||||
|
||||
If the actual run is significantly better than the baseline, the improved cases with their updated baseline will be printed
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from sglang.multimodal_gen.test.server.common.case_fixtures import (
|
||||
diffusion_case_fixture,
|
||||
)
|
||||
from sglang.multimodal_gen.test.server.gpu_cases import ONE_GPU_CASES
|
||||
from sglang.multimodal_gen.test.server.test_server_common import ( # noqa: F401
|
||||
DiffusionServerBase,
|
||||
diffusion_server,
|
||||
)
|
||||
|
||||
|
||||
class TestDiffusionServerOneGpu(DiffusionServerBase):
|
||||
"""Performance tests for 1-GPU diffusion cases."""
|
||||
|
||||
case = diffusion_case_fixture(ONE_GPU_CASES)
|
||||
@@ -0,0 +1,20 @@
|
||||
"""
|
||||
Config-driven diffusion canary tests for the 1-GPU 5090 PR runner.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from sglang.multimodal_gen.test.server.common.case_fixtures import (
|
||||
diffusion_case_fixture,
|
||||
)
|
||||
from sglang.multimodal_gen.test.server.gpu_cases import ONE_GPU_5090_CASES
|
||||
from sglang.multimodal_gen.test.server.test_server_common import ( # noqa: F401
|
||||
DiffusionServerBase,
|
||||
diffusion_server,
|
||||
)
|
||||
|
||||
|
||||
class TestDiffusionServerOneGpu5090(DiffusionServerBase):
|
||||
"""Canary tests for lightweight 1-GPU diffusion cases on 5090."""
|
||||
|
||||
case = diffusion_case_fixture(ONE_GPU_5090_CASES)
|
||||
@@ -0,0 +1,20 @@
|
||||
"""
|
||||
2 GPU tests
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from sglang.multimodal_gen.test.server.common.case_fixtures import (
|
||||
diffusion_case_fixture,
|
||||
)
|
||||
from sglang.multimodal_gen.test.server.gpu_cases import TWO_GPU_CASES
|
||||
from sglang.multimodal_gen.test.server.test_server_common import ( # noqa: F401
|
||||
DiffusionServerBase,
|
||||
diffusion_server,
|
||||
)
|
||||
|
||||
|
||||
class TestDiffusionServerTwoGpu(DiffusionServerBase):
|
||||
"""Performance tests for 2-GPU diffusion cases."""
|
||||
|
||||
case = diffusion_case_fixture(TWO_GPU_CASES)
|
||||
@@ -0,0 +1,20 @@
|
||||
"""
|
||||
Config-driven diffusion performance test with pytest parametrization.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from sglang.multimodal_gen.test.server.common.case_fixtures import (
|
||||
diffusion_case_fixture,
|
||||
)
|
||||
from sglang.multimodal_gen.test.server.gpu_cases import ONE_GPU_B200_CASES
|
||||
from sglang.multimodal_gen.test.server.test_server_common import ( # noqa: F401
|
||||
DiffusionServerBase,
|
||||
diffusion_server,
|
||||
)
|
||||
|
||||
|
||||
class TestDiffusionServerOneGpuB200(DiffusionServerBase):
|
||||
"""B200-targeted CI tests for 1-GPU Blackwell-only diffusion cases."""
|
||||
|
||||
case = diffusion_case_fixture(ONE_GPU_B200_CASES)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,790 @@
|
||||
"""
|
||||
Configuration and data structures for diffusion performance tests.
|
||||
|
||||
Usage:
|
||||
|
||||
pytest python/sglang/multimodal_gen/test/server/test_server_1_gpu.py
|
||||
# for a single testcase, look for the name of the testcase in ONE_GPU_CASES,
|
||||
# ONE_GPU_MODELOPT_FP8_CASES, ONE_GPU_B200_CASES, or TWO_GPU_CASES
|
||||
pytest python/sglang/multimodal_gen/test/server/test_server_1_gpu.py -k qwen_image_t2i
|
||||
|
||||
|
||||
To add a new testcase:
|
||||
1. add your testcase with case-id: `my_new_test_case_id` to `ONE_GPU_CASES`, `ONE_GPU_MODELOPT_FP8_CASES`, `ONE_GPU_B200_CASES`, or `TWO_GPU_CASES`
|
||||
2. run `SGLANG_GEN_BASELINE=1 pytest -s python/sglang/multimodal_gen/test/server/ -k my_new_test_case_id`
|
||||
3. insert or override the corresponding scenario in the platform JSON under `perf_baselines/`
|
||||
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import shlex
|
||||
import statistics
|
||||
from dataclasses import dataclass, field, replace
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from typing import Any, Sequence
|
||||
|
||||
from sglang.multimodal_gen.configs.pipeline_configs.base import ModelTaskType
|
||||
from sglang.multimodal_gen.registry import (
|
||||
get_model_info,
|
||||
get_pipeline_config_classes,
|
||||
)
|
||||
from sglang.multimodal_gen.runtime.platforms import current_platform
|
||||
from sglang.multimodal_gen.runtime.utils.perf_logger import RequestPerfRecord
|
||||
|
||||
|
||||
@dataclass
|
||||
class ToleranceConfig:
|
||||
"""Tolerance ratios for performance validation."""
|
||||
|
||||
e2e: float
|
||||
denoise_stage: float
|
||||
non_denoise_stage: float
|
||||
denoise_step: float
|
||||
denoise_agg: float
|
||||
|
||||
@classmethod
|
||||
def load_profile(cls, all_tolerances: dict, profile_name: str) -> ToleranceConfig:
|
||||
"""Load a specific tolerance profile from a dictionary of profiles."""
|
||||
# Support both flat structure (backward compatibility) and profiled structure
|
||||
if "e2e" in all_tolerances and not isinstance(all_tolerances["e2e"], dict):
|
||||
tol_data = all_tolerances
|
||||
actual_profile = "legacy/flat"
|
||||
else:
|
||||
tol_data = all_tolerances.get(
|
||||
profile_name, all_tolerances.get("pr_test", {})
|
||||
)
|
||||
actual_profile = (
|
||||
profile_name if profile_name in all_tolerances else "pr_test"
|
||||
)
|
||||
|
||||
if not tol_data:
|
||||
raise ValueError(
|
||||
f"No tolerance profile found for '{profile_name}' and no default 'pr_test' profile exists."
|
||||
)
|
||||
|
||||
print(f"--- Performance Tolerance Profile: {actual_profile} ---")
|
||||
|
||||
return cls(
|
||||
e2e=float(os.getenv("SGLANG_E2E_TOLERANCE", tol_data["e2e"])),
|
||||
denoise_stage=float(
|
||||
os.getenv("SGLANG_STAGE_TIME_TOLERANCE", tol_data["denoise_stage"])
|
||||
),
|
||||
non_denoise_stage=float(
|
||||
os.getenv(
|
||||
"SGLANG_NON_DENOISE_STAGE_TIME_TOLERANCE",
|
||||
tol_data["non_denoise_stage"],
|
||||
)
|
||||
),
|
||||
denoise_step=float(
|
||||
os.getenv("SGLANG_DENOISE_STEP_TOLERANCE", tol_data["denoise_step"])
|
||||
),
|
||||
denoise_agg=float(
|
||||
os.getenv("SGLANG_DENOISE_AGG_TOLERANCE", tol_data["denoise_agg"])
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class ScenarioConfig:
|
||||
"""Expected performance metrics for a test scenario."""
|
||||
|
||||
stages_ms: dict[str, float]
|
||||
denoise_step_ms: dict[int, float]
|
||||
expected_e2e_ms: float
|
||||
expected_avg_denoise_ms: float
|
||||
expected_median_denoise_ms: float
|
||||
estimated_full_test_time_s: float | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class BaselineConfig:
|
||||
"""Full baseline configuration."""
|
||||
|
||||
scenarios: dict[str, ScenarioConfig]
|
||||
step_fractions: Sequence[float]
|
||||
tolerances: ToleranceConfig
|
||||
improvement_threshold: float
|
||||
|
||||
@classmethod
|
||||
def load(cls, path: Path) -> BaselineConfig:
|
||||
"""Load baseline configuration from JSON file."""
|
||||
with path.open("r", encoding="utf-8") as fh:
|
||||
data = json.load(fh)
|
||||
|
||||
# Get tolerance profile, defaulting to 'pr_test'
|
||||
profile_name = "pr_test"
|
||||
tolerances = ToleranceConfig.load_profile(
|
||||
data.get("tolerances", {}), profile_name
|
||||
)
|
||||
|
||||
scenarios = {}
|
||||
for name, cfg in data["scenarios"].items():
|
||||
scenarios[name] = ScenarioConfig(
|
||||
stages_ms=cfg["stages_ms"],
|
||||
denoise_step_ms={int(k): v for k, v in cfg["denoise_step_ms"].items()},
|
||||
expected_e2e_ms=float(cfg["expected_e2e_ms"]),
|
||||
expected_avg_denoise_ms=float(cfg["expected_avg_denoise_ms"]),
|
||||
expected_median_denoise_ms=float(cfg["expected_median_denoise_ms"]),
|
||||
estimated_full_test_time_s=cfg.get("estimated_full_test_time_s"),
|
||||
)
|
||||
|
||||
return cls(
|
||||
scenarios=scenarios,
|
||||
step_fractions=tuple(data["sampling"]["step_fractions"]),
|
||||
tolerances=tolerances,
|
||||
improvement_threshold=data.get("improvement_reporting", {}).get(
|
||||
"threshold", 0.2
|
||||
),
|
||||
)
|
||||
|
||||
def update(self, path: Path):
|
||||
"""Load baseline configuration from JSON file."""
|
||||
with path.open("r", encoding="utf-8") as fh:
|
||||
data = json.load(fh)
|
||||
|
||||
scenarios_new = {}
|
||||
for name, cfg in data["scenarios"].items():
|
||||
scenarios_new[name] = ScenarioConfig(
|
||||
stages_ms=cfg["stages_ms"],
|
||||
denoise_step_ms={int(k): v for k, v in cfg["denoise_step_ms"].items()},
|
||||
expected_e2e_ms=float(cfg["expected_e2e_ms"]),
|
||||
expected_avg_denoise_ms=float(cfg["expected_avg_denoise_ms"]),
|
||||
expected_median_denoise_ms=float(cfg["expected_median_denoise_ms"]),
|
||||
estimated_full_test_time_s=cfg.get("estimated_full_test_time_s"),
|
||||
)
|
||||
|
||||
self.scenarios.update(scenarios_new)
|
||||
return self
|
||||
|
||||
|
||||
@dataclass
|
||||
class DiffusionServerArgs:
|
||||
"""Configuration for a single model/scenario test case."""
|
||||
|
||||
model_path: str # HF repo or local path
|
||||
modality: str | None = None # auto-inferred: "image", "video", "3d", or "action"
|
||||
|
||||
custom_validator: str | None = None # auto-derived unless explicitly overridden
|
||||
# resources
|
||||
num_gpus: int = 1
|
||||
tp_size: int | None = None
|
||||
ulysses_degree: int | None = None
|
||||
ring_degree: int | None = None
|
||||
cfg_parallel: bool | None = None
|
||||
# LoRA
|
||||
lora_path: str | None = (
|
||||
None # LoRA adapter path (HF repo or local path, loaded at startup)
|
||||
)
|
||||
dynamic_lora_path: str | None = (
|
||||
None # LoRA path for dynamic loading test (loaded via set_lora after startup)
|
||||
)
|
||||
second_lora_path: str | None = (
|
||||
None # Second LoRA adapter path for multi-LoRA testing
|
||||
)
|
||||
|
||||
dit_layerwise_offload: bool = False
|
||||
dit_offload_prefetch_size: int | float | None = None
|
||||
enable_cache_dit: bool = False
|
||||
text_encoder_cpu_offload: bool = False
|
||||
|
||||
extras: list[str] = field(default_factory=lambda: [])
|
||||
env_vars: dict[str, str] = field(default_factory=dict)
|
||||
|
||||
def __post_init__(self):
|
||||
if self.modality is None:
|
||||
self.modality = _infer_modality_from_model_path(self.model_path)
|
||||
|
||||
if self.custom_validator is not None:
|
||||
return
|
||||
|
||||
if self.modality == "image":
|
||||
self.custom_validator = "image"
|
||||
elif self.modality == "video":
|
||||
self.custom_validator = "video"
|
||||
elif self.modality == "3d":
|
||||
self.custom_validator = "mesh"
|
||||
elif self.modality == "action":
|
||||
self.custom_validator = "action"
|
||||
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def _infer_modality_from_model_path(model_path: str) -> str:
|
||||
model_info = get_model_info(model_path)
|
||||
if model_info is None:
|
||||
raise ValueError(f"Could not resolve model info for {model_path!r}")
|
||||
|
||||
task_type = model_info.pipeline_config_cls.task_type
|
||||
if task_type == ModelTaskType.I2M:
|
||||
return "3d"
|
||||
if task_type.is_action_gen():
|
||||
return "action"
|
||||
if task_type.is_image_gen():
|
||||
return "image"
|
||||
return "video"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DiffusionSamplingParams:
|
||||
"""Configuration for a single model/scenario test case."""
|
||||
|
||||
output_size: str = ""
|
||||
|
||||
# inputs and conditioning
|
||||
prompt: str | None = None # text prompt for generation
|
||||
image_path: Path | str | None = None # input image/video for editing (Path or URL)
|
||||
|
||||
# duration
|
||||
seconds: int = 1 # for video: duration in seconds
|
||||
num_frames: int | None = None # for video: number of frames
|
||||
fps: int | None = None # for video: frames per second
|
||||
|
||||
# URL direct test flag - if True, don't pre-download URL images
|
||||
direct_url_test: bool = False
|
||||
|
||||
# output format
|
||||
output_format: str | None = None # "png", "jpeg", "mp4", etc.
|
||||
|
||||
num_outputs_per_prompt: int = 1
|
||||
|
||||
# Realtime video consistency harness. When set, server tests use
|
||||
# /v1/realtime_video/generate and fold streamed chunks back into mp4 bytes.
|
||||
realtime_num_chunks: int | None = None
|
||||
realtime_events: list[dict[str, Any]] = field(default_factory=list)
|
||||
realtime_perf_thresholds: dict[str, float] = field(default_factory=dict)
|
||||
realtime_perf_ignore_initial_chunks: int = 0
|
||||
# None keeps the lossless/raw transport used by GT-backed consistency checks.
|
||||
realtime_output_format: str | None = None
|
||||
|
||||
# Additional request-level parameters (e.g. enable_teacache, enable_upscaling, …)
|
||||
# merged directly into the OpenAI extra_body dict.
|
||||
extras: dict = field(default_factory=dict)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DiffusionTestCase:
|
||||
"""Configuration for a single model/scenario test case."""
|
||||
|
||||
id: str # pytest test id and scenario name
|
||||
server_args: DiffusionServerArgs
|
||||
sampling_params: DiffusionSamplingParams | None = None
|
||||
run_perf_check: bool = True
|
||||
run_consistency_check: bool = True
|
||||
run_component_accuracy_check: bool = True
|
||||
run_models_api_check: bool = True
|
||||
run_t2v_input_reference_check: bool = True
|
||||
run_lora_basic_api_check: bool = False
|
||||
run_lora_dynamic_load_check: bool = False
|
||||
run_lora_dynamic_switch_check: bool = False
|
||||
run_multi_lora_api_check: bool = False
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.sampling_params is None:
|
||||
object.__setattr__(
|
||||
self,
|
||||
"sampling_params",
|
||||
get_default_sampling_params_for_server_args(self.server_args),
|
||||
)
|
||||
|
||||
has_startup_lora = self.server_args.lora_path is not None
|
||||
has_dynamic_lora = self.server_args.dynamic_lora_path is not None
|
||||
has_second_lora = self.server_args.second_lora_path is not None
|
||||
|
||||
if self.run_lora_basic_api_check and not (has_startup_lora or has_dynamic_lora):
|
||||
raise ValueError(
|
||||
f"{self.id}: run_lora_basic_api_check requires lora_path or dynamic_lora_path"
|
||||
)
|
||||
|
||||
if self.run_lora_dynamic_load_check and not has_dynamic_lora:
|
||||
raise ValueError(
|
||||
f"{self.id}: run_lora_dynamic_load_check requires dynamic_lora_path"
|
||||
)
|
||||
|
||||
if self.run_lora_dynamic_switch_check and not has_second_lora:
|
||||
raise ValueError(
|
||||
f"{self.id}: run_lora_dynamic_switch_check requires second_lora_path"
|
||||
)
|
||||
|
||||
if self.run_multi_lora_api_check and not (has_startup_lora and has_second_lora):
|
||||
raise ValueError(
|
||||
f"{self.id}: run_multi_lora_api_check requires lora_path and second_lora_path"
|
||||
)
|
||||
|
||||
|
||||
LINGBOT_WORLD_REALTIME_sampling_params = DiffusionSamplingParams(
|
||||
prompt=(
|
||||
"A slow aerial orbit around a pastel floating island hotel in the open "
|
||||
"ocean, hazy sunlight, turquoise water, toy-like architectural detail, "
|
||||
"clean horizon, cinematic but playful."
|
||||
),
|
||||
image_path=(
|
||||
"https://is1-ssl.mzstatic.com/image/thumb/Music/v4/b8/f9/b9/"
|
||||
"b8f9b9f8-a609-bde2-0302-349436ffc508/825646291038.jpg/600x600bb.jpg"
|
||||
),
|
||||
output_size="832x480",
|
||||
num_frames=9,
|
||||
fps=16,
|
||||
realtime_num_chunks=4,
|
||||
realtime_perf_thresholds={
|
||||
"p95_chunk_total_ms": 5000.0,
|
||||
"p95_scheduler_forward_ms": 4500.0,
|
||||
"p95_ws_payload_mb": 16.0,
|
||||
},
|
||||
realtime_perf_ignore_initial_chunks=2,
|
||||
extras={
|
||||
"seed": 42,
|
||||
"num_inference_steps": 4,
|
||||
"guidance_scale": 1.0,
|
||||
"realtime_causal_sink_size": 9,
|
||||
"realtime_causal_kv_cache_num_frames": 18,
|
||||
"condition_inputs": {
|
||||
"camera_actions": [
|
||||
["w"],
|
||||
["w"],
|
||||
["w"],
|
||||
["w"],
|
||||
["w"],
|
||||
["w"],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
]
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
PI05_ACTION_CI_sampling_params = DiffusionSamplingParams(
|
||||
prompt="pick up the blue block",
|
||||
extras={
|
||||
"action_horizon": 50,
|
||||
"action_dim": 32,
|
||||
"state_dim": 32,
|
||||
"image_size": 64,
|
||||
"num_inference_steps": 2,
|
||||
"seed": 0,
|
||||
"enable_prefix_cache": False,
|
||||
"enable_cuda_graph": True,
|
||||
"action_max_abs_diff_threshold": 0.05,
|
||||
"action_mean_abs_diff_threshold": 0.005,
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
def sample_step_indices(
|
||||
step_map: dict[int, float], fractions: Sequence[float]
|
||||
) -> list[int]:
|
||||
if not step_map:
|
||||
return []
|
||||
max_idx = max(step_map.keys())
|
||||
indices = set()
|
||||
for fraction in fractions:
|
||||
idx = min(max_idx, max(0, int(round(fraction * max_idx))))
|
||||
if idx in step_map:
|
||||
indices.add(idx)
|
||||
return sorted(indices)
|
||||
|
||||
|
||||
@dataclass
|
||||
class PerformanceSummary:
|
||||
"""Summary of performance of a request, built from RequestPerfRecord"""
|
||||
|
||||
e2e_ms: float
|
||||
avg_denoise_ms: float
|
||||
median_denoise_ms: float
|
||||
# { "stage_1": time_1, "stage_2": time_2 }
|
||||
stage_metrics: dict[str, float]
|
||||
step_metrics: list[float]
|
||||
sampled_steps: dict[int, float]
|
||||
all_denoise_steps: dict[int, float]
|
||||
frames_per_second: float | None = None
|
||||
total_frames: int | None = None
|
||||
avg_frame_time_ms: float | None = None
|
||||
|
||||
@staticmethod
|
||||
def from_req_perf_record(
|
||||
record: RequestPerfRecord, step_fractions: Sequence[float]
|
||||
):
|
||||
"""Collect all performance metrics into a summary without validation."""
|
||||
e2e_ms = record.total_duration_ms
|
||||
|
||||
step_durations = record.steps
|
||||
avg_denoise = 0.0
|
||||
median_denoise = 0.0
|
||||
if step_durations:
|
||||
avg_denoise = sum(step_durations) / len(step_durations)
|
||||
median_denoise = statistics.median(step_durations)
|
||||
|
||||
per_step = {index: s for index, s in enumerate(step_durations)}
|
||||
sample_indices = sample_step_indices(per_step, step_fractions)
|
||||
sampled_steps = {idx: per_step[idx] for idx in sample_indices}
|
||||
|
||||
# convert from list to dict
|
||||
stage_metrics = {}
|
||||
for item in record.stages:
|
||||
if isinstance(item, dict) and "name" in item:
|
||||
val = item.get("execution_time_ms", 0.0)
|
||||
stage_metrics[item["name"]] = val
|
||||
|
||||
return PerformanceSummary(
|
||||
e2e_ms=e2e_ms,
|
||||
avg_denoise_ms=avg_denoise,
|
||||
median_denoise_ms=median_denoise,
|
||||
stage_metrics=stage_metrics,
|
||||
step_metrics=step_durations,
|
||||
sampled_steps=sampled_steps,
|
||||
all_denoise_steps=per_step,
|
||||
)
|
||||
|
||||
|
||||
T2I_sampling_params = DiffusionSamplingParams(
|
||||
prompt="Doraemon is eating dorayaki",
|
||||
output_size="1024x1024",
|
||||
)
|
||||
|
||||
IDEOGRAM4_CI_TEXT_PROMPT = "A cat sitting on a bench"
|
||||
|
||||
IDEOGRAM4_CI_PROMPT = json.dumps(
|
||||
{
|
||||
"high_level_description": IDEOGRAM4_CI_TEXT_PROMPT,
|
||||
"style_description": {
|
||||
"aesthetics": "warm, peaceful, vibrant",
|
||||
"lighting": "bright afternoon sunlight, long soft shadows",
|
||||
"photo": "shallow depth of field, eye-level, 85mm lens",
|
||||
"medium": "photograph",
|
||||
"color_palette": [
|
||||
"#F5C542",
|
||||
"#87CEEB",
|
||||
"#4A4A4A",
|
||||
"#FFFFFF",
|
||||
"#2E8B57",
|
||||
],
|
||||
},
|
||||
"compositional_deconstruction": {
|
||||
"background": (
|
||||
"A sunlit garden path with green hedges and a wooden bench. "
|
||||
"Dappled light filters through overhead trees."
|
||||
),
|
||||
"elements": [
|
||||
{
|
||||
"type": "obj",
|
||||
"bbox": [260, 260, 760, 780],
|
||||
"desc": (
|
||||
"A small tabby cat sitting calmly on a wooden bench, "
|
||||
"looking toward the camera."
|
||||
),
|
||||
},
|
||||
{
|
||||
"type": "obj",
|
||||
"bbox": [180, 580, 840, 840],
|
||||
"desc": (
|
||||
"A weathered wooden garden bench with soft sunlight "
|
||||
"falling across the seat."
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
separators=(",", ":"),
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
COSMOS3_NANO_CI_sampling_params = DiffusionSamplingParams(
|
||||
prompt="A red cube on a white table, product photo.",
|
||||
output_size="832x480",
|
||||
output_format="png",
|
||||
extras={
|
||||
"num_inference_steps": 35,
|
||||
"seed": 0,
|
||||
"max_sequence_length": 128,
|
||||
"extra_args": {
|
||||
"guardrails": False,
|
||||
"use_resolution_template": False,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
IDEOGRAM4_CI_sampling_params = replace(
|
||||
T2I_sampling_params,
|
||||
prompt=IDEOGRAM4_CI_PROMPT,
|
||||
output_size="1024x1024",
|
||||
output_format="png",
|
||||
extras={"preset": "V4_QUALITY_48", "seed": 0},
|
||||
)
|
||||
|
||||
MODELOPT_T2I_CI_sampling_params = DiffusionSamplingParams(
|
||||
prompt="Doraemon is eating dorayaki",
|
||||
output_size="768x768",
|
||||
extras={"num_inference_steps": 12, "seed": 0},
|
||||
)
|
||||
|
||||
MODELOPT_QWEN_IMAGE_2512_NVFP4_CI_sampling_params = replace(
|
||||
MODELOPT_T2I_CI_sampling_params,
|
||||
extras={"num_inference_steps": 50, "seed": 0},
|
||||
)
|
||||
|
||||
MODELOPT_TI2I_CI_sampling_params = DiffusionSamplingParams(
|
||||
prompt="Convert 2D style to 3D style",
|
||||
image_path="https://github.com/lm-sys/lm-sys.github.io/releases/download/test/TI2I_Qwen_Image_Edit_Input.jpg",
|
||||
output_size="512x512",
|
||||
extras={"num_inference_steps": 8, "seed": 0},
|
||||
)
|
||||
|
||||
TI2I_sampling_params = DiffusionSamplingParams(
|
||||
prompt="Convert 2D style to 3D style",
|
||||
image_path="https://github.com/lm-sys/lm-sys.github.io/releases/download/test/TI2I_Qwen_Image_Edit_Input.jpg",
|
||||
)
|
||||
|
||||
MULTI_IMAGE_TI2I_sampling_params = DiffusionSamplingParams(
|
||||
prompt="The magician bear is on the left, the alchemist bear is on the right, facing each other in the central park square.",
|
||||
image_path=[
|
||||
"https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen-Image/edit2509/edit2509_1.jpg",
|
||||
"https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen-Image/edit2509/edit2509_2.jpg",
|
||||
],
|
||||
direct_url_test=True,
|
||||
)
|
||||
MULTI_IMAGE_TI2I_UPLOAD_sampling_params = DiffusionSamplingParams(
|
||||
prompt="The magician bear is on the left, the alchemist bear is on the right, facing each other in the central park square.",
|
||||
image_path=[
|
||||
"https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen-Image/edit2509/edit2509_1.jpg",
|
||||
"https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen-Image/edit2509/edit2509_2.jpg",
|
||||
],
|
||||
)
|
||||
MULTI_FRAME_I2I_sampling_params = DiffusionSamplingParams(
|
||||
prompt="a high quality, cute halloween themed illustration, consistent style and lighting",
|
||||
image_path=[
|
||||
"https://raw.githubusercontent.com/QwenLM/Qwen-Image-Layered/main/assets/test_images/4.png"
|
||||
],
|
||||
num_frames=4,
|
||||
direct_url_test=True,
|
||||
output_format="png",
|
||||
)
|
||||
|
||||
T2V_PROMPT = "A curious raccoon"
|
||||
|
||||
T2V_sampling_params = DiffusionSamplingParams(
|
||||
prompt=T2V_PROMPT,
|
||||
)
|
||||
|
||||
JOY_ECHO_T2V_CI_sampling_params = DiffusionSamplingParams(
|
||||
prompt=T2V_PROMPT,
|
||||
output_size="640x384",
|
||||
num_frames=33,
|
||||
extras={
|
||||
"num_inference_steps": 8,
|
||||
"seed": 42,
|
||||
"enable_memory_bank": False,
|
||||
},
|
||||
)
|
||||
|
||||
MODELOPT_T2V_CI_sampling_params = DiffusionSamplingParams(
|
||||
prompt=T2V_PROMPT,
|
||||
output_size="640x384",
|
||||
seconds=5,
|
||||
num_frames=17,
|
||||
extras={"num_inference_steps": 12, "seed": 0},
|
||||
)
|
||||
|
||||
TI2V_sampling_params = DiffusionSamplingParams(
|
||||
prompt="The man in the picture slowly turns his head, his expression enigmatic and otherworldly. The camera performs a slow, cinematic dolly out, focusing on his face. Moody lighting, neon signs glowing in the background, shallow depth of field.",
|
||||
image_path="https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/5f/fa/56/5ffa56c2-ea1f-7a17-6bad-192ff9b6476d/825646124206.jpg/600x600bb.jpg",
|
||||
direct_url_test=True,
|
||||
)
|
||||
|
||||
SANA_WM_TI2V_CI_sampling_params = DiffusionSamplingParams(
|
||||
prompt=TI2V_sampling_params.prompt,
|
||||
image_path=TI2V_sampling_params.image_path,
|
||||
direct_url_test=True,
|
||||
output_size="384x640",
|
||||
num_frames=17,
|
||||
extras={"num_inference_steps": 12, "seed": 0, "guidance_scale": 4.5},
|
||||
)
|
||||
|
||||
TURBOWAN_I2V_sampling_params = DiffusionSamplingParams(
|
||||
prompt="The man in the picture slowly turns his head, his expression enigmatic and otherworldly. The camera performs a slow, cinematic dolly out, focusing on his face. Moody lighting, neon signs glowing in the background, shallow depth of field.",
|
||||
image_path="https://is1-ssl.mzstatic.com/image/thumb/Music114/v4/5f/fa/56/5ffa56c2-ea1f-7a17-6bad-192ff9b6476d/825646124206.jpg/600x600bb.jpg",
|
||||
direct_url_test=True,
|
||||
output_size="960x960",
|
||||
num_frames=4,
|
||||
fps=4,
|
||||
)
|
||||
|
||||
HUNYUAN3D_SHAPE_sampling_params = DiffusionSamplingParams(
|
||||
prompt="",
|
||||
image_path="https://raw.githubusercontent.com/sgl-project/sgl-test-files/main/diffusion-ci/consistency_gt/1-gpu/hunyuan3d_2_0/hunyuan3d.png",
|
||||
)
|
||||
|
||||
|
||||
def _get_extra_arg_value(extras: Sequence[str], option_name: str) -> str | None:
|
||||
tokens: list[str] = []
|
||||
for item in extras:
|
||||
tokens.extend(shlex.split(item))
|
||||
|
||||
option_prefix = f"{option_name}="
|
||||
for index, token in enumerate(tokens):
|
||||
if token.startswith(option_prefix):
|
||||
return token[len(option_prefix) :]
|
||||
if token == option_name and index + 1 < len(tokens):
|
||||
return tokens[index + 1]
|
||||
return None
|
||||
|
||||
|
||||
def get_model_task_type_for_server_args(
|
||||
server_args: DiffusionServerArgs,
|
||||
) -> ModelTaskType:
|
||||
pipeline_class_name = _get_extra_arg_value(
|
||||
server_args.extras, "--pipeline-class-name"
|
||||
)
|
||||
if pipeline_class_name:
|
||||
config_classes = get_pipeline_config_classes(pipeline_class_name)
|
||||
if config_classes is not None:
|
||||
pipeline_config_cls, _ = config_classes
|
||||
return pipeline_config_cls.task_type
|
||||
|
||||
model_info = get_model_info(server_args.model_path)
|
||||
if model_info is None:
|
||||
raise ValueError(f"Could not resolve model info for {server_args.model_path!r}")
|
||||
return model_info.pipeline_config_cls.task_type
|
||||
|
||||
|
||||
def get_default_sampling_params_for_model_task(
|
||||
task_type: ModelTaskType,
|
||||
) -> DiffusionSamplingParams:
|
||||
if task_type == ModelTaskType.T2I:
|
||||
return T2I_sampling_params
|
||||
if task_type in (ModelTaskType.I2I, ModelTaskType.TI2I):
|
||||
return TI2I_sampling_params
|
||||
if task_type == ModelTaskType.T2V:
|
||||
return T2V_sampling_params
|
||||
if task_type in (ModelTaskType.I2V, ModelTaskType.TI2V):
|
||||
return TI2V_sampling_params
|
||||
if task_type == ModelTaskType.I2M:
|
||||
return HUNYUAN3D_SHAPE_sampling_params
|
||||
if task_type.is_action_gen():
|
||||
return PI05_ACTION_CI_sampling_params
|
||||
raise ValueError(f"No default sampling params for model task {task_type!r}")
|
||||
|
||||
|
||||
def get_default_sampling_params_for_server_args(
|
||||
server_args: DiffusionServerArgs,
|
||||
) -> DiffusionSamplingParams:
|
||||
task_type = get_model_task_type_for_server_args(server_args)
|
||||
return get_default_sampling_params_for_model_task(task_type)
|
||||
|
||||
|
||||
MODELOPT_FLUX1_FP8_TRANSFORMER = "lmsys/flux1-dev-modelopt-fp8-sglang-transformer"
|
||||
MODELOPT_FLUX2_FP8_TRANSFORMER = "lmsys/flux2-dev-modelopt-fp8-sglang-transformer"
|
||||
MODELOPT_WAN22_FP8_MODEL = "nvidia/Wan2.2-T2V-A14B-Diffusers-FP8"
|
||||
MODELOPT_HUNYUANVIDEO_FP8_TRANSFORMER = (
|
||||
"lmsys/hunyuanvideo-modelopt-fp8-sglang-transformer"
|
||||
)
|
||||
MODELOPT_QWEN_IMAGE_FP8_TRANSFORMER = "lmsys/qwen-image-modelopt-fp8-sglang-transformer"
|
||||
MODELOPT_QWEN_IMAGE_EDIT_FP8_TRANSFORMER = (
|
||||
"lmsys/qwen-image-edit-modelopt-fp8-sglang-transformer"
|
||||
)
|
||||
MODELOPT_FLUX1_NVFP4_TRANSFORMER = "lmsys/flux1-dev-modelopt-nvfp4-sglang-transformer"
|
||||
MODELOPT_FLUX2_NVFP4_WEIGHTS = "black-forest-labs/FLUX.2-dev-NVFP4"
|
||||
MODELOPT_QWEN_IMAGE_2512_NVFP4_MODEL = "lmsys/qwen-image-2512-modelopt-nvfp4-sglang"
|
||||
MODELOPT_WAN22_NVFP4_MODEL = "nvidia/Wan2.2-T2V-A14B-Diffusers-NVFP4"
|
||||
MODELOPT_NVFP4_B200_ENV_VARS = {}
|
||||
MODELOPT_WAN22_NVFP4_B200_ENV_VARS = {}
|
||||
|
||||
PERF_BASELINE_PLATFORM_ENV = "SGLANG_DIFFUSION_PERF_BASELINE_PLATFORM"
|
||||
PERF_BASELINE_DIR = Path(__file__).with_name("perf_baselines")
|
||||
PERF_BASELINE_FILE_BY_PLATFORM = {
|
||||
"h100": "h100.json",
|
||||
"b200": "b200.json",
|
||||
"5090": "5090.json",
|
||||
}
|
||||
PERF_BASELINE_PLATFORM_ALIASES = {
|
||||
"sm90": "h100",
|
||||
"hopper": "h100",
|
||||
"h100": "h100",
|
||||
"sm100": "b200",
|
||||
"blackwell": "b200",
|
||||
"b200": "b200",
|
||||
"sm120": "5090",
|
||||
"rtx5090": "5090",
|
||||
"5090": "5090",
|
||||
}
|
||||
|
||||
|
||||
def _normalize_perf_baseline_platform(platform: str) -> str:
|
||||
normalized = platform.strip().lower().replace("_", "-")
|
||||
normalized = normalized.replace("-", "")
|
||||
if normalized not in PERF_BASELINE_PLATFORM_ALIASES:
|
||||
valid = ", ".join(sorted(PERF_BASELINE_FILE_BY_PLATFORM))
|
||||
raise ValueError(
|
||||
f"Invalid diffusion perf baseline platform {platform!r}. "
|
||||
f"Expected one of: {valid}"
|
||||
)
|
||||
return PERF_BASELINE_PLATFORM_ALIASES[normalized]
|
||||
|
||||
|
||||
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_sm120():
|
||||
return "5090"
|
||||
if current_platform.is_blackwell():
|
||||
return "b200"
|
||||
return "h100"
|
||||
|
||||
|
||||
def get_perf_baseline_path(platform: str | None = None) -> Path:
|
||||
baseline_platform = (
|
||||
_normalize_perf_baseline_platform(platform)
|
||||
if platform is not None
|
||||
else get_perf_baseline_platform()
|
||||
)
|
||||
return PERF_BASELINE_DIR / PERF_BASELINE_FILE_BY_PLATFORM[baseline_platform]
|
||||
|
||||
|
||||
def _make_modelopt_ci_case(
|
||||
case_id: str,
|
||||
*,
|
||||
model_path: str,
|
||||
modality: str,
|
||||
sampling_params: DiffusionSamplingParams,
|
||||
extras: list[str],
|
||||
env_vars: dict[str, str] | None = None,
|
||||
run_consistency_check: bool = False,
|
||||
) -> DiffusionTestCase:
|
||||
return DiffusionTestCase(
|
||||
case_id,
|
||||
DiffusionServerArgs(
|
||||
model_path=model_path,
|
||||
modality=modality,
|
||||
extras=extras,
|
||||
env_vars=env_vars or {},
|
||||
),
|
||||
sampling_params,
|
||||
run_perf_check=False,
|
||||
run_consistency_check=run_consistency_check,
|
||||
run_component_accuracy_check=False,
|
||||
)
|
||||
|
||||
|
||||
def _with_default_num_gpus(
|
||||
cases: list[DiffusionTestCase], num_gpus: int
|
||||
) -> list[DiffusionTestCase]:
|
||||
return [
|
||||
replace(case, server_args=replace(case.server_args, num_gpus=num_gpus))
|
||||
for case in cases
|
||||
]
|
||||
|
||||
|
||||
# Load global configuration
|
||||
BASELINE_CONFIG = (
|
||||
BaselineConfig.load(get_perf_baseline_path())
|
||||
.update(Path(__file__).parent / "ascend" / "perf_baselines_npu.json")
|
||||
.update(Path(__file__).parent / "musa" / "perf_baselines_musa.json")
|
||||
)
|
||||
Reference in New Issue
Block a user