Tensor原地操作(inplace接口)是一种优化技术,全局申请、保留LocalTensor内存,避免了频繁创建和销毁LocalTensor对象。AllocTensor、FreeTensor、EnQue、DeQue接口不产生新的LocalTensor,而是在该全局LocalTensor上反复申请、释放、入队、出队。其实现原理如下图所示:
既然Tensor原地操作没有执行真正的入队出队操作,为什么还需要保留EnQue和DeQue接口呢?
适合计算循环次数多的场景:如图1所示,inplace接口虽然增加了TQue对象InitBuffer的初始化开销,但显著减少了每次循环中AllocTensor、EnQue、DeQue和FreeTensor内部对LocalTensor和事件的操作次数,特别适合需要多次循环来完成计算的场景。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
// ... namespace AscendC { class MyKernel { public: __aicore__ inline MyKernel() {} __aicore__ inline void Init(__gm__ uint8_t* src0Gm, __gm__ uint8_t* src1Gm, __gm__ uint8_t* dstGm) { src0Global.SetGlobalBuffer((__gm__ half*)src0Gm); src1Global.SetGlobalBuffer((__gm__ half*)src1Gm); dstGlobal.SetGlobalBuffer((__gm__ half*)dstGm); pipe.InitBuffer(srcQue0, 1, BLOCK_SIZE * sizeof(half)); pipe.InitBuffer(srcQue1, 1, BLOCK_SIZE * sizeof(half)); pipe.InitBuffer(dstQue0, 1, BLOCK_SIZE * sizeof(half)); } __aicore__ inline void Process() { for (int i = 0; i < REPTIMES; i++) { CopyIn(i); Compute(i); CopyOut(i); } } private: __aicore__ inline void CopyIn(int32_t i) { srcQue0.AllocTensor<half>(src0Local); srcQue1.AllocTensor<half>(src1Local); DataCopy(src0Local, src0Global[i*BLOCK_SIZE], BLOCK_SIZE); DataCopy(src1Local, src1Global[i*BLOCK_SIZE], BLOCK_SIZE); srcQue0.EnQue(src0Local); srcQue1.EnQue(src1Local); } __aicore__ inline void Compute(int32_t i) { srcQue0.DeQue<half>(src0Local); srcQue1.DeQue<half>(src1Local); dstQue0.AllocTensor<half>(dstLocal); Add(dstLocal, src0Local, src1Local, BLOCK_SIZE); dstQue0.EnQue<half>(dstLocal); srcQue0.FreeTensor(src0Local); srcQue1.FreeTensor(src1Local); } __aicore__ inline void CopyOut(int32_t i) { dstQue0.DeQue<half>(dstLocal); DataCopy(dstGlobal[i*BLOCK_SIZE], dstLocal, BLOCK_SIZE); dstQue0.FreeTensor(dstLocal); } private: TPipe pipe; TQue<QuePosition::VECIN, 0> srcQue0, srcQue1; TQue<QuePosition::VECOUT, 0> dstQue0; GlobalTensor<half> src0Global, src1Global, dstGlobal; LocalTensor<half> src0Local; LocalTensor<half> src1Local; LocalTensor<half> dstLocal; }; } // namespace AscendC // ... |