siboehm/SGEMM_CUDA (19 files):
siboehm_sgemm.cu, siboehm_runner.cu, siboehm_runner.cuh, siboehm_kernels.cuh
siboehm_cuBLAS_sgemm.cu, siboehm_simplest_kernel.cu, siboehm_CMakeLists.txt
siboehm_{1_naive..12_kernel_double_buffering}.cuh
wangzyon/NVIDIA_SGEMM_PRACTICE (12 files):
wangzyon_sgemm.cu, wangzyon_utils.cu, wangzyon_utils.cuh, wangzyon_kernel.cuh
wangzyon_CMakeLists.txt, wangzyon_kernel_{1..7}.cuh
edtallison/sgemm-cuda (19 files):
edtallison_sgemm.cu, edtallison_runner.cu, edtallison_runner.cuh
edtallison_kernels.cuh, edtallison_cuBLAS_sgemm.cu, edtallison_simplest_kernel.cu
edtallison_CMakeLists.txt, edtallison_{01_naive..12_kernel_double_buffering}.cuh
cat_files/ total: 25 → 75 files
57 lines
2.1 KiB
Plaintext
57 lines
2.1 KiB
Plaintext
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cublas_v2.h>
|
|
#include <cuda_runtime.h>
|
|
|
|
#define CEIL_DIV(M, N) (((M) + (N)-1) / (N))
|
|
|
|
template <const int BLOCKSIZE>
|
|
__global__ void sgemm_shared_mem_block(int M, int N, int K, float alpha,
|
|
const float *A, const float *B,
|
|
float beta, float *C) {
|
|
// the output block that we want to compute in this threadblock
|
|
const uint cRow = blockIdx.x;
|
|
const uint cCol = blockIdx.y;
|
|
|
|
// allocate buffer for current block in fast shared mem
|
|
// shared mem is shared between all threads in a block
|
|
__shared__ float As[BLOCKSIZE * BLOCKSIZE];
|
|
__shared__ float Bs[BLOCKSIZE * BLOCKSIZE];
|
|
|
|
// the inner row & col that we're accessing in this thread
|
|
const uint threadCol = threadIdx.x % BLOCKSIZE;
|
|
const uint threadRow = threadIdx.x / BLOCKSIZE;
|
|
|
|
// advance pointers to the starting positions
|
|
A += cRow * BLOCKSIZE * K; // row=cRow, col=0
|
|
B += cCol * BLOCKSIZE; // row=0, col=cCol
|
|
C += cRow * BLOCKSIZE * N + cCol * BLOCKSIZE; // row=cRow, col=cCol
|
|
|
|
float tmp = 0.0;
|
|
for (int bkIdx = 0; bkIdx < K; bkIdx += BLOCKSIZE) {
|
|
// Have each thread load one of the elements in A & B
|
|
// Make the threadCol (=threadIdx.x) the consecutive index
|
|
// to allow global memory access coalescing
|
|
As[threadRow * BLOCKSIZE + threadCol] = A[threadRow * K + threadCol];
|
|
Bs[threadRow * BLOCKSIZE + threadCol] = B[threadRow * N + threadCol];
|
|
|
|
// block threads in this block until cache is fully populated
|
|
__syncthreads();
|
|
A += BLOCKSIZE;
|
|
B += BLOCKSIZE * N;
|
|
|
|
// execute the dotproduct on the currently cached block
|
|
for (int dotIdx = 0; dotIdx < BLOCKSIZE; ++dotIdx) {
|
|
tmp += As[threadRow * BLOCKSIZE + dotIdx] *
|
|
Bs[dotIdx * BLOCKSIZE + threadCol];
|
|
}
|
|
// need to sync again at the end, to avoid faster threads
|
|
// fetching the next block into the cache before slower threads are done
|
|
__syncthreads();
|
|
}
|
|
C[threadRow * N + threadCol] =
|
|
alpha * tmp + beta * C[threadRow * N + threadCol];
|
|
} |