Skip to content

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

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

[Common] Experimental CuTeDSL MXFP8 backends in C++ via TVM-FFI#3137
kainzhong wants to merge 96 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.

TODO:

  • see if we can enable CuTeDSL kernel in the C++ MXFP8 tests and also test this on JAX. Try making it by default on and run CI to see if there are problems
  • Try running it from C++ without loading libtvmffi.so and see if falls back to CUDA successfully

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 from python now requires apache-tvm-ffi package installed. If building the C++ lib, you can pass NVTE_WITH_CUTEDSL to cmake to opt-out.
  • apache-tvm-ffi and nvidia-cutlass-dsl packages are TE's dependency now.

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        58.11        48.17    1.21     4105.1     4951.9        20.00        25.26    0.79
            dbias_bf16_e4m3_sw   4096x14336   col        39.87        37.00    1.08     4464.1     4810.5        16.54        21.90    0.76
            dbias_bf16_e4m3_sw   4096x14336   row        47.02        44.22    1.06     3785.5     4025.0        18.29        21.44    0.85
            dbias_bf16_e4m3_sw    4096x4096  both        24.41        21.23    1.15     2792.7     3210.6        19.82        24.78    0.80
            dbias_bf16_e4m3_sw    4096x4096   col        17.99        16.43    1.10     2826.2     3096.2        16.40        21.18    0.77
            dbias_bf16_e4m3_sw    4096x4096   row        19.85        19.43    1.02     2562.6     2616.8        17.04        21.63    0.79
            dbias_bf16_e4m3_sw    4096x8192  both        38.65        32.07    1.21     3527.1     4250.4        19.84        24.86    0.80
            dbias_bf16_e4m3_sw    4096x8192   col        27.22        25.45    1.07     3736.7     3996.0        16.83        21.52    0.78
            dbias_bf16_e4m3_sw    4096x8192   row        31.44        29.38    1.07     3235.5     3462.0        18.21        20.95    0.87
            dbias_bf16_e4m3_sw    8192x8192  both        70.58        60.03    1.18     3862.8     4541.3        19.20        24.59    0.78
            dbias_bf16_e4m3_sw    8192x8192   col        49.62        47.44    1.05     4100.0     4287.8        16.20        22.40    0.72
            dbias_bf16_e4m3_sw    8192x8192   row        57.70        54.92    1.05     3525.5     3704.3        17.77        20.91    0.85
               dbias_bf16_e4m3   4096x14336  both        57.28        47.97    1.19     4164.5     4973.4        19.75        24.53    0.80
               dbias_bf16_e4m3   4096x14336   col        39.74        36.76    1.08     4478.9     4841.5        18.68        21.22    0.88
               dbias_bf16_e4m3   4096x14336   row        52.20        44.07    1.18     3410.1     4039.0        17.16        21.14    0.81
               dbias_bf16_e4m3    4096x4096  both        23.98        20.69    1.16     2841.9     3293.7        18.55        25.52    0.73
               dbias_bf16_e4m3    4096x4096   col        18.00        16.43    1.10     2824.6     3094.7        17.02        21.28    0.80
               dbias_bf16_e4m3    4096x4096   row        21.72        19.55    1.11     2341.7     2601.1        16.21        20.26    0.80
               dbias_bf16_e4m3    4096x8192  both        38.13        31.50    1.21     3574.9     4326.9        19.23        24.82    0.77
               dbias_bf16_e4m3    4096x8192   col        27.35        25.28    1.08     3718.4     4024.0        18.10        21.54    0.84
               dbias_bf16_e4m3    4096x8192   row        34.53        29.48    1.17     2945.6     3449.8        17.12        21.21    0.81
               dbias_bf16_e4m3    8192x8192  both        69.63        59.30    1.17     3915.7     4597.5        19.09        23.96    0.80
               dbias_bf16_e4m3    8192x8192   col        49.73        47.43    1.05     4090.6     4288.9        17.28        20.99    0.82
               dbias_bf16_e4m3    8192x8192   row        63.74        54.88    1.16     3191.6     3706.9        16.11        20.72    0.78
            dgelu_bf16_e4m3_sw   4096x14336  both       148.09        96.19    1.54     2403.9     3701.0        13.64        17.46    0.78
            dgelu_bf16_e4m3_sw   4096x14336   col        93.53        78.15    1.20     3158.7     3780.4        10.12        14.69    0.69
            dgelu_bf16_e4m3_sw   4096x14336   row        95.01        77.21    1.23     3109.6     3826.5        10.40        14.98    0.69
            dgelu_bf16_e4m3_sw    4096x4096  both        47.01        32.54    1.44     2163.8     3125.5        13.26        17.97    0.74
            dgelu_bf16_e4m3_sw    4096x4096   col        31.24        26.84    1.16     2702.3     3144.9         9.84        14.27    0.69
            dgelu_bf16_e4m3_sw    4096x4096   row        32.31        26.63    1.21     2612.3     3169.8        10.36        14.04    0.74
            dgelu_bf16_e4m3_sw    4096x8192  both        87.17        57.99    1.50     2333.7     3508.2        13.10        16.98    0.77
            dgelu_bf16_e4m3_sw    4096x8192   col        56.07        47.45    1.18     3010.7     3557.6         9.81        14.27    0.69
            dgelu_bf16_e4m3_sw    4096x8192   row        57.97        46.88    1.24     2912.4     3601.0        10.24        13.10    0.78
            dgelu_bf16_e4m3_sw    8192x8192  both       168.28       108.88    1.55     2417.6     3736.8        13.36        17.45    0.77
            dgelu_bf16_e4m3_sw    8192x8192   col       106.11        88.26    1.20     3181.9     3825.7         9.93        14.60    0.68
            dgelu_bf16_e4m3_sw    8192x8192   row       107.25        87.16    1.23     3148.1     3873.7        10.22        13.96    0.73
               dgelu_bf16_e4m3   4096x14336  both       145.12        96.46    1.50     2453.0     3690.7        13.07        17.39    0.75
               dgelu_bf16_e4m3   4096x14336   col        92.20        77.95    1.18     3204.3     3789.9        10.10        13.87    0.73
               dgelu_bf16_e4m3   4096x14336   row        93.93        76.33    1.23     3145.2     3870.3        10.08        15.07    0.67
               dgelu_bf16_e4m3    4096x4096  both        46.17        32.64    1.41     2202.8     3116.5        12.46        17.02    0.73
               dgelu_bf16_e4m3    4096x4096   col        31.11        26.87    1.16     2713.7     3141.8        10.57        14.44    0.73
               dgelu_bf16_e4m3    4096x4096   row        31.92        26.26    1.22     2644.3     3214.2         9.92        13.81    0.72
               dgelu_bf16_e4m3    4096x8192  both        85.63        58.18    1.47     2375.5     3496.3        12.69        17.07    0.74
               dgelu_bf16_e4m3    4096x8192   col        55.56        47.34    1.17     3038.6     3566.4        10.14        16.94    0.60
               dgelu_bf16_e4m3    4096x8192   row        57.29        46.33    1.24     2946.6     3644.1         9.86        14.25    0.69
               dgelu_bf16_e4m3    8192x8192  both       165.01       109.19    1.51     2465.5     3726.0        13.36        17.02    0.78
               dgelu_bf16_e4m3    8192x8192   col       104.83        88.07    1.19     3220.8     3833.7        10.00        13.95    0.72
               dgelu_bf16_e4m3    8192x8192   row       105.99        86.16    1.23     3185.6     3918.6         9.96        13.50    0.74
             gelu_bf16_e4m3_sw   4096x14336  both       104.94        77.57    1.35     2273.2     3075.4        13.52        17.79    0.76
             gelu_bf16_e4m3_sw   4096x14336   col        67.92        60.87    1.12     2620.5     2924.2         9.48        14.47    0.66
             gelu_bf16_e4m3_sw   4096x14336   row        71.59        60.21    1.19     2486.4     2956.5        10.65        13.83    0.77
             gelu_bf16_e4m3_sw    4096x4096  both        32.02        26.49    1.21     2128.5     2573.0        13.47        17.52    0.77
             gelu_bf16_e4m3_sw    4096x4096   col        23.46        21.32    1.10     2167.5     2384.8         9.55        13.98    0.68
             gelu_bf16_e4m3_sw    4096x4096   row        23.93        21.02    1.14     2124.8     2419.7        10.30        14.95    0.69
             gelu_bf16_e4m3_sw    4096x8192  both        61.86        47.08    1.31     2203.6     2895.5        12.44        16.90    0.74
             gelu_bf16_e4m3_sw    4096x8192   col        41.38        37.27    1.11     2457.8     2729.2         9.28        14.53    0.64
             gelu_bf16_e4m3_sw    4096x8192   row        43.17        36.85    1.17     2356.0     2759.9        10.22        13.67    0.75
             gelu_bf16_e4m3_sw    8192x8192  both       119.73        87.65    1.37     2277.0     3110.3        13.77        17.29    0.80
             gelu_bf16_e4m3_sw    8192x8192   col        76.64        68.55    1.12     2654.4     2967.6         9.38        14.25    0.66
             gelu_bf16_e4m3_sw    8192x8192   row        80.98        67.80    1.19     2512.1     3000.6        10.25        13.36    0.77
                gelu_bf16_e4m3   4096x14336  both       102.88        77.85    1.32     2318.6     3064.1        13.37        16.88    0.79
                gelu_bf16_e4m3   4096x14336   col        66.64        60.56    1.10     2671.1     2939.0        10.81        14.23    0.76
                gelu_bf16_e4m3   4096x14336   row        70.38        60.05    1.17     2529.1     2964.0        10.00        13.23    0.76
                gelu_bf16_e4m3    4096x4096  both        31.65        26.56    1.19     2153.6     2566.3        12.88        17.05    0.75
                gelu_bf16_e4m3    4096x4096   col        23.08        21.21    1.09     2203.4     2397.6        10.01        13.41    0.75
                gelu_bf16_e4m3    4096x4096   row        23.79        20.51    1.16     2137.7     2479.7         9.75        13.31    0.73
                gelu_bf16_e4m3    4096x8192  both        60.68        47.24    1.28     2246.3     2885.8        12.43        17.67    0.70
                gelu_bf16_e4m3    4096x8192   col        40.73        37.09    1.10     2497.0     2742.0         9.98        13.08    0.76
                gelu_bf16_e4m3    4096x8192   row        42.65        36.52    1.17     2384.8     2785.4         9.60        12.97    0.74
                gelu_bf16_e4m3    8192x8192  both       117.36        87.98    1.33     2323.1     3098.7        13.33        16.39    0.81
                gelu_bf16_e4m3    8192x8192   col        75.26        68.21    1.10     2702.9     2982.3        10.07        13.40    0.75
                gelu_bf16_e4m3    8192x8192   row        79.56        67.75    1.17     2556.8     3002.6         9.60        13.79    0.70
            plain_bf16_e4m3_sw   4096x14336  both        42.52        39.14    1.09     5610.6     6094.9        16.02        19.12    0.84
            plain_bf16_e4m3_sw   4096x14336   col        31.99        29.92    1.07     5564.6     5949.8        12.16        15.43    0.79
            plain_bf16_e4m3_sw   4096x14336   row        30.19        29.77    1.01     5895.9     5978.2        12.42        15.01    0.83
            plain_bf16_e4m3_sw    4096x4096  both        15.32        14.57    1.05     4450.0     4677.6        16.40        18.22    0.90
            plain_bf16_e4m3_sw    4096x4096   col        11.90        11.31    1.05     4272.5     4496.1        12.91        14.98    0.86
            plain_bf16_e4m3_sw    4096x4096   row        11.09        11.18    0.99     4584.8     4549.2        13.54        14.32    0.95
            plain_bf16_e4m3_sw    4096x8192  both        26.22        24.14    1.09     5198.5     5646.1        15.83        18.04    0.88
            plain_bf16_e4m3_sw    4096x8192   col        20.15        18.72    1.08     5047.9     5432.0        12.58        14.88    0.85
            plain_bf16_e4m3_sw    4096x8192   row        19.12        18.61    1.03     5319.5     5464.3        12.66        14.63    0.87
            plain_bf16_e4m3_sw    8192x8192  both        47.87        44.25    1.08     5694.9     6160.5        16.33        18.67    0.87
            plain_bf16_e4m3_sw    8192x8192   col        35.74        33.07    1.08     5691.9     6151.6        11.80        15.38    0.77
            plain_bf16_e4m3_sw    8192x8192   row        33.81        33.54    1.01     6016.3     6064.7        12.34        14.58    0.85
               plain_bf16_e4m3   4096x14336  both        41.88        41.96    1.00     5696.5     5684.6        17.08        17.73    0.96
               plain_bf16_e4m3   4096x14336   col        31.63        28.96    1.09     5627.2     6145.8        12.31        14.63    0.84
               plain_bf16_e4m3   4096x14336   row        28.20        27.94    1.01     6311.5     6370.2        12.12        14.57    0.83
               plain_bf16_e4m3    4096x4096  both        16.22        15.44    1.05     4201.0     4413.1        17.02        16.96    1.00
               plain_bf16_e4m3    4096x4096   col        11.83        11.20    1.06     4300.7     4539.0        12.60        14.17    0.89
               plain_bf16_e4m3    4096x4096   row        10.10         9.94    1.02     5037.4     5118.5        13.71        13.54    1.01
               plain_bf16_e4m3    4096x8192  both        26.66        25.85    1.03     5113.0     5274.0        15.82        17.08    0.93
               plain_bf16_e4m3    4096x8192   col        19.89        17.95    1.11     5114.9     5665.4        12.58        13.74    0.92
               plain_bf16_e4m3    4096x8192   row        17.41        16.95    1.03     5843.7     6001.9        11.80        14.09    0.84
               plain_bf16_e4m3    8192x8192  both        46.78        46.39    1.01     5827.4     5876.5        15.68        18.21    0.86
               plain_bf16_e4m3    8192x8192   col        35.50        32.67    1.09     5730.8     6226.2        12.54        14.06    0.89
               plain_bf16_e4m3    8192x8192   row        31.79        31.29    1.02     6398.6     6501.2        11.62        13.72    0.85
            
    us = microseconds/call; *_x = cpp/dsl speedup (>1 = CuTeDSL faster)
    GB/s = effective HBM bandwidth (in+out+scale bytes / GPU kernel time)
    GPU = kernel time from nsys summary (cold L2); CPU = host dispatch time

