Skip to content

[BugFix] Fix H100 CuTeDSL full-run edge cases#1

Closed
JayceSu98 wants to merge 4 commits into
mainfrom
jayce/h100-cutedsl-tilekernels-fixes
Closed

[BugFix] Fix H100 CuTeDSL full-run edge cases#1
JayceSu98 wants to merge 4 commits into
mainfrom
jayce/h100-cutedsl-tilekernels-fixes

Conversation

@JayceSu98

Copy link
Copy Markdown
Owner

Context

This PR collects the TileKernels-side fixes needed after running the full H100 CuTeDSL correctness and benchmark coverage with a local TileLang CuTeDSL backend.

The failures were not tied to a single benchmark configuration. They came from broader edge cases that full coverage exposes more reliably:

  • SM90 persistent-block counts that are valid for the supported hardware but are not divisible by four.
  • MoE fused layout paths where kernel loops are rounded up to warp/alignment extents while the logical tensor shape is smaller.
  • Quantization edge tiles where scaling-factor grids or packed E5M6 output rows/columns are smaller than the scheduled tile.
  • BF16/narrow-input per-token quantization paths where the absmax accumulator should be FP32 rather than the input storage dtype.

Changes

Engram

  • Replace the fixed num_batches = 4 assumption in engram_grad_w_reduce_kernel.py with the largest batch count up to four that divides the persistent block count.
  • This keeps the original layout when possible, but allows SM90 GPUs such as H100 PCIe, which exposes 114 SMs, to run the kernel instead of failing an assertion before code generation.

MoE

  • Guard expand_to_fused writes with the real hidden and scaling-factor extents when iterating over aligned loop sizes.
  • Initialize the shared cumsum buffer for all threads in fused mapping.
  • Avoid speculative out-of-range topk_idx loads in the aligned tail of get_fused_mapping.
  • Reserve a rounded-up upper bound for independently aligned expert ranges before trimming with synchronized expert counts.

Quantization

  • Guard cast-back and lossless/per-token scaling-factor loads and stores against the real scaling-factor grid dimensions.
  • Guard packed E5M6 output stores for token and hidden tail tiles.
  • Use FP32 fragments for per-token absmax reductions before computing reciprocal scales, instead of using in_config.dtype as the accumulator dtype.

Test and benchmark tooling

  • Add run_cutedsl_tests.sh for one-command CuTeDSL correctness, benchmark, or combined full runs.
  • Preserve externally provided CUDA_VISIBLE_DEVICES under xdist instead of always overriding it.
  • Add optional per-worker TileLang cache directories and failure/trace report files for long full-suite runs.
  • Add an opt-in missing-baseline override for benchmark sweeps that generate new JSONL data before a baseline exists.
  • Make the benchmark timer backend configurable through TK_BENCHMARK_BACKEND.

Why these are TileKernels fixes

These changes address TileKernels assumptions about launch geometry, tensor bounds, allocation sizing, and reduction accumulator dtype. They are not CuTeDSL-version-specific workarounds:

  • The Engram issue follows from the kernel assuming a persistent block count divisible by four while the project requirements state SM90 support.
  • The MoE and quant changes guard logical tensor bounds when the implementation intentionally uses aligned loop extents.
  • The FP32 absmax change fixes the accumulator dtype used to derive quantization scales, independent of backend code generation details.

Validation

Validated on NVIDIA H100 PCIe with the local TileLang CuTeDSL backend after the corresponding TileLang CuTeDSL fixes:

  • Full correctness coverage: passed after rerunning the large OOM-sensitive cases in a single-worker H100 run.
  • Full benchmark coverage: passed for run-through status with benchmark JSONL emission enabled.
  • Current PR sanity checks:
    • git diff --check HEAD~4..HEAD
    • .venv-tk-test/bin/python -m ruff check ... on changed Python files
    • .venv-tk-test/bin/python -m py_compile ... on changed Python files
    • bash -n run_cutedsl_tests.sh

Commit Structure

  • [BugFix][Engram] Support non-divisible SM90 block counts
  • [BugFix][MoE] Guard fused mapping edge tiles
  • [BugFix][Quant] Guard scale tails and FP32 absmax
  • [Test] Add reusable CuTeDSL full-run controls

