简介#

Warp是SIMT线程执行和调度的基本单位。一个线程块内的线程按照线性线程索引划分为多个Warp,当前一个Warp包含32个线程。同一Warp内的线程执行相同的指令流,每个线程拥有独立的寄存器和Lane ID,可以处理不同的数据地址和分支路径。

Warp函数用于同一Warp内的轻量级线程协作,提供Lane信息查询、条件投票、寄存器数据交换和Warp内归约等能力。与通过Unified Buffer(UB)中转数据相比,Warp Shuffle函数可以直接交换Lane持有的标量值,适合低开销的小范围协作。

相关基本概念如下表所示:

概念

说明

Warp

SIMT执行中的线程分组,当前一个Warp包含32个线程。

Lane

Warp内单个线程对应的执行位置。

Lane ID

线程在当前Warp内的编号,取值范围为[0, 31]。

活跃线程

在当前指令位置实际参与执行的线程,也称为活跃Lane。活跃状态与指令位置有关,不是线程的固定属性。

分支发散

同一Warp内的线程进入不同分支路径。硬件依次执行各条路径,并暂时屏蔽不属于当前路径的Lane。

逻辑子组

Shuffle函数通过width将一个Warp划分得到的独立交换分组。

活跃线程是指在当前指令位置实际执行指令的线程。活跃状态会随着程序执行位置变化:某个Lane在一条分支路径中可能暂时处于非活跃状态,进入后续公共路径后又会重新处于活跃状态。因此,“非活跃”通常不表示线程已经结束,只表示该Lane不执行当前路径上的指令。

当同一Warp内的Lane根据各自的数据进入不同分支时,会发生分支发散。硬件先执行其中一条路径,并屏蔽不属于该路径的Lane;再执行其他路径;各条路径结束后,Lane在公共路径上重新汇合。下面以一个包含32个Lane的Warp为例,前后各16个Lane进入不同分支:

lane = pl.simt.lane_id()
if lane < 16:
    lower_mask = pl.simt.warp_active_mask()
else:
    upper_mask = pl.simt.warp_active_mask()
merged_mask = pl.simt.warp_active_mask()

各调用位置观察到的活跃Lane如下:

调用位置

正在执行的Lane

32位活跃掩码(bit 31到bit 0)

lower_mask

Lane 0~15

00000000 00000000 11111111 11111111

upper_mask

Lane 16~31

11111111 11111111 00000000 00000000

merged_mask

Lane 0~31

11111111 11111111 11111111 11111111

这里的lower_mask和upper_mask虽然位于同一个Warp中,但处于不同分支路径,因此得到不同的活跃Lane集合。分支结束后,32个Lane在merged_mask处重新汇合。