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.
139 lines
5.1 KiB
Plaintext
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"
|