在一线互联网公司就职,对技术工作充满热爱,希望一生走技术的道路。
分类: 高性能计算
2025-03-24 18:56:59
CPU:大量的面积用来做了控制单元和cache,尽量保证低延迟,计算单元有限
GPU: 拥有大量的计算单元可以同时执行大量线程,有比较大的并发吞吐量,控制逻辑简单,缓存有限。
逻辑层:线程thread -> 线程块(block) -> 线程网格 Gird
物理层:GPU核心 cores -> 流多处理器SM -> GPU
目前的设备:
一个SM{BANNED}最佳多容纳32个block或者64个warp,共有64个寄存器,{BANNED}最佳大2048个线程。
一个block{BANNED}最佳大有1024个线程,一个warp按照32个线程一组划分
一个block会被分配到一个SM上执行(一个线程块的所有线程都在一个SM上执行)。
一个SM会被分配多个线程块block。
所以建议block的数量也就是 gird大于等于SM数。否则会有SM空闲。(L20显卡有92个SM, 拥有 11,776 个 CUDA 核心、368 个 Tensor 核心).
线程块分配给SM后会以32个线程为一组Warp 来分割成多个组,一个组(warp)也可以叫做线程束。
一个SM真正并行的是一个线程束,一个block的多个线程束是并发执行,并发和并行是不同的(并行是同时执行互不影响,并发是按时间片切换对外看上去是并行执行,实际单个核对线程有切换顺序执行的情况)
CUDA Stream(流):是一系列指令的队列。不同的流互不影响独立执行。
每个线程束(warp)只能是一个线程块block内部的线程。
一个线程束(warp){BANNED}最佳多32个线程,按照线程块block开头开始每32个线程划分一组。所以需要定义block的线程数量尽量是32的整数倍,否则{BANNED}最佳后一个线程束warp就会有浪费。
线程束才是真正在硬件SM上并行执行的单位,线程块block实际上是并发执行。
寄存器:每个线程独有的内存,只能线程内部使用。
共享内存:block内线程可共享的内存,可以提高块内线程数据通信效率。
本地内存:也是线程独有的内存,线程内部可用,性能比寄存器慢,线程内部寄存器分配不下的大的变量会分配到本地内存。单线程{BANNED}最佳大本地内存为512KB,为了性能尽量避免过多使用本地内存。
常量内存和纹理内存:可以跟主机的内存进行数据交互,所有线程都可以读取,但不可以修改。
全局内存:就是GPU显存,存储空间大,GPU内所有线程都可访问,但是{BANNED}最佳慢。
L1缓存:SM内部的缓存,跟sharememory总共192KB
L2缓存:GPU上的缓存,所有对显存(全局内存)的访问都是要经过L2, L2的数据是全局的。L2的访问速度比显存也就是全局内存快3倍。
L1 L2缓存是不支持编程控制的。 L20GPU参数: L1 128KB ,L2 96MB。
CPU和GPU的通信是靠PCie 速度较慢。多GPU间可通过PCIe连接但速度慢,也可以通过NVLink通信,速度较快。
可用于加速的CUDA库:
统计GPU核函数的耗时:
这个例子调用一个核函数addFromGPU多次,不统计{BANNED}中国第一次({BANNED}中国第一次启动核函数很慢),统计平均耗时。
性能分析工具:nvprof
使用方式:nvprof ./可执行的cuda程序
英伟达GPU分析工具:nvidia-smi
其中Perf列 性能由高到低 P0-P12.
命令:nvidia-smi 可以看到 GPU当前的信息
nvidia-smi -h 帮助指令 可以查看如何使用各种命令参数
nvidia-smi -q 查看显卡的详细信息
nvidia-smi -q -i 显卡编号 可以指定查看某个显卡的详细信息
nvidia-smi -q -i 0 -d memory查看0号显卡显存信息
cudaDeviceSynchronize用于同步当前设备上所有的CUDA流,它会阻塞当前线程直到GPU上的CUDA流都执行完毕。用于时序控制等待GPU线程执行完毕,然后确定结果可用。另外调用cudaMemorycpy()函数将结果拷贝回主机的时候,为了避免GPU还未执行完毕,函数内部隐含了cudaDeviceSynchronize的功能,cudaMemorycpy()函数会阻塞等待 GPU核函数执行完毕然后再做数据拷贝。
定义一个通用的错误检测函数,用于检测CUDA运行时API的返回值。
对核函数执行进行检测
调用的例子:
轻量级CUDA c++封装,Thin C++-flavored wrappers for CUDA APIs:cuda-api-wrappers
CUDA Toolkit Documentation 12.6 Update 3
按节点调度GPU
#SBATCH --gpus-per-node=1
#SBATCH --gres=gpu:4每个节点使用 4 个 GPU 资源
任务共享GPU
#SBATCH --gpus-per-task=0.5
#SBATCH --gres=gpu:all # 请求每个节点上的所有GPU