Files
nvfp4-megamoe-kernel/dsv4/kernels/attention/fmha_multitile_capi.cu
biondizzle c0379a0f86 P6: Remove broken TMA store — use direct GMEM write from SMEM
cp.async.bulk.tensor store (SMEM→GMEM) is NOT available on SM100.
The CUTLASS SM100 epilogue uses st.global directly.

The one-way epilogue pipeline is now:
  1. TMEM → regs (tcgen05.ld, warp-collective)
  2. epilogue_op in regs (normalize, FP4 hook via ENABLE_FP4_EPILOGUE)
  3. regs → SMEM (row-major, sO_epi)
  4. SMEM → GMEM (direct write)

This is the same pattern as the MoE kernel but with st.global instead
of TMA store. Multi-CTA (D2) will use st.global with flat_divide coords.

Removed: tma_o from FmhaParams, fmha_multihead_decode_tma_launch,
sMbarStore from SMEM, broken TMA store PTX from fmha_tma.cuh.
2026-05-30 17:11:17 +00:00

139 lines
5.1 KiB
Plaintext

/**
* DSV4 FMHA — Multi-tile kernel C API (TMA-based).
*
* Wraps fmha_6warp_tma_multirow_multitile_kernel with TMA descriptor
* creation and launch. Uses create_tma_desc_2d_bf16 from fmha_tma.cuh
* for correct descriptor format.
*/
#include <cuda.h>
#include <cuda_runtime.h>
#include <cstdint>
#include <cstdio>
#include "fmha_common.cuh"
#include "fmha_umma_desc.cuh"
#include "fmha_tma.cuh"
#include "fmha_6warp_tma_multirow_multitile.cuh"
using namespace dsv4::kernels::attention;
extern "C" {
int fmha_multitile_decode_launch(
const void* q_ptr,
const void* k_ptr,
const void* v_ptr,
void* o_ptr,
void* lse_ptr,
int batch, int n_h, int T, int N, int hd,
int q_head_stride, int q_batch_stride,
int k_head_stride, int k_batch_stride,
int v_head_stride, int v_batch_stride,
int o_head_stride, int o_batch_stride,
int lse_head_stride, int lse_batch_stride,
float scale
) {
size_t desc_count = n_h * batch;
CUtensorMap* d_tma_k;
CUtensorMap* d_tma_v;
cudaMalloc(&d_tma_k, desc_count * sizeof(CUtensorMap));
cudaMalloc(&d_tma_v, desc_count * sizeof(CUtensorMap));
for (int b = 0; b < batch; b++) {
for (int h = 0; h < n_h; h++) {
const bf16_t* k_head = (const bf16_t*)k_ptr + h * k_head_stride + b * k_batch_stride;
const bf16_t* v_head = (const bf16_t*)v_ptr + h * v_head_stride + b * v_batch_stride;
int idx = b * n_h + h;
// K: (N, hd), TMA tile (128, 16)
CUtensorMap h_desc;
if (!create_tma_desc_2d_bf16(&h_desc, k_head, N, hd, 128, 16)) {
cudaFree(d_tma_k); cudaFree(d_tma_v);
return -1;
}
cudaMemcpy(d_tma_k + idx, &h_desc, sizeof(CUtensorMap), cudaMemcpyHostToDevice);
// V: (hd, N), TMA tile (16, 16)
if (!create_tma_desc_2d_bf16(&h_desc, v_head, hd, N, 16, 16)) {
cudaFree(d_tma_k); cudaFree(d_tma_v);
return -1;
}
cudaMemcpy(d_tma_v + idx, &h_desc, sizeof(CUtensorMap), cudaMemcpyHostToDevice);
}
}
FmhaTmaMultiRowMultiTileParams params;
params.q = (const bf16_t*)q_ptr;
params.tma_k = d_tma_k;
params.tma_v = d_tma_v;
params.o = (bf16_t*)o_ptr;
params.lse = (float*)lse_ptr;
params.s_k = N;
params.T = T;
params.n_h = n_h;
params.scale = scale;
params.q_head_stride = q_head_stride;
params.q_batch_stride = q_batch_stride;
params.o_head_stride = o_head_stride;
params.o_batch_stride = o_batch_stride;
params.lse_head_stride = lse_head_stride;
params.lse_batch_stride = lse_batch_stride;
// SMEM size (match kernel layout)
constexpr int HD_CHUNK = 256;
constexpr int TILE_SZ = 128 * MMA_K_BF16;
constexpr int V_SUB_SZ = 16 * MMA_K_BF16;
int hc = (hd <= 256) ? hd : HD_CHUNK;
size_t off = 4;
off = (off+127)&~(size_t)127; // sTmemBase
off += 16; // sMbar
off = (off+127)&~(size_t)127;
off += TILE_SZ * 2; // sTmaBuf
off = (off+127)&~(size_t)127;
off += TILE_SZ * 2; // sQ0
off = (off+127)&~(size_t)127;
off += TILE_SZ * 2; // sK0
off = (off+127)&~(size_t)127;
off += TILE_SZ * 2; // sPk
off = (off+127)&~(size_t)127;
off += V_SUB_SZ * 2; // sV
off = (off+127)&~(size_t)127;
off += 128 * hc * 4; // sOacc
off += 128 * 4; // sRunningMax
off += 128 * 4; // sRunningSum
off += 128 * 4; // sTileRowMax
off += 128 * 4; // sTileRowSum
// P6: sO_epi_rowmajor + sMbarStore
off = (off+127)&~(size_t)127;
off += 128 * hc * 2; // sO_epi_rowmajor (MAX_ROWS * HD_CHUNK BF16)
off += 256; // slack
int smem = (int)((off + 127) & ~(size_t)127);
dim3 grid(1, n_h, batch);
dim3 block(NTHREADS);
if (smem > 48 * 1024) {
if (hd == 64) cudaFuncSetAttribute(fmha_6warp_tma_multirow_multitile_kernel<64>, cudaFuncAttributeMaxDynamicSharedMemorySize, smem);
else if (hd == 128) cudaFuncSetAttribute(fmha_6warp_tma_multirow_multitile_kernel<128>, cudaFuncAttributeMaxDynamicSharedMemorySize, smem);
else if (hd == 256) cudaFuncSetAttribute(fmha_6warp_tma_multirow_multitile_kernel<256>, cudaFuncAttributeMaxDynamicSharedMemorySize, smem);
else if (hd == 512) cudaFuncSetAttribute(fmha_6warp_tma_multirow_multitile_kernel<512>, cudaFuncAttributeMaxDynamicSharedMemorySize, smem);
}
cudaError_t err;
if (hd == 64) fmha_6warp_tma_multirow_multitile_kernel<64><<<grid, block, smem>>>(params);
else if (hd == 128) fmha_6warp_tma_multirow_multitile_kernel<128><<<grid, block, smem>>>(params);
else if (hd == 256) fmha_6warp_tma_multirow_multitile_kernel<256><<<grid, block, smem>>>(params);
else if (hd == 512) fmha_6warp_tma_multirow_multitile_kernel<512><<<grid, block, smem>>>(params);
else { cudaFree(d_tma_k); cudaFree(d_tma_v); return -1; }
err = cudaGetLastError();
cudaFree(d_tma_k);
cudaFree(d_tma_v);
if (err != cudaSuccess) return (int)err;
return 0;
}
} // extern "C"