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)
120 lines
4.4 KiB
Plaintext
120 lines
4.4 KiB
Plaintext
#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;
|
||
};
|