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:
119
upstream_ref/nvidia_sgemm_practice/sgemm.cu
Normal file
119
upstream_ref/nvidia_sgemm_practice/sgemm.cu
Normal file
@@ -0,0 +1,119 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/time.h>
|
||||
#include <utils.cuh>
|
||||
|
||||
#define cudaCheck(err) (cudaCheck(err, __FILE__, __LINE__))
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 2) {
|
||||
printf("Please select a kernel (range 0 - 11, here 0 is for NVIDIA cuBLAS).\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// cuda kernel num
|
||||
int kernel_num = atoi(argv[1]);
|
||||
if (kernel_num < 0 || kernel_num > 11) {
|
||||
printf("Please enter a valid kernel number (0-11).\n");
|
||||
exit(EXIT_FAILURE);
|
||||
} else {
|
||||
printf("Select kernel %d.\n", kernel_num);
|
||||
};
|
||||
|
||||
// 申明句柄,创建句柄, cublasCreate会返回一个cublasStatus_t类型的值,用来判断句柄是否创建成功(值为0)
|
||||
cublasHandle_t handle;
|
||||
if (cublasCreate(&handle)) {
|
||||
printf("Create cublas handle error.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
};
|
||||
|
||||
// 采用cudaEvent进行gpu流计时,cudaEvent相当于在目标流中发布事件任务
|
||||
float elapsed_time;
|
||||
cudaEvent_t beg, end;
|
||||
cudaEventCreate(&beg);
|
||||
cudaEventCreate(&end);
|
||||
|
||||
// matrix size
|
||||
int size_len = 24;
|
||||
int SIZE[size_len];
|
||||
for (int i = 0; i < size_len; i++)
|
||||
SIZE[i] = 256 * (i + 1);
|
||||
|
||||
int m, n, k, max_size;
|
||||
max_size = SIZE[size_len - 1];
|
||||
printf("max_size=%d\n", max_size);
|
||||
|
||||
float alpha = 1.0, beta = 0.; //two arbitary input parameters,C=α*AB+β*C
|
||||
|
||||
float *A = NULL, *B = NULL, *C = NULL, *C_ref = NULL; //host matrices
|
||||
float *dA = NULL, *dB = NULL, *dC = NULL, *dC_ref = NULL; //device matrices
|
||||
|
||||
A = (float *) malloc(sizeof(float) * max_size * max_size);
|
||||
B = (float *) malloc(sizeof(float) * max_size * max_size);
|
||||
C = (float *) malloc(sizeof(float) * max_size * max_size);
|
||||
C_ref = (float *) malloc(sizeof(float) * max_size * max_size);
|
||||
|
||||
randomize_matrix(A, max_size * max_size);
|
||||
randomize_matrix(B, max_size * max_size);
|
||||
randomize_matrix(C, max_size * max_size);
|
||||
copy_matrix(C, C_ref, max_size * max_size);
|
||||
|
||||
cudaCheck(cudaMalloc((void **) &dA, sizeof(float) * max_size * max_size));
|
||||
cudaCheck(cudaMalloc((void **) &dB, sizeof(float) * max_size * max_size));
|
||||
cudaCheck(cudaMalloc((void **) &dC, sizeof(float) * max_size * max_size));
|
||||
cudaCheck(cudaMalloc((void **) &dC_ref, sizeof(float) * max_size * max_size));
|
||||
|
||||
cudaCheck(cudaMemcpy(dA, A, sizeof(float) * max_size * max_size, cudaMemcpyHostToDevice));
|
||||
cudaCheck(cudaMemcpy(dB, B, sizeof(float) * max_size * max_size, cudaMemcpyHostToDevice));
|
||||
cudaCheck(cudaMemcpy(dC, C, sizeof(float) * max_size * max_size, cudaMemcpyHostToDevice));
|
||||
cudaCheck(cudaMemcpy(dC_ref, C_ref, sizeof(float) * max_size * max_size, cudaMemcpyHostToDevice));
|
||||
|
||||
int repeat_times = 10;
|
||||
for (int i = 0; i < size_len; i++) {
|
||||
m = n = k = SIZE[i];
|
||||
|
||||
printf("m=n=k=%d\n", m);
|
||||
// 验证计算正确性,同时在核函数计时前预先执行一次,避免冷启动误差
|
||||
if (kernel_num != 0) {
|
||||
test_kernel(0, m, n, k, alpha, dA, dB, beta, dC_ref, handle); // cuBLAS
|
||||
test_kernel(kernel_num, m, n, k, alpha, dA, dB, beta, dC, handle); // user define
|
||||
cudaDeviceSynchronize();
|
||||
cudaMemcpy(C, dC, sizeof(float) * m * n, cudaMemcpyDeviceToHost);
|
||||
cudaMemcpy(C_ref, dC_ref, sizeof(float) * m * n, cudaMemcpyDeviceToHost);
|
||||
cudaDeviceSynchronize();
|
||||
|
||||
if (!verify_matrix(C_ref, C, m * n)) {
|
||||
printf("Failed to pass the correctness verification against NVIDIA cuBLAS. Exited.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
cudaDeviceSynchronize();
|
||||
|
||||
cudaEventRecord(beg);
|
||||
for (int j = 0; j < repeat_times; j++) {
|
||||
test_kernel(kernel_num, m, n, k, alpha, dA, dB, beta, dC, handle);
|
||||
}
|
||||
cudaEventRecord(end);
|
||||
cudaEventSynchronize(beg);
|
||||
cudaEventSynchronize(end);
|
||||
cudaEventElapsedTime(&elapsed_time, beg, end);
|
||||
elapsed_time /= 1000.; //换算成秒
|
||||
|
||||
printf("Average elasped time: (%f) second, performance: (%f) GFLOPS. size: (%d).\n",
|
||||
elapsed_time / repeat_times, 2. * 1e-9 * repeat_times * m * n * k / elapsed_time, m);
|
||||
fflush(stdout);
|
||||
copy_matrix(C_ref, C, m * n); //sync C with cuBLAS to prepare for the next run
|
||||
}
|
||||
|
||||
// 释放CPU和GPU空间
|
||||
free(A);
|
||||
free(B);
|
||||
free(C);
|
||||
free(C_ref);
|
||||
cudaFree(dA);
|
||||
cudaFree(dB);
|
||||
cudaFree(dC);
|
||||
cudaFree(dC_ref);
|
||||
|
||||
return 0;
|
||||
};
|
||||
Reference in New Issue
Block a user