TIK C++算子编程范式

TIK C++编程范式把算子内部的处理程序,分成多个流水任务(Stage),以张量(Tensor)为数据载体,以队列(Queue)进行任务之间的通信与同步,以内存管理模块(Pipe)管理任务间的通信内存。

一、流水任务

流水任务(Stage)指的是单核处理程序中主程序调度的并行任务。在核函数内部,可以通过流水任务实现数据的并行处理来提升性能。

矢量算子编程范式把算子的实现流程分为3个基本任务:CopyIn,Compute,CopyOut。其中,CopyIn负责数据搬入操作,Compute负责矢量计算操作,CopyOut负责数据搬出操作。

二、任务间通信和同步

不同的流水任务之间存在数据依赖,需要进行数据传递。TIK C++中使用Queue队列完成任务之间的数据通信和同步,Queue提供了EnQue、DeQue等基础API。Queue队列管理NPU上不同层级的物理内存时,用一种抽象的逻辑位置(QuePosition)来表达各个级别的存储(Storage Scope),代替了片上物理存储的概念,开发者无需感知硬件架构。

矢量编程中的逻辑位置(QuePosition):搬入数据的存放位置:VECIN、搬出数据的存放位置:VECOUT。

矢量编程主要分为CopyIn、Compute、CopyOut三个任务:

Stage1:CopyIn任务使用DataCopy接口将GlobalTensor拷贝到LocalTensor使用EnQue将LocalTensor放入VECIN的Queue中。		Stage2:Compute任务使用DeQue从VECIN中取出LocalTensor使用TIK C++指令API完成矢量计算:Add使用EnQue将结果LocalTensor放入VECOUT的Queue中。

	Stage3:CopyOut任务使用DeQue接口从VECOUT的Queue中取出LocalTensor使用DataCopy接口将LocalTensor拷贝到GlobalTensor。

三、内存管理

任务间数据传递使用到的内存统一由内存管理模块Pipe进行管理。

Pipe作为片上内存管理者,通过InitBuffer接口对外提供Queue内存初始化功能,开发者可以通过该接口为指定的Queue分配内存。

Queue队列内存初始化完成后,需要使用内存时,通过调用AllocTensor来为LocalTensor分配内存给Tensor,当创建的LocalTensor完成相关计算无需再使用时,再调用FreeTensor来回收LocalTensor的内存。

编程过程中使用到的临时变量内存同样通过Pipe进行管理。临时变量可以使用TBuf数据结构来申请指定QuePosition上的存储空间,并使用Get()来将分配到的存储空间分配给新的LocalTensor从TBuf上获取全部长度,或者获取指定长度的LocalTensor 。

【注】使用TBuf申请的内存空间只能参与计算,无法执行Queue队列的入队出队操作。