@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 that JIT-compiles Python kernels (via cute.compile()) and dispatches them from C++ through the apache-tvm-ffi bridge, falling back to the existing CUDA C++ kernels on any unsupported configuration. The bridge is guarded by NVTE_ENABLE_CUTEDSL_QUANT_BACKEND=1 at the Python registration layer and by TVMFFIConfigCache (shared-mutex protected) in C++.

  • tvm_ffi_bridge.h introduces DLTensorWrapper, TVMFFICentral (dlopen singleton), and TVMFFIConfigCache (lazy-load, thread-safe) to route C++ kernel calls into the TVM-FFI global function registry.
  • quantize_mxfp8_cutedsl.cuh and quantize_mxfp8.py implement the full dispatch chain: shape validation, per-config JIT compilation, zero-scale padding, and cross-CTA dbias reduction via the existing CUDA C++ reduce_dbias.
  • setup.py unconditionally adds apache-tvm-ffi and nvidia-cutlass-dsl to install_requires, making two heavy optional packages mandatory for all users regardless of whether they use the experimental backend.

Confidence Score: 4/5

  • Safe to merge with one blocking concern: the apache-tvm-ffi and nvidia-cutlass-dsl packages should not be hard dependencies for all users of an opt-in experimental feature.
  • The core dispatch chain (TVM-FFI bridge, cache, JIT, CUDA fallback) is well-constructed and all previously-flagged blocking issues have been resolved. The one remaining P1 is the mandatory install_requires entries for two heavy packages that are only needed when the experimental backend is explicitly opted into via environment variable; this should be an extras group. All other concerns are P2 (test tolerances, arch string warning message) and don't block correctness.
  • setup.py — mandatory apache-tvm-ffi/nvidia-cutlass-dsl dependencies should be moved to an extras group for the experimental opt-in backend.

