1、算子分析
例子以Add算子为例,数学公式:z= x+y,为简单起见,设定输入张量x, y,z为固定shape(8,2048),数据类型dtype为half类型,数据排布类型format为ND,核函数名称为add_custom。
2、核函数定义
在add_custom核函数的实现中实例化kernelAdd算子类,调用Init()数完成内存初始化,调用Process()函数完成核心逻辑
3、算子类定义
4、函数实现
1)CPU模式下使用ICPU_RUN_KF宏进行CPU调试。
2)NPU模式下使用<<<>>>方式调用,由于CPU模式g++没有<<<>>>的表达,需要使用内置宏 __CCE_KT_TEST。
1、算子分析
例子以Add算子为例,数学公式:z= x+y,为简单起见,设定输入张量x, y,z为固定shape(8,2048),数据类型dtype为half类型,数据排布类型format为ND,核函数名称为add_custom。
2、核函数定义
在add_custom核函数的实现中实例化kernelAdd算子类,调用Init()数完成内存初始化,调用Process()函数完成核心逻辑
// 实现核函数 extern "C" __global__ __aicore__ void add_custom(GM_ADDR x, GM_ADDR y, GM_ADDR z) { // 初始化算子类,算子类提供算子初始化和核心处理等方法 KernelAdd op; // 初始化函数,获取该核函数需要处理的输入输出地址,同时完成必要的内存初始化工作 op.Init(x, y, z); // 核心处理函数,完成算子的数据搬运与计算等核心逻辑 op.Process(); }3、算子类定义
class KernelAdd { public: __aicore__ inline KernelAdd() {} __aicore__ inline void Init(GM_ADDR x, GM_ADDR y, GM_ADDR z {} __aicore__ inline void Process(){} private: __aicore__ inline void CopyIn(int32_t progress) {} __aicore__ inline void Compute(int32_t progress) {} __aicore__ inline void CopyOut(int32_t progress){} private: TPipe pipe; // create queues for input, in this case depth is equal to buffer num TQue<QuePosition::VECIN, BUFFER_NUM> inQueueX, inQueueY; // create queue for output, in this case depth is equal to buffer num TQue<QuePosition::VECOUT, BUFFER_NUM> outQueueZ; GlobalTensor<half> xGm, yGm, zGm; };4、函数实现
class KernelAdd { public: __aicore__ inline KernelAdd() {} __aicore__ inline void Init(GM_ADDR x, GM_ADDR y, GM_ADDR z) { // get start index for current core, core parallel xGm.SetGlobalBuffer((__gm__ half*)x + BLOCK_LENGTH * GetBlockIdx(), BLOCK_LENGTH); yGm.SetGlobalBuffer((__gm__ half*)y + BLOCK_LENGTH * GetBlockIdx(), BLOCK_LENGTH); zGm.SetGlobalBuffer((__gm__ half*)z + BLOCK_LENGTH * GetBlockIdx(), BLOCK_LENGTH); // pipe alloc memory to queue, the unit is Bytes pipe.InitBuffer(inQueueX, BUFFER_NUM, TILE_LENGTH * sizeof(half)); pipe.InitBuffer(inQueueY, BUFFER_NUM, TILE_LENGTH * sizeof(half)); pipe.InitBuffer(outQueueZ, BUFFER_NUM, TILE_LENGTH * sizeof(half)); } __aicore__ inline void Process() { // loop count need to be doubled, due to double buffer constexpr int32_t loopCount = TILE_NUM * BUFFER_NUM; // tiling strategy, pipeline parallel for (int32_t i = 0; i < loopCount; i++) { CopyIn(i); Compute(i); CopyOut(i); } } private: __aicore__ inline void CopyIn(int32_t progress) { // alloc tensor from queue memory LocalTensor<half> xLocal = inQueueX.AllocTensor<half>(); LocalTensor<half> yLocal = inQueueY.AllocTensor<half>(); // copy progress_th tile from global tensor to local tensor DataCopy(xLocal, xGm[progress * TILE_LENGTH], TILE_LENGTH); DataCopy(yLocal, yGm[progress * TILE_LENGTH], TILE_LENGTH); // enque input tensors to VECIN queue inQueueX.EnQue(xLocal); inQueueY.EnQue(yLocal); } __aicore__ inline void Compute(int32_t progress) { // deque input tensors from VECIN queue LocalTensor<half> xLocal = inQueueX.DeQue<half>(); LocalTensor<half> yLocal = inQueueY.DeQue<half>(); LocalTensor<half> zLocal = outQueueZ.AllocTensor<half>(); // call Add instr for computation Add(zLocal, xLocal, yLocal, TILE_LENGTH); // enque the output tensor to VECOUT queue outQueueZ.EnQue<half>(zLocal); // free input tensors for reuse inQueueX.FreeTensor(xLocal); inQueueY.FreeTensor(yLocal); } __aicore__ inline void CopyOut(int32_t progress) { // deque output tensor from VECOUT queue LocalTensor<half> zLocal = outQueueZ.DeQue<half>(); // copy progress_th tile from local tensor to global tensor DataCopy(zGm[progress * TILE_LENGTH], zLocal, TILE_LENGTH); // free output tensor for reuse outQueueZ.FreeTensor(zLocal); } private: TPipe pipe; // create queues for input, in this case depth is equal to buffer num TQue<QuePosition::VECIN, BUFFER_NUM> inQueueX, inQueueY; // create queue for output, in this case depth is equal to buffer num TQue<QuePosition::VECOUT, BUFFER_NUM> outQueueZ; GlobalTensor<half> xGm, yGm, zGm; };1)CPU模式下使用ICPU_RUN_KF宏进行CPU调试。
2)NPU模式下使用<<<>>>方式调用,由于CPU模式g++没有<<<>>>的表达,需要使用内置宏 __CCE_KT_TEST。
#ifndef __CCE_KT_TEST__ //call of kernel function void add_custom_do(uint32_t blockDim, void* l2ctrl, void* stream, uint8_t* x, uint8_t* y, uint8_t* z); { add_custom<<<blockDim, l2ctrl, stream>>> (x, y, z); } #endif