CUDA 核函数 API
CUDA 内置目标弃用通知
Numba 内置的 CUDA 目标已被弃用,进一步的开发已移至 NVIDIA numba-cuda 包。请参阅 内置 CUDA 目标弃用和维护状态。
核函数声明
@cuda.jit
装饰器用于创建可配置和启动的 CUDA 调度器对象。
- numba.cuda.jit(func_or_sig=None, device=False, inline=False, link=[], debug=None, opt=True, lineinfo=False, cache=False, **kws)
为 CUDA GPU JIT 编译 Python 函数。
- 参数
func_or_sig –
要进行 JIT 编译的函数,或要编译函数的签名。如果提供函数,则返回
Dispatcher
。否则,func_or_sig
可以是单个签名或签名列表,并返回一个函数。返回的函数接受另一个函数,该函数将被编译并返回一个Dispatcher
。有关传递签名的更多信息,请参阅 JIT 函数。注意
核函数不能有任何返回值。
device (bool) – 指示这是否为设备函数。
link (list) – 包含 PTX 或 CUDA C/C++ 源文件的列表,用于与函数链接。
debug – 如果为 True,则在执行核函数时检查抛出的异常。由于这会降低性能,因此应仅用于调试目的。如果设置为 True,则
opt
应设置为 False。默认为 False。(默认值可以通过设置环境变量NUMBA_CUDA_DEBUGINFO=1
来覆盖。)fastmath – 当为 True 时,启用 CUDA Fast Math 文档中概述的快速数学优化。
max_registers – 请求将核函数限制为每个线程最多使用此数量的寄存器。如果 ABI 要求比请求更多的寄存器,则此限制可能不被遵守。对于提高占用率很有用。
opt (bool) – 是否启用优化从 LLVM IR 编译到 PTX。当为
True
时,-opt=3
传递给 NVVM。当为False
时,-opt=0
传递给 NVVM。默认为True
。lineinfo (bool) – 如果为 True,则生成源代码和汇编代码之间的行映射。这使得在 NVIDIA 分析工具中检查源代码并与程序计数器采样相关联成为可能。
cache (bool) – 如果为 True,则为此函数启用基于文件的缓存。
调度器对象
使用下标配置调度器以进行启动的常用语法如下,其参数如下:
# func is some function decorated with @cuda.jit
func[griddim, blockdim, stream, sharedmem]
griddim
和 blockdim
参数指定网格和线程块的大小,可以是整数或长度最多为 3 的元组。stream
参数是可选的,表示核函数将在此流上启动,而 sharedmem
参数指定动态共享内存的大小(以字节为单位)。
对调度器进行下标操作会返回一个配置对象,该对象可以通过核函数参数调用
configured = func[griddim, blockdim, stream, sharedmem]
configured(x, y, z)
然而,更惯用的做法是在一个语句中配置和调用核函数
func[griddim, blockdim, stream, sharedmem](x, y, z)
这与 CUDA C/C++ 中的启动配置类似
func<<<griddim, blockdim, sharedmem, stream>>>(x, y, z)
注意
Numba 中 stream
和 sharedmem
的顺序与 CUDA C/C++ 中相反。
调度器对象还提供了几个用于检查和创建专门实例的实用方法
- class numba.cuda.dispatcher.CUDADispatcher(py_func, targetoptions, pipeline_class=<class 'numba.cuda.compiler.CUDACompiler'>)
CUDA 调度器对象。配置并调用后,调度器将根据给定的参数(如果尚无合适的专用版本)和计算能力进行专门化,并在与当前上下文关联的设备上启动。
调度器对象不由用户构造,而是使用
numba.cuda.jit()
装饰器创建。- property extensions
一个对象列表,这些对象必须具有 prepare_args 函数。当调用专用核函数时,每个参数都将通过 prepare_args(从列表中最后一个对象到第一个对象)传递。传递给 prepare_args 的参数是:
ty 参数的 numba 类型
val 参数值本身
stream 用于当前核函数调用的 CUDA 流
retr 一个零参数函数列表,你可以向其追加调用后的清理工作。
prepare_args 函数必须返回一个元组 (ty, val),该元组将依次传递给下一个最右侧的 extension。在所有扩展都被调用后,结果 (ty, val) 将传递给 Numba 的默认参数调度逻辑。
- forall(ntasks, tpb=0, stream=0, sharedmem=0)
返回针对给定任务数量的 1D 配置调度器。
这假定:
核函数将全局线程 ID
cuda.grid(1)
与任务一对一映射。核函数检查全局线程 ID 不超过
ntasks
,如果不符合则不执行任何操作。
- 参数
ntasks – 任务数量。
tpb – 块的大小。如果未提供此参数,则选择适当的值。
stream – 配置好的调度器将在此流上启动。
sharedmem – 核函数所需的动态共享内存字节数。
- 返回
一个配置好的调度器,准备好在一组参数上启动。
- get_const_mem_size(signature=None)
返回此核函数在当前上下文的设备上使用的常量内存大小(以字节为单位)。
- 参数
signature – 要获取常量内存用量的已编译核函数的签名。对于专用核函数,此项可以省略。
- 返回
针对给定签名和当前设备的已编译核函数变体所分配的常量内存大小(以字节为单位)。
- get_local_mem_per_thread(signature=None)
返回此核函数每个线程的局部内存大小(以字节为单位)。
- 参数
signature – 要获取局部内存用量的已编译核函数的签名。对于专用核函数,此项可以省略。
- 返回
针对给定签名和当前设备的已编译核函数变体所分配的局部内存量。
- get_max_threads_per_block(signature=None)
返回此核函数每个块允许的最大线程数。超过此阈值将导致核函数无法启动。
- 参数
signature – 要获取每个块最大线程数的已编译核函数的签名。对于专用核函数,此项可以省略。
- 返回
针对给定签名和当前设备的已编译核函数变体允许的最大每个块线程数。
- get_regs_per_thread(signature=None)
返回此核函数中每个线程在当前上下文的设备上使用的寄存器数量。
- 参数
signature – 要获取寄存器用量的已编译核函数的签名。对于专用核函数,此项可以省略。
- 返回
针对给定签名和当前设备的已编译核函数变体使用的寄存器数量。
返回此核函数静态分配的共享内存大小(以字节为单位)。
- 参数
signature – 要获取共享内存用量的已编译核函数的签名。对于专用核函数,此项可以省略。
- 返回
针对给定签名和当前设备的已编译核函数变体所分配的共享内存量。
- inspect_asm(signature=None)
返回此核函数在当前上下文的设备上的 PTX 汇编代码。
- 参数
signature – 参数类型的元组。
- 返回
给定签名的 PTX 代码,或所有先前遇到的签名的 PTX 代码字典。
- inspect_llvm(signature=None)
返回此核函数的 LLVM IR。
- 参数
signature – 参数类型的元组。
- 返回
给定签名的 LLVM IR,或所有先前遇到的签名的 LLVM IR 字典。
- inspect_sass(signature=None)
返回此核函数在当前上下文的设备上的 SASS 汇编代码。
- 参数
signature – 参数类型的元组。
- 返回
给定签名的 SASS 代码,或所有先前遇到的签名的 SASS 代码字典。
返回当前上下文设备上的 SASS。
需要 nvdisasm 在 PATH 中可用。
- inspect_types(file=None)
生成此函数的 Python 源代码转储,并附带相应的 Numba IR 和类型信息。转储写入到 file,如果 file 为 None 则写入 sys.stdout。
- specialize(*args)
创建此调度器的新实例,并针对给定 args 进行专门化。
- property specialized
如果调度器已专门化,则为 True。
内在属性和函数
本节其余属性和函数只能在 CUDA 核函数内部调用。
线程索引
- numba.cuda.threadIdx
当前线程块中的线程索引,通过属性
x
,y
和z
访问。每个索引都是一个整数,范围从 0(包含)到numba.cuda.blockDim
中对应属性值(不包含)的范围。
- numba.cuda.blockIdx
线程块网格中的块索引,通过属性
x
,y
和z
访问。每个索引都是一个整数,范围从 0(包含)到numba.cuda.gridDim
中对应属性值(不包含)的范围。
- numba.cuda.blockDim
线程块的形状,在实例化核函数时声明。此值对于给定核函数中的所有线程都相同,即使它们属于不同的块(即每个块都是“满的”)。
- numba.cuda.gridDim
块网格的形状,通过属性
x
,y
和z
访问。
- numba.cuda.laneid
当前 warp 中的线程索引,一个整数,范围从 0(包含)到
numba.cuda.warpsize
(不包含)。
- numba.cuda.warpsize
GPU 上一个 warp 的线程大小。目前始终为 32。
- numba.cuda.grid(ndim)
返回当前线程在整个块网格中的绝对位置。ndim 应与实例化核函数时声明的维度数量相对应。如果 ndim 为 1,则返回一个整数。如果 ndim 为 2 或 3,则返回给定数量整数的元组。
第一个整数的计算方式如下:
cuda.threadIdx.x + cuda.blockIdx.x * cuda.blockDim.x
其他两个索引的计算方式类似,但使用
y
和z
属性。
- numba.cuda.gridsize(ndim)
返回整个块网格的绝对大小(或形状)(以线程为单位)。ndim 应与实例化核函数时声明的维度数量相对应。
第一个整数的计算方式如下:
cuda.blockDim.x * cuda.gridDim.x
其他两个索引的计算方式类似,但使用
y
和z
属性。
内存管理
使用给定的
shape
和dtype
在 CUDA 核函数的局部内存空间中创建一个数组。返回一个内容未初始化的数组。
注意
同一线程块中的所有线程都看到相同的数组。
- numba.cuda.local.array(shape, dtype)
使用给定的
shape
和dtype
在 CUDA 核函数的局部内存空间中创建一个数组。返回一个内容未初始化的数组。
注意
每个线程看到一个唯一的数组。
- numba.cuda.const.array_like(ary)
在编译时将
ary
复制到 CUDA 核函数的常量内存空间中。返回一个类似于
ary
参数的数组。注意
所有线程和块都看到相同的数组。
同步和原子操作
- numba.cuda.atomic.add(array, idx, value)
执行
array[idx] += value
。仅支持 int32、int64、float32 和 float64。idx
参数可以是整数,也可以是整数索引元组,用于多维数组索引。idx
中的元素数量必须与array
的维度数量匹配。返回存储新值之前
array[idx]
的值。行为类似于原子加载。
- numba.cuda.atomic.sub(array, idx, value)
执行
array[idx] -= value
。仅支持 int32、int64、float32 和 float64。idx
参数可以是整数,也可以是整数索引元组,用于多维数组索引。idx
中的元素数量必须与array
的维度数量匹配。返回存储新值之前
array[idx]
的值。行为类似于原子加载。
- numba.cuda.atomic.and_(array, idx, value)
执行
array[idx] &= value
。仅支持 int32、uint32、int64 和 uint64。idx
参数可以是整数,也可以是整数索引元组,用于多维数组索引。idx
中的元素数量必须与array
的维度数量匹配。返回存储新值之前
array[idx]
的值。行为类似于原子加载。
- numba.cuda.atomic.or_(array, idx, value)
执行
array[idx] |= value
。仅支持 int32、uint32、int64 和 uint64。idx
参数可以是整数,也可以是整数索引元组,用于多维数组索引。idx
中的元素数量必须与array
的维度数量匹配。返回存储新值之前
array[idx]
的值。行为类似于原子加载。
- numba.cuda.atomic.xor(array, idx, value)
执行
array[idx] ^= value
。仅支持 int32、uint32、int64 和 uint64。idx
参数可以是整数,也可以是整数索引元组,用于多维数组索引。idx
中的元素数量必须与array
的维度数量匹配。返回存储新值之前
array[idx]
的值。行为类似于原子加载。
- numba.cuda.atomic.exch(array, idx, value)
执行
array[idx] = value
。仅支持 int32、uint32、int64 和 uint64。idx
参数可以是整数,也可以是整数索引元组,用于多维数组索引。idx
中的元素数量必须与array
的维度数量匹配。返回存储新值之前
array[idx]
的值。行为类似于原子加载。
- numba.cuda.atomic.inc(array, idx, value)
执行
array[idx] = (0 if array[idx] >= value else array[idx] + 1)
。仅支持 uint32 和 uint64。idx
参数可以是整数,也可以是整数索引元组,用于多维数组索引。idx
中的元素数量必须与array
的维度数量匹配。返回存储新值之前
array[idx]
的值。行为类似于原子加载。
- numba.cuda.atomic.dec(array, idx, value)
执行
array[idx] = (value if (array[idx] == 0) or (array[idx] > value) else array[idx] - 1)
。仅支持 uint32 和 uint64。idx
参数可以是整数,也可以是整数索引元组,用于多维数组索引。idx
中的元素数量必须与array
的维度数量匹配。返回存储新值之前
array[idx]
的值。行为类似于原子加载。
- numba.cuda.atomic.max(array, idx, value)
执行
array[idx] = max(array[idx], value)
。仅支持 int32、int64、float32 和 float64 类型。idx
参数可以是整数,也可以是用于索引多维数组的整数索引元组。idx
中的元素数量必须与array
的维度数量匹配。返回存储新值之前
array[idx]
的值。行为类似于原子加载。
- numba.cuda.atomic.cas(array, idx, old, value)
执行
if array[idx] == old: array[idx] = value
。仅支持 int32、int64、uint32、uint64 索引。idx
参数可以是整数,也可以是用于索引多维数组的整数索引元组。idx
中的元素数量必须与array
的维度数量匹配。返回存储新值之前
array[idx]
的值。行为类似于原子比较并交换操作。
- numba.cuda.syncthreads()
同步同一线程块中的所有线程。此函数实现了传统多线程编程中屏障的相同模式:此函数会等待块中的所有线程都调用它,然后它会将控制权返回给所有调用者。
- numba.cuda.syncthreads_count(predicate)
是
numba.cuda.syncthreads
的扩展,其返回值是predicate
为真的线程数量。
- numba.cuda.syncthreads_and(predicate)
是
numba.cuda.syncthreads
的扩展,如果predicate
对所有线程都为真,则返回 1,否则返回 0。
- numba.cuda.syncthreads_or(predicate)
是
numba.cuda.syncthreads
的扩展,如果predicate
对任何线程都为真,则返回 1,否则返回 0。警告
所有 syncthreads 函数都必须由线程块中的每个线程调用。未能这样做可能会导致未定义的行为。
协作组
- numba.cuda.cg.this_grid()
获取当前网格组。
- 返回
当前网格组
- 返回类型
- class numba.cuda.cg.GridGroup
一个网格组。用户不应直接构造 GridGroup,而应使用
cg.this_grid()
获取当前网格组。- sync()
同步当前网格组。
内存屏障
内存屏障用于保证内存操作的效果在同一线程块、同一 GPU 设备和同一系统(跨 GPU 的全局内存)中的其他线程可见。优化过程保证内存加载和存储不会跨越内存屏障。
警告
内存屏障被认为是高级 API,大多数用例应使用线程屏障(例如 syncthreads()
)。
- numba.cuda.threadfence()
设备级别的内存屏障(在 GPU 内部)。
- numba.cuda.threadfence_block()
线程块级别的内存屏障。
- numba.cuda.threadfence_system()
系统级别的内存屏障(跨 GPU)。
Warp 内联函数
参数 membermask
是一个 32 位整数掩码,其中每个位对应 warp 中的一个线程,1 表示该线程位于函数调用中的线程子集中。如果 GPU 计算能力低于 7.x,则 membermask
必须全为 1。
- numba.cuda.syncwarp(membermask)
同步 warp 中线程的掩码子集。
- numba.cuda.all_sync(membermask, predicate)
如果掩码 warp 中的所有线程的
predicate
都为真,则返回非零值,否则返回 0。
- numba.cuda.any_sync(membermask, predicate)
如果掩码 warp 中的任何线程的
predicate
为真,则返回非零值,否则返回 0。
- numba.cuda.eq_sync(membermask, predicate)
如果掩码 warp 中所有线程的布尔
predicate
都相同,则返回非零值,否则返回 0。
- numba.cuda.ballot_sync(membermask, predicate)
返回 warp 中
predicate
为真且在给定掩码内的所有线程的掩码。
- numba.cuda.shfl_sync(membermask, value, src_lane)
在掩码 warp 中随机重排
value
并返回来自src_lane
的value
。如果此超出 warp 范围,则返回给定的value
。
- numba.cuda.shfl_up_sync(membermask, value, delta)
在掩码 warp 中随机重排
value
并返回来自laneid - delta
的value
。如果此超出 warp 范围,则返回给定的value
。
- numba.cuda.shfl_down_sync(membermask, value, delta)
在掩码 warp 中随机重排
value
并返回来自laneid + delta
的value
。如果此超出 warp 范围,则返回给定的value
。
- numba.cuda.shfl_xor_sync(membermask, value, lane_mask)
在掩码 warp 中随机重排
value
并返回来自laneid ^ lane_mask
的value
。
- numba.cuda.match_any_sync(membermask, value, lane_mask)
返回掩码 warp 中与给定
value
具有相同value
的线程的掩码。
- numba.cuda.match_all_sync(membermask, value, lane_mask)
返回一个元组 (mask, pred),其中 mask 是掩码 warp 中与给定
value
具有相同value
的线程的掩码(如果它们都具有相同的值,否则为 0)。pred 是一个布尔值,指示掩码 warp 中的所有线程是否都具有相同的值。
- numba.cuda.activemask()
返回调用 warp 中所有当前活动线程的 32 位整数掩码。如果在调用 `activemask()` 时 warp 中的第 N 个 lane 处于活动状态,则第 N 位将被设置。不活动线程在返回的掩码中以 0 位表示。已退出内核的线程始终标记为不活动。
- numba.cuda.lanemask_lt()
返回所有 ID 小于当前 lane 的 lane(包括不活动 lane)的 32 位整数掩码。
整数内联函数
CUDA 数学 API 的整数内联函数的一个子集可用。有关更多文档,包括语义,请参阅 CUDA 工具包文档。
- numba.cuda.popc(x)
返回
x
中设置的位数。
- numba.cuda.brev(x)
返回
x
的位模式的反转。例如,0b10110110
变为0b01101101
。
- numba.cuda.clz(x)
返回
x
中前导零的数量。
- numba.cuda.ffs(x)
返回
x
中第一个(最低有效)设置为 1 的位的位置,其中最低有效位的位置为 1。ffs(0)
返回 0。
浮点内联函数
CUDA 数学 API 的浮点内联函数的一个子集可用。有关更多文档,包括语义,请参阅 CUDA 工具包文档的单精度和双精度部分。
- numba.cuda.fma()
执行融合乘加操作。以 C API 中的
fma
和fmaf
命名,但映射到fma.rn.f32
和fma.rn.f64
(就近舍入)PTX 指令。
- numba.cuda.cbrt(x)
执行立方根操作,即 x ** (1/3)。以 C API 中的函数
cbrt
和cbrtf
命名。仅支持 float32 和 float64 参数。
16 位浮点内联函数
cuda.fp16
模块中的函数用于操作 16 位浮点操作数。这些函数返回 16 位浮点结果。
要确定 Numba 在当前配置中是否支持编译使用 float16
类型的代码,请使用
- numba.cuda.is_float16_supported()
如果支持 16 位浮点数,则返回
True
,否则返回False
。
要检查设备是否支持 float16
,请使用其 supports_float16
属性。
- numba.cuda.fp16.hfma(a, b, c)
在就近舍入模式下,对 16 位浮点参数执行融合乘加操作
(a * b) + c
。映射到fma.rn.f16
PTX 指令。返回融合乘加的 16 位浮点结果。
- numba.cuda.fp16.hadd(a, b)
在就近舍入模式下,对 16 位浮点参数执行加法操作
a + b
。映射到add.f16
PTX 指令。返回加法的 16 位浮点结果。
- numba.cuda.fp16.hsub(a, b)
在就近舍入模式下,对 16 位浮点参数执行减法操作
a - b
。映射到sub.f16
PTX 指令。返回减法的 16 位浮点结果。
- numba.cuda.fp16.hmul(a, b)
在就近舍入模式下,对 16 位浮点参数执行乘法操作
a * b
。映射到mul.f16
PTX 指令。返回乘法的 16 位浮点结果。
- numba.cuda.fp16.hdiv(a, b)
在就近舍入模式下,对 16 位浮点参数执行除法操作
a / b
。返回除法的 16 位浮点结果。
- numba.cuda.fp16.hneg(a)
对 16 位浮点参数执行取反操作
-a
。映射到neg.f16
PTX 指令。返回取反的 16 位浮点结果。
- numba.cuda.fp16.habs(a)
对 16 位浮点参数执行绝对值操作
|a|
。返回绝对值操作的 16 位浮点结果。
- numba.cuda.fp16.hsin(a)
计算 16 位浮点参数的三角正弦函数。
返回正弦操作的 16 位浮点结果。
- numba.cuda.fp16.hcos(a)
计算 16 位浮点参数的三角余弦函数。
返回余弦操作的 16 位浮点结果。
- numba.cuda.fp16.hlog(a)
计算 16 位浮点参数的自然对数。
返回自然对数操作的 16 位浮点结果。
- numba.cuda.fp16.hlog10(a)
计算 16 位浮点参数的以 10 为底的对数。
返回以 10 为底的对数操作的 16 位浮点结果。
- numba.cuda.fp16.hlog2(a)
计算 16 位浮点参数的以 2 为底的对数。
返回以 2 为底的对数操作的 16 位浮点结果。
- numba.cuda.fp16.hexp(a)
计算 16 位浮点参数的自然指数操作。
返回指数操作的 16 位浮点结果。
- numba.cuda.fp16.hexp10(a)
计算 16 位浮点参数的以 10 为底的指数。
返回指数操作的 16 位浮点结果。
- numba.cuda.fp16.hexp2(a)
计算 16 位浮点参数的以 2 为底的指数。
返回指数操作的 16 位浮点结果。
- numba.cuda.fp16.hfloor(a)
对 16 位浮点参数执行向下取整操作,即小于或等于
a
的最大整数。返回向下取整操作的 16 位浮点结果。
- numba.cuda.fp16.hceil(a)
对 16 位浮点参数执行向上取整操作,即大于或等于
a
的最小整数。返回向上取整操作的 16 位浮点结果。
- numba.cuda.fp16.hsqrt(a)
计算 16 位浮点参数的平方根操作。
返回平方根操作的 16 位浮点结果。
- numba.cuda.fp16.hrsqrt(a)
计算16位浮点参数的平方根的倒数。
返回倒数平方根操作的16位浮点结果。
- numba.cuda.fp16.hrcp(a)
计算16位浮点参数的倒数。
返回倒数的16位浮点结果。
- numba.cuda.fp16.hrint(a)
将输入的16位浮点参数四舍五入到最接近的整数值。
返回四舍五入的16位浮点结果。
- numba.cuda.fp16.htrunc(a)
将输入的16位浮点参数截断为不大于其绝对值的最接近整数。
返回截断的16位浮点结果。
- numba.cuda.fp16.heq(a, b)
对16位浮点参数执行比较操作
a == b
。返回布尔值。
- numba.cuda.fp16.hne(a, b)
对16位浮点参数执行比较操作
a != b
。返回布尔值。
- numba.cuda.fp16.hgt(a, b)
对16位浮点参数执行比较操作
a > b
。返回布尔值。
- numba.cuda.fp16.hge(a, b)
对16位浮点参数执行比较操作
a >= b
。返回布尔值。
- numba.cuda.fp16.hlt(a, b)
对16位浮点参数执行比较操作
a < b
。返回布尔值。
- numba.cuda.fp16.hle(a, b)
对16位浮点参数执行比较操作
a <= b
。返回布尔值。
- numba.cuda.fp16.hmax(a, b)
执行操作
a if a > b else b.
返回一个16位浮点值。
- numba.cuda.fp16.hmin(a, b)
执行操作
a if a < b else b.
返回一个16位浮点值。
控制流指令
CUDA 的一部分控制流指令可直接作为内置函数使用。避免分支是提高 CUDA 性能的关键方法,使用这些内置函数意味着您无需依赖 nvcc
优化器来识别和消除分支。有关更多文档,包括语义,请参阅 相关 CUDA Toolkit 文档。
- numba.cuda.selp()
根据第一个参数的值在两个表达式之间进行选择。类似于 LLVM 的
select
指令。