Skip to content

Commit 3196835

Browse files
committed
feat(vsa): add native sm103a support
Signed-off-by: lishunyang12 <lishunyang12@163.com>
1 parent 0bd19a9 commit 3196835

18 files changed

Lines changed: 94 additions & 81 deletions

.github/workflows/publish-kernel.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ jobs:
6363
torch-cuda-short: 'cu130'
6464
platform:
6565
# x86_64 builds the full cu126 + cu130 set. cu130 ships the
66-
# data-center Blackwell sm_100a VSA and consumer sm_120a FP4
66+
# data-center Blackwell sm_100a/sm_103a VSA and consumer sm_120a FP4
6767
# kernels.
6868
- os: ubuntu-22.04
6969
arch: x86_64
@@ -169,7 +169,7 @@ jobs:
169169
# covers sm_120a; turbodiffusion covers sm_100a+sm_120a. The sm_100 FP4
170170
# forward is the FA4 CuTe DSL path in the fastvideo package (PR #1221),
171171
# JIT-compiled at runtime — not built into this wheel.
172-
# * x86_64 cu130 = Hopper TK + data-center Blackwell sm_100a VSA
172+
# * x86_64 cu130 = Hopper TK + data-center Blackwell sm_100a/sm_103a VSA
173173
# + consumer Blackwell sm_120a FP4.
174174
# * x86_64 cu126 = Hopper TK only (older drivers; CUDA < 12.8 has no FP4).
175175
# The per-arch split in CMakeLists pins the FP4 targets to sm_120a and builds

fastvideo-kernel/CMakeLists.txt

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ if(NOT GPU_BACKEND STREQUAL "ROCM")
7272
else()
7373
# Best-effort probe of the visible GPU (mirrors build.sh detect_with_torch).
7474
execute_process(
75-
COMMAND "${Python_EXECUTABLE}" -c "import torch; assert torch.cuda.is_available(); mj, mn = torch.cuda.get_device_capability(0); print(f'{mj}.{mn}a' if (mj, mn) in ((9, 0), (12, 0)) else f'{mj}.{mn}')"
75+
COMMAND "${Python_EXECUTABLE}" -c "import torch; assert torch.cuda.is_available(); mj, mn = torch.cuda.get_device_capability(0); print(f'{mj}.{mn}a' if (mj, mn) in ((9, 0), (10, 0), (10, 3), (12, 0)) else f'{mj}.{mn}')"
7676
OUTPUT_VARIABLE _FV_ARCH_LIST
7777
OUTPUT_STRIP_TRAILING_WHITESPACE
7878
RESULT_VARIABLE _fv_detect_rc
@@ -382,11 +382,11 @@ if(BUILD_CXX_KERNELS)
382382
# Combined FastVideo Extension
383383
# Using name 'fastvideo_kernel_ops' to distinguish from the python package namespace
384384
# ---------------------------------------------------------------------------
385-
# VSA block-sparse attention forward, Blackwell (sm_100a) only.
385+
# VSA block-sparse attention forward, data-center Blackwell (sm_100a/sm_103a).
386386
#
387-
# NOTE the "a" suffix: -arch=sm_100a is NOT enough -- it emits a plain sm_100 target and
388-
# ptxas rejects every tcgen05 / setmaxnreg instruction. The explicit gencode spelling
389-
# below is required, and matches the 10.0a entry in TORCH_CUDA_ARCH_LIST.
387+
# NOTE the "a" suffix: these kernels use architecture-conditional tcgen05 / setmaxnreg
388+
# instructions. Explicit gencode entries are required for both the GB200 (sm_100a) and
389+
# B300/GB300 (sm_103a) images. The source body is shared; ptxas specializes each image.
390390
#
391391
# Built for 64-token sparse blocks -- FastVideo's default (4,4,4) tiling, so no
392392
# tile-size change and no top-k granularity change is needed. VSA_BHSD
@@ -396,21 +396,21 @@ if(BUILD_CXX_KERNELS)
396396
# exported (build.sh, and `pip install` with it set) the branch above only prints it --
397397
# the cmake variable stays empty, so testing that alone silently skips the kernel and
398398
# leaves a build that succeeds with the op missing.
399-
set(ENABLE_VSA_SM100A OFF)
399+
set(ENABLE_VSA_SM100_FAMILY OFF)
400400
set(_VSA_ARCH_LIST "${TORCH_CUDA_ARCH_LIST}")
401401
if(NOT _VSA_ARCH_LIST AND DEFINED ENV{TORCH_CUDA_ARCH_LIST})
402402
set(_VSA_ARCH_LIST "$ENV{TORCH_CUDA_ARCH_LIST}")
403403
endif()
404-
if(_VSA_ARCH_LIST MATCHES "(^|[; ,])(10\\.0a|100a|sm_100a)([; ,]|$)")
405-
set(ENABLE_VSA_SM100A ON)
404+
if(_VSA_ARCH_LIST MATCHES "(^|[; ,])(10\\.(0|3)a|10(0|3)a|sm_10(0|3)a)([; ,]|$)")
405+
set(ENABLE_VSA_SM100_FAMILY ON)
406406
endif()
407-
if(ENABLE_VSA_SM100A)
408-
message(STATUS "fastvideo-kernel: building block_sparse_sm100a (Blackwell, 64- and 128-token blocks)")
407+
if(ENABLE_VSA_SM100_FAMILY)
408+
message(STATUS "fastvideo-kernel: building block_sparse_sm100a (sm_100a/sm_103a, 64- and 128-token blocks)")
409409
list(APPEND EXTENSION_SOURCES csrc/attention/block_sparse_sm100a.cu
410410
csrc/attention/block_sparse_blk128_sm100a.cu)
411411
set_source_files_properties(csrc/attention/block_sparse_sm100a.cu
412412
csrc/attention/block_sparse_blk128_sm100a.cu PROPERTIES
413-
COMPILE_OPTIONS "-gencode;arch=compute_100a,code=sm_100a;-DVSA_BHSD=true")
413+
COMPILE_OPTIONS "-gencode;arch=compute_100a,code=sm_100a;-gencode;arch=compute_103a,code=sm_103a;-DVSA_BHSD=true")
414414
endif()
415415

