拷贝SIMD向量数组:循环赋值与memcpy的正确性及性能对比
问题1:循环赋值写法是否正确
是正确的。
当前参数下kNumOscs=4、numVoices=16,内层循环步长为4,v的取值范围固定是0~3,刚好覆盖osc[4][4]的所有下标,不会出现越界访问。赋值时机处于osc乘完vol之后、乘out之前,完全符合注释里“保存前序输出”的逻辑需求,计算结果没有问题。
问题2:单次memcpy拷贝是否性能更高
首先要注意逻辑适配:如果要改用memcpy,不能直接替换原来的单条赋值语句,需要调整循环顺序:原逻辑是单元素粒度的「乘vol → 赋值给mPrevOutput → 乘out」,要做单次memcpy的话,需要先遍历所有元素完成vol乘法,再调用memcpy把整个osc数组拷贝到mPrevOutput,最后再遍历所有元素完成out乘法,调整后的逻辑和原逻辑计算结果完全等价,因为每个元素的计算没有交叉依赖。
两者的性能差异极小,甚至原循环写法可能更优:
- 你当前的数据集非常小,总拷贝大小是4×4×16B=256B,属于超小块内存拷贝,不管是循环赋值还是
memcpy,耗时都在纳秒级,实际运行中几乎感知不到差异。 - 开了
-O3优化的前提下,编译器会自动把你现在的固定次数循环完全展开,逐个赋值的逻辑会被优化成连续的SIMD存储指令,和memcpy底层生成的指令几乎没有区别。 - 原循环的缓存局部性更好:原逻辑对同一个元素的三次操作(乘vol、拷贝、乘out)是连续执行的,数据一直留在CPU缓存中;如果拆成三个独立的遍历步骤(全量乘vol、全量拷贝、全量乘out),反而可能出现缓存重新加载的开销。
补充说明:mPrevOutput和osc都是16字节对齐的内存,且m128是平凡可复制类型,使用memcpy拷贝完全合法,不会出现未定义行为,写法参考:memcpy(&mPrevOutput[0][0], &osc[0][0], sizeof(osc));。
内容的提问来源于stack exchange,提问作者markzzz
相关产品推荐
相关产品推荐