Important Files Changed

Filename Overview
transformer_engine/common/tvm_ffi_bridge.h New TVM-FFI bridge: DLTensorWrapper for tensor argument marshalling, TVMFFICentral singleton for dlopen + enable/disable, TVMFFIConfigCache with shared_mutex for concurrent-safe lazy-loading. Cache stores std::nullopt for unsupported configs (preventing redundant Python calls). Null DLTensorWrapper pointers are packed as TVM-FFI None via the TypeTraits specialization.
transformer_engine/common/cast/mxfp8/quantize_mxfp8_cutedsl.cuh C++ side of the CuTeDSL dispatch: MXFP8QuantConfig encodes the kernel config into a 32-bit ID for cache lookups, builds a unique key for Python-side JIT compilation, and uses TVMFFIConfigCache for lazy-load. Workspace-size query returns correctly before the JIT path. The flat_n alignment check now uses return false (not NVTE_CHECK). reduce_dbias is called unconditionally regardless of noop state — noted but consistent with the CUDA path per comments.
transformer_engine/common/CuTeDSL/cast/mxfp8/quantize_mxfp8.py 2741-line CuTeDSL kernel for MXFP8 quantization. Implements rowwise, colwise, and bidimensional paths with TMA pipelining, activation fusion (gelu/relu/silu/qgelu/srelu and derivatives), and dbias reduction. MXFP8QuantizeEntry selects specialized kernels (vectorized rowwise, swizzled bidim) based on compile-time config flags and runtime shapes. get_mxfp8_quantization_function() correctly guards device check before compilation and wraps all errors in a try/except that returns False to trigger CUDA fallback.
transformer_engine/common/CuTeDSL/utils.py Low-level CuTeDSL helpers including device_compute_capability() and device_is_blackwell(). The arch string parsing (taking last char as minor version) works for numeric strings like "100" → (10, 0) but fails silently for letter-suffixed strings like "90a", returning (0, 0) via the broad except. Backend is still correctly disabled for non-Blackwell in either case, but warning messages may be inaccurate.
transformer_engine/common/init.py CuTeDSL registration is now correctly gated behind NVTE_ENABLE_CUTEDSL_QUANT_BACKEND env var; neither _load_tvm_ffi_library() nor _register_cutedsl_backends() runs when the feature is disabled. Both are decorated with @functools.lru_cache so double-registration is impossible.
transformer_engine/common/CuTeDSL/utils_fp8.py FP8 conversion helpers using PTX inline asm. The f-string expressions now correctly use single-quoted strings inside double-quoted f-strings (e.g., f"...{'.relu' if relu else ''}..."), which is valid Python 3.10+. No import of the previously-missing _target_arch_is_blackwell symbol.
tests/pytorch/mxfp8/test_mxfp8_cutedsl_backend.py Bit-exactness comparison test between CuTeDSL and CUDA backends. Uses pytest.importorskip("tvm_ffi") for clean collection-time skip when tvm_ffi is absent, and skips the whole module when NVTE_ENABLE_CUTEDSL_QUANT_BACKEND is unset. The dbias comparison uses torch.testing.assert_close with default tolerances for a case that is documented as non-bit-identical.
tests/jax/test_mxfp8_cutedsl_backend.py JAX companion to the PyTorch CuTeDSL test. Uses pytest.importorskip("tvm_ffi") and the same NVTE_ENABLE_CUTEDSL_QUANT_BACKEND gate. Correctly excludes COLWISE-only tests (JAX routes those through pure-JAX paths before the FFI).
transformer_engine/common/CMakeLists.txt Adds NVTE_WITH_CUTEDSL option (default ON) that queries the Python environment for the tvm_ffi include path at configure time. Fails with FATAL_ERROR if the package is absent and the option is ON, which is intentional given the tight coupling between C++ and Python-side TVM-FFI globals.
setup.py Adds apache-tvm-ffi>=0.1.12 and nvidia-cutlass-dsl>=4.5.0 to install_requires. These are now mandatory build and runtime dependencies for all Python users, consistent with the decision to always ship CuTeDSL support in Python wheels (runtime opt-out only).

