犰狳向量 vec/fvec 的内存对齐

Posted

技术标签:

【中文标题】犰狳向量 vec/fvec 的内存对齐【英文标题】:Memory alignment of Armadillo vectors vec/fvec 【发布时间】:2021-03-08 16:03:22 【问题描述】:

我想直接从带有.memptr() 的犰狳矢量数据中加载__m256。 Armadillo 是否确保数据存储器是 256 位对齐的?如果是这样,那么我只需将.memptr() 返回的浮点/双精度指针转换为__m256 指针并跳过_mm256_load_ps(),如果它在性能方面有意义的话。

【问题讨论】:

【参考方案1】:

犰狳似乎没有在文档中讨论这一点,因此未指定。因此,矢量数据可能无法保证 32 字节对齐。

但是,您不需要对齐矢量数据即可将它们加载到 AVX 寄存器中:您可以使用未对齐的加载内在函数_mm256_loadu_ps。 AFAIK,_mm256_load_ps_mm256_loadu_ps 在相对较新的 x86 处理器上的性能大致相同。

【讨论】:

谢谢。我很好奇当我用reinterpret_castfloat * 转换为a __m256* 然后简单地取消引用指针时会发生什么,编译器会自动选择_mm256_loadu_ps 吗? 对未与sizeof(Type) 对齐的数据使用reinterpret_cast<Type> 会使您的程序在标准C++ 中格式错误。因此,使用这种转换加载 32 字节未对齐数据会导致未定义的行为。实际上,我建议您即使数据对齐也不要使用reinterpret_cast。您可以找到有关 here 的更多信息。 @Noob: alignof(__m256) == 32,所以 deref 等价于load,而不是loadu。有趣的事实:像 GNU C 这样的编译器可以使用 __attribute__((aligned(1),may_alias,vector_size(32))) 类型的 deref 来实现 loadu。 Is `reinterpret_cast`ing between hardware SIMD vector pointer and the corresponding type an undefined behavior?。对于整数数据,您通常需要某种类型的强制转换(因为英特尔恼人地将内在函数定义为采用 __m256i* 而不是 void*),但是对于浮点数,只需使用 _mm256_loadu_ps(const float*) 如果你的数据在运行时恰好是 32 字节对齐的,那么很好,否则硬件会处理它;如果所有 32 个字节都来自同一高速缓存行,则不存在惩罚。但是缓存行拆分对于 OoO exec 隐藏有额外的延迟,并且执行 2 次缓存访问时吞吐量会更差。页面拆分甚至更糟,尤其是在 Skylake 之前的 CPU 上,但对于顺序循环当然很少发生。

以上是关于犰狳向量 vec/fvec 的内存对齐的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Altivec 将向量存储到内存中未对齐的位置

GCC 向量扩展和 ARM NEON 的内存对齐问题

Vector的Vector如何在内存中对齐?

SSE 向量重新对齐?

内存对齐问题

内存对齐以及如何关闭内存对齐