在大多数算子开发时,核函数计算过程需要使用临时内存来存储运算的中间结果,这些中间结果以临时变量表示,临时变量占用的内存可以使用TBuf数据结构来管理,具体介绍请参考TBuf。下文将以输入的数据类型为bfloat16_t、在单核上运行的Add算子为例,介绍TBuf的使用方式。本样例中介绍的算子完整代码请参见使用临时内存的Add算子样例。
在
通过以上分析,得到Ascend C Add算子的设计规格如下:
|
name |
shape |
data type |
format |
|---|---|---|---|
|
x(输入) |
(1, 2048) |
bfloat16_t |
ND |
|
y(输入) |
(1, 2048) |
bfloat16_t |
ND |
|
z(输出) |
(1, 2048) |
bfloat16_t |
ND |
该样例的CopyIn,CopyOut任务与基础矢量算子相同,Compute任务的具体流程如下图所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
class KernelAdd { public: __aicore__ inline KernelAdd() {} __aicore__ inline void Init(GM_ADDR x, GM_ADDR y, GM_ADDR z, AscendC::TPipe* pipeIn){} __aicore__ inline void Process(){} private: __aicore__ inline void CopyIn(){} __aicore__ inline void Compute(){} __aicore__ inline void CopyOut(){} private: AscendC::TPipe* pipe; AscendC::TQue<AscendC::TPosition::VECIN, 1> inQueueX; AscendC::TQue<AscendC::TPosition::VECIN, 1> inQueueY; AscendC::TQue<AscendC::TPosition::VECOUT, 1> outQueueZ; AscendC::TBuf<AscendC::TPosition::VECCALC> tmpBuf0; AscendC::TBuf<AscendC::TPosition::VECCALC> tmpBuf1; AscendC::GlobalTensor<bfloat16_t> xGm; AscendC::GlobalTensor<bfloat16_t> yGm; AscendC::GlobalTensor<bfloat16_t> zGm; }; |
初始化函数阶段除原有步骤外,需要调用InitBuffer接口为TBuf变量分配内存,具体的初始化函数代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
__aicore__ inline void Init(GM_ADDR x, GM_ADDR y, GM_ADDR z, AscendC::TPipe* pipeIn) { pipe = pipeIn; xGm.SetGlobalBuffer((__gm__ bfloat16_t*)x, TOTAL_LENGTH); yGm.SetGlobalBuffer((__gm__ bfloat16_t*)y, TOTAL_LENGTH); zGm.SetGlobalBuffer((__gm__ bfloat16_t*)z, TOTAL_LENGTH); pipe->InitBuffer(inQueueX, 1, TOTAL_LENGTH * sizeof(bfloat16_t)); pipe->InitBuffer(inQueueY, 1, TOTAL_LENGTH * sizeof(bfloat16_t)); pipe->InitBuffer(outQueueZ, 1, TOTAL_LENGTH * sizeof(bfloat16_t)); pipe->InitBuffer(tmpBuf0, TOTAL_LENGTH * sizeof(float)); pipe->InitBuffer(tmpBuf1, TOTAL_LENGTH * sizeof(float)); } |
基于矢量编程范式,核函数需要实现3个基本任务:CopyIn,Compute,CopyOut。与基础矢量算子实现相同,Process函数按顺序调用CopyIn函数,Compute函数,CopyOut函数。其中,CopyIn函数,CopyOut函数与基础矢量算子的CopyIn函数、基础矢量算子的CopyOut函数的实现没有差异,此处不过多赘述。Compute函数的实现步骤如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
__aicore__ inline void Compute() { AscendC::LocalTensor<bfloat16_t> xLocal = inQueueX.DeQue<bfloat16_t> (); AscendC::LocalTensor<bfloat16_t> yLocal = inQueueY.DeQue<bfloat16_t> (); AscendC::LocalTensor<bfloat16_t> zLocal = outQueueZ.AllocTensor<bfloat16_t> (); AscendC::LocalTensor<float> tmpTensor0 = tmpBuf0.Get<float>(); AscendC::LocalTensor<float> tmpTensor1 = tmpBuf1.Get<float>(); AscendC::Cast(tmpTensor0, xLocal, AscendC::RoundMode::CAST_NONE, TOTAL_LENGTH); AscendC::Cast(tmpTensor1, yLocal, AscendC::RoundMode::CAST_NONE, TOTAL_LENGTH); AscendC::Add(tmpTensor0, tmpTensor0, tmpTensor1, TOTAL_LENGTH); AscendC::Cast(zLocal, tmpTensor0, AscendC::RoundMode::CAST_RINT, TOTAL_LENGTH); outQueueZ.EnQue<bfloat16_t>(zLocal); inQueueX.FreeTensor(xLocal); inQueueY.FreeTensor(yLocal); } |