Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
ddb0d8e
[AMD] Experimental GEMM implementation with Triton
wenchenvincent Nov 18, 2025
8486379
Very rudimentary enablement of bf16. No epilogues.
wenchenvincent Nov 18, 2025
f319f79
Add FP8 support to te_generic_gemm_triton() wrapper
wenchenvincent Jan 11, 2026
760bd42
Add MXFP8 support for Triton GEMM backend
wenchenvincent Jan 27, 2026
9b5f353
Add MXFP8 GEMM test suite
wenchenvincent Jan 27, 2026
0297a51
Fix the fp8 data type for gfx950.
wenchenvincent Jan 28, 2026
26f38b0
Fix MXFP8 Triton implementation to match BLAS behavior
wenchenvincent Feb 18, 2026
281c511
Fix MXFP8 dimension handling in kernel call
wenchenvincent Feb 18, 2026
47b0c59
Fix MXFP8TensorWrapper size determination for columnwise-only tensors
wenchenvincent Feb 18, 2026
0bac3ef
Adopted API change in v2.10.
wenchenvincent Mar 13, 2026
dfdd863
Restructured tests and disabled Triton GEMM for fp8 hybrid recipe due…
wenchenvincent Mar 17, 2026
56268f4
A mxfp8 Triton bug required pytorch release 2.10
wenchenvincent Mar 17, 2026
7fc4c8e
Remove temporary debug/analysis files accidentally included in 2de8c6d
wenchenvincent Mar 17, 2026
46c657c
Fix Triton GEMM tests after rebase onto dev
wenchenvincent Apr 19, 2026
e1fda4d
Fix bias epilogue wiring in te_generic_gemm_triton wrapper
wenchenvincent Apr 19, 2026
2e5ec67
Triton GEMM: α/β accumulate, gfx950 test fixes, mixed-FP8 skip gate, …
wenchenvincent Jul 1, 2026
1d841f7
Triton GEMM: narrow mxfp8/ CI sweep to our tests; drop mxfp8/__init__.py
wenchenvincent Jul 1, 2026
b34b086
Triton GEMM: tighten mixed-FP8 skip gate to torch>=(2,14)
wenchenvincent Jul 8, 2026
818c4d7
Triton GEMM CI: split multi-file mxfp8 line into two calls
wenchenvincent Jul 8, 2026
4695d4b
Triton GEMM: promote M/N pointer offsets to int64 to fix >2^31 addres…
wenchenvincent Jul 8, 2026
8d5542f
test_float8_current_scaling_exact: skip HYBRID recipe under Triton GEMM
wenchenvincent Jul 8, 2026
f2a19d2
Triton GEMM: refuse unsupported QuantizedTensorStorage; skip gate-hit…
wenchenvincent Jul 8, 2026
6892337
test_numerics: skip grouped-vs-sequential equivalence tests under Triton
wenchenvincent Jul 9, 2026
8b3f7d6
Triton GEMM: apply output quantizer when caller requests FP8 output
wenchenvincent Jul 9, 2026
26b3e37
Triton GEMM: prune redundant skip logic and tighten comments
wenchenvincent Jul 9, 2026
e1c5dda
Triton GEMM: move gemm_triton.py into triton_kernels/gemm/ subpackage
wenchenvincent Jul 10, 2026
6177136
Triton GEMM tests: relocate under tests/pytorch/triton_kernels/
wenchenvincent Jul 10, 2026
db6c724
tests/pytorch/mxfp8/: drop our old README
wenchenvincent Jul 10, 2026
3b9bb72
Triton GEMM tests: consolidate test_gemm_fp8 into test_gemm; rename
wenchenvincent Jul 10, 2026
8751219
Triton GEMM: address PR review comments (lazy import, style, tests)
wenchenvincent Jul 10, 2026
e5099e4
Triton GEMM: address wangye805 PR review batch
wenchenvincent Jul 13, 2026
3077ef6
Triton GEMM tests: drop test_gemm_mxfp8.py, redundant with test_gemm.py
wenchenvincent Jul 13, 2026
7a74c6d
test_numerics: reframe grouped-under-Triton skip as sequential-vs-mul…
wenchenvincent Jul 13, 2026
fe5d9d6
Triton GEMM: drop Float8TensorWrapper / MXFP8TensorWrapper, read stor…
wenchenvincent Jul 13, 2026
2379e73
Triton GEMM: post-refactor follow-ups from thorough review
wenchenvincent Jul 13, 2026
f209e01
test_gemm_kernel: reuse str_to_torch_dtype from test_common
wenchenvincent Jul 13, 2026
27a2828
Trigger CI rerun after failures were confirmed to be flakes/unrelated
wenchenvincent Jul 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ci/pytorch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ run_test_config(){
run_default_fa 1 test_fused_router.py
run_default_fa 1 test_fusible_ops.py
run_default_fa 1 test_gemm_autotune.py
NVTE_USE_GEMM_TRITON=1 run_default_fa_lbl "triton" 1 triton_kernels/test_gemm.py
NVTE_USE_GEMM_TRITON=1 run_default_fa_lbl "triton" 1 triton_kernels/test_gemm_kernel.py
run 1 test_gqa.py
run 1 test_jit.py
NVTE_ROCM_ENABLE_MXFP8=1 run_default_fa 1 test_multi_tensor.py
Expand Down Expand Up @@ -85,6 +87,9 @@ run_test_config(){
NVTE_USE_DEQUANTIZE_TRITON=1 NVTE_USE_CAST_TRANSPOSE_TRITON=1 NVTE_USE_RMSNORM_TRITON=1 NVTE_USE_LAYERNORM_TRITON=1 run_default_fa_lbl "triton" 3 test_numerics.py
NVTE_USE_CAST_TRANSPOSE_TRITON=1 NVTE_USE_RMSNORM_TRITON=1 run_default_fa_lbl "triton" 1 test_fusible_ops.py
NVTE_USE_CAST_TRANSPOSE_TRITON=1 run_default_fa_lbl "triton" 1 test_float8_current_scaling_exact.py
NVTE_USE_GEMM_TRITON=1 run_default_fa_lbl "gemm-triton" 3 test_numerics.py
NVTE_USE_GEMM_TRITON=1 run_default_fa_lbl "gemm-triton" 1 test_fusible_ops.py
NVTE_USE_GEMM_TRITON=1 run_default_fa_lbl "gemm-triton" 1 test_float8_current_scaling_exact.py
NVTE_USE_ATOMIC_AMAX=1 run_default_fa_lbl "amax" 3 test_numerics.py
NVTE_USE_ATOMIC_AMAX=1 run_default_fa_lbl "amax" 3 test_fusible_ops.py
NVTE_USE_ATOMIC_AMAX=1 NVTE_USE_CAST_TRANSPOSE_TRITON=1 run_default_fa_lbl "amax+triton" 3 test_numerics.py
Expand Down
42 changes: 42 additions & 0 deletions tests/pytorch/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright (c) 2026, Advanced Micro Devices, Inc. All rights reserved.
#
# See LICENSE for license information.

"""Convert Triton GEMM backend refusals (HYBRID, mixed FP8, NVFP4, ...)
into pytest.skip so the CI sweep under NVTE_USE_GEMM_TRITON=1 does not
flag intentionally-unsupported combinations as failures.
The gates raise ValueError from quantization.py and
triton_kernels/gemm/gemm_wrapper.py; when they are relaxed the marker
text disappears and this hook stops firing.
"""
Comment thread
wangye805 marked this conversation as resolved.

import pytest


# Substrings identifying our Triton GEMM backend refusals. Kept short so
# they are easy to grep.
_TRITON_GEMM_GATE_MARKERS = (
# Mixed FP8 (e4m3 x e5m2) refused at the low-level matmul entry.
"Mixed FP8 types",
# Covers both quantization.py::check_recipe_support (HYBRID) and
# gemm_wrapper._classify_input's refusal of NVFP4 / other
# QuantizedTensorStorage subclasses.
"The Triton GEMM backend (NVTE_USE_GEMM_TRITON=1) does not support",
)


@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_call(item):
"""Convert known Triton GEMM backend gate errors into skips."""
outcome = yield
if outcome.excinfo is None:
return
exc = outcome.excinfo[1]
if not isinstance(exc, ValueError):
return
msg = str(exc)
if any(marker in msg for marker in _TRITON_GEMM_GATE_MARKERS):
outcome.force_exception(
pytest.skip.Exception(f"Triton GEMM backend gate: {msg}")
)
29 changes: 29 additions & 0 deletions tests/pytorch/test_numerics.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,27 @@ def get_nvfp4_inp_supported_dtypes(recipe: recipe.Recipe, dtype: torch.dtype) ->
use_cutlass_grouped_gemm.append(True)


# Marker for tests that compare a sequence of individual `Linear` layers
# against a multi-stream / grouped GEMM (or that otherwise assume a
# bit-exact `rtol=0, atol=0` match). The original invariant these tests
# check is that the same GEMM kernel, used both sequentially and inside
# the multi-stream GEMM, reproduces the same result -- see the upstream
# `# cuBLAS implementation should be bit-wise match` comment.
#
# Under NVTE_USE_GEMM_TRITON=1 the Triton GEMM kernel is NOT used inside
# the multi-stream GEMM path, so the invariant no longer applies to these
# tests. Skip them under the override rather than loosen tolerances just
# to make them pass vacuously.
_skip_grouped_under_gemm_triton = pytest.mark.skipif(
bool(int(os.environ.get("NVTE_USE_GEMM_TRITON", "0"))),
reason=(
"The Triton GEMM kernel is not used inside the multi-stream GEMM "
"path, so the sequential-vs-multi-stream equivalence these tests "
"check does not apply under NVTE_USE_GEMM_TRITON=1."
),
)


def get_causal_attn_mask(sq: int) -> torch.Tensor:
return torch.triu(torch.ones(sq, sq, device="cuda"), diagonal=1).bool()

Expand Down Expand Up @@ -2103,6 +2124,7 @@ def _test_grouped_linear_accuracy(
return outputs


@_skip_grouped_under_gemm_triton
@pytest.mark.parametrize("dtype", param_types, ids=str)
@pytest.mark.parametrize("num_gemms", [3, 6])
@pytest.mark.parametrize("bs", batch_sizes)
Expand Down Expand Up @@ -2231,6 +2253,7 @@ def test_grouped_linear_accuracy(
torch.testing.assert_close(o, o_ref, rtol=rtol, atol=atol)


@_skip_grouped_under_gemm_triton
@pytest.mark.skipif(
torch.cuda.get_device_capability() != (9, 0) and not IS_HIP_EXTENSION,
reason="Only enable CUTLASS grouped gemm on Hopper",
Expand Down Expand Up @@ -2277,6 +2300,7 @@ def test_grouped_linear_accuracy_cutlass(
os.environ.pop("NVTE_USE_CUTLASS_GROUPED_GEMM", None)


@_skip_grouped_under_gemm_triton
@pytest.mark.parametrize("dtype", param_types, ids=str)
@pytest.mark.parametrize("num_gemms", [3])
@pytest.mark.parametrize("bs", [1])
Expand Down Expand Up @@ -2383,6 +2407,7 @@ def test_grouped_linear_accuracy_save_original_input(
torch.testing.assert_close(o, o_ref, rtol=0, atol=0)


@_skip_grouped_under_gemm_triton
@pytest.mark.parametrize("recipe", fp8_recipes + [None])
def test_grouped_linear_accuracy_single_gemm(recipe):
"""Split the tests to save CI time"""
Expand Down Expand Up @@ -2493,6 +2518,7 @@ def _generate_random_numbers(n, total_sum):
return outputs


@_skip_grouped_under_gemm_triton
@pytest.mark.parametrize("dtype", param_types)
@pytest.mark.parametrize("num_gemms", [3, 6])
@pytest.mark.parametrize("bs", batch_sizes)
Expand Down Expand Up @@ -2568,6 +2594,7 @@ def test_padding_grouped_linear_accuracy(
torch.testing.assert_close(o, o_ref, rtol=0, atol=0)


@_skip_grouped_under_gemm_triton
@pytest.mark.parametrize("dtype", param_types)
@pytest.mark.parametrize("num_gemms", [3])
@pytest.mark.parametrize("bs", [1])
Expand Down Expand Up @@ -2988,6 +3015,7 @@ def test_transformer_layer_hidden_states_format(dtype, bs, model):
)


@_skip_grouped_under_gemm_triton
@pytest.mark.parametrize(
"shape",
[
Expand Down Expand Up @@ -3740,6 +3768,7 @@ def test_fp8gemm_with_unfused_quantization(N, datatype, input_quantizer, out_qua
torch.testing.assert_close(expected_quantized_out.dequantize(), quantized_out.dequantize())


@_skip_grouped_under_gemm_triton
@pytest.mark.parametrize(
"shape",
[
Expand Down
Loading
Loading