为啥 AVX2 和 SSE2 按位 OR 运算符并不比简单的快?操作员?
Posted
技术标签:
【中文标题】为啥 AVX2 和 SSE2 按位 OR 运算符并不比简单的快?操作员?【英文标题】:Why AVX2 and SSE2 bitwise OR operators are not faster than a simple | operator?为什么 AVX2 和 SSE2 按位 OR 运算符并不比简单的快?操作员? 【发布时间】:2019-11-13 15:31:09 【问题描述】:我正在尝试使用 32 位整数来加速非常长的二进制向量的按位或运算。
在这个例子中,我们可以假设 nwords 是单词的数量,它是 4 和 8 的倍数。因此,没有循环提醒。这个二进制向量可以包含数千位。
此外,所有三个位向量都是使用 _align_malloc() 分配的,分别用于 SSE2 和 AVX2 的 16 位和 18 位对齐。
令我惊讶的是,以下三个标量、SSE2 和 AVX2 代码在我的 i7 CPU 上执行的时间完全相同。我没有体验到 SSE2 和 AVX2 寄存器的预期 x4 和 x8 加速。
我的 MVisual Studio 版本是 15.1。
标量代码:
void vectorOr_Scalar(unsigned int *ptr1, unsigned int *ptr2, unsigned int *out, int nwords)
for (end = ptr1 + nwords; ptr1 < end; ptr1++, ptr2++, out++) *out = *ptr1 | *ptr2;
SSE2 代码:
void vectorOr_SSE2(unsigned int *ptr1, unsigned int *ptr2, unsigned int *out, int nwords)
for (i = 0; i < nwords; i += 4, ptr1 += 4, ptr2 += 4, out += 4)
__m128i v1 = _mm_load_si128((__m128i *)ptr1);
__m128i v2 = _mm_load_si128((__m128i *)ptr2);
_mm_store_si128((__m128i *)out, _mm_or_si128(v1, v2));
AVX2 代码:
void vectorOr_AVX2(unsigned int *ptr1, unsigned int *ptr2, unsigned int *out, int nwords)
for (i = 0; i < nwords; i += 8, ptr1 += 8, ptr2 += 8, out += 8)
__m256i v1 = _mm256_load_si256((__m256i *)ptr1);
__m256i v2 = _mm256_load_si256((__m256i *)ptr2);
_mm256_store_si256((__m256i *)out, _mm256_or_si256(v1, v2));
也许由于加载和存储之间的寄存器操作数量有限,此应用程序不适合矢量化?
【问题讨论】:
编译器现在非常聪明,你确定他们不会为你的标量情况生成类似的代码吗? 0。检查您是否启用了优化的 AVX2(否则编译器将调用向量替换函数,而无需硬件提升)。 1. 可以试试用OpenMP 加#pragma omp parallel for simd
正如@MarkRansom 所说,您的编译器可能自己想出了如何对您的函数进行矢量化。在热循环中查找vorps
或vpor
指令:godbolt.org/z/MR2x8V
大家好,是的,好像马克说的。非常感谢!
我找了一个副本;我确定我已经看过问答,答案是标量版本很简单,可以自动矢量化,但没有找到任何答案。
【参考方案1】:
您没有观察到一次处理一个 unsigned
的循环和一次处理 8 个 unsigned
的 SIMD 循环之间的性能差异的原因是编译器会为您生成 SIMD 代码,以及展开循环,请参阅the generated assembly。
【讨论】:
以上是关于为啥 AVX2 和 SSE2 按位 OR 运算符并不比简单的快?操作员?的主要内容,如果未能解决你的问题,请参考以下文章