当运行的线程数超过内核数时,CUDA性能会得到提高

CUDA performance improves when running more threads than there are cores

本文关键字:性能 CUDA 运行 线程 内核      更新时间:2023-10-16

当我每个块运行超过32个线程时,为什么性能会提高?

我的显卡有480个CUDA核心(15 MS*32 SP)。

每个SM都有1-4个warp调度器(Tesla=1,Fermi=2,Kepler=4)。每个warp调度器负责执行分配给SM的warp的子集。每个warp调度程序都维护一个合格warp的列表。如果warp能够在下一个周期发出指令,那么它就是合格的。如果扭曲因数据依赖关系而暂停,等待获取和指令,或者下一条指令的执行单元正忙,则它不符合条件。在每个循环中,每个曲速调度器将从符合条件的曲速列表中选择一个曲速,并发出1或2条指令。

每个SM的活动扭曲越多,每个扭曲调度器在每个周期上必须从中挑选的扭曲数量就越大。在大多数情况下,当每个SM有足够的活动翘曲以使每个翘曲调度器每个周期有1个合格的翘曲时,可以实现最佳性能。增加占用率超过此点不会提高性能,可能会降低性能。

主动翘曲的典型目标是SM最大翘曲的50-66%。由发射配置支持的翘曲与最大翘曲的比率称为理论占有率。每个周期的活动扭曲与每个周期的最大扭曲的运行时比率为"已实现占用"。对于GTX480(CC 2.0设备),设计内核时的一个良好起点是50-66%的理论占用率。CC 2.0 SM最多可以有48次翘曲。50%的占有率意味着每SM 24次翘曲或768条线程。

Nsight Visual Studio Edition中的CUDA评测活动可以显示理论占用率、实现的占用率、每个SM的活动扭曲、每个SM符合条件的扭曲以及失速原因。

CUDA Visual Profiler、nvprof和命令行探查器可以显示理论占用率、活动扭曲率和已实现占用率。

注:CUDA核心的计数只能用于比较类似体系结构的卡,计算理论FLOPS,以及潜在地比较体系结构之间的差异。在设计算法时不要使用计数。

欢迎使用堆栈溢出。原因是CUDA内核是流水线式的。在费米上,这条管道大约有20个时钟长。这意味着要使GPU饱和,每个内核可能需要多达20个线程。

主要原因是CUDA的内存延迟隐藏模型。大多数现代CPU使用缓存来隐藏主内存的延迟。这导致很大比例的芯片资源被用于高速缓存。大多数台式机和服务器处理器的裸片上都有几兆字节的缓存,这实际上占了大部分裸片空间。为了封装更多具有相同能耗和散热特性的内核,基于CUDA的芯片转而将其芯片空间用于部署大量的CUDA内核(这些内核大多只是浮点ALU)。由于缓存非常少,相反,它们依赖于让更多的线程准备好运行,而其他线程则在等待内存访问返回,以隐藏延迟。这为内核提供了一些高效的工作,而一些扭曲正在等待内存访问。每个SM的翘曲越多,其中一个在任何给定时间都能运行的机会就越大。

CUDA还具有零成本线程切换,以帮助实现这种内存延迟隐藏方案。一个普通的CPU从一个线程的执行切换到下一个线程会产生很大的开销,因为它需要将要切换的线程的所有寄存器值存储到堆栈上,然后加载要切换到的线程的全部寄存器值。CUDA SM只有大量的寄存器,因此,在线程的整个生命周期中,每个线程都有自己的一组物理寄存器分配给它。由于不需要存储和加载寄存器值,每个SM可以在一个时钟周期上执行来自一个扭曲的线程,并在下一个时钟循环上执行来自不同扭曲的线程。