416416
Python_add_library(fastvideo_kernel_ops MODULE USE_SABI ${SKBUILD_SABI_VERSION} WITH_SOABI
@@ -428,7 +428,7 @@ if(BUILD_CXX_KERNELS)
428428

429429
# Build compile definitions list
430430
set(COMPILE_DEFS TORCH_EXTENSION_NAME=fastvideo_kernel_ops)
431-
if(ENABLE_VSA_SM100A)
431+
if(ENABLE_VSA_SM100_FAMILY)
432432
list(APPEND COMPILE_DEFS TK_COMPILE_BLOCK_SPARSE_VSA_SM100A)
433433
endif()
434434
if(ENABLE_TK_KERNELS)

fastvideo-kernel/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Compiled CUDA extensions (CMake, see the build summary printed at the end of eve
1010
|---|---|---|---|---|
1111
| `fastvideo_kernel._C.fastvideo_kernel_ops` | TurboDiffusion INT8 GEMM, quant, RMSNorm, LayerNorm | `csrc/turbodiffusion/` | every arch in `TORCH_CUDA_ARCH_LIST` | always built |
1212
| same extension, optional part | ThunderKittens sliding-tile attention (`sta_fwd`) and VSA block-sparse (`block_sparse_fwd/bwd`) | `csrc/attention/*_h100.cu` | Hopper `sm_90a` only | `FASTVIDEO_KERNEL_BUILD_TK` (AUTO = ON iff `9.0a` is in the arch list; always OFF on aarch64 hosts — TK headers don't compile there) |
13-
| same extension, optional part | MiniMax-H3 block-sparse VSA forward (64- and 128-token blocks) | `csrc/attention/block_sparse*_sm100a.cu` | Blackwell `sm_100a` only | ON iff `10.0a` is in `TORCH_CUDA_ARCH_LIST` |
13+
| same extension, optional part | MiniMax-H3 block-sparse VSA forward (64- and 128-token blocks) | `csrc/attention/block_sparse*_sm100a.cu` | Data-center Blackwell `sm_100a`/`sm_103a` | ON iff `10.0a` or `10.3a` is in `TORCH_CUDA_ARCH_LIST` |
1414
| same extension, optional part | fused NVLink Ulysses all-to-all | `csrc/comm/ulysses_all_to_all.cu` | CUDA | `FASTVIDEO_KERNEL_BUILD_ULYSSES_A2A` (AUTO = ON with NCCL 2.29+ device headers and library; always OFF on ROCm) |
1515
| `fp4attn_cuda`, `fp4quant_cuda` | FP4 attention + quantization ("attn_qat_infer", modified SageAttention3) | `attn_qat_infer/` | consumer Blackwell `sm_120a` only, CUDA ≥ 12.8 | `FASTVIDEO_KERNEL_BUILD_ATTN_QAT_INFER` (AUTO = ON iff `12.0a` is in the arch list) |
1616

@@ -37,7 +37,7 @@ Runtime-JIT kernels (no build step, ship in every wheel/image):
3737
Notes:
3838

3939
- No Docker image ships the FP4 kernels; only the x86_64/aarch64 cu130 wheels do.
40-
- Both cu130 PyPI wheels ship the MiniMax-H3 sm_100a VSA forward.
40+
- Both cu130 PyPI wheels ship native sm_100a and sm_103a images for the MiniMax-H3 VSA forward.
4141
- On arm64 images (GH200 included) STA/VSA run on the Triton fallbacks, since TK never builds on aarch64.
4242
- Ulysses AUTO builds only when CMake finds a NCCL library and device-API headers with the 2.29 initializers. Use
4343
`-DFASTVIDEO_KERNEL_BUILD_ULYSSES_A2A=ON` to require it or `OFF` to test the portable build.

fastvideo-kernel/build.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ if [ "${GPU_BACKEND}" = "CUDA" ]; then
139139
if [ -z "${TORCH_CUDA_ARCH_LIST:-}" ]; then
140140
if [ "${cc_major}" = "9" ] && [ "${cc_minor}" = "0" ]; then
141141
export TORCH_CUDA_ARCH_LIST="9.0a"
142+
elif [ "${cc_major}" = "10" ] && { [ "${cc_minor}" = "0" ] || [ "${cc_minor}" = "3" ]; }; then
143+
# Data-center Blackwell VSA uses architecture-conditional tcgen05
144+
# instructions and therefore requires the 'a' target.
145+
export TORCH_CUDA_ARCH_LIST="${cc_major}.${cc_minor}a"
142146
elif [ "${cc_major}" = "12" ] && [ "${cc_minor}" = "0" ]; then
143147
# Blackwell sm_120 needs the arch-conditional 'a' suffix so CMake's
144148
# AUTO gate (matches 12.0a/120a/sm_120a) builds the attn_qat_infer

fastvideo-kernel/csrc/attention/block_sparse_kernel_sm100a.cuh

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
// block_sparse_kernel_sm100a.cuh -- VSA block-sparse FMHA forward (per-q-block top-k), sm_100a.
1+
// block_sparse_kernel_sm100a.cuh -- VSA block-sparse FMHA forward (per-q-block top-k),
2+
// data-center Blackwell sm_100a/sm_103a. The filename is retained for API compatibility.
23
// Warp-specialized: load / MMA (tcgen05) / softmax / correction / epilogue / scheduler.
34
// Writes O and, when asked, the log-sum-exp the backward consumes.
45
//
@@ -202,15 +203,14 @@ fmha_context_bf16_gen_kernel(const __grid_constant__ CUtensorMap tmap_q,
202203
const int* __restrict__ variable_block_sizes,
203204
float* __restrict__ lse_out) {
204205
// Multi-arch builds: torch's cmake appends -gencode for EVERY entry of
205-
// TORCH_CUDA_ARCH_LIST to this TU on top of the pinned compute_100a pass, and
206-
// tcgen05/setmaxnreg do not exist outside sm_100a -- ptxas rejects the sm_120a
207-
// (or plain sm_100) pass outright. Keep the body only where it can compile:
208-
// the host pass (no __CUDA_ARCH__, needed for launch plumbing) and the
209-
// sm_100a device pass (arch 1000 WITH the family-specific feature set that the
210-
// "a" suffix defines). Every other device pass gets an empty stub; the Python
211-
// is_supported() / host launcher never dispatch here off sm_100, so the stub
212-
// is unreachable at runtime.
213-
#if !defined(__CUDA_ARCH__) || (__CUDA_ARCH__ == 1000 && defined(__CUDA_ARCH_FEAT_SM100_ALL))
206+
// TORCH_CUDA_ARCH_LIST to this TU on top of the pinned data-center Blackwell
207+
// passes. tcgen05/setmaxnreg require an architecture-conditional target, so
208+
// plain sm_100/sm_103 and consumer sm_120 passes cannot compile this body.
209+
// Keep it for the host pass (needed for launch plumbing) plus sm_100a/sm_103a;
210+
// every other device pass gets an unreachable empty stub.
211+
#if !defined(__CUDA_ARCH__) || \
212+
((__CUDA_ARCH__ == 1000 && defined(__CUDA_ARCH_FEAT_SM100_ALL)) || \
213+
(__CUDA_ARCH__ == 1030 && defined(__CUDA_ARCH_FEAT_SM103_ALL)))
214214

215215
const int total_workitems = num_samples * num_heads * packed_mtiles_per_seq;
216216

@@ -1070,7 +1070,7 @@ fmha_context_bf16_gen_kernel(const __grid_constant__ CUtensorMap tmap_q,
10701070
}
10711071
__syncthreads();
10721072
if (warp_id == 0) tcgen05_dealloc<1>(tmem_base, TMEM_TOTAL);
1073-
#endif // host pass or sm_100a device pass (multi-arch guard; see note at the top of the body)
1073+
#endif // host pass or sm_100a/sm_103a device pass (see multi-arch note above)
10741074
}
10751075

10761076
} // namespace VSA_NAMESPACE

fastvideo-kernel/csrc/attention/block_sparse_launch_sm100a.cuh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef BLOCK_SPARSE_VSA_LAUNCH_SM100A_CUH
22
#define BLOCK_SPARSE_VSA_LAUNCH_SM100A_CUH
33

4-
// Launch surface for the sm_100a VSA block-sparse FMHA forward.
4+
// Launch surface for the sm_100a/sm_103a VSA block-sparse FMHA forward.
55
//
66
// Everything a caller needs: a POD argument struct, a predicate saying whether this build can
77
// run those arguments, and one launch entry point. The benchmark in

fastvideo-kernel/csrc/attention/block_sparse_sm100a.cu

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// block_sparse_sm100a.cu -- torch binding for the sm_100a VSA block-sparse FMHA forward.
1+
// block_sparse_sm100a.cu -- torch binding for the sm_100a/sm_103a VSA block-sparse FMHA forward.
22
//
33
// Forward only: returns (out, lse) so FastVideo's existing Triton backward keeps working
44
// unchanged. lse is exactly the M tensor triton_block_sparse_attn_forward writes --

fastvideo-kernel/csrc/attention/primitives.cuh

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// primitives.cuh -- device primitives for the sm_100a VSA block-sparse attention
1+
// primitives.cuh -- device primitives for the sm_100a/sm_103a VSA block-sparse attention
22
// forward: tcgen05 (alloc / mma / ld / st / commit / wait / fence), TMA load / store /
33
// tensormap, mbarrier, cluster launch control, setmaxnreg, fast math, and the FMHA helpers.
44
//
@@ -874,4 +874,3 @@ __device__ __forceinline__
874874
void sts_f32(uint32_t smem_addr, float val) {
875875
asm volatile("st.shared.f32 [%0], %1;" :: "r"(smem_addr), "f"(val) : "memory");
876876
}
877-

fastvideo-kernel/csrc/common_extension.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,10 @@ PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
5050
#ifdef TK_COMPILE_BLOCK_SPARSE_VSA_SM100A
5151
m.def("block_sparse_sm100a_fwd",
5252
torch::wrap_pybind_function(block_sparse_sm100a_fwd),
53-
"VSA block-sparse attention forward, 64-token blocks (Blackwell sm100a)");
53+
"VSA block-sparse attention forward, 64-token blocks (Blackwell sm100a/sm103a)");
5454
m.def("block_sparse_sm100a_blk128_fwd",
5555
torch::wrap_pybind_function(block_sparse_sm100a_blk128_fwd),
56-
"VSA block-sparse attention forward, 128-token blocks (Blackwell sm100a)");
56+
"VSA block-sparse attention forward, 128-token blocks (Blackwell sm100a/sm103a)");
5757
#endif
5858

