Ascend C核内同步控制
指令流水分类
Ascend的指令流水类型分为以下几种:
- PIPE_S:scalar流水(如Tensor.GetValue)
- PIPE_V:vec计算
- PIPE_M:cube计算
- PIPE_MTE1:LM Tensor内部搬运(L1->L0A等)
- PIPE_MTE2:GM到LM的搬运(GM->L1等)
- PIPE_MTE3:LM到GM的搬运
- PIPE_FIX:FixPipe,从L0C向外的搬运
同步控制分类
- 多流水同步:通过SetFlag和WaitFlag实现
- SetFlag:前序指令的数据读写全部执行完毕后执行,设置硬件标志位为1
- WaitFlag:等待直到对应标志位变为1,然后重置为0
- 单流水同步:PipeBarrier,阻塞指令流直到前序指令读写全部完成
数据流举例
以纯vec操作为例,其数据流包括三个阶段:
- DMA(VECIN) 将数据从GM搬运到LM
- 在LM上调用vec单元进行计算
- DMA(VECOUT) 将数据从LM搬运到GM
SetFlag & WaitFlag
同一个核内部不同流水之间的同步指令,用于具有数据依赖的不同流水指令。
1 | template <HardEvent event> |
调用示例:
1 | AscendC::GlobalTensor<half> dstGlobal; |
这份代码里展示了一个MTE3对Scalar的依赖;DataCopy指令(PIPE_MTE3)需要等待SetValue(PIPE_S)结束之后才能运行;所以对应的HardEvent是S_MTE3。
PipeBarrier
这个指令控制的是具有数据依赖的相同流水(如PIPE_V与PIPE_V之间的依赖)
1 | template <pipe_t pipe> |
调用示例:
1 | AscendC::LocalTensor<half> src0Local; |
这里计算了 src2 * (src0 + src1),乘法依赖于加法运算执行。
不过上述代码只是一个示例,实际上编译器会自动控制VEC上的信号量,无需手动插入PIPE_V同步。
来源
资料整理自公开文档: