Automated PR - 2026-07-07
This commit is contained in:
@@ -0,0 +1,287 @@
|
||||
#include "cutlass/cutlass.h"
|
||||
#include "cutlass/layout/layout.h"
|
||||
#include <cute/tensor.hpp>
|
||||
#include <c10/cuda/CUDAException.h>
|
||||
#include <torch/extension.h>
|
||||
#include <torch/python.h>
|
||||
#include <cuda_runtime.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "kernel_traits.cuh"
|
||||
#include "static_switch.h"
|
||||
|
||||
namespace sm89{
|
||||
using namespace cute;
|
||||
|
||||
__device__ static void copy_1d(float* gmem_src, float* smem_dst)
|
||||
{
|
||||
|
||||
uint32_t smem_int_ptr = cast_smem_ptr_to_uint((void*)smem_dst);
|
||||
asm volatile("cp.async.ca.shared.global.L2::128B [%0], [%1], %2;\n"
|
||||
:: "r"(smem_int_ptr),
|
||||
"l"(gmem_src),
|
||||
"n"(sizeof(float)));
|
||||
}
|
||||
|
||||
template <typename KernelTraits=gemm_traits<128, 256, 2, 4096, 2, 4, true, half_t, bfloat16_t>>
|
||||
__global__ void gemm_fp8_kernel(float_e4m3_t* Aptr, float* sfa, float_e4m3_t* Bptr, float* sfb, float* bias_ptr, void* out, int M, int N, int K, int TMA_ALIGNED_M){
|
||||
using output_t = typename KernelTraits::out_t;
|
||||
using SmemLayoutA = typename KernelTraits::SmemLayoutA;
|
||||
using SmemLayoutB = typename KernelTraits::SmemLayoutB;
|
||||
using SmemLayoutC = typename KernelTraits::SmemLayoutC;
|
||||
|
||||
constexpr int BM = KernelTraits::BM;
|
||||
constexpr int BN = KernelTraits::BN;
|
||||
constexpr int BK = KernelTraits::BK;
|
||||
constexpr int Ksfa = KernelTraits::KSF;
|
||||
constexpr bool has_bias = KernelTraits::HasBias;
|
||||
extern __shared__ float smem_[];
|
||||
float *bias_shm = smem_;
|
||||
float *sfa_shm = reinterpret_cast<float*>(bias_shm + cosize(typename KernelTraits::SmemLayoutBias{}));
|
||||
|
||||
output_t* C_shm = reinterpret_cast<output_t*>(sfa_shm + cosize(typename KernelTraits::SmemLayoutSFA{}));
|
||||
float_e4m3_t* A_shm = reinterpret_cast<float_e4m3_t*>(sfa_shm + cosize(typename KernelTraits::SmemLayoutSFA{}));
|
||||
float_e4m3_t* B_shm = reinterpret_cast<float_e4m3_t*>(A_shm + cosize(SmemLayoutA{}));
|
||||
|
||||
int idx = threadIdx.x;
|
||||
int ix = blockIdx.x;
|
||||
int iy = blockIdx.y;
|
||||
// sfa += BM * iy;
|
||||
sfb += KernelTraits::NUM_SFB_PER_STEP * ix * Ksfa;
|
||||
|
||||
|
||||
output_t* Cptr = reinterpret_cast<output_t*>(out);
|
||||
|
||||
Tensor A = make_tensor(make_gmem_ptr(Aptr), make_shape(M, K), make_stride(K, Int<1>{}));
|
||||
Tensor B = make_tensor(make_gmem_ptr(Bptr), make_shape(N, K), make_stride(K, Int<1>{}));
|
||||
Tensor D = make_tensor(make_gmem_ptr(Cptr), make_shape(M, N), make_stride(N, Int<1>{}));
|
||||
Tensor SFA = make_tensor(make_gmem_ptr(sfa), make_shape(M, Ksfa), make_stride(Int<1>{}, TMA_ALIGNED_M));
|
||||
|
||||
Tensor gA = local_tile(A, make_tile(Int<BM>{}, Int<BK>{}), make_coord(iy, _));
|
||||
Tensor gB = local_tile(B, make_tile(Int<BN>{}, Int<BK>{}), make_coord(ix, _));
|
||||
Tensor gD = local_tile(D, make_tile(Int<BM>{}, Int<BN>{}), make_coord(iy, ix));
|
||||
Tensor gSFA = local_tile(SFA, make_tile(Int<BM>{}, Int<1>{}), make_coord(iy, _));
|
||||
|
||||
auto sBias = make_tensor(make_smem_ptr(bias_shm), typename KernelTraits::SmemLayoutBias{});
|
||||
if constexpr (has_bias){
|
||||
Tensor Bias = make_tensor(make_gmem_ptr(bias_ptr), make_shape(_1{}, N), make_stride(N, Int<1>{}));
|
||||
Tensor gBias = local_tile(Bias, make_tile(Int<1>{}, Int<BN>{}), make_coord(_, ix));
|
||||
typename KernelTraits::G2SBiasCopy g2s_bias_copy;
|
||||
auto g2s_bias_thr_copy = g2s_bias_copy.get_slice(idx);
|
||||
auto tCBiasgBias = g2s_bias_thr_copy.partition_S(gBias);
|
||||
auto tCBiassBias = g2s_bias_thr_copy.partition_D(sBias);
|
||||
if(idx < BN){
|
||||
copy_1d((float*)&gBias(0) + idx, (float*)&sBias(0) + idx);
|
||||
}
|
||||
}
|
||||
|
||||
auto sSFA = make_tensor(make_smem_ptr(sfa_shm), typename KernelTraits::SmemLayoutSFA{});
|
||||
auto sA = make_tensor(make_smem_ptr(A_shm), SmemLayoutA{});
|
||||
auto sB = make_tensor(make_smem_ptr(B_shm), SmemLayoutB{});
|
||||
|
||||
typename KernelTraits::MMATile tiled_mma;
|
||||
auto thr_mma = tiled_mma.get_slice(threadIdx.x);
|
||||
|
||||
auto tCrA = thr_mma.partition_fragment_A(gA(_, _, 0));
|
||||
auto tCrB = thr_mma.partition_fragment_B(gB(_, _, 0));
|
||||
auto tCrD = thr_mma.partition_fragment_C(gD);
|
||||
clear(tCrD);
|
||||
auto tCrD_fp32 = make_tensor_like<float>(tCrD);
|
||||
clear(tCrD_fp32);
|
||||
|
||||
typename KernelTraits::G2STiledCopy g2s_tiled_copy;
|
||||
auto g2s_thr_copy = g2s_tiled_copy.get_slice(idx);
|
||||
auto tAgA_copy = g2s_thr_copy.partition_S(gA);
|
||||
auto tAsA_copy = g2s_thr_copy.partition_D(sA);
|
||||
auto tBgB_copy = g2s_thr_copy.partition_S(gB);
|
||||
auto tBsB_copy = g2s_thr_copy.partition_D(sB);
|
||||
|
||||
auto s2r_tiled_copy_a = make_tiled_copy_A(typename KernelTraits::S2RCopyAtomA{}, tiled_mma);
|
||||
auto s2r_thr_copy_a = s2r_tiled_copy_a.get_slice(idx);
|
||||
auto tAsA = s2r_thr_copy_a.partition_S(sA);
|
||||
auto tCrA_view = s2r_thr_copy_a.retile_D(tCrA);
|
||||
|
||||
|
||||
auto s2r_tiled_copy_b = make_tiled_copy_B(typename KernelTraits::S2RCopyAtomB{}, tiled_mma);
|
||||
auto s2r_thr_copy_b = s2r_tiled_copy_b.get_slice(idx);
|
||||
auto tBsB = s2r_thr_copy_b.partition_S(sB);
|
||||
auto tCrB_view = s2r_thr_copy_b.retile_D(tCrB);
|
||||
|
||||
auto cA = make_identity_tensor(make_shape(size<0>(sA), size<1>(sA)));
|
||||
auto tAcA = g2s_thr_copy.partition_S(cA);
|
||||
int residual = M - iy*BM;
|
||||
|
||||
int itile_to_read = 0;
|
||||
int ismem_read = 0;
|
||||
int ismem_write = 0;
|
||||
int ismem_read_sfa = 0;
|
||||
constexpr int kStages = KernelTraits::KStages;
|
||||
|
||||
#pragma unroll
|
||||
for(int istage=0; istage<kStages - 1; ++istage){
|
||||
for (size_t m = 0; m < size<1>(tAsA_copy); m++)
|
||||
{
|
||||
for (size_t k = 0; k < size<2>(tAsA_copy); k++)
|
||||
{
|
||||
if(get<0>(tAcA(0, m, k)) < residual){
|
||||
cute::copy(g2s_tiled_copy, tAgA_copy(_, m, k, istage), tAsA_copy(_, m, k, istage));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(idx < KernelTraits::THREADS_SFA_COPY && (BM * iy + idx * KernelTraits::SFA_ELEMS_PER_COPY < M)) {
|
||||
copy_1d((float*)&gSFA(0, 0, istage) + idx*KernelTraits::SFA_ELEMS_PER_COPY, (float*)&sSFA(0, istage) + idx*KernelTraits::SFA_ELEMS_PER_COPY);
|
||||
}
|
||||
cute::copy(g2s_tiled_copy, tBgB_copy(_, _, _, istage), tBsB_copy(_, _, _, istage));
|
||||
cp_async_fence();
|
||||
++itile_to_read;
|
||||
++ismem_write;
|
||||
}
|
||||
|
||||
cp_async_wait<kStages - 2>();
|
||||
__syncthreads();
|
||||
|
||||
cute::copy(s2r_tiled_copy_a, tAsA(_, _, 0, ismem_read), tCrA_view(_, _, 0));
|
||||
cute::copy(s2r_tiled_copy_b, tBsB(_, _, 0, ismem_read), tCrB_view(_, _, 0));
|
||||
|
||||
static constexpr int nk = size<2>(tCrA);
|
||||
auto sfa_tv = typename KernelTraits::SFAThreadLayout{};
|
||||
static constexpr int NTILES = KernelTraits::NTiles;
|
||||
#pragma unroll
|
||||
for(int itile = 0; itile < NTILES; itile++){
|
||||
clear(tCrD);
|
||||
#pragma unroll
|
||||
for(int ik = 0; ik < nk; ik++){
|
||||
int ik_next = (ik + 1) % nk;
|
||||
if(ik == nk - 1) {
|
||||
cp_async_wait<kStages - 2>();
|
||||
__syncthreads();
|
||||
ismem_read = (ismem_read + 1) % kStages;
|
||||
}
|
||||
cute::copy(s2r_tiled_copy_a, tAsA(_, _, ik_next, ismem_read), tCrA_view(_, _, ik_next));
|
||||
cute::copy(s2r_tiled_copy_b, tBsB(_, _, ik_next, ismem_read), tCrB_view(_, _, ik_next));
|
||||
if(ik == 0){
|
||||
if(itile_to_read < NTILES){
|
||||
for (size_t m = 0; m < size<1>(tAsA_copy); m++)
|
||||
{
|
||||
for (size_t k = 0; k < size<2>(tAsA_copy); k++)
|
||||
{
|
||||
if(get<0>(tAcA(0, m, k)) < residual){
|
||||
cute::copy(g2s_tiled_copy, tAgA_copy(_, m, k, itile_to_read), tAsA_copy(_, m, k, ismem_write));
|
||||
}
|
||||
}
|
||||
}
|
||||
cute::copy(g2s_tiled_copy, tBgB_copy(_, _, _, itile_to_read), tBsB_copy(_, _, _, ismem_write));
|
||||
if(idx < KernelTraits::THREADS_SFA_COPY && (BM * iy + idx * KernelTraits::SFA_ELEMS_PER_COPY < M)) {
|
||||
copy_1d((float*)&gSFA(0, 0, itile_to_read) + idx * KernelTraits::SFA_ELEMS_PER_COPY, (float*)&sSFA(0, ismem_write) + idx*KernelTraits::SFA_ELEMS_PER_COPY);
|
||||
}
|
||||
++itile_to_read;
|
||||
ismem_write = (ismem_write + 1) % kStages;
|
||||
}
|
||||
cp_async_fence();
|
||||
}
|
||||
cute::gemm(tiled_mma, tCrD, tCrA(_, _, ik), tCrB(_, _, ik), tCrD);
|
||||
}
|
||||
|
||||
int sf_ind = itile / KernelTraits::TILES_PER_BLOCK;
|
||||
float sfb_val = sfb[sf_ind];
|
||||
#pragma unroll
|
||||
for(int i = 0; i < size<1>(tCrD); i++){ // (MMA, MMA_M, MMA_N) = (4, 4, 4)
|
||||
float sfa_val_1 = sSFA(sfa_tv(idx) + i * KernelTraits::MMA_WARP_M, ismem_read_sfa);
|
||||
float sfa_val_2 = sSFA(sfa_tv(idx) + 8 + i * KernelTraits::MMA_WARP_M, ismem_read_sfa);
|
||||
#pragma unroll
|
||||
for(int j = 0; j < size<2>(tCrD); j++){
|
||||
tCrD_fp32(0, i, j) += sfa_val_1 * sfb_val * float(tCrD(0, i, j));
|
||||
tCrD_fp32(1, i, j) += sfa_val_1 * sfb_val * float(tCrD(1, i, j));
|
||||
tCrD_fp32(2, i, j) += sfa_val_2 * sfb_val * float(tCrD(2, i, j));
|
||||
tCrD_fp32(3, i, j) += sfa_val_2 * sfb_val * float(tCrD(3, i, j));
|
||||
}
|
||||
}
|
||||
ismem_read_sfa = (ismem_read_sfa + 1) % kStages;
|
||||
__syncthreads();
|
||||
}
|
||||
|
||||
auto tCrBias = make_tensor<float>(Layout<Shape<_2, Int<size<2>(tCrD_fp32)>>>{});
|
||||
auto bias_threads = typename KernelTraits::BiasThreadLayout{};
|
||||
if constexpr (has_bias){
|
||||
#pragma unroll
|
||||
for(int i = 0; i<size<2>(tCrD_fp32); i++){
|
||||
tCrBias(0, i) = sBias(bias_threads(idx) + i * KernelTraits::MMA_WARP_N);
|
||||
tCrBias(1, i) = sBias(1 + bias_threads(idx) + i * KernelTraits::MMA_WARP_N);
|
||||
}
|
||||
#pragma unroll
|
||||
for(int i = 0; i<size<1>(tCrD_fp32); i++){
|
||||
#pragma unroll
|
||||
for (int j = 0; j < size<2>(tCrD_fp32) ; j++)
|
||||
{
|
||||
tCrD_fp32(0, i, j) += tCrBias(0, j);
|
||||
tCrD_fp32(1, i, j) += tCrBias(1, j);
|
||||
tCrD_fp32(2, i, j) += tCrBias(0, j);
|
||||
tCrD_fp32(3, i, j) += tCrBias(1, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto sC = make_tensor(make_smem_ptr(C_shm), SmemLayoutC{});
|
||||
auto r2s_tiled_copy_c = make_tiled_copy_C(typename KernelTraits::R2SCopyAtomC{}, tiled_mma);
|
||||
auto r2s_thr_copy_c = r2s_tiled_copy_c.get_slice(idx);
|
||||
auto tCrC_r2s = r2s_thr_copy_c.retile_S(tCrD_fp32);
|
||||
auto tCsC_r2s = r2s_thr_copy_c.partition_D(sC);
|
||||
|
||||
typename KernelTraits::S2GCopyC s2g_tiled_copy_c;
|
||||
auto s2g_thr_copy_c = s2g_tiled_copy_c.get_thread_slice(idx);
|
||||
auto tCsC_s2g = s2g_thr_copy_c.partition_S(sC);
|
||||
auto tCgC_s2g = s2g_thr_copy_c.partition_D(gD);
|
||||
|
||||
int pipe = size<2>(tCsC_r2s);
|
||||
|
||||
auto cC = make_identity_tensor(make_shape(size<0>(gD), size<1>(gD)));
|
||||
auto tCcC = s2g_thr_copy_c.partition_D(cC);
|
||||
|
||||
for(int i = 0; i< size<1>(tCrC_r2s); i++){
|
||||
for(int j = 0; j < size<2>(tCrC_r2s); j+=pipe){
|
||||
for(int step = 0; step < pipe; ++step){
|
||||
auto fragment = make_tensor_like<output_t>(tCrC_r2s(_, i, j + step));
|
||||
cute::copy(tCrC_r2s(_, i, j + step), fragment);
|
||||
cute::copy(r2s_tiled_copy_c, fragment, tCsC_r2s(_, 0, step));
|
||||
}
|
||||
__syncthreads();
|
||||
if (get<0>(tCcC(0, i, j / pipe)) < residual){
|
||||
cute::copy(s2g_tiled_copy_c, tCsC_s2g(_, 0, 0), tCgC_s2g(_, i, j / pipe));
|
||||
}
|
||||
__syncthreads();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <bool has_bias, typename accum_type>
|
||||
void fp8_kernel_launch(void* Aptr, void* sfa, void* Bptr, void* sfb, void* bias_ptr, void* out, int M, int N, int K, cudaStream_t stream) {
|
||||
int TMA_ALIGNED_M = ((M + sizeof(float) - 1) / sizeof(float)) * sizeof(float); // SIZEOF(float) = 4
|
||||
BLOCK_K_SWITCH(K_, M_SWITCH(
|
||||
using KernelTraits = gemm_traits<BM, BN, 3, K_, WARP_ROW, WARP_COL, has_bias, accum_type, bfloat16_t>;
|
||||
auto kernel = &gemm_fp8_kernel<KernelTraits>;
|
||||
int BX = (N + KernelTraits::BN - 1) / KernelTraits::BN;
|
||||
int BY = (M + KernelTraits::BM - 1) / KernelTraits::BM;
|
||||
dim3 block(KernelTraits::NUM_THREADS);
|
||||
dim3 gridDim(BX, BY);
|
||||
cudaFuncSetAttribute(kernel, cudaFuncAttributeMaxDynamicSharedMemorySize, KernelTraits::SmemSize);
|
||||
kernel<<<gridDim, KernelTraits::NUM_THREADS, KernelTraits::SmemSize, stream>>>((float_e4m3_t*)Aptr, (float*)sfa, (float_e4m3_t*)Bptr, (float*)sfb, (float*)bias_ptr, out, M, N, K, TMA_ALIGNED_M);
|
||||
C10_CUDA_KERNEL_LAUNCH_CHECK();))
|
||||
}
|
||||
|
||||
template<bool use_fast_accum>
|
||||
void fp8_bias_gemm_cuda(void* Aptr, void* SFA, void* Bptr, void* SFB, void* bias_ptr, void* out, int M, int N, int K, cudaStream_t stream){
|
||||
using accum_type = std::conditional_t<use_fast_accum, half_t, float>;
|
||||
fp8_kernel_launch<true, accum_type>(Aptr, SFA, Bptr, SFB, bias_ptr, out, M, N, K, stream);
|
||||
}
|
||||
// template<bool use_fast_accum>
|
||||
// void fp8_gemm_cuda(void* Aptr, void* SFA, void* Bptr, void* SFB, void* out, int M, int N, int K, cudaStream_t stream){
|
||||
// using accum_type = std::conditional_t<use_fast_accum, half_t, float>;
|
||||
// BLOCK_K_SWITCH(num_acc_upcast_steps, fp8_kernel_launch<false, num_acc_upcast_steps, accum_type>(Aptr, SFA, Bptr, SFB, nullptr, out, M, N, K, stream);)
|
||||
// }
|
||||
|
||||
// template void fp8_gemm_cuda<true>(void* Aptr, void* SFA, void* Bptr, void* SFB, void* out, int M, int N, int K, cudaStream_t stream);
|
||||
// template void fp8_gemm_cuda<false>(void* Aptr, void* SFA, void* Bptr, void* SFB, void* out, int M, int N, int K, cudaStream_t stream);
|
||||
|
||||
template void fp8_bias_gemm_cuda<true>(void* Aptr, void* SFA, void* Bptr, void* SFB, void* bias_ptr, void* out, int M, int N, int K, cudaStream_t stream);
|
||||
template void fp8_bias_gemm_cuda<false>(void* Aptr, void* SFA, void* Bptr, void* SFB, void* bias_ptr, void* out, int M, int N, int K, cudaStream_t stream);
|
||||
}; // namespace sm89
|
||||
@@ -0,0 +1,121 @@
|
||||
#pragma once
|
||||
|
||||
#include <cute/tensor.hpp>
|
||||
|
||||
#include <cutlass/cutlass.h>
|
||||
#include <cutlass/layout/layout.h>
|
||||
#include <cutlass/numeric_types.h>
|
||||
|
||||
#include "mma_sm89_fp16.hpp"
|
||||
#include "mma_traits_sm89_fp16.hpp"
|
||||
|
||||
using namespace cute;
|
||||
|
||||
template<int BYTES> struct BytesToType {};
|
||||
template<> struct BytesToType<4> {
|
||||
using Type = uint32_t;
|
||||
static_assert(sizeof(Type) == 4);
|
||||
};
|
||||
template<> struct BytesToType<2> {
|
||||
using Type = uint16_t;
|
||||
static_assert(sizeof(Type) == 2);
|
||||
};
|
||||
|
||||
template<int BM_, int BN_, int KStages_, int K_, int WARP_ROW_=2, int WARP_COL_=2, bool HasBias_=false, typename accum_t_=cutlass::half_t, typename out_t_=cutlass::bfloat16_t>
|
||||
struct gemm_traits {
|
||||
static constexpr int BLOCK_SIZE = 128;
|
||||
static constexpr int K = K_;
|
||||
static constexpr int BM = BM_;
|
||||
static constexpr int BN = BN_;
|
||||
static constexpr int BK = 128;
|
||||
static constexpr int TILES_PER_BLOCK = BLOCK_SIZE / BK;
|
||||
static constexpr int NUM_SFB_PER_STEP = BN / BLOCK_SIZE;
|
||||
static constexpr int NTiles = K / BK;
|
||||
static constexpr int KSF = K / BLOCK_SIZE;
|
||||
static constexpr int KStages = KStages_;
|
||||
static constexpr int WARP_ROW = WARP_ROW_;
|
||||
static constexpr int WARP_COL = WARP_COL_;
|
||||
static constexpr int NUM_WARPS = WARP_ROW * WARP_COL;
|
||||
static constexpr int NUM_THREADS = NUM_WARPS * 32;
|
||||
static constexpr int MMA_WARP_M = WARP_ROW * 16;
|
||||
static constexpr int MMA_WARP_N = WARP_COL * 8;
|
||||
static constexpr int MMA_WARP_K = 32;
|
||||
using accum_t = accum_t_;
|
||||
using out_t = out_t_;
|
||||
using SwizzleLayoutO = std::conditional_t<
|
||||
std::is_same_v<out_t_, cutlass::bfloat16_t>,
|
||||
Swizzle<3, 3, 3>,
|
||||
Swizzle<2, 4, 3>
|
||||
>;
|
||||
using SwizzleLayoutAB = Swizzle<2, 4, 3>;
|
||||
using MMA_Atom_SM89 = std::conditional_t<
|
||||
std::is_same_v<accum_t, cutlass::half_t>,
|
||||
MMA_Atom<SM89_16x8x32_F16E4M3E4M3F16_TN>,
|
||||
MMA_Atom<SM89_16x8x32_F32E4M3E4M3F32_TN>
|
||||
>;
|
||||
static constexpr int INPUT_ELEMS_PER_COPY = sizeof(uint128_t) / sizeof(float_e4m3_t);
|
||||
static constexpr int OUTPUT_ELEMS_PER_COPY = sizeof(uint128_t) / sizeof(out_t_);
|
||||
static constexpr int THREADS_PER_ROW = BK / INPUT_ELEMS_PER_COPY;
|
||||
using GMEMLayout = Layout< Shape <Int<NUM_THREADS / THREADS_PER_ROW>, Int<THREADS_PER_ROW>>, Stride<Int<THREADS_PER_ROW>, _1>>;
|
||||
using G2SCopyAtom = Copy_Atom<SM80_CP_ASYNC_CACHEGLOBAL<cute::uint128_t>, float_e4m3_t>;
|
||||
using G2STiledCopy = decltype(
|
||||
make_tiled_copy(
|
||||
G2SCopyAtom{},
|
||||
GMEMLayout{},
|
||||
Layout<Shape<_1, Int<INPUT_ELEMS_PER_COPY>>>{}
|
||||
)
|
||||
);
|
||||
using S2RCopyAtomA = Copy_Atom<SM75_U32x4_LDSM_N, float_e4m3_t>;
|
||||
using S2RCopyAtomB = Copy_Atom<SM75_U32x2_LDSM_N, float_e4m3_t>;
|
||||
using SmemLayoutAtom = decltype(composition(
|
||||
Swizzle<2, 4, 3>{},
|
||||
make_layout(make_shape(Int<8>{}, Int<BK>{}),
|
||||
make_stride(Int<BK>{}, Int<1>{}))));
|
||||
using SmemLayoutA = decltype(
|
||||
tile_to_shape(SmemLayoutAtom{}, make_shape(Int<BM>{}, Int<BK>{}, Int<KStages>{}))
|
||||
);
|
||||
using SmemLayoutB = decltype(
|
||||
tile_to_shape(SmemLayoutAtom{}, make_shape(Int<BN>{}, Int<BK>{}, Int<KStages>{}))
|
||||
);
|
||||
using MMATile = decltype(
|
||||
make_tiled_mma(
|
||||
MMA_Atom_SM89{},
|
||||
Layout<Shape<Int<WARP_ROW>, Int<WARP_COL>, _1>>{},
|
||||
Tile<Int<MMA_WARP_M>, Int<MMA_WARP_N>, Int<MMA_WARP_K>>{}
|
||||
)
|
||||
);
|
||||
|
||||
static constexpr int ELEMS_PER_TILE = MMA_WARP_M * MMA_WARP_N;
|
||||
static constexpr int NUM_ELEMS_PER_WRITE = NUM_THREADS * sizeof(cute::uint128_t) / sizeof(out_t_);
|
||||
static constexpr int OUT_PIPE = NUM_ELEMS_PER_WRITE / ELEMS_PER_TILE;
|
||||
// using SmemLayoutC = Layout<Shape<Int<BM>, Int<BN>>, Stride<Int<BN>, Int<1>>>;
|
||||
|
||||
using SmemLayoutC = decltype(
|
||||
make_layout(
|
||||
make_shape(Int<MMA_WARP_M>{}, Int<MMA_WARP_N*OUT_PIPE>{}),
|
||||
make_stride(Int<MMA_WARP_N*OUT_PIPE>{}, Int<1>{})
|
||||
)
|
||||
);
|
||||
static constexpr int THREADS_PER_ROW_WRITE = MMA_WARP_N * OUT_PIPE / OUTPUT_ELEMS_PER_COPY;
|
||||
using R2SCopyAtomC = Copy_Atom<UniversalCopy<typename BytesToType<2*sizeof(out_t)>::Type>, out_t>;
|
||||
using S2GCopyAtomC = Copy_Atom<UniversalCopy<cute::uint128_t>, out_t>;
|
||||
using S2GCopyC = decltype(make_tiled_copy(S2GCopyAtomC{},
|
||||
make_layout(make_shape(Int<NUM_THREADS / THREADS_PER_ROW_WRITE>{}, Int<THREADS_PER_ROW_WRITE>{}),
|
||||
make_stride(Int<THREADS_PER_ROW_WRITE>{}, Int<1>{})),
|
||||
make_layout(make_shape(Int<1>{}, Int<OUTPUT_ELEMS_PER_COPY>{}))));
|
||||
|
||||
using G2SBiasCopyAtom = Copy_Atom<SM80_CP_ASYNC_CACHEALWAYS<float>, float>;
|
||||
using G2SBiasCopy = decltype(make_tiled_copy(G2SBiasCopyAtom{}, make_layout(
|
||||
make_shape(Int<1>{},Int<BN>{}), make_stride(Int<BN>{}, Int<1>{})),
|
||||
make_layout(make_shape(Int<1>{},Int<1>{}), make_stride(Int<1>{}, Int<1>{}))));
|
||||
using sfa_copy_vtype = float;
|
||||
static constexpr int SFA_ELEMS_PER_COPY = sizeof(sfa_copy_vtype)/sizeof(float);
|
||||
static constexpr int THREADS_SFA_COPY = BM * sizeof(float) / sizeof(sfa_copy_vtype);
|
||||
// using G2SSFACopyAtom = Copy_Atom<SM80_CP_ASYNC_CACHEALWAYS<cute::uint128_t>, float>;
|
||||
static constexpr bool HasBias = HasBias_;
|
||||
using SmemLayoutBias = Layout<Shape<Int<1>, Int<BN>>, Stride<Int<BN>, Int<1>>>;
|
||||
using SmemLayoutSFA = Layout<Shape<Int<BM>, Int<KStages>>, Stride<Int<1>, Int<BM>>>;
|
||||
using BiasThreadLayout = Layout<Shape<Shape<_4, _8>, Shape<Int<WARP_ROW>, Int<WARP_COL>>>, Stride<Stride<_2, _0>, Stride<_0, _8>>>;
|
||||
using SFAThreadLayout = Layout<Shape<Shape<_4, _8>, Shape<Int<WARP_ROW>, Int<WARP_COL>>>, Stride<Stride<_0, _1>, Stride<_16, _0>>>;
|
||||
static constexpr int SmemSize = cute::max(cute::cosize(SmemLayoutA{})+cute::cosize(SmemLayoutB{}), cute::cosize(SmemLayoutC{})*sizeof(out_t)) + cute::cosize(SmemLayoutBias{}) * sizeof(float) + cute::cosize(SmemLayoutSFA{})*sizeof(float);
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
#include <cute/config.hpp>
|
||||
#include <cute/arch/mma.hpp>
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if (__CUDACC_VER_MAJOR__ > 12) || (__CUDACC_VER_MAJOR__ == 12 && __CUDACC_VER_MINOR__ >= 4)
|
||||
# define CUTE_ARCH_MMA_F32_SM89_SUPPORTED
|
||||
#endif
|
||||
|
||||
#if (__CUDACC_VER_MAJOR__ > 12) || (__CUDACC_VER_MAJOR__ == 12 && __CUDACC_VER_MINOR__ >= 8)
|
||||
# define CUTE_ARCH_MMA_F16_SM89_SUPPORTED
|
||||
#endif
|
||||
|
||||
#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 890)
|
||||
# if defined(CUTE_ARCH_MMA_F32_SM89_SUPPORTED)
|
||||
# define CUTE_ARCH_MMA_F32_SM89_ENABLED
|
||||
# endif
|
||||
|
||||
# if defined(CUTE_ARCH_MMA_F16_SM89_SUPPORTED)
|
||||
# define CUTE_ARCH_MMA_F16_SM89_ENABLED
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace cute {
|
||||
struct SM89_16x8x32_F32E4M3E4M3F32_TN
|
||||
{
|
||||
using DRegisters = float[4];
|
||||
using ARegisters = uint32_t[4];
|
||||
using BRegisters = uint32_t[2];
|
||||
using CRegisters = float[4];
|
||||
|
||||
CUTE_HOST_DEVICE static void
|
||||
fma(float & d0, float & d1, float & d2, float & d3,
|
||||
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
||||
uint32_t const& b0, uint32_t const& b1,
|
||||
float const& c0, float const& c1, float const& c2, float const& c3)
|
||||
{
|
||||
#if defined(CUTE_ARCH_MMA_F32_SM89_ENABLED)
|
||||
asm(
|
||||
"mma.sync.aligned.m16n8k32.row.col.f32.e4m3.e4m3.f32 "
|
||||
"{%0,%1,%2,%3}, {%4,%5,%6,%7}, {%8,%9}, {%10,%11,%12,%13};\n"
|
||||
: "=f"(d0), "=f"(d1), "=f"(d2), "=f"(d3)
|
||||
:
|
||||
"r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
||||
"r"(b0), "r"(b1),
|
||||
"f"(c0), "f"(c1), "f"(c2), "f"(c3)
|
||||
);
|
||||
#else
|
||||
CUTE_INVALID_CONTROL_PATH("Attempting to use SM89_16x8x32_F32E4M3E4M3F32_TN without CUTE_ARCH_MMA_F32_SM89_ENABLED");
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
// MMA 16x8x32 TN
|
||||
struct SM89_16x8x32_F16E4M3E4M3F16_TN
|
||||
{
|
||||
using DRegisters = uint32_t[2];
|
||||
using ARegisters = uint32_t[4];
|
||||
using BRegisters = uint32_t[2];
|
||||
using CRegisters = uint32_t[2];
|
||||
|
||||
CUTE_HOST_DEVICE static void
|
||||
fma(uint32_t & d0, uint32_t & d1,
|
||||
uint32_t const& a0, uint32_t const& a1, uint32_t const& a2, uint32_t const& a3,
|
||||
uint32_t const& b0, uint32_t const& b1,
|
||||
uint32_t const& c0, uint32_t const& c1)
|
||||
{
|
||||
#if defined(CUTE_ARCH_MMA_F16_SM89_ENABLED)
|
||||
asm(
|
||||
"mma.sync.aligned.m16n8k32.row.col.f16.e4m3.e4m3.f16 "
|
||||
"{%0,%1}, {%2,%3,%4,%5}, {%6,%7}, {%8,%9};\n"
|
||||
: "=r"(d0), "=r"(d1)
|
||||
:
|
||||
"r"(a0), "r"(a1), "r"(a2), "r"(a3),
|
||||
"r"(b0), "r"(b1),
|
||||
"r"(c0), "r"(c1)
|
||||
);
|
||||
#else
|
||||
CUTE_INVALID_CONTROL_PATH("Attempting to use SM89_16x8x32_F32E4M3E4M3F32_TN without CUTE_ARCH_MMA_F16_SM89_ENABLED");
|
||||
#endif
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#include <cute/atom/mma_traits.hpp>
|
||||
#include <cute/layout.hpp>
|
||||
#include <cute/numeric/numeric_types.hpp>
|
||||
#include "mma_sm89_fp16.hpp"
|
||||
|
||||
namespace cute
|
||||
{
|
||||
|
||||
namespace {
|
||||
|
||||
// (T32,V4) -> (M16,N8)
|
||||
using SM80_16x8_Row = Layout<Shape <Shape < _4,_8>,Shape < _2,_2>>,
|
||||
Stride<Stride<_32,_1>,Stride<_16,_8>>>;
|
||||
|
||||
}
|
||||
|
||||
template <>
|
||||
struct MMA_Traits<SM89_16x8x32_F32E4M3E4M3F32_TN> {
|
||||
using ValTypeD = float;
|
||||
using ValTypeA = float_e4m3_t;
|
||||
using ValTypeB = float_e4m3_t;
|
||||
using ValTypeC = float;
|
||||
|
||||
using Shape_MNK = Shape<_16,_8,_32>;
|
||||
using ThrID = Layout<_32>;
|
||||
using ALayout = Layout<Shape <Shape < _4,_8>,Shape < _4,_2, _2>>,
|
||||
Stride<Stride<_64,_1>,Stride<_16,_8,_256>>>;
|
||||
using BLayout = Layout<Shape <Shape < _4,_8>,Shape <_4, _2>>,
|
||||
Stride<Stride<_32,_1>,Stride<_8,_128>>>;
|
||||
using CLayout = SM80_16x8_Row;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MMA_Traits<SM89_16x8x32_F16E4M3E4M3F16_TN> {
|
||||
using ValTypeD = half_t;
|
||||
using ValTypeA = float_e4m3_t;
|
||||
using ValTypeB = float_e4m3_t;
|
||||
using ValTypeC = half_t;
|
||||
|
||||
using Shape_MNK = Shape<_16,_8,_32>;
|
||||
using ThrID = Layout<_32>;
|
||||
using ALayout = Layout<Shape <Shape < _4,_8>,Shape < _4,_2, _2>>,
|
||||
Stride<Stride<_64,_1>,Stride<_16,_8,_256>>>;
|
||||
using BLayout = Layout<Shape <Shape < _4,_8>,Shape <_4, _2>>,
|
||||
Stride<Stride<_32,_1>,Stride<_8,_128>>>;
|
||||
using CLayout = SM80_16x8_Row;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#define BOOL_SWITCH(COND, CONST_NAME, ...) \
|
||||
if (COND) { \
|
||||
constexpr static bool CONST_NAME = true; \
|
||||
__VA_ARGS__ \
|
||||
} else { \
|
||||
constexpr static bool CONST_NAME = false; \
|
||||
__VA_ARGS__ \
|
||||
}
|
||||
//K/128
|
||||
#define BLOCK_K_SWITCH(COSNT_NAME, ...) \
|
||||
if (K == 2048) { \
|
||||
constexpr static int COSNT_NAME = 2048; \
|
||||
__VA_ARGS__ \
|
||||
} \
|
||||
else if (K == 4096) { \
|
||||
constexpr static int COSNT_NAME = 4096; \
|
||||
__VA_ARGS__ \
|
||||
} else if (K == 8192) { \
|
||||
constexpr static int COSNT_NAME = 8192; \
|
||||
__VA_ARGS__ \
|
||||
} else if (K == 16384) { \
|
||||
constexpr static int COSNT_NAME = 16384; \
|
||||
__VA_ARGS__ \
|
||||
} else { \
|
||||
TORCH_CHECK(false, "Unsupported K value: ", K); \
|
||||
}
|
||||
|
||||
#define M_SWITCH(...) \
|
||||
constexpr static int BM = 64; \
|
||||
constexpr static int BN = 128; \
|
||||
constexpr static int WARP_ROW = 2; \
|
||||
constexpr static int WARP_COL = 4; \
|
||||
__VA_ARGS__
|
||||
Reference in New Issue
Block a user