连续非对齐场景优化

连续非对齐搬运优化建议

【正例】

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搬出接口如下:

非对齐寄存器原理

本节主要介绍在非对齐搬运过程中,非对齐寄存器如何发挥其作用,并详细解释内部原理,帮助开发者理解为什么上文的性能优化建议能够带来性能收益。首先介绍连续非对齐数据搬入、连续非对齐数据搬出以及MaskReg连续非对齐数据搬出的实现原理,然后通过一个具体的搬入搬出例子将这些关键流程串接起来。