CUDA
参考资料
官方资料:
其他
英伟达各型号 GPU 的关键参数: https://en.wikipedia.org/wiki/List_of_Nvidia_graphics_processing_units
一些未仔细核验的资料:
基本概念
术语方面, GPU 硬件与 CUDA 软件术语有些使用了同样的词。
一个 GPU 由如下部分组成 (参考 https://medium.com/analytics-vidhya/cuda-memory-model-823f02cef0bf)
多个 SM (Streaming Multiprocessor, 有时候也被简称为 Multiprocessor)
多个 CUDA Cores
Shared Memory
L1 Cache
Read-Only DataCache
L2 Cache
DRAM (GPU主存)
机器信息:
GeForce MX250: Windows + WSL2
Tesla V100-PCIE-16GB: 虚拟化 linux 云主机
GeForce GTX 1650: Windows + WSL2
使用 cuda-samples 可以查看 GPU 的设备信心
输出 (重新 format 了一下, 便于对比):
这里我们先关注这几个值 (以 V100 为例):
deviceProp.maxThreadsPerBlock=1024: CUDA 编程模型视角里 block 的三个维度之积不能超过 1024deviceProp.maxThreadsPerMultiProcessor=2048: 一个 SM 可以同时执行的最大硬件线程数为 2048, 注意从 CUDA 编程视角来看, 一个 block 里的所有线程都会被运行在同一个 SM 上 (注意可能不会是并发执行的), 而最终在运行 thread 时, thread 会映射到硬件线程上, 例如 block 的三个维度之积为 68 (这不是最佳实践, 假设硬件的 warp 的大小为 32), 那么这 68 个软件意义上的线程会被分为 32+32+4 三组, 其中每组内的软件线程总是会映射到同一个硬件线程束 (warp) 上并发执行的, 但这三组 warp 有可能不是并发执行的, 但无论如何, 这 68 个线程一定都在同一个 SM 上执行.deviceProp.multiProcessorCount=80: GPU 包含 80 个 SM_ConvertSMVer2Cores(deviceProp.major, deviceProp.minor)=64: 每个 SM 包含 64 个 CUDA CoredeviceProp.maxThreadsDim=(1024, 1024, 64). 这代表了 CUDA 编程模型视角里每个 block 的软件线程数在三个维度上的最大值, 注意还需满足三个维度之积不超过deviceProp.maxThreadsPerBlock=1024deviceProp.maxGridSize=(2147483647, 65535, 65535). 这代表了 CUDA 编程模型视角里每个 grid 的 block 数在三个维度上的最大值, 也就是说一个核函数最多只能由2147483647*65535*65535*1024个线程来完成整个任务.
关于 warp: warp 是硬件层的概念, 一个 warp 里的 32 个物理线程严格并发执行, 且并发执行的指令一模一样, 当然, 操作数可以是不一样的 (这种模式也被称作 SIMD, 即 Single Instruction, Multiple Data).
关于 block: block 是纯粹的软件视角的概念
warp 与 CUDA Core 的关系: 这篇 博客 里有个误解是 1 个 CUDA Core 就对应 1 个 warp, 但根据这个问答:
Now your Card has a total Number of 384 cores on 2 SMs with 192 cores each. The CUDA core count represents the total number of single precision floating point or integer thread instructions that can be executed per cycle. Do not consider CUDA cores in any calculation.
我们在使用这种方式调用核函数时:
理论上说:
threadIdx, blockDim, blockIdx, gridDim
https://erangad.medium.com/1d-2d-and-3d-thread-allocation-for-loops-in-cuda-e0f908537a52
注意: threadIdx.x 和 blockIdx.x 是变化最快的维度: 上面的例子里: threadIdx.x=0, threadIdx.y=1, threadIdx.z=2 的下一个 thread 是 threadIdx.x=1, threadIdx.y=1, threadIdx.z=2, 即:
执行逻辑
参考: https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#compute-capability-5-x
假设一次调用包含 8 个 block, 每个 block 中有 512 个 thread, 即使用这种方式进行调用, kernel_fun <<<8, 512>>> (p); 假设 warp 大小为 32, 那么每个 block 的前 32 个 thread 将会最终映射到一个 warp 上, 后 32 个也会映射到一个 warp 上 (warp 不是硬件概念, 而是意味着前 32 个 thread 在同一时钟周期内会执行相同的指令). 假设 GPU 有 80 个 SM, 而每个 SM 包含 4 个 warp scheduler, 那么当一个 block 被调度到一个 SM 上后 (block 一旦被调度到 SM, 那么一定会将其完成, 不会被切换到别的 SM 上), SM 会进一步分配给 4 个 warp scheduler 来处理, 在前面的例子里, 一个 block 被分为 16 组, 一个可能的情况是:
而以 2 号调度器为例, 假设之前描述的每个 thread 只包含 2 个指令, 具体的执行顺序可能是:
注意, 在 warp2, warp3, warp6 在执行过程中, 有可能会插入别的 block 的执行, 但是 warp scheduler 的同一时间, 只能执行一个 warp. 也就是说在这个例子里, 一个 SM 的最大并发量是 4 * 32 = 128 个线程.
FAQ & 杂录
compute-capability 与 cuda-architecture 是同一个意思: 问答
最大单精度浮点数计算次数: MX250: 797.2 GFLOPS, V100: 14028 GFLOPS, GTX1650: 2984 GFLOPS
矩阵乘法
benchmark for (1024 x 1024) x (1024 x 1024)
cuda-sample/matrixMul
MX250: 140 GFLOPS / 797.2 GFLOPS
V100: 3800 GFLOPS / 14028 GFLOPS
GTX1650: 426 GFLOPS / 2984 GFLOPS
Last updated
Was this helpful?