Sequence Diagram

sequenceDiagram
    participant PY as Python __init__.py
    participant TVM as tvm_ffi registry
    participant CPP as C++ nvte_quantize
    participant CACHE as TVMFFIConfigCache
    participant JIT as cute.compile()
    participant CUDA as CUDA C++ fallback

    Note over PY: NVTE_ENABLE_CUTEDSL_QUANT_BACKEND=1
    PY->>TVM: register_global_func("get_mxfp8_quantization_function", ...)
    PY->>TVM: load_tvm_ffi_library() via dlopen

    CPP->>CPP: "mxfp8_quantize_cutedsl<IS_DBIAS,...>()"
    CPP->>CACHE: config.get_kernel() → cache.get_or_load(config)
    CACHE->>CACHE: shared_lock: check map_[id]
    alt cache miss
        CACHE->>TVM: Function::GetGlobal("get_mxfp8_quantization_function")
        CACHE->>TVM: entrypoint(fn_name, dtype, fp8_dtype, rowwise, ...)
        TVM->>JIT: compile_cutedsl_function_from_cfg(cfg)
        JIT-->>TVM: cute.compile() → tvm_ffi registered fn
        TVM-->>CACHE: returns True / False
        CACHE->>CACHE: unique_lock: map_.emplace(id, fn_opt)
    end
    CACHE-->>CPP: "optional<Function>"

    alt kernel available
        CPP->>TVM: "(*fn)(mX, mO_row, mS_row, mO_col, mS_col, mAmax, noop, mActInput, mWorkspace, stream)"
        TVM-->>CPP: kernel runs on GPU
        opt WITH_DBIAS
            CPP->>CUDA: reduce_dbias(workspace → dbias)
        end
    else no kernel (unsupported shape/dtype/device)
        CPP->>CUDA: return false → CUDA C++ kernel path
    end
Loading

Reviews (48): Last reviewed commit: "[pre-commit.ci] auto fixes from pre-comm..." | 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 thread build_tools/pytorch.py Outdated
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 thread transformer_engine/common/CuTeDSL/__init__.py Outdated
Comment thread transformer_engine/common/CuTeDSL/activations.py Outdated
Comment thread transformer_engine/common/CuTeDSL/activations.py Outdated
Comment thread transformer_engine/common/CuTeDSL/activations.py Outdated
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?

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.

You still need to create those additional 1-letter strings in this version. At the very least you could make a "1_" and "0_" strings upfront and use those instead (also, you don't even need the underscore there between those 1s and 0s).

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 OK I just made some changes. Now every quantization config owns their cache and the cache key is uint32 now. This to_key is now only used to build the function name used when registering the function to TVM-FFI registry and it happens only once when you request a not yet ready kernel. Later we will fetch it from C++ cache with uint32 cache key which is more efficient.

Comment thread transformer_engine/common/cast/mxfp8/quantize_mxfp8_cutedsl.cuh
Comment thread transformer_engine/common/cast/mxfp8/quantize_mxfp8_cutedsl.cuh
Comment thread transformer_engine/common/CMakeLists.txt Outdated
@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 Outdated
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 Outdated
Comment thread transformer_engine/common/cast/mxfp8/quantize_mxfp8_cutedsl.cuh Outdated
Comment thread tests/pytorch/mxfp8/test_mxfp8_cutedsl_backend.py Outdated
Comment thread tests/pytorch/mxfp8/test_mxfp8_cutedsl_backend.py
@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>
kainzhong and others added 5 commits August 20, 2026 17:51
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Comment thread transformer_engine/common/CuTeDSL/cast/mxfp8/quantize_mxfp8.py Outdated
kainzhong and others added 6 commits August 20, 2026 21:34
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>
@kainzhong

Copy link
Copy Markdown
Collaborator Author

@greptileai

CHECK_NOOP_FLAG: cutlass.const_expr = (
      not self.cfg.WITH_ACT and not self.cfg.WITH_DACT and not self.cfg.WITH_DBIAS
  )

noop flag won't fire with dbias.

Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
@greptile-apps

greptile-apps Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

You're right. With WITH_DBIAS=True, CHECK_NOOP_FLAG is always False at compile time, so the kernel never reads the noop tensor at runtime — meaning even if the caller sets noop=1.0 to signal "skip this step," the dbias accumulation runs unconditionally.

The question is what the intended noop semantics are when WITH_DBIAS=True:

  1. "Noop skips everything including dbias" — then not self.cfg.WITH_DBIAS in the condition is a bug. The kernel should still check the noop flag and, if set, skip both the FP8 write and the dbias workspace writes. The fix would be to remove not self.cfg.WITH_DBIAS from CHECK_NOOP_FLAG and handle both branches inside the kernel (noop=1 → skip _kernel_main + skip dbias workspace writes → skip reduce_dbias).

  2. "Noop only skips FP8 output, dbias always accumulates" — then forcing CHECK_NOOP_FLAG=False for dbias configs is also wrong, because now even the FP8-write noop path is gone, not just the dbias step.

The CUDA C++ reference path checks the noop tensor before dbias-related work (as the earlier resolved reduce_dbias-on-nooped-workspace comment established), which implies semantics #1 is the intent. If so, CHECK_NOOP_FLAG should remain True even when WITH_DBIAS=True, and the kernel body should skip both the main computation and the dbias workspace writes when the noop flag fires at runtime.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules.md and .greptile/config.json.

@kainzhong

Copy link
Copy Markdown
Collaborator Author

@greptileai in the latest main branch noop is ignored with dbias already:

if constexpr (NO_ACTIVATIONS && !IS_DBIAS) {
    if (noop != nullptr && noop[0] == 1.0f) {
      return;
    }
  }

@greptile-apps

greptile-apps Bot commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

You're right. Looking at the code:

  1. In main, mxfp8::quantize only does the host-side noop early-exit when NO_ACTIVATIONS && !IS_DBIAS — so noop+dbias is already handled correctly there.
  2. In the CuTeDSL path, zero_scales_kernel also mirrors this with check_noop_flag = !config.with_act && !config.with_dact && !config.with_dbias, and the noop pointer is passed to the CuTeDSL kernel to handle on device.

The behaviors are aligned. My concern was unfounded — no issue here.

Comment thread tests/pytorch/mxfp8/test_mxfp8_cutedsl_backend.py Outdated
Comment thread transformer_engine/common/CuTeDSL/utils_fp8.py Outdated
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Comment thread pyproject.toml
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Comment thread transformer_engine/common/CMakeLists.txt
# or if the shape is already divisible by the tile size (so no masking is needed)
if cutlass.const_expr(self.ACT_NEED_MASKING):
skip_masking = (
mX.shape[0] % self.general_divisible_kernel._TILE_ROWS == 0

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.

Don't need to check both directions if we are not quantizing both directions. Only check the direction you quantize

Comment thread transformer_engine/common/CuTeDSL/utils.py
Comment on lines +105 to +121
option(NVTE_WITH_CUTEDSL
"Build the CuTeDSL quantize backend bridge (requires the apache-tvm-ffi Python package)" ON)
if(NVTE_WITH_CUTEDSL)
execute_process(
COMMAND ${Python_EXECUTABLE} -c "import tvm_ffi.libinfo as li; print(li.find_include_path())"
OUTPUT_VARIABLE TVM_FFI_INCLUDE_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE TVM_FFI_INCLUDE_QUERY)
if(NOT TVM_FFI_INCLUDE_QUERY EQUAL 0)
message(FATAL_ERROR
"Could not import the tvm_ffi Python package (with '${Python_EXECUTABLE}'), "
"whose headers Transformer Engine needs to compile the CuTeDSL quantize "
"backend bridge (common/tvm_ffi_bridge.h). Install it into this Python "
"environment: `pip install apache-tvm-ffi`, or configure with "
"-DNVTE_WITH_CUTEDSL=OFF to build the C++ library without the backend.")
endif()
endif()

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.

@fheinecke Could you review this part (+pyproject/setup.py changes) - will this work under build isolation?

kainzhong and others added 2 commits August 22, 2026 00:44
Signed-off-by: Kaining Zhong <kainingz@nvidia.com>
Comment on lines +105 to +120
option(NVTE_WITH_CUTEDSL
"Build the CuTeDSL quantize backend bridge (requires the apache-tvm-ffi Python package)" ON)
if(NVTE_WITH_CUTEDSL)
execute_process(
COMMAND ${Python_EXECUTABLE} -c "import tvm_ffi.libinfo as li; print(li.find_include_path())"
OUTPUT_VARIABLE TVM_FFI_INCLUDE_DIR
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE TVM_FFI_INCLUDE_QUERY)
if(NOT TVM_FFI_INCLUDE_QUERY EQUAL 0)
message(FATAL_ERROR
"Could not import the tvm_ffi Python package (with '${Python_EXECUTABLE}'), "
"whose headers Transformer Engine needs to compile the CuTeDSL quantize "
"backend bridge (common/tvm_ffi_bridge.h). Install it into this Python "
"environment: `pip install apache-tvm-ffi`, or configure with "
"-DNVTE_WITH_CUTEDSL=OFF to build the C++ library without the backend.")
endif()

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 NVTE_WITH_CUTEDSL=ON default breaks builds without apache-tvm-ffi

The option advertises itself as opt-in but defaults to ON, and the failure path is a hard FATAL_ERROR rather than a graceful downgrade. Any existing CMake-based CI pipeline or development environment that does not have apache-tvm-ffi installed will now fail at configure time with no way to proceed without either installing the new package or explicitly passing -DNVTE_WITH_CUTEDSL=OFF. Defaulting the option to OFF — or downgrading the missing-package diagnostic to a WARNING that automatically sets NVTE_WITH_CUTEDSL OFF — would preserve backward compatibility for builds that don't need the CuTeDSL backend.

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.

4 participants