【正例】
1 2 3 4 5 6 7 8 |
// 非对齐搬入初始化,使用uint32_t管理偏移量,移至for循环外部。 AscendC::Reg::LoadUnAlignPre(ureg0, srcAddr); for (uint16_t i = 0; i < repeatTimes; ++i) { AscendC::Reg::LoadUnAlign(srcReg, ureg0, srcAddr + i * postUpdateStride); AscendC::Reg::StoreUnAlign(dstAddr, srcReg, ureg1, postUpdateStride); } // 非对齐搬出后处理,移至for循环外部。 AscendC::Reg::StoreUnAlignPost(dstAddr, ureg1, 0); |
【反例】
1 2 3 4 5 6 |
for (uint16_t i = 0; i < repeatTimes; ++i) { AscendC::Reg::LoadUnAlignPre(ureg0, srcAddr + i * postUpdateStride); AscendC::Reg::LoadUnAlign(srcReg, ureg0, srcAddr + i * postUpdateStride); AscendC::Reg::StoreUnAlign(dstAddr, srcReg, ureg1, postUpdateStride); AscendC::Reg::StoreUnAlignPost(dstAddr, ureg1, 0); } |
为提升对不规则内存地址的处理能力,Reg矢量计算支持在数据搬运过程中对非32字节对齐的地址进行访问,适用于从UB向RegTensor非对齐搬运,或从RegTensor向UB非对齐搬运的场景。为降低非对齐访问带来的性能开销,RegBase引入非对齐寄存器缓存机制,该机制利用非对齐寄存器UnalignRegForLoad和UnalignRegForStore作为临时缓存区,用于暂存跨对齐边界的数据,从而实现高效的连续非对齐数据传输。
在读非对齐地址前,应该先通过LoadUnAlignPre进行初始化,然后再使用LoadUnAlign。在写非对齐地址时,先使用StoreUnAlign,再使用StoreUnAlignPost进行后处理。使用uint32_t管理偏移量的搬入搬出接口和maskReg搬出接口如下:
1 2 |
__simd_callee__ inline void LoadUnAlignPre(UnalignRegForLoad& ureg, __ubuf__ T* srcAddr); __simd_callee__ inline void LoadUnAlign(U& dstReg, UnalignRegForLoad& ureg, __ubuf__ T*& srcAddr, uint32_t postUpdateStride); |
1 2 |
__simd_callee__ inline void StoreUnAlign(__ubuf__ T*& dstAddr, U& srcReg, UnalignRegForStore& ureg, uint32_t postUpdateStride); __simd_callee__ inline void StoreUnAlignPost(__ubuf__ T*& dstAddr, UnalignRegForStore& ureg, int32_t postUpdateStride); |
1 2 |
__simd_callee__ inline void StoreUnAlign(__ubuf__ T*& dstAddr, MaskReg& mask, UnalignRegForStore& ureg); __simd_callee__ inline void StoreUnAlignPost(__ubuf__ T*& dstAddr, UnalignRegForStore& ureg, int32_t postUpdateStride); |
本节主要介绍在非对齐搬运过程中,非对齐寄存器如何发挥其作用,并详细解释内部原理,帮助开发者理解为什么上文的性能优化建议能够带来性能收益。首先介绍连续非对齐数据搬入、连续非对齐数据搬出以及MaskReg连续非对齐数据搬出的实现原理,然后通过一个具体的搬入搬出例子将这些关键流程串接起来。
如下图所示,从UB地址srcAddr ~ 304读取数据,并将其搬运至目标寄存器dstReg(256B)。处理流程如下:

将源寄存器srcReg中的非对齐数据写入UB地址dstAddr,根据ureg当前状态,分为两种场景:
场景一:ureg为空

场景二:ureg不为空

将源寄存器MaskReg(32B)搬出至UB。
以UB地址上数据类型为b16为例,将两个MaskReg数据写入dstAddr ~ 72,按以下步骤进行非对齐搬出:

如下图,将UB地址48 ~ 560的uint32_t数据[1, 2, 3, ... , 128]搬入至dstReg,再搬回UB,需要两次搬入搬出操作,即for循环执行两次,初始化和后处理移至for循环外。
