Skip to content

[Common] Experimental CuTeDSL MXFP8 backends in C++ via TVM-FFI - #3137

Open
kainzhong wants to merge 47 commits into
NVIDIA:mainfrom
kainzhong:cutedsl_mxfp8_common
Open

[Common] Experimental CuTeDSL MXFP8 backends in C++ via TVM-FFI#3137
kainzhong wants to merge 47 commits into
NVIDIA:mainfrom
kainzhong:cutedsl_mxfp8_common

Conversation

@kainzhong

@kainzhong kainzhong commented Jun 21, 2026

Copy link
Copy Markdown
Collaborator

Description

Adds an experimental, opt-in CuTeDSL backend for MXFP8 quantization. MXFP8 nvte_quantize calls can be routed to JIT-compiled CuTeDSL (CUTLASS Python DSL) kernels instead of the existing CUDA C++ kernels, bridged into the C++ dispatcher via apache-tvm-ffi (https://github.com/apache/tvm-ffi).

It's off by default (use NVTE_ENABLE_CUTEDSL_QUANT_BACKEND=1 to enable) and transparently falls back to the CUDA kernels for any unsupported config or shape (use NVTE_WARN_IF_CUTEDSL_BACKEND_NOT_CHOSEN=1 to enable warning for unsupported cases).

How it works

  • Python CuTeDSL kernels (transformer_engine/common/CuTeDSL/) register a factory as a TVM-FFI global.
  • On a matching MXFP8 quantize, the C++ dispatcher builds a config key, asks Python to JIT-compile + register a kernel for that config (cached), then invokes it with DLTensor views of the TE tensors.
  • Any miss (backend disabled, unsupported config, non-32-aligned shape) returns false → existing mxfp8::quantize CUDA path runs unchanged.

Type of change

  • Documentation change (change only to the documentation, either a fix or a new content)
  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Infra/Build change
  • Code refactoring

Changes

  • Added utility classes and functions to retrieve TVM-FFI global functions using strings
  • Ported MXFP8 CUDA C++ quantization code to CuTeDSL

Breaking changes:

  • Building TE now requires apache-tvm-ffi package installed
  • TE uses now need to install apache-tvm-ffi and nvidia-cutlass-dsl packages if they set NVTE_ENABLE_CUTEDSL_QUANT_BACKEND=1. Otherwise they should be fine (pythonwouldn't load tvm-ffi library to make it available in C++ and register CuTeDSL kernels, and C++ wouldn't be able to use dlopen to load libtvm_ffi.so loaded from python so it will fall back to CUDA kernels)

Checklist:

  • I have read and followed the contributing guidelines
  • The functionality is complete
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

@kainzhong
kainzhong force-pushed the cutedsl_mxfp8_common branch from daee750 to 218cd24 Compare June 27, 2026 08:27
@kainzhong
kainzhong force-pushed the cutedsl_mxfp8_common branch 4 times, most recently from 2f8c8da to 8448930 Compare July 8, 2026 21:44
@kainzhong

kainzhong commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

Benchmark on ptyche (B200 GPU, ARM CPU):
The benchmark scripts can be found in https://github.com/kainzhong/TransformerEngine/blob/cutedsl_mxfp8_common_bench/tests/pytorch/mxfp8/run_mxfp8_benchmark.py

                         tag        shape   dir   GPU_cpp_us   GPU_dsl_us   GPU_x   cpp_GB/s   dsl_GB/s   CPU_cpp_us   CPU_dsl_us   CPU_x
-----------------------------------------------------------------------------------------------------------------------------------------
          dbias_bf16_e4m3_sw   4096x14336  both        57.75        47.05    1.23     4130.8     5070.4        19.77        23.02    0.86
          dbias_bf16_e4m3_sw   4096x14336   col        39.31        37.20    1.06     4527.9     4785.3        16.89        20.73    0.81
          dbias_bf16_e4m3_sw   4096x14336   row        46.60        43.50    1.07     3820.0     4092.0        17.55        20.32    0.86
          dbias_bf16_e4m3_sw    4096x4096  both        23.87        20.74    1.15     2854.9     3285.8        20.93        22.20    0.94
          dbias_bf16_e4m3_sw    4096x4096   col        17.62        16.27    1.08     2886.7     3126.5        16.55        19.64    0.84
          dbias_bf16_e4m3_sw    4096x4096   row        19.54        19.14    1.02     2602.1     2657.5        16.55        20.25    0.82
          dbias_bf16_e4m3_sw    4096x8192  both        37.81        31.37    1.21     3605.0     4345.0        19.95        22.01    0.91
          dbias_bf16_e4m3_sw    4096x8192   col        26.70        25.56    1.04     3809.4     3979.9        17.23        20.80    0.83
          dbias_bf16_e4m3_sw    4096x8192   row        31.01        28.86    1.07     3279.5     3524.1        17.34        20.11    0.86
          dbias_bf16_e4m3_sw    8192x8192  both        70.53        59.30    1.19     3865.3     4597.6        19.70        23.57    0.84
          dbias_bf16_e4m3_sw    8192x8192   col        49.02        47.63    1.03     4150.0     4271.3        17.35        20.26    0.86
          dbias_bf16_e4m3_sw    8192x8192   row        57.26        54.08    1.06     3552.7     3761.6        17.71        20.02    0.88
             dbias_bf16_e4m3   4096x14336  both        56.96        48.11    1.18     4188.0     4958.7        20.00        23.56    0.85
             dbias_bf16_e4m3   4096x14336   col        39.12        36.81    1.06     4549.9     4835.0        16.74        19.95    0.84
             dbias_bf16_e4m3   4096x14336   row        51.61        43.53    1.19     3448.6     4088.6        16.73        20.37    0.82
             dbias_bf16_e4m3    4096x4096  both        23.45        20.51    1.14     2906.8     3323.9        19.88        22.98    0.87
             dbias_bf16_e4m3    4096x4096   col        17.55        16.20    1.08     2897.9     3139.1        16.59        19.27    0.86
             dbias_bf16_e4m3    4096x4096   row        21.50        19.23    1.12     2365.6     2644.9        16.92        19.80    0.85
             dbias_bf16_e4m3    4096x8192  both        37.33        31.24    1.19     3651.2     4363.0        19.78        23.39    0.85
             dbias_bf16_e4m3    4096x8192   col        26.74        25.20    1.06     3803.8     4035.9        16.39        19.72    0.83
             dbias_bf16_e4m3    4096x8192   row        34.06        29.10    1.17     2986.4     3495.0        17.27        20.58    0.84
             dbias_bf16_e4m3    8192x8192  both        69.48        59.39    1.17     3924.0     4590.9        19.50        23.61    0.83
             dbias_bf16_e4m3    8192x8192   col        49.12        47.46    1.03     4141.7     4286.5        16.99        19.98    0.85
             dbias_bf16_e4m3    8192x8192   row        63.04        54.15    1.16     3226.9     3756.7        16.86        20.39    0.83
          dgelu_bf16_e4m3_sw   4096x14336  both       145.47        94.98    1.53     2447.2     3748.0        13.40        16.82    0.80
          dgelu_bf16_e4m3_sw   4096x14336   col        91.89        76.65    1.20     3215.2     3854.2        10.51        13.22    0.79
          dgelu_bf16_e4m3_sw   4096x14336   row        93.62        76.58    1.22     3155.7     3857.9        10.50        14.35    0.73
          dgelu_bf16_e4m3_sw    4096x4096  both        45.90        31.29    1.47     2216.0     3250.5        13.06        16.04    0.81
          dgelu_bf16_e4m3_sw    4096x4096   col        30.34        25.68    1.18     2781.8     3287.5        10.09        13.34    0.76
          dgelu_bf16_e4m3_sw    4096x4096   row        31.47        25.69    1.22     2682.5     3285.8        10.22        13.96    0.73
          dgelu_bf16_e4m3_sw    4096x8192  both        85.39        56.75    1.50     2382.4     3584.7        13.10        16.46    0.80
          dgelu_bf16_e4m3_sw    4096x8192   col        54.98        46.14    1.19     3070.5     3659.2        10.18        13.55    0.75
          dgelu_bf16_e4m3_sw    4096x8192   row        56.86        46.11    1.23     2969.2     3661.6        10.04        14.69    0.68
          dgelu_bf16_e4m3_sw    8192x8192  both       166.02       107.60    1.54     2450.6     3781.2        13.44        16.56    0.81
          dgelu_bf16_e4m3_sw    8192x8192   col       104.29        86.54    1.21     3237.4     3901.5        10.20        13.42    0.76
          dgelu_bf16_e4m3_sw    8192x8192   row       105.63        86.63    1.22     3196.3     3897.7        10.33        14.30    0.72
             dgelu_bf16_e4m3   4096x14336  both       142.52        94.93    1.50     2497.8     3750.0        13.46        17.52    0.77
             dgelu_bf16_e4m3   4096x14336   col        90.69        76.78    1.18     3257.7     3847.7        10.51        14.02    0.75
             dgelu_bf16_e4m3   4096x14336   row        92.58        76.40    1.21     3191.2     3866.9        10.72        14.03    0.76
             dgelu_bf16_e4m3    4096x4096  both        45.08        31.17    1.45     2256.3     3263.0        13.36        16.63    0.80
             dgelu_bf16_e4m3    4096x4096   col        30.26        25.79    1.17     2789.8     3273.5        10.14        13.61    0.75
             dgelu_bf16_e4m3    4096x4096   row        31.02        25.42    1.22     2721.4     3321.1        10.52        13.89    0.76
             dgelu_bf16_e4m3    4096x8192  both        83.77        56.75    1.48     2428.4     3584.6        12.93        17.22    0.75
             dgelu_bf16_e4m3    4096x8192   col        54.39        46.25    1.18     3104.0     3650.5        10.18        13.78    0.74
             dgelu_bf16_e4m3    4096x8192   row        56.26        45.84    1.23     3000.8     3682.4        10.22        13.88    0.74
             dgelu_bf16_e4m3    8192x8192  both       162.62       107.35    1.51     2501.8     3789.8        13.02        17.42    0.75
             dgelu_bf16_e4m3    8192x8192   col       103.14        86.69    1.19     3273.6     3894.9        10.33        13.56    0.76
             dgelu_bf16_e4m3    8192x8192   row       104.59        86.24    1.21     3228.3     3915.2        10.48        13.50    0.78
           gelu_bf16_e4m3_sw   4096x14336  both       102.85        75.15    1.37     2319.4     3174.2        13.37        16.20    0.83
           gelu_bf16_e4m3_sw   4096x14336   col        66.47        58.58    1.13     2677.9     3038.7        10.22        12.98    0.79
           gelu_bf16_e4m3_sw   4096x14336   row        70.06        58.84    1.19     2540.6     3025.0        10.00        14.69    0.68
           gelu_bf16_e4m3_sw    4096x4096  both        30.98        24.85    1.25     2199.9     2743.0        13.07        15.30    0.85
           gelu_bf16_e4m3_sw    4096x4096   col        22.69        20.13    1.13     2241.4     2526.0         9.89        13.09    0.76
           gelu_bf16_e4m3_sw    4096x4096   row        23.10        20.17    1.15     2201.9     2521.3        10.20        14.37    0.71
           gelu_bf16_e4m3_sw    4096x8192  both        60.52        45.05    1.34     2252.4     3025.7        12.48        15.62    0.80
           gelu_bf16_e4m3_sw    4096x8192   col        40.29        35.49    1.14     2524.4     2866.1         9.85        13.00    0.76
           gelu_bf16_e4m3_sw    4096x8192   row        42.03        35.59    1.18     2420.1     2857.6        10.14        14.00    0.72
           gelu_bf16_e4m3_sw    8192x8192  both       117.61        84.98    1.38     2318.1     3208.1        13.30        15.88    0.84
           gelu_bf16_e4m3_sw    8192x8192   col        75.08        66.11    1.14     2709.4     3076.9         9.98        13.07    0.76
           gelu_bf16_e4m3_sw    8192x8192   row        78.25        66.35    1.18     2599.7     3065.8         9.96        13.84    0.72
              gelu_bf16_e4m3   4096x14336  both       101.10        76.18    1.33     2359.5     3131.4        13.31        16.64    0.80
              gelu_bf16_e4m3   4096x14336   col        65.20        58.74    1.11     2730.1     3030.0         9.77        13.46    0.73
              gelu_bf16_e4m3   4096x14336   row        68.84        58.89    1.17     2585.8     3022.3        10.18        13.01    0.78
              gelu_bf16_e4m3    4096x4096  both        30.60        25.22    1.21     2227.1     2702.2        12.81        15.29    0.84
              gelu_bf16_e4m3    4096x4096   col        22.29        20.20    1.10     2281.1     2517.2         9.66        12.91    0.75
              gelu_bf16_e4m3    4096x4096   row        22.91        19.69    1.16     2219.6     2583.3        10.22        13.91    0.73
              gelu_bf16_e4m3    4096x8192  both        59.19        45.71    1.29     2303.1     2981.8        12.07        15.37    0.79
              gelu_bf16_e4m3    4096x8192   col        39.62        35.56    1.11     2567.2     2859.9         9.76        13.40    0.73
              gelu_bf16_e4m3    4096x8192   row        41.53        35.37    1.17     2449.0     2875.6         9.78        13.79    0.71
              gelu_bf16_e4m3    8192x8192  both       115.28        86.14    1.34     2365.0     3165.0        12.92        15.31    0.84
              gelu_bf16_e4m3    8192x8192   col        73.23        66.20    1.11     2777.9     3072.9         9.86        13.08    0.75
              gelu_bf16_e4m3    8192x8192   row        78.11        66.50    1.17     2604.4     3058.9         9.96        13.50    0.74
          plain_bf16_e4m3_sw   4096x14336  both        42.08        39.30    1.07     5668.9     6070.0        15.96        16.41    0.97
          plain_bf16_e4m3_sw   4096x14336   col        31.21        30.01    1.04     5702.4     5931.2        13.66        14.51    0.94
          plain_bf16_e4m3_sw   4096x14336   row        30.25        29.86    1.01     5883.5     5961.5        13.32        13.88    0.96
          plain_bf16_e4m3_sw    4096x4096  both        14.88        14.60    1.02     4579.4     4668.7        16.81        15.65    1.07
          plain_bf16_e4m3_sw    4096x4096   col        11.74        11.34    1.03     4333.4     4484.3        13.90        13.26    1.05
          plain_bf16_e4m3_sw    4096x4096   row        11.14        11.14    1.00     4565.2     4565.1        13.95        13.86    1.01
          plain_bf16_e4m3_sw    4096x8192  both        25.59        24.35    1.05     5326.8     5597.4        16.56        15.41    1.07
          plain_bf16_e4m3_sw    4096x8192   col        19.76        18.78    1.05     5146.3     5416.4        13.47        14.17    0.95
          plain_bf16_e4m3_sw    4096x8192   row        19.18        18.57    1.03     5303.1     5475.8        13.30        13.91    0.96
          plain_bf16_e4m3_sw    8192x8192  both        47.63        44.45    1.07     5724.2     6132.9        15.76        15.56    1.01
          plain_bf16_e4m3_sw    8192x8192   col        35.16        33.22    1.06     5786.3     6123.5        13.29        13.41    0.99
          plain_bf16_e4m3_sw    8192x8192   row        33.97        33.50    1.01     5987.9     6071.6        14.33        13.38    1.07
             plain_bf16_e4m3   4096x14336  both        41.91        42.19    0.99     5691.5     5654.6        16.54        16.84    0.98
             plain_bf16_e4m3   4096x14336   col        30.83        29.16    1.06     5773.2     6104.0        12.77        13.39    0.95
             plain_bf16_e4m3   4096x14336   row        28.29        28.03    1.01     6292.4     6351.0        11.91        13.92    0.86
             plain_bf16_e4m3    4096x4096  both        16.46        15.72    1.05     4140.2     4335.2        16.70        16.17    1.03
             plain_bf16_e4m3    4096x4096   col        11.59        11.23    1.03     4389.6     4528.9        13.10        13.98    0.94
             plain_bf16_e4m3    4096x4096   row        10.05        10.12    0.99     5059.4     5023.9        12.27        13.21    0.93
             plain_bf16_e4m3    4096x8192  both        26.72        25.95    1.03     5102.0     5253.9        15.80        15.45    1.02
             plain_bf16_e4m3    4096x8192   col        19.20        18.13    1.06     5298.5     5609.1        13.40        14.04    0.96
             plain_bf16_e4m3    4096x8192   row        17.44        16.90    1.03     5831.2     6016.8        11.87        12.82    0.93
             plain_bf16_e4m3    8192x8192  both        46.70        46.56    1.00     5837.4     5854.9        16.19        16.35    0.99
             plain_bf16_e4m3    8192x8192   col        34.80        32.76    1.06     5844.9     6209.4        12.66        13.93    0.91
             plain_bf16_e4m3    8192x8192   row        31.84        31.33    1.02     6389.5     6493.7        12.02        13.37    0.90

@kainzhong
kainzhong marked this pull request as ready for review July 8, 2026 23:25
@greptile-apps

greptile-apps Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR introduces an experimental, opt-in CuTeDSL backend for MXFP8 quantization in Transformer Engine, bridging JIT-compiled CUTLASS Python DSL kernels into the existing C++ MXFP8 quantize() dispatcher via apache-tvm-ffi. The feature is off by default (NVTE_ENABLE_CUTEDSL_QUANT_BACKEND=1 to enable) and falls back transparently to existing CUDA C++ kernels for unsupported configs or shapes.

  • Dispatch bridge (tvm_ffi_bridge.h, quantize_mxfp8_cutedsl.cuh): A new TVMFFICentral singleton manages a per-config cache of JIT-resolved tvm::ffi::Function handles. On first use the C++ side calls back into a Python-registered entrypoint to compile and register the kernel, then stores it; subsequent calls hit the cache.
  • Python CuTeDSL kernels (CuTeDSL/cast/mxfp8/quantize_mxfp8.py): Full re-implementation of the MXFP8 quantize logic in CuTeDSL; registered via tvm_ffi.register_global_func.
  • Dependency changes (setup.py, pyproject.toml, CMakeLists.txt): apache-tvm-ffi and nvidia-cutlass-dsl are added as unconditional build and runtime requirements, affecting all users regardless of whether they enable the CuTeDSL backend.

Confidence Score: 3/5

Not yet safe to merge: several correctness and deployment issues remain unresolved.

The dispatch shim calls lazyload_function (which may trigger tens-of-seconds of NVCC JIT) before the cheap workspace-size-query early-return, stalling latency-sensitive callers on first use. The reduce_dbias step after the TVM-FFI kernel call runs unconditionally — if the noop flag caused the GPU kernel to skip writing the workspace, reduce_dbias sums uninitialized memory into dbias_tensor. Both apache-tvm-ffi and nvidia-cutlass-dsl are now hard install_requires for every TE user and a CMake FATAL_ERROR with no opt-out flag, despite the feature being opt-in.

Files Needing Attention: quantize_mxfp8_cutedsl.cuh (workspace-query JIT stall, reduce_dbias noop ordering), setup.py + pyproject.toml + CMakeLists.txt (unconditional hard dependencies), quantize_mxfp8.py (device-0 hardcode in capability check)

Important Files Changed

Filename Overview
transformer_engine/common/tvm_ffi_bridge.h New header: TVMFFICentral singleton manages per-config JIT kernel cache with shared_mutex; DLTensorWrapper bridges NVTETensor to DLPack. Concurrent first-calls for the same config can trigger double JIT compilation with no per-key mutex before the cache write.
transformer_engine/common/cast/mxfp8/quantize_mxfp8_cutedsl.cuh New CuTeDSL dispatch shim. lazyload_function is called before the workspace-size-query early-return on line 171, causing a multi-second JIT stall on the first workspace-size probe. The reduce_dbias call at line 235 is unconditional regardless of whether the noop flag caused the GPU kernel to skip writing the workspace.
transformer_engine/common/CuTeDSL/cast/mxfp8/quantize_mxfp8.py Large new file (~2500 lines): CuTeDSL MXFP8 kernel classes and JIT entry-point. Compilation failures are caught broadly. The device_compute_capability() call at line 2432 defaults to device 0, causing multi-GPU environments to gate the backend on the wrong device.
setup.py apache-tvm-ffi>=0.1.12 and nvidia-cutlass-dsl>=4.4.2 added to install_requires, making them hard runtime dependencies for every TE user, not just CuTeDSL opt-ins.
transformer_engine/common/CMakeLists.txt tvm_ffi detection is unconditional: missing package causes a FATAL_ERROR with no opt-out CMake flag, unlike every other optional feature in this file.
tests/pytorch/mxfp8/test_mxfp8_cutedsl_backend.py New cross-backend correctness test. import tvm_ffi at module level (line 17) causes a collection ERROR for users without apache-tvm-ffi, contaminating the existing test_mxfp8 CI run.
pyproject.toml apache-tvm-ffi added to build-system.requires, making it a mandatory build-time dependency for all users regardless of CuTeDSL opt-in.
transformer_engine/common/CuTeDSL/utils.py New utility module with device capability queries and MLIR PTX intrinsic wrappers. device_compute_capability() always defaults to device_id=0. Arch-string parsing correctly handles 2- and 3-digit SM strings.
transformer_engine/common/CuTeDSL/utils_fp8.py New FP8 conversion intrinsics; correctly imports device_is_blackwell. Module-level cvt_f32_to_fp8e8m0 assignment calls device_is_blackwell() at import time, always querying device 0.
transformer_engine/common/init.py CuTeDSL registration is correctly gated behind NVTE_ENABLE_CUTEDSL_QUANT_BACKEND env-var check. Both _load_tvm_ffi_library() and _register_cutedsl_backends() are lru_cached.
qa/L0_pytorch_unittest/test.sh Adds CuTeDSL test run with NVTE_ENABLE_CUTEDSL_QUANT_BACKEND=1. The preceding mxfp8 test without env var now collects test_mxfp8_cutedsl_backend.py, which has a module-level import tvm_ffi that fails in environments without apache-tvm-ffi.

Sequence Diagram

sequenceDiagram
    participant App as Application
    participant QCUH as quantize.cuh (dispatch)
    participant CDSL as quantize_mxfp8_cutedsl.cuh
    participant TVMC as TVMFFICentral (singleton)
    participant PY as Python: get_mxfp8_quantization_function
    participant CUDA as CUDA C++ mxfp8::quantize

    App->>QCUH: nvte_quantize(input, output, config)
    QCUH->>CDSL: "mxfp8_quantize_cutedsl<IS_DBIAS,...>(...)"
    CDSL->>CDSL: shape alignment check (% 32)
    alt shape not 32-aligned
        CDSL-->>QCUH: false (fall back)
        QCUH->>CUDA: mxfp8::quantize(...)
    else shape OK
        CDSL->>TVMC: lazyload_function(config)
        alt cache hit
            TVMC-->>CDSL: "optional<Function>"
        else cache miss (first call)
            TVMC->>PY: retrieve_func_from_python(key)
            PY->>PY: cute.compile(kernel_obj, ...) [JIT via NVCC]
            PY->>PY: tvm_ffi.register_global_func(key, compiled)
            PY-->>TVMC: true/false
            TVMC->>TVMC: cache_.emplace(key, fn_or_nullopt)
            TVMC-->>CDSL: "optional<Function>"
        end
        alt function found
            CDSL->>CDSL: zero_scales_kernel (if swizzled+padding)
            CDSL->>PY: "(*fn)(mX, mO_row, mS_row, ..., stream)"
            PY-->>CDSL: kernel executes on GPU
            opt WITH_DBIAS
                CDSL->>CDSL: reduce_dbias(workspace to dbias_tensor)
            end
            CDSL-->>QCUH: true
        else no function (unsupported)
            CDSL-->>QCUH: false
            QCUH->>CUDA: mxfp8::quantize(...)
        end
    end
Loading

Reviews (23): Last reviewed commit: "warn only once if dlopen fails" | Re-trigger Greptile

Comment thread build_tools/pytorch.py
Comment thread transformer_engine/common/CuTeDSL/cast/mxfp8/quantize_mxfp8.py Outdated
Comment thread build_tools/pytorch.py Outdated
Comment on lines +71 to +74
# apache-tvm-ffi: headers for the C++ API (Module / Function / TensorView)
# and libtvm_ffi.so for symbol resolution. Used by tvm_ffi_bridge.h /
# applyTVMFunction. Python registers AOT-compiled CuTeDSL kernels into
# the global registry; TE C++ looks them up via Function::GetGlobalRequired.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment is too verbose and talks about things not needed in the context of the build system.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

Comment thread build_tools/pytorch.py Outdated
Comment on lines +121 to +123
# rpath pinned to the pip install dir so the loader finds libtvm_ffi.so
# without LD_LIBRARY_PATH at runtime.
extra_link_args = [f"-Wl,-rpath,{tvm_ffi_lib_dir}"]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will (maybe) work in the sdist installation, but what if we decide to do the binary wheel?
All of the other such libraries are linked normally and either loaded using LD_LIBRARY_PATH or
being found and loaded at runtime before we load libtransformer_engine.so.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, what about JAX? It will also use those functions - shouldn't those changes land on the common side instead?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK I think I need to delete this from the pytorch side and make them dependencies in common instead

Comment thread setup.py Outdated
"importlib-metadata>=1.0",
"packaging",
"apache-tvm-ffi>=0.1.12",
"nvidia-cutlass-dsl>=4.2.0",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Due to other things (like cudnn frontend CuTeDSL kernels), I'm pretty sure we need a later version
of that package (4.4.2 I think?). Adding @ksivaman to comment.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll change this to 4.4.2

Comment on lines +21 to +22
GTEST_SKIPs the mismatched half), non-32-divisible shapes are omitted (the
dispatcher can never route them to CuTeDSL), and a missing kernel registration

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are the non-32-divisible shapes omitted? Is this a limitation of the cutedsl implementation?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because my CuTeDSL kernels are compiled with

