在Volta之前,warp使用在warp中的所有32个线程中共享的单个程序计数器,以及指定warp的活动线程的活动掩码。 结果,来自发散区域或不同执行状态的相同的线程的线程不能互相发送信号或交换数据,并且要求由锁或互斥锁保护的数据的细粒度共享的算法可容易地导致死锁,这取决于哪个warp 争夺线程来自。
从Volta体系结构开始,独立线程调度允许线程之间完全并发,而不管是否发生变形。 使用独立线程调度,GPU保持每个线程的执行状态,包括程序计数器和调用堆栈,并且可以以每线程粒度产生执行,以更好地使用执行资源或允许一个线程等待数据 由另一个生产。 计划优化程序确定如何将来自同一个warp的活动线程一起分组到SIMT单元中。 与以前的NVIDIA GPU一样,这保留了SIMT执行的高吞吐量,但具有更多的灵活性:线程现在可以在次级粒度下分离和重新对齐。
如果开发人员对以前的硬件体系结构的warpsynchronicity1进行了假设,那么独立线程调度可能导致参与执行代码的一组相当不同的线程。 特别是,应该重新考虑任何warp同步代码(如同步自由,内部warp减少),以确保与volta及以后的兼容性。 有关更多详细信息,请参阅计算能力7.x。
术语“同步同步”是指隐含地假设在同一个warp中的线程在每个指令处同步的代码。
参与当前指令的warp线程称为活动线程,而不在当前指令的线程处于非活动状态(禁用状态)。 由于多种原因,线程可以是不活动的,包括比其他线程更早退出,采用与当前执行的分支路径不同的分支路径,或者是线程数量不是最后的线程 经纱大小的倍数。
如果由warp执行的非原子指令写入全局或共享内存中的warp的多个线程中的相同位置,则发生到该位置的序列化写入的数目根据设备的计算能力 (请参阅计算能力3.x,计算能力5.x,计算能力6.x和计算能力7.x),以及哪个线程执行最终写入是未定义的。
如果由warp执行的原子指令读取,修改并写入全局内存中的多个线程的相同位置,则每个读取/修改/写入到该位置,并且它们全部被序列化,但是 它们发生的顺序是不确定的。
硬件多线程:
由多处理器处理的每个warp的执行上下文(程序计数器,寄存器等)在warp的整个生命周期内都被保持在芯片上。 因此,从一个执行上下文切换到另一个执行上下文没有成本,并且在每个指令发布时间,warp调度器选择具有准备好执行其下一个指令(warp的活动线程)的线程的warp,并向这些线程发出指令。
特别是,每个多处理器都有一组32位的寄存器,这些寄存器被划分在各个线程之间,以及一个并行数据缓存或在线程块之间分配的共享内存。
在一个给定的内核中,可以在多处理器中驻留和处理的块和变量的数量取决于内核使用的寄存器和共享内存的数量以及多处理器上可用的寄存器和共享内存的数量。 每个多处理器也有最大数量的驻留块和最大驻留量。 这些限制以及多处理器上可用的寄存器和共享内存的数量是设备计算能力的函数,并在附录计算能力中给出。 如果每个多处理器没有足够的寄存器或共享内存来处理至少一个块,则内核将无法启动。
在一个block中warps的总数如下:
$ceil(\frac{T}{W_{size}},1)$
- T是每块的线程数
- $W_{size}$是warp的大小等于32
- $ceil(x,y)$等于x四舍五入到y的最接近的倍数。