JayceSu98 and others added 4 commits June 12, 2026 06:29
The README declares SM90 GPUs as supported, but the Engram grad-w reduce kernel hard-coded four persistent batches and asserted that the persistent block count was divisible by four.

That assumption is not true for all SM90 parts. For example, H100 PCIe exposes 114 SMs, so the CUDA/CuTeDSL full test path can fail before code generation reaches the actual kernel logic.

Choose the largest batch count up to four that divides the persistent block count. This keeps the original four-batch layout when it is valid, while allowing other SM90 block counts to use the same persistent kernel shape without tripping the launch-time assertion.

Co-authored-by: dingsg <shengge.ding@enflame-tech.com>
Full H100/CuTeDSL coverage exercises MoE routing shapes where the generated work loops are rounded up to alignment or warp-size boundaries. The logical tensors remain sized by the real hidden dimension, scaling-factor dimension, and token-topk count.

The expand-to-fused kernel previously iterated over aligned hidden and scaling-factor extents and wrote every lane into the destination tensors. For tail dimensions this can address columns outside the real tensor shape, especially with TMA-aligned column-major scaling-factor layouts.

The fused mapping kernel also used a Select expression whose inactive arm could still expose an out-of-range topk_idx load to code generation, and its fallback allocation estimate rounded the per-expert alignment upper bound down to an alignment multiple.

Guard aligned expand stores with the real hidden/scaling-factor extents, initialize the shared cumsum buffer for all threads, avoid the speculative out-of-range topk load, and reserve a rounded-up per-expert alignment upper bound before trimming with the synchronized expert counts.

Co-authored-by: dingsg <shengge.ding@enflame-tech.com>
The full H100/CuTeDSL correctness run covers token and hidden sizes that do not land exactly on the kernel tile, scaling-factor block, or E5M6 packing granularity. Those edge tiles exposed two independent quantization issues.

First, cast-back and lossless/per-token cast kernels could load or store scaling factors for padded token/channel blocks. The same edge condition also applied to packed E5M6 output rows and columns, where the final tile may not contain a full logical token row or hidden group.

Second, per-token scale generation used in_config.dtype as the absmax fragment dtype. That dtype describes the input tensor storage, not the reduction accumulator. For BF16 and narrow quantization paths, keeping absmax in the input dtype can round or overflow the scale path before the final output cast, producing byte mismatches against the PyTorch reference.

Guard scale loads/stores and packed E5M6 stores with the real token/channel extents, keep invalid scale lanes zero-initialized, and use FP32 fragments for per-token absmax reductions before computing the reciprocal scale.

Co-authored-by: dingsg <shengge.ding@enflame-tech.com>
Full H100/CuTeDSL validation needs to run correctness and benchmark coverage under xdist while preserving host GPU pinning, separating TileLang compile caches, and collecting enough per-worker information to debug late failures without re-running the whole suite blindly.

Keep externally provided CUDA_VISIBLE_DEVICES instead of overwriting it in every xdist worker, allow per-worker TileLang cache directories, add optional per-test CUDA synchronization for benchmark/debug runs, and write optional trace/failure reports controlled by environment variables.

Benchmark-only sweeps also need a way to record new results before a baseline file exists. Add an opt-in missing-baseline override and make the timer backend configurable so local H100 runs can use CUDA events when CUPTI is not the desired backend.

Add a small run_cutedsl_tests.sh wrapper that rebuilds a local TileLang checkout, selects correctness/benchmark/all modes, stores logs and JSONL output under .test-logs, and leaves local virtualenv/log directories ignored.

Co-authored-by: dingsg <shengge.ding@enflame-tech.com>
@JayceSu98

Copy link
Copy Markdown
Owner Author

Superseded by the three split bugfix PRs: #2 for Engram, #3 for MoE, and #4 for Quant. The previous combined PR also contained reusable test tooling, which is intentionally left out of the split bugfix review.

@JayceSu98 JayceSu98 closed this Jun 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant