Skip to content

Commit 1bf0393

Browse files
committed
Auto-select MXFP8 consumer warps
1 parent 70adfec commit 1bf0393

3 files changed

Lines changed: 44 additions & 3 deletions

File tree

test/test_mxfp8_tma.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
MXFP8_TMA_PROFILE_TAGS,
1414
get_mxfp8_tma_gemv,
1515
mxfp8_tma_gemv,
16+
select_mxfp8_tma_compute_warps,
1617
)
1718
from transformer_nuggets.cute.mxfp8_tma import app
1819
from transformer_nuggets.cute.profiler import profile_session
@@ -30,6 +31,16 @@ def quantize_mxfp8(value: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
3031
return quantized.reshape_as(value), (exponent + 127).to(torch.uint8)
3132

3233

34+
@pytest.mark.parametrize(
35+
("k", "block_n", "expected_sm100"),
36+
[(8192, 4, 1), (8192, 8, 2), (8192, 16, 4), (4096, 4, 2), (4096, 8, 4)],
37+
)
38+
def test_select_mxfp8_tma_compute_warps(k, block_n, expected_sm100):
39+
"""Bake in the measured B200 rows-per-warp crossover."""
40+
expected = expected_sm100 if torch.cuda.get_device_capability() == (10, 0) else 1
41+
assert select_mxfp8_tma_compute_warps(k, block_n) == expected
42+
43+
3344
def dequantize_mxfp8(value: torch.Tensor, scale: torch.Tensor) -> torch.Tensor:
3445
"""Dequantize raw MXFP8 storage to float32."""
3546
expanded_scale = scale.view(torch.float8_e8m0fnu).float().repeat_interleave(32, dim=1)

transformer_nuggets/cute/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"Mxfp8TmaGemv",
1919
"get_mxfp8_tma_gemv",
2020
"mxfp8_tma_gemv",
21+
"select_mxfp8_tma_compute_warps",
2122
}
2223

2324
_SYMMETRIC_MEMORY_EXPORTS = {

transformer_nuggets/cute/mxfp8_tma.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import operator
66
from functools import cache
77
from pathlib import Path
8+
from typing import Annotated
89

910
import torch
1011
import typer
@@ -559,6 +560,24 @@ def get_mxfp8_tma_gemv(
559560
)
560561

561562

563+
def select_mxfp8_tma_compute_warps(
564+
k: int,
565+
block_n: int,
566+
device: torch.device | str | int | None = None,
567+
) -> int:
568+
"""Select the B200-tuned consumer-warp count for a CTA row tile."""
569+
if torch.cuda.get_device_capability(device) != (10, 0):
570+
return 1
571+
target_rows_per_warp = 4 if k >= 8192 else 2
572+
for num_compute_warps in (4, 2, 1):
573+
if (
574+
block_n % num_compute_warps == 0
575+
and block_n // num_compute_warps >= target_rows_per_warp
576+
):
577+
return num_compute_warps
578+
return 1
579+
580+
562581
def mxfp8_tma_gemv(
563582
q_input: torch.Tensor,
564583
weight: torch.Tensor,
@@ -570,7 +589,7 @@ def mxfp8_tma_gemv(
570589
output: torch.Tensor | None = None,
571590
enable_profiling: bool = False,
572591
profile_buffer: torch.Tensor | None = None,
573-
num_compute_warps: int = 1,
592+
num_compute_warps: int | None = None,
574593
) -> torch.Tensor:
575594
"""Compute raw-layout MXFP8 GEMV on prequantized inputs.
576595
@@ -584,13 +603,18 @@ def mxfp8_tma_gemv(
584603
output: Optional caller-owned contiguous ``[1, N]`` BF16 output.
585604
enable_profiling: Compile a separate specialization with labeled region timing.
586605
profile_buffer: Buffer from ``profile_session`` for the profiled specialization.
587-
num_compute_warps: Consumer warps sharing each CTA's output-row tile.
606+
num_compute_warps: Consumer warps sharing each CTA's output-row tile. ``None``
607+
selects the B200-tuned value and remains one warp on other architectures.
588608
589609
Returns:
590610
The provided or newly allocated output tensor.
591611
"""
592612
if q_input.ndim != 2 or weight.ndim != 2:
593613
raise ValueError("q_input and weight must be rank-2 tensors")
614+
if num_compute_warps is None:
615+
num_compute_warps = select_mxfp8_tma_compute_warps(
616+
q_input.shape[1], block_n, q_input.device
617+
)
594618
return get_mxfp8_tma_gemv(
595619
weight.shape[0],
596620
q_input.shape[1],
@@ -627,7 +651,10 @@ def profile_mxfp8_tma(
627651
k: int = 8192,
628652
block_n: int = 4,
629653
num_stages: int = 2,
630-
num_compute_warps: int = 1,
654+
num_compute_warps: Annotated[
655+
int | None,
656+
typer.Option(help="Compute warps per CTA; defaults to the architecture-tuned value."),
657+
] = None,
631658
output: Path = Path("mxfp8_tma.pftrace"),
632659
seed: int = 0,
633660
warmups: int = 1,
@@ -647,6 +674,8 @@ def profile_mxfp8_tma(
647674
weight, weight_scale = quantize_mxfp8_tensor(
648675
torch.randn((n, k), dtype=torch.bfloat16, device=torch_device)
649676
)
677+
if num_compute_warps is None:
678+
num_compute_warps = select_mxfp8_tma_compute_warps(k, block_n, torch_device)
650679
op = get_mxfp8_tma_gemv(
651680
n,
652681
k,

0 commit comments

Comments
 (0)