sym_M = cute.sym_int32(divisibility=MXFP8_BLOCK_SCALING_SIZE)
sym_N = cute.sym_int32(divisibility=MXFP8_BLOCK_SCALING_SIZE)

So it assumes 32-divisible shape. Maybe non-32-divisible can be supported as well. I'll run some benchmarks and see if it hurts performance but I think normally people wouldn't use these weird shapes?

#
# See LICENSE for license information.

"""Cross-backend bit-exactness tests for the CuTeDSL MXFP8 quantize kernels.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense in this initial stage, but I would explicitly mark this file as temporary, since
ultimately we will want to standardize on this backend.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could port the CUDA C++ tests to python and make this a standalone test instead of comparing with CUDA kernel's output, but then I thought since we already validated CUDA implementation it would be easier to just make that the reference and compare the result instead.
If we want to standardize on this then should this be python MXFP8 reference implementation on its own?

Comment on lines +7 to +14
Registration is explicit: call :func:`register_cutedsl_backends` to expose the
CuTeDSL kernel entrypoints (e.g. ``get_mxfp8_quantization_function``) as
TVM-FFI global functions. The C++ dispatcher (init_cutedsl_extension in the
PyTorch extension) imports this package and calls it once per process; it then
probes the names via ``tvm::ffi::Function::GetGlobal`` — finding one means the
CuTeDSL toolchain is available and the kernel may be compiled on demand, not
finding it means a plain C++ environment and the dispatcher falls back to the
CUDA C++ kernel.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is too verbose and mostly belongs to the register_cutedsl_backends function instead.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

Comment on lines +21 to +27
"""Tanh-approximation GELU. Constants and operator grouping match TE's
`transformer_engine/common/util/math.h::gelu` exactly (factored form
`x · (0.5 + 0.5·tanh(x·(a + b·x²)))`) so quantized output is bit-exact
against the C++ fused IS_ACT path. Uses `cute.math.tanh(fastmath=False)`
rather than the `tanh.approx.f32` PTX intrinsic — TE compiles activation
kernels without `--use_fast_math` by default, so its `tanhf` is the
IEEE-precise expansion."""

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This raises a question - we do actually have a knob to use fast math for activations - I assume that
there is no equivalent for that here? We should add that.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yes I just found NVTE_BUILD_ACTIVATION_WITH_FAST_MATH. Fixed my code

def act_silu(x: Float32) -> Float32:
"""SiLU/Swish: x · σ(x) = x / (1 + e^-x).
Matches TE's `silu` (`val / (1 + expf(-val))`)."""
return x / (Float32(1.0) + cute.math.exp(-x, fastmath=True))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think expf (compiled without fast math) is the same as cute.math.exp(fastmath=True) - is it?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

