CUDA GEMM 优化
简介
本仓库包含通用矩阵-矩阵乘法(GEMM)的 CUDA 核心及相应的性能分析。CUDA 核心的正确性对任何矩阵大小都有保证。CUDA 核心的参数针对 NVIDIA GeForce RTX 3090 GPU 上的 4096 x 4096 x 4096 GEMM 做了微调。这些 CUDA 核心应该与任何计算能力 7.0 或更高的 NVIDIA GPU 兼容。
使用方法
使用 Docker 来构建和运行 CUDA 核心。自定义 Docker 容器基于 NVIDIA NGC CUDA 12.2.2 Docker 容器构建。
如果主机有不同的 CUDA 版本,请调整基础 Docker 容器的 CUDA 版本。否则可能会出现奇怪的编译错误和运行时错误。
构建 Docker 镜像
要构建自定义 Docker 镜像,请运行以下命令:
$ docker build -f docker/gemm-cuda.Dockerfile --no-cache --tag=gemm-cuda:12.2.2 .
运行 Docker 容器
要运行自定义 Docker 容器,请运行以下命令:
$ docker run -it --rm --gpus device=0 -v $(pwd):/mnt gemm-cuda:12.2.2
如果我们想使用 NVIDIA Nsight Compute 对 CUDA 核心进行分析,在运行 Docker 容器时需要添加额外的标志 --cap-add=SYS_ADMIN
和 --security-opt seccomp=unconfined
。
构建 CUDA 核心
要构建 CUDA 核心,请在 Docker 容器内运行以下命令:
$ cmake -B build
$ cmake --build build --config Release --parallel
$ cmake --install build
运行 CUDA 核心
要运行 FP32 和 FP16 GEMM CUDA 核心,请在 Docker 容器内运行以下命令:
$ ./build/src/profile_cuda_gemm_fp32
$ ./build/src/profile_cuda_gemm_fp16
性能
所有实验都在单个 NVIDIA GeForce RTX 3090 GPU 上进行。性能可能会有所波动,有时一次测量到另一次测量的差异可达 25%。
FP32 GEMM
所有 FP32 GEMM 核心都无法利用 NVIDIA Tensor Cores。
GEMM 核心 | TFLOPS | 核心描述 |
---|---|---|
cuBLAS GEMM 核心 | 24.5971 | cuBLAS 实现 |
自定义 GEMM 核心 V00 | 0.278129 | 非合并全局内存访问 |
自定义 GEMM 核心 V01 | 1.7218 | 合并全局内存访问 |
自定义 GEMM 核心 V02 | 2.66157 | 2D 块平铺 |
自定义 GEMM 核心 V02 向量化 | 1.90514 | 2D 块平铺和向量化内存访问 |
自定义 GEMM 核心 V03 | 8.91318 | 2D 块平铺和 1D 线程平铺 |
自定义 GEMM 核心 V03 向量化 | 4.04796 | 2D 块平铺和 1D 线程平铺,带向量化内存访问 |
自定义 GEMM 核心 V04 | 13.0247 | 2D 块平铺和 2D 线程平铺 |
自定义 GEMM 核心 V04 向量化 | 15.027 | 2D 块平铺和 2D 线程平铺,带向量化内存访问 |
自定义 GEMM 核心 V05 | 11.1448 | 2D 块平铺和 2D 线程平铺和矩阵转置 |
自定义 GEMM 核心 V05 向量化 | 19.6688 | 2D 块平铺和 2D 线程平铺和矩阵转置,带向量化内存访问 |
自定义 GEMM 核心 V06 | 11.0703 | 2D 块平铺和 2D 线程束平铺和 2D 线程平铺和矩阵转置 |
自定义 GEMM 核心 V06 向量化 | 20.1649 | 2D 块平铺和 2D 线程束平铺和 2D 线程平铺和矩阵转置,带向量化内存访问 |
FP16 GEMM
FP16 自定义 GEMM 核心 V00 到 V06 不使用 NVIDIA Tensor Cores。FP16 cuBLAS GEMM 核心和自定义 GEMM 核心 V07 使用 NVIDIA Tensor Cores。
GEMM 核心 | TFLOPS | 核心描述 |
---|---|---|
cuBLAS GEMM 核心 | 138.955 | cuBLAS 实现 |
自定义 GEMM 核心 V00 | 0.284095 | 非合并全局内存访问 |
自定义 GEMM 核心 V01 | 1.7316 | 合并全局内存访问 |
自定义 GEMM 核心 V02 | 2.46677 | 2D 块平铺 GEMM |
自定义 GEMM 核心 V02 向量化 | 1.93088 | 2D 块平铺,带向量化内存访问 |
自定义 GEMM 核心 V03 | 8.67563 | 2D 块平铺和 1D 线程平铺 GEMM |
自定义 GEMM 核心 V03 向量化 | 2.14047 | 2D 块平铺和 1D 线程平铺,带向量化内存访问 |
自定义 GEMM 核心 V04 | 20.2746 | 2D 块平铺和 2D 线程平铺 GEMM |
自定义 GEMM 核心 V04 向量化 | 22.9001 | 2D 块平铺和 2D 线程平铺,带向量化内存访问 |
自定义 GEMM 核心 V05 | 18.3736 | 2D 块平铺和 2D 线程平铺和矩阵转置 GEMM |
自定义 GEMM 核心 V05 向量化 | 27.962 | 2D 块平铺和 2D 线程平铺和矩阵转置,带向量化内存访问 |
自定义 GEMM 核心 V06 | 14.7622 | 2D 块平铺和 2D 线程束平铺和 2D 线程平铺和矩阵转置 GEMM |
自定义 GEMM 核心 V06 向量化 | 28.4588 | 2D 块平铺和 2D 线程束平铺和 2D 线程平铺和矩阵转置,带向量化内存访问 |
自定义 GEMM 核心 V07 | 35.2312 | 2D 块平铺和 2D 线程束平铺和 WMMA 和矩阵转置 |
自定义 GEMM 核心 V07 向量化 | 55.0298 | 2D 块平铺和 2D 线程束平铺和 WMMA 和矩阵转置,带向量化内存访问 |