upstream: add GEMM kernel references from 4 repos for BI-V100 porting
Sources (all CUDA 10.2 compatible, no CUTLASS/Triton dependency): - leimao/CUDA-GEMM-Optimization: v00-v07, fp16 WMMA variant, double buffered - siboehm/SGEMM_CUDA: kernel 1-12, warp tiling + double buffering - wangzyon/NVIDIA_SGEMM_PRACTICE: kernel 1-7 - edtallison/sgemm-cuda: kernel 1-12 (reimplementation with notes) Key porting issue: ALL kernels hardcode WARPSIZE=32. BI-V100 has warp_size=64. Need to: 1. Replace all 32U / WARPSIZE constants with 64 2. Adjust warp subtile decomposition (WMITER, WNITER, WSUBM, WSUBN) 3. Adjust shared memory bank conflict avoidance (may have different bank count) 4. Test __shfl_down_sync with mask=0xFFFFFFFFFFFFFFFF (64-bit)
This commit is contained in:
102
upstream_ref/sgemm_cuda/5_kernel_2D_blocktiling.cuh
Normal file
102
upstream_ref/sgemm_cuda/5_kernel_2D_blocktiling.cuh
Normal file
@@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cublas_v2.h>
|
||||
#include <cuda_runtime.h>
|
||||
|
||||
#define CEIL_DIV(M, N) (((M) + (N)-1) / (N))
|
||||
|
||||
template <const int BM, const int BN, const int BK, const int TM, const int TN>
|
||||
__global__ void __launch_bounds__((BM * BN) / (TM * TN), 1)
|
||||
sgemm2DBlocktiling(int M, int N, int K, float alpha, const float *A,
|
||||
const float *B, float beta, float *C) {
|
||||
const uint cRow = blockIdx.y;
|
||||
const uint cCol = blockIdx.x;
|
||||
|
||||
const uint totalResultsBlocktile = BM * BN;
|
||||
// A thread is responsible for calculating TM*TN elements in the blocktile
|
||||
const uint numThreadsBlocktile = totalResultsBlocktile / (TM * TN);
|
||||
|
||||
// ResultsPerBlock / ResultsPerThread == ThreadsPerBlock
|
||||
assert(numThreadsBlocktile == blockDim.x);
|
||||
|
||||
// BN/TN are the number of threads to span a column
|
||||
const int threadCol = threadIdx.x % (BN / TN);
|
||||
const int threadRow = threadIdx.x / (BN / TN);
|
||||
|
||||
// allocate space for the current blocktile in smem
|
||||
__shared__ float As[BM * BK];
|
||||
__shared__ float Bs[BK * BN];
|
||||
|
||||
// Move blocktile to beginning of A's row and B's column
|
||||
A += cRow * BM * K;
|
||||
B += cCol * BN;
|
||||
C += cRow * BM * N + cCol * BN;
|
||||
|
||||
// calculating the indices that this thread will load into SMEM
|
||||
const uint innerRowA = threadIdx.x / BK;
|
||||
const uint innerColA = threadIdx.x % BK;
|
||||
// calculates the number of rows of As that are being loaded in a single step
|
||||
// by a single block
|
||||
const uint strideA = numThreadsBlocktile / BK;
|
||||
const uint innerRowB = threadIdx.x / BN;
|
||||
const uint innerColB = threadIdx.x % BN;
|
||||
// for both As and Bs we want each load to span the full column-width, for
|
||||
// better GMEM coalescing (as opposed to spanning full row-width and iterating
|
||||
// across columns)
|
||||
const uint strideB = numThreadsBlocktile / BN;
|
||||
|
||||
// allocate thread-local cache for results in registerfile
|
||||
float threadResults[TM * TN] = {0.0};
|
||||
// register caches for As and Bs
|
||||
float regM[TM] = {0.0};
|
||||
float regN[TN] = {0.0};
|
||||
|
||||
// outer-most loop over block tiles
|
||||
for (uint bkIdx = 0; bkIdx < K; bkIdx += BK) {
|
||||
// populate the SMEM caches
|
||||
for (uint loadOffset = 0; loadOffset < BM; loadOffset += strideA) {
|
||||
As[(innerRowA + loadOffset) * BK + innerColA] =
|
||||
A[(innerRowA + loadOffset) * K + innerColA];
|
||||
}
|
||||
for (uint loadOffset = 0; loadOffset < BK; loadOffset += strideB) {
|
||||
Bs[(innerRowB + loadOffset) * BN + innerColB] =
|
||||
B[(innerRowB + loadOffset) * N + innerColB];
|
||||
}
|
||||
__syncthreads();
|
||||
|
||||
// advance blocktile
|
||||
A += BK; // move BK columns to right
|
||||
B += BK * N; // move BK rows down
|
||||
|
||||
// calculate per-thread results
|
||||
for (uint dotIdx = 0; dotIdx < BK; ++dotIdx) {
|
||||
// block into registers
|
||||
for (uint i = 0; i < TM; ++i) {
|
||||
regM[i] = As[(threadRow * TM + i) * BK + dotIdx];
|
||||
}
|
||||
for (uint i = 0; i < TN; ++i) {
|
||||
regN[i] = Bs[dotIdx * BN + threadCol * TN + i];
|
||||
}
|
||||
for (uint resIdxM = 0; resIdxM < TM; ++resIdxM) {
|
||||
for (uint resIdxN = 0; resIdxN < TN; ++resIdxN) {
|
||||
threadResults[resIdxM * TN + resIdxN] +=
|
||||
regM[resIdxM] * regN[resIdxN];
|
||||
}
|
||||
}
|
||||
}
|
||||
__syncthreads();
|
||||
}
|
||||
|
||||
// write out the results
|
||||
for (uint resIdxM = 0; resIdxM < TM; ++resIdxM) {
|
||||
for (uint resIdxN = 0; resIdxN < TN; ++resIdxN) {
|
||||
C[(threadRow * TM + resIdxM) * N + threadCol * TN + resIdxN] =
|
||||
alpha * threadResults[resIdxM * TN + resIdxN] +
|
||||
beta * C[(threadRow * TM + resIdxM) * N + threadCol * TN + resIdxN];
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user