"""Quick GELU: x · σ(1.702·x). Matches TE `qgelu_with_alpha(val, 1.702)` =
`cval · (1 / (1 + expf(-1.702·cval)))` (multiply by sigmoid, not a divide)."""
z = Float32(1.702) * x
return x * (Float32(1.0) / (Float32(1.0) + cute.math.exp(-z, fastmath=True)))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So why are we not reusing the sigmoid function here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah Claude Code wrote that. Refactored this

Comment on lines +44 to +70
std::string to_key() const {
std::string key;
key.reserve(56);
key.append("cutedsl_mxfp8_")
.append(te_dtype_to_str(dtype))
.append("_")
.append(te_dtype_to_str(fp8_dtype))
.append("_")
.append(rowwise ? "1" : "0")
.append("_")
.append(colwise ? "1" : "0")
.append("_")
.append(swizzled ? "1" : "0")
.append("_")
.append(with_amax ? "1" : "0")
.append("_")
.append(with_dbias ? "1" : "0")
.append("_")
.append(with_dact ? "1" : "0")
.append("_")
.append(with_act ? "1" : "0")
.append("_")
.append(with_noop ? "1" : "0")
.append("_")
.append(activation_to_str(activation));
return key;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kind of random, but this function is quite slow. You could do the same much faster with raw char*
manipulation.

@kainzhong kainzhong Jul 9, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Emmmm but I reserved 56 chars before I do append. I don't know if char* will be faster than this since they both don't require resizing the string?

Comment thread transformer_engine/common/cast/mxfp8/quantize_mxfp8_cutedsl.cuh
Comment thread transformer_engine/common/cast/mxfp8/quantize_mxfp8_cutedsl.cuh
Comment on lines +113 to +121
if(NOT TVM_FFI_CMAKE_QUERY EQUAL 0)
message(FATAL_ERROR
"Could not import the tvm_ffi Python package (with '${Python_EXECUTABLE}'), "
"which Transformer Engine requires to build the CuTeDSL quantize backend "
"bridge (common/tvm_ffi_bridge.h). Install it into this Python environment: "
"`pip install apache-tvm-ffi`.")
endif()
find_package(tvm_ffi CONFIG REQUIRED PATHS "${TVM_FFI_CMAKE_DIR}")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 No opt-out CMake option for tvm_ffi dependency

The tvm_ffi detection is unconditional: if the package is absent the build hard-fails with FATAL_ERROR, with no NVTE_ENABLE_CUTEDSL CMake option to disable it. Every other optional feature in this file that has a build-time cost (NVTE_ENABLE_NVSHMEM, NVTE_WITH_CUBLASMP, etc.) is guarded by an option() flag. Without an analogous guard here, any environment where apache-tvm-ffi is not installed — CI images, embedded build systems, custom wheels — cannot build Transformer Engine at all, even if the CuTeDSL backend is never used at runtime.

@kainzhong
kainzhong force-pushed the cutedsl_mxfp8_common branch from 948fab5 to 2930b1b Compare July 10, 2026 00:34
Comment thread transformer_engine/common/CuTeDSL/utils_fp8.py
Comment thread transformer_engine/common/CuTeDSL/utils.py Outdated
Comment thread transformer_engine/common/__init__.py Outdated
Comment thread transformer_engine/common/CuTeDSL/utils.py
Comment on lines +158 to +179
std::optional<tvm::ffi::Function> mxfp8_quant_func_opt =
tvm_ffi_bridge::TVMFFICentral::getInstance().lazyload_function(config);
if (!mxfp8_quant_func_opt.has_value()) {
return false;
}

// When only WITH_DBIAS is true, we use a larger tile size (align with CUDA C++ implementation)
const bool cast_dbias_only = config.with_dbias && !config.with_dact && !config.with_act;
const size_t chunk_rows = cast_dbias_only ? 128 : 64; // input rows reduced per CTA
// Each CTA writes one partial-dbias row, so the workspace (and the cross-CTA
// reduction below) has ceil(M / chunk_rows) rows.
const size_t workspace_rows = (flat_m + chunk_rows - 1) / chunk_rows;

// dbias workspace-size query, mirroring mxfp8::quantize: the framework first
// calls with an unallocated workspace to learn its shape, allocates a buffer of
// that shape, then calls again to run. The kernel writes per-row-block partial
// dbias into this workspace; reducing it to the final dbias is a separate step.
if (config.with_dbias && workspace_tensor != nullptr && workspace_tensor->data.dptr == nullptr) {
workspace_tensor->data.shape = {workspace_rows, flat_n};
workspace_tensor->data.dtype = DType::kFloat32;
return true;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 JIT compilation triggered on workspace-size query call

lazyload_function(config) — which may compile the CUDA kernel (tens of seconds of NVCC JIT) — runs before the workspace-size-query early-return on line 175. The very first call with workspace_tensor->data.dptr == nullptr for a with_dbias config blocks the calling thread for the full JIT duration before returning only the workspace dimensions. The CUDA C++ path computes this immediately from DIVUP(rows, CHUNK_DIM_Y) without any compilation.

In frameworks that call the workspace-size query in a latency-sensitive context (e.g., during graph capture or model init), this causes an unexpected multi-second stall on first use. Moving the workspace-size query before the lazyload_function call (or checking the cache hit before compiling) would decouple the size calculation from JIT and keep the workspace query cheap for cached configs.

Comment thread tests/pytorch/mxfp8/test_mxfp8_cutedsl_backend.py Outdated
Comment on lines +1 to +10
# Copyright (c) 2022-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
#
# See LICENSE for license information.

"""Cross-backend bit-exactness tests for the CuTeDSL MXFP8 quantize kernels."""

import ctypes
import os
from typing import Callable, NamedTuple, Optional

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Unconditional top-level import tvm_ffi raises ImportError for users without the package

The test file imports tvm_ffi at module level before the pytestmark skip guard is evaluated. Pytest collects all test modules regardless of environment; users without apache-tvm-ffi installed will see a collection error instead of a clean skip. The import should be moved inside the test body or placed under a try/except ImportError guard that sets tvm_ffi_available = False, similar to how the test already conditionally sets cutedsl_enabled.

@kainzhong
kainzhong force-pushed the cutedsl_mxfp8_common branch from 6e55eef to c47fc5c Compare July 27, 2026 20:09
kainzhong and others added 4 commits July 27, 2026 20:09
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
for more information, see https://pre-commit.ci

Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
pre-commit-ci Bot and others added 29 commits July 27, 2026 20:10
for more information, see https://pre-commit.ci

Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
…it__.py

Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
for more information, see https://pre-commit.ci

Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
for more information, see https://pre-commit.ci

Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
for more information, see https://pre-commit.ci

Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
for more information, see https://pre-commit.ci

Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
for more information, see https://pre-commit.ci

Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Perform noop tensor check on device

Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
@kainzhong
kainzhong force-pushed the cutedsl_mxfp8_common branch from c47fc5c to 4815598 Compare July 27, 2026 20:10
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.

3 participants