CANN学习资源开源仓的算子开发一
Ascend C核函数(Kernel)的函数声明里面,__global__:表明该函数是可以被主机端(Host)调用的核函数。
Ascend C算子编程是SPMD(Single-Program Multiple-Data)编程,通俗来讲就是“一份代码,多处执行,处理的数据不同”。具体是将需要处理的数据拆分并同时在多个计算核心上运行,多个AI Core共享相同的指令代码,每个核上的运行实例唯一的区别是block_idx不同,每个核通过不同的block_idx来识别自己的身份。block的概念类似于进程的概念,block_idx类似于标识进程唯一性的进程ID。
算子代码最后是通过毕昇编译器编译为可以执行的程序的,常用编译选项:
| 编译选项 | 是否必填 | 说明 |
|---|---|---|
| -help | 否 | 查看帮助。 |
| --npu-arch | 是 | 编译时指定的昇腾AI处理器架构,取值为dav-<arch-version>,其中<arch-version>为NPU架构版本号,各产品型号对应的架构版本号如下: ├─ Atlas A3 训练系列产品/Atlas A3 推理系列产品:2201 ├─ Atlas A2 训练系列产品/Atlas A2 推理系列产品:2201 ├─ Atlas 200I/500 A2 推理产品:3002 ├─ Atlas 推理系列产品:2002 └─ Atlas 训练系列产品:1001 当前只支持--npu-arch=dav-2201 |
| --npu-soc | 否 | 编译时指定的昇腾AI处理器型号,npu-soc和npu-arch同时配置时,优先使能npu-arch。 |
| -o <file> | 否 | 指定输出文件的名称和位置。 |
| -c | 否 | 编译生成目标文件。 |
| -O | 否 | 用于指定编译器的优化级别,当前支持-O3,-O2,-O0。 |
| -fPIC | 否 | 告知编译器产生位置无关代码。 |
| -shared,--shared | 否 | 编译生成动态链接库。 |
| -lib,--cce-build-static-lib | 否 | 用于编译生成静态链接库。编译器会将Device侧的代码进行编译链接,生成Device侧二进制文件,随后将该文件作为Host侧编译的输入进行编译,最后链接生成静态链接库。 |
| --cce-auto-sync | 否 | 开启自动同步。AI Core内部的执行单元是异步并行的,LocalTensor的读写可能存在数据依赖,可以通过该选项进行自动同步,无需用户通过接口手动插入同步。 |
| --cce-auto-sync-log | 否 | “--cce-auto-sync-log=<file>”编译选项可以输出同步插入信息到<file>文件中。 |
| --std=c++17 | 否 | 用于配置使用的C++标准。当编译Ascend C算子时,需要使用C++17标准,该选项为必选项,使用asc作为文件后缀时,std默认为c++17。 |
| -x | 否 | 将该选项后的输入文件按照特定语法接口进行解析编译,支持cce、asc、aicpu后缀。不支持ccache编译缓存加速,若需使用ccache,请使用--cce-aicore-lang替代选项。 |
| --cce-aicore-lang | 否 | 将该选项后的输入文件按照cce异构语言模式编译。支持ccache编译缓存加速(不可与-xcce同时使用)。 |
| -g | 否 | 编译时增加调试信息。 |
| --sanitizer,--cce-enable-sanitizer | 否 | 编译时增加代码正确性校验信息。使用sanitizer选项时,需要同步添加-g选项,且不能在-O0场景下使用。 |
在高效的流水线作业中,如何清晰地定义各工序?如何安全、高效地在工序间传递半成品数据?如何管理整个流水线共享的资源?
Ascend C编程范式正是为解决这些问题而设计的流水线式的编程范式。 它将一个Ascend C算子核函数内的实现,逻辑上划分为多个流水任务(对应流水线上的工序)。任务之间通过专门的队列(TQue) 进行通信和同步,确保数据像在传送带上一样,从一个任务平稳地交付到下一个任务。同时,通过统一的资源管理模块(TPipe),对任务间共享的内存、事件等资源进行生命周期管理和调度,保障整条流水线顺畅、无冲突地运转。基于Ascend C编程范式进行开发,意味着遵循一套与硬件架构深度匹配的固定流程:开发者首先将算子的计算过程解耦为若干流水任务,然后定义连接它们的队列,最后实现每个任务的具体计算逻辑。这套范式屏蔽了底层硬件的并行同步细节,使开发者能够快速搭建起算子实现的代码框架,并天然地发挥出AI Core的流水线并行优势。基本的矢量编程范式就是最基础、最常用的范式:CopyIn(数据搬入)、Compute(矢量计算)、CopyOut(结果搬出)。
任务间数据传递使用到的内存统一由内存管理模块Pipe进行管理,一个Kernel函数必须且只能初始化一个TPipe对象。Pipe作为片上内存管理者,通过InitBuffer接口,对外提供Queue内存初始化功能,开发者可以通过该接口为指定的Queue分配内存。Queue队列内存初始化完成后,需要使用内存时,通过调用AllocTensor来为LocalTensor分配内存,当创建的LocalTensor完成相关计算无需再使用时,再调用FreeTensor来回收LocalTensor的内存。
在任务内部进行计算时,可能会用到一些临时变量。(比如用于类型转换后的存储空间)这些临时变量占用的内存同样通过Pipe进行管理。为TBuf分配的内存空间只能参与计算,无法执行Queue队列的入队出队操作。通过Pipe的InitBuffer接口为TBuf进行内存初始化操作,之后即可通过Get获取指定长度的Tensor参与计算。
DoubleBuffer可以通过为队列申请内存时设置内存块的个数来实现数据并行。
- 点赞
- 收藏
- 关注作者
评论(0)