5959
#ifdef TK_COMPILE_ST_ATTN

fastvideo-kernel/python/fastvideo_kernel/block_sparse_attn.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ def _force_tk() -> bool:
5050

5151

5252
def _force_sm100a() -> bool:
53-
"""True iff the sm_100a (Blackwell) forward is explicitly opted into.
53+
"""True iff the data-center Blackwell forward is explicitly opted into.
5454
55-
Opt-in only (same env the H3 backend honors): the sm_100a extension is
55+
Opt-in only (same legacy-named env the H3 backend honors): the extension is
5656
forward-only, so this routing pairs it with the Triton backward -- its lse
5757
is already in Triton's M format. Honored only when
5858
``block_sparse_attn_sm100a.is_supported`` passes. Unsupported 64-token
@@ -370,10 +370,10 @@ def _backward_sm90(ctx, grad_o, grad_lse):
370370
block_sparse_attn_sm90.register_autograd(_backward_sm90, setup_context=_setup_context_sm90)
371371

372372
# ---------------------------------------------------------------------------
373-
# SM100A backend custom op (index-native)
373+
# Data-center Blackwell backend custom op (index-native; legacy sm100a API name)
374374
#
375-
# Forward runs the sm_100a CUDA extension; backward reuses the Triton kernels.
376-
# The sm_100a forward emits lse in exactly Triton's M format (max*log2e +
375+
# Forward runs the sm_100a/sm_103a CUDA extension; backward reuses the Triton kernels.
376+
# The native forward emits lse in exactly Triton's M format (max*log2e +
377377
# log2(l)), so the pairing needs no conversion. The Triton backward is
378378
# hardcoded to 64-token blocks, hence the block-size assert below.
379379
# ---------------------------------------------------------------------------
@@ -428,7 +428,7 @@ def _backward_sm100a(ctx, grad_o, grad_M):
428428
block = q.shape[2] // variable_block_sizes.numel()
429429
if block != 64:
430430
raise RuntimeError(
431-
"block_sparse_attn_sm100a backward pairs the sm_100a forward with the "
431+
"block_sparse_attn_sm100a backward pairs the sm_100a/sm_103a forward with the "
432432
f"Triton backward, which is hardcoded to 64-token blocks; got {block}. "
433433
"Run 128-token-block metadata without grad, or use the Triton forward.")
434434
dq, dk, dv = block_sparse_attn_backward_triton(grad_o, q, k, v, o, M, q2k_idx,
@@ -464,7 +464,8 @@ def block_sparse_attn_from_indices(
464464

465465
# Backend resolution:
466466
# - FASTVIDEO_VSA_TRITON forces Triton everywhere.
467-
# - FASTVIDEO_VSA_SM100A opts into the sm_100a forward (Triton backward).
467+
# - FASTVIDEO_VSA_SM100A opts into the data-center Blackwell forward
468+
# (Triton backward). The environment name is retained for compatibility.
468469
# Unsupported 64-token metadata falls through; unsupported 128-token
469470
# metadata raises because Triton cannot consume it.
470471
# - FASTVIDEO_VSA_TK requests sm_90 TK; honored only when it's actually
@@ -478,9 +479,9 @@ def block_sparse_attn_from_indices(
478479
variable_block_sizes)
479480
if _infer_block_size(q, variable_block_sizes) == 128:
480481
raise NotImplementedError(
481-
"128-token block-sparse attention requires the sm_100a forward; "
482+
"128-token block-sparse attention requires the sm_100a/sm_103a forward; "
482483
"the Triton fallback only supports 64-token blocks, and the "
483-
"sm_100a route is unavailable for this input.")
484+
"native data-center Blackwell route is unavailable for this input.")
484485
use_sm90 = sm90_available
485486
elif _force_tk():
486487
use_sm90 = sm90_available

0 commit comments

Comments
 (0)