以下是关于warp function的一些理解
主要参考资料是nVidia的官方文档
前提
warp的概念不加赘述,且建议在capability 7.x以上且cuda9.0以上的GPU上测试,有些函数在例如 any, all, and __ballot等在cuda9.0上已经被移除。
predicate表示线程的一种状况
以下所有的实例,使用一个block,block块的大小是32,所说的线程号就是laneID
mask中的第i个bit表示第i个线程
warp vote functions
- 允许给定warp中的线程执行规约和广播操作
- 所有线程的lane的mask必须一致
1 | int __all_sync(unsigned mask, int predicate); |
__all_sync
评估mask
中所有non-exited的线程(线程对应mask的位是1)的predicate,返回非零值当且仅当mask中对应线程的predicate都是非零的。
__any_sync
评估mask
中所有non-exited的线程(线程对应mask的位是1)的predicate,返回非零值当且仅当mask中对应线程的predicate存在非零的。
_ballot_sync
评估mask
中所有non-exited线程的predicate,返回一个unsigned数,其第N位为1当且仅当mask
中线程的predicate非零
__activemask()
返回unsigned数 mask
,表示这个warp中所有的active状态的线程
1 | __global__ void wall(){ |
0x55555555
表示所有偶数位是1,奇数位是0。predicate
是所有的偶数线程是0,奇数线程是1。在__all_sync
下,所有线程的n是0,因为其只统计mask中non-exited的线程,0x55555555
使得__all_sync
只检查偶数位的线程,结果偶数位线程的predicate都是0。其余函数同理。
warp match functions
- 执行warp内线程之间变量的广播和比较操作
1 | unsigned int __match_any_sync(unsigned mask, T value); |
warp shuffle function
- 交换warp内部的线程的值
- 采用可选的width,必须是2的幂次,且不能大于warpsize
- mask的值没有影响,不管mask是什么,结果都一致
1
2
3
4
5
6
7T __shfl_sync(unsigned mask, T var, int srcLane, int width=warpSize);
T __shfl_up_sync(unsigned mask, T var, unsigned int delta, int width=warpSize);
T __shfl_down_sync(unsigned mask, T var, unsigned int delta, int width=warpSize);
T __shfl_xor_sync(unsigned mask, T var, int laneMask, int width=warpSize);
//T can be int, unsigned int, long, unsigned long, long long, unsigned long long, float or double. With the cuda_fp16.h header included, T can also be __halfor __half2. Similarly, with the cuda_bf16.h header included, T can also be __nv_bfloat16 or __nv_bfloat162.__shfl_sync()
返回srclane号线程的var,width
将warpsize的线程数进行划分,每个子段长度为width
。每个width
中的线程得到srclane
所指示的var
,注意这里srclane
都是width
中的相对位置。
若是每个线程的var
是它本身的线程值,那么__shfl_sync(mask,threadIdx.x,0,4)
,得到的结果是 4x0, 4x4, 4x8, 4x12, 4x16, 4x20, 4x24, 4x28, 4x32__shfl_sync(mask,x,2,8)
, 得到的结果是2x8, 10x8, 18x8, 26x8
_shfl_up_sync()
返回向前偏移为 delta
的线程中的变量 var
的值,其余线程返回0。width
将warpsize划分成warpsize/width个部分,每个部分返回的是当前的线程-delta的线程的value,若是减法结果为-,那么结果就不会变。注意这里是相对值,记得上面这个减法必须是要一个分组内。
例如
n=__shfl_up_sync(0xffffffff,value,15,16);
结果是0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 0 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 16
__shfl_down_sync()
线程返回向后偏移为 delta 的线程中的变量 var 的值,其余线程返回0 。
调用
__shfl_down_sync(mask, x, 2, 16)
; 则标号为 0-13 的线程分别获得标号为 2-15 的线程中变量 x 的值;标号为 16 -29 的线程分别获得标号为 18 - 31 的线程中变量 x 的值。
__shfl_xor_sync()
通过对调用者的通道ID与laneMask
进行按位异或(XOR)运算来计算源通道ID。返回值为计算所得源通道中的var值。此模式实现了蝶形寻址模式。如果width
小于warpsize,那么对于异或的结果,若是处于前面的group,那么可以获取异或的结果,若是处于后面的group,则会返回本身的var
例如
n=__shfl_xor_sync(0,threadIdx.x,3,4);
的结果是3 2 1 0 7 6 5 4 11 10 9 8 15 14 13 12 19 18 17 16 23 22 21 27 26 25 24 31 30 29 28
例如n=__shfl_xor_sync(0,threadIdx.x,3,2);
的结果是0 1 1 0 4 5 5 4 8 9 9 8 12 13 13 12 16 17 17 16 20 21 21 20 24 25 25 24 28 29 29 28