核函数配置
核函数定义
核函数是SIMD与SIMT混合编程的Device侧入口函数,负责协调整个算子的执行流程,包括VF的调度和调用。vector计算单元的混合编程场景下,函数定义语法为:
__global__ __vector__ void kernel_name(__gm__ type* param1, __gm__ type* param2, ...);
关键修饰符说明如下:
- __global__:必需修饰符,作用为标识核函数,表明可在Host侧通过<<<...>>>调用。
- __vector__:必需修饰符,作用为标识函数是在Device侧AIV核上执行。
核函数定义有以下几个约束:
- 返回值类型必须是void;
- 入参支持指针类型(需使用__gm__修饰)和Ascend C内置数据类型;
- 指针参数必须是指向Global Memory上的内存地址,使用__gm__修饰。
__launch_bounds__(N)
在多线程并发执行时,每个线程使用较少的寄存器可以让更多的线程和线程块驻留在AI处理器上,从而提升性能。因此,编译器会采用启发式算法,将寄存器溢出(register spilling)和指令数量控制在最低水平,同时尽量减少寄存器的使用量。应用程序可以通过在__global__函数定义中使用__launch_bounds__()限定符来限制启动边界(launch bounds),提供附加信息辅助编译器优化这一过程,这属于可选配置。
__launch_bounds__(N):函数标记宏,在SIMT VF入口函数上可选配置,用于在编译期指定SIMT VF启动的最大线程数。若未配置__launch_bounds__,最大线程数默认为1024。参数N需要满足:
- N >= dimx * dimy * dimz;dimx,dimy,dimz为表示线程的dim3结构体。
- N的取值范围为1到2048。
最大线程数决定了每个线程可分配的寄存器数量,具体对应关系请见下表,寄存器用于存储线程中的局部变量,若局部变量的个数超出寄存器个数,容易出现栈溢出等问题。建议最大线程数与启动VF任务的dim3线程数保持一致。
表1 __launch_bounds__的Thread数量与每个Thread可用寄存器数 Thread的个数(个)
每个Thread可用寄存器个数(个)
1025~2048
16
513~1024
32
257~512
64
1~256
127
kernel_name<<<block_num, dyn_ub_size, stream>>>(args...);
内核调用符内的配置参数说明如下:
参数 |
类型 |
说明 |
约束 |
|---|---|---|---|
block_num |
uint32_t |
设置核函数启用的核数 |
取值范围[1, 65535] |
dyn_ub_size |
uint32_t |
指定动态内存大小,单位为字节 |
不超过最大可配置值:256KB - 8KB - 32KB - 静态内存 |
stream |
aclrtStream |
用于维护异步操作执行顺序 |
无 |
asc_vf_call调用
在SIMD与SIMT混合编程场景,需使用asc_vf_call启动SIMT VF(Vector Function)子任务,通过参数配置,启动指定数目的线程,执行指定的SIMT VF函数。其函数原型如下:
1 2 | template <auto funcPtr, typename... Args> __aicore__ inline void asc_vf_call(dim3 threadNums, Args &&...args) |
其中模板参数为指定的SIMT VF函数名以及SIMT VF函数参数,具体描述如下:
参数名 |
描述 |
|---|---|
funcPtr |
用于指定SIMT入口核函数。 |
Args |
定义可变参数,用于传递实参到SIMT入口核函数。 |
参数名 |
输入/输出 |
描述 |
|---|---|---|
threadNums |
输入 |
dim3结构,定义为{dimx,dimy,dimz},用于指定SIMT线程块内线程数量。线程总数为dimx * dimy * dimz,该值的大小必须小于等于2048,建议为32的倍数。 |
args |
输入 |
可变参数,用于传递实参到SIMT入口核函数。 |
以下示例展示了SIMD与SIMT混合编程场景下如何使用asc_vf_call调用__simt_vf__函数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include "simt_api/common_functions.h" __simt_vf__ inline void add_simt( __gm__ float* dst, __gm__ float* src0, __gm__ float* src1) { // simt 代码 int idx = threadIdx.x + blockIdx.x * blockDim.x; dst[idx] = src0[idx] + src1[idx]; } __global__ __vector__ void add_custom(__gm__ float* x, __gm__ float* y, __gm__ float* z) { // asc_vf_call启动SIMT VF子任务,函数名为:add_simt,配置blockDim为dim3{1024, 1, 1} asc_vf_call<add_simt>(dim3{1024, 1, 1}, z, x, y); } |