[Kernel] Route large SM90 row/column-scaled FP8 GEMMs to Torch - #34318
Conversation
|
@mickqian could you take a look pls and help me understand who to ask for review since the change is probably affecting many architectures, not only h3 |
|
@BBuf would appreciate you taking a look too) thx |
6c5086d to
8fa5eb9
Compare
|
/tag-and-rerun-ci |
|
unfortunately, the multimodal_gen tests are not triggered |
|
@mickqian should I run them myself? I have H200 and H100 nodes |
|
| Category | Failures/errors at PR head | Reproduced at merge base | Contention artifacts |
|---|---|---|---|
| 1-GPU server cases | 15 | 13 | 2 |
| 2-GPU server-model cases | 17 | 17 | 0 |
| Standalone 2-GPU pytest nodes | 4 | 4 | 0 |
| Component-accuracy cases | 5 | 5 | 0 |
| Unit tests | 1 | 1 | 0 |
| Total | 42 | 40 | 2 |
Additional clean suites:
4-gpu-h100: 1 passedbcg-diffusion: 2 passedkernel-namespace: 59 passed- Unit suite overall: 1865 passed, 8 skipped, 173 subtests passed, 1 pre-existing failure
Investigation of the two non-reproducing timing failures
Both cases produced correct outputs and passed their numerical/consistency checks. Only wall-clock performance guards failed while multiple GPU and component partitions were packed onto the same host.
wan2_1_t2v_1.3b_frame_interp_2x_upscaling_4x
The original packed run failed only this timing check:
denoise step 0: 699.5128 ms > allowed 550.05 ms
Observed step-zero times in controlled retries:
- Isolated PR-head retry: 504.37 ms — passed
- Ordered Cosmos → Wan retry: 466.03 ms — passed
- Merge-base warm-cache retry: 112.98 ms — passed
All consistency thresholds passed in the original run. The failure occurred while five 1-GPU partitions plus component-accuracy work were active concurrently. The ordered predecessor retry also passed, ruling out a persistent Cosmos-to-Wan process-state leak.
This is consistent with cold first-step CUDA/Triton initialization being amplified by shared-host contention. Upstream CI normally gives each 1-gpu-h100 partition its own runner.
flux_2_ti2i_multi_image_cache_dit
The original packed run failed only the input-validation timing guard:
InputValidationStage: 333.0807 ms > allowed 204.29 ms
Controlled retries:
- Isolated PR-head retry: 133.19 ms — passed
- Merge-base retry: 130.16 ms — passed
- Ordered Sana → FLUX retry: 103.15 ms — passed
The stage includes two local uploaded-image opens plus PIL/config preprocessing and is measured with wall-clock time.perf_counter, so CPU scheduling and filesystem contention are included. Four other 1-GPU partitions plus component-accuracy work were active at the original failure time.
The ordered predecessor retry passed, ruling out a persistent Sana-to-FLUX state leak.
Pre-existing merge-base failures
13 reproduced 1-GPU server failures
flux_2_klein_base_image_t2icosmos3_nano_t2vzimage_image_t2i_multi_loraflux_2_image_t2i_upscaling_4xwan2_1_t2v_1.3bfast_hunyuan_videowan2_1_t2v_1.3b_frame_interp_2xhunyuan3d_shape_genturbo_wan2_1_t2v_1.3bflux_2_klein_image_t2iwan2_1_t2v_1_3b_lora_1gpultx_2_3_hq_pipelinewan2_1_t2v_1.3b_upscaling_4x
17 reproduced 2-GPU server-model failures
minimax_h3_t2va_2gpu_h100minimax_h3_ref2va_video_audio_2gpu_h100wan2_2_i2v_a14b_2gpufsdp-inferenceltx_2.3_one_stage_ti2vwan2_2_t2v_a14b_lora_2gpumova_360p_ring1_uly2ltx_2_two_stage_t2vltx_2_3_two_stage_ti2v_2gpuswan2_1_i2v_14b_480P_2gpuqwen_image_t2i_2_gpuszimage_image_t2i_2_gpusflux_image_t2i_2_gpusltx_2.3_two_stage_t2v_2gpuszimage_image_t2i_2_gpus_non_squareflux_2_image_t2i_2_gpusflux2_modelopt_fp8_tp2_t2i
4 reproduced standalone distributed failures/errors
- IPC bitwise all-to-all diverged from the NCCL result and exhausted its retry.
- Three disaggregated-inference tests errored in the denoiser with:
unsupported operand type(s) for *: 'NoneType' and 'int'
5 reproduced component-accuracy failures
- Wan2.1 1.3B transformer, 1 GPU
- Wan2.2 I2V A14B, 2 GPUs
- Wan2.2 T2V A14B, 2 GPUs
- Wan2.1 T2V 14B, 2 GPUs
- Wan2.1 T2V 1.3B CFG-parallel, 2 GPUs
Unit-test failure
The remaining unit failure was:
test_server_args.py::TestOffloadDefaults::
test_auto_ltx_original_replaces_component_cpu_offload
It fails identically at both the PR head and merge base when the NVIDIA device is exposed:
AssertionError: 'resident' != 'original'
The test mocks CUDA availability and an 80 GiB device but does not mock the device name. On a real H200, the production resolver deliberately selects resident, while the test expects the H100-style original result.
Earlier no-GPU isolated retries passed because the platform reported an X86_64 device name, which hid the H200-specific behavior. The matched GPU reruns confirm this is a pre-existing test-isolation issue, not a change introduced by this PR.
A future test fix should mock an H100-like device name for the original expectation and add an explicit H200 case expecting resident.
PR-relevant checks
The H3 T2VA case produced identical head/base metrics:
similarity: 0.9432
SSIM: 0.8971
PSNR: 32.4219
MAD: 2.7732
The FLUX.2 ModelOpt FP8 case also produced the same consistency result and metrics at the PR head and merge base.
Conclusion
No functional, numerical, or reproducible performance regression unique to this PR was found.
Of the 42 failing/error nodes at the PR head:
- 40 reproduced at the merge base under the same GPU environment.
- 2 were performance-only artifacts caused by packing multiple partitions onto one host; both passed in isolated and ordered PR-head retries.
- 0 were PR-head-only functional or numerical failures.
|
@mickqian wdyt? |
|
The routing heuristic here regresses W8A8 FP8 decode on H100: Cause: |
|
Thank you for pointing this out, I will make a followup PR to add gating on M too (will take 20 mins to determine which M is the cutoff) |
|
here is the fix, update the cutoffs to make sure that we only get the big minimax-related shapes while not including anything smaller |
Summary
Follow-up to #33275, which added MiniMax-H3 and its online FP8 transformer path.
The current
sgl_kernel.fp8_scaled_mmis slower than Torch_scaled_mmon the larger H3 dense shapes on SM90. This PR adds both implementations toBaseFusedOpand routes shapes using:(K >= 5376 and N >= 3584) or (K >= 3584 and M >= 8192)The AOT kernel remains the fallback for smaller shapes. The Torch path requires FP8 E4M3FN inputs, BF16 output, FP32 row/column scales, compatible layouts, and no bias.
Kernel results
H100 80 GB, median of 10 measurements after 5 warmups:
The sweep covered all 64 H3 dense shapes across TP1/2/4/8 and four production sequence lengths. Torch won 49 shapes, AOT won 15, and the heuristic selected the measured winner for all 64.
Full MiniMax-H3 result
H100 ×8, TP2/Ulysses4, FP8, FlashAttention, 768×1120 FL2VA request with 49 denoising steps. Medians from three matched runs after two warmups:
The matched outputs were byte-identical. All eight profiler traces confirmed the routed path while retaining AOT for smaller shapes.
Newer GPUs
I only have access to SM90 hardware, so the capability gate is intentionally limited to SM90. Help benchmarking and tuning these shapes on SM100/SM120 would be appreciated. Torch
_scaled_mmmay also win thereCI States
Latest PR Test (Base): ❌ Run #32853520330
Latest PR Test (Extra): ❌ Run #32853520160
Latest PR Test (AMD ROCm 7.2): ❌ Run #32853520280