矢量化 - SSE、AVX 和 AVX2 预计加速

5 c sse vectorization avx avx512

我正在使用以下处理器 i7 在 MacOS 上进行矢量化基准测试:

$ sysctl -n machdep.cpu.brand_string

Intel(R) Core(TM) i7-4960HQ CPU @ 2.60GHz
Run Code Online (Sandbox Code Playgroud)

我的 MacBook Pro 是 2014 年中期的。

我尝试使用不同的标志选项进行矢量化:我感兴趣的 3 个是 SSE、AVX 和 AVX2。

对于我的基准测试,我将 2 个数组的每个元素相加,并将总和存储在第三个数组中。

我必须让您注意到我正在使用double这些数组的类型。

以下是我的基准代码中使用的函数:

1*) 首先使用 SSE 矢量化:

#ifdef SSE
#include <x86intrin.h>
#define ALIGN 16
void addition_tab(int size, double *a, double *b, double *c)
{

 int i;
 // Main loop
 for (i=size-1; i>=0; i-=2)
 {
  // Intrinsic SSE syntax
  const __m128d x = _mm_load_pd(a); // Load two x elements
  const __m128d y = _mm_load_pd(b); // Load two y elements
  const __m128d sum = _mm_add_pd(x, y); // Compute two sum elements
  _mm_store_pd(c, sum); // Store two sum elements

  // Increment pointers by 2 since SSE vectorizes on 128 bits = 16 bytes = 2*sizeof(double)
  a += 2;
  b += 2;
  c += 2;
 }

}
#endif
Run Code Online (Sandbox Code Playgroud)

2*) 第二个使用 AVX256 矢量化:

#ifdef AVX256
#include <immintrin.h>
#define ALIGN 32
void addition_tab(int size, double *a, double *b, double *c)
{

 int i;
 // Main loop
 for (i=size-1; i>=0; i-=4)
 {
  // Intrinsic AVX syntax
  const __m256d x = _mm256_load_pd(a); // Load two x elements
  const __m256d y = _mm256_load_pd(b); // Load two y elements
  const __m256d sum = _mm256_add_pd(x, y); // Compute two sum elements
  _mm256_store_pd(c, sum); // Store two sum elements

  // Increment pointers by 4 since AVX256 vectorizes on 256 bits = 32 bytes = 4*sizeof(double)
  a += 4;
  b += 4;
  c += 4;
 }

}
#endif
Run Code Online (Sandbox Code Playgroud)

对于 SSE 矢量化,我预计加速约为 2,因为我将数据对齐 128 位 = 16 字节 = 2* sizeof(double)。

我得到的 SSE 矢量化结果如下图所示:

SSE 结果

所以,我认为这些结果是有效的,因为加速大约是因子 2。

现在对于AVX256,我得到下图:

AVX256 的结果

对于 AVX256 矢量化,我预计加速约为 4,因为我在 256 位 = 32 字节 = 4* sizeof(double) 上对齐数据。

但正如你所看到的,我仍然得到 afactor 2而不是4SpeedUp。

我不明白为什么使用 SSE 和 AVX 矢量化加速会得到相同的结果。

它是否来自“编译标志”,来自我的处理器模型,......我不知道。

以下是我为上述所有结果所做的编译命令行:

对于上交所:

gcc-mp-4.9 -DSSE -O3 -msse main_benchmark.c -o vectorizedExe
Run Code Online (Sandbox Code Playgroud)

对于 AVX256:

gcc-mp-4.9 -DAVX256 -O3 -Wa,-q -mavx main_benchmark.c -o vectorizedExe
Run Code Online (Sandbox Code Playgroud)

此外,对于我的处理器型号,我可以使用 AVX512 矢量化吗?(一旦这个问题的问题就解决了)。

感谢您的帮助

更新1

我尝试了不同的选项,@Mischa但仍然无法通过 AVX 标志和选项获得 4 倍的加速。你可以在http://example.com/test_vectorization/main_benchmark.c.txt上查看我的 C 源代码(带有 .txt 扩展名,可以直接查看浏览器),用于基准测试的 shell 脚本是http://example.com /test_vectorization/run_benchmark

正如@Mischa所说,我尝试应用以下命令行进行编译:

$GCC -O3 -Wa,-q -mavx -fprefetch-loop-arrays main_benchmark.c -o vectorizedExe

但生成的代码没有 AVX 指令。

如果你能看一下这些文件,那就太好了。谢谢。

Mis*_*cha 0

NP。有以下选项:

(1)x86特定代码:

#include <emmintrin.h> ... for (int i=size; ...) { _mm_prefetch(256+(char*)c, _MM_HINT_T0); ... _mm256_store_pd(c, sum);

(2) gcc特定代码: for (int i=size; ...) { __builtin_prefetch(c+32); ...

(3) gcc -fprefetch-array-loops---编译器最了解。

如果您的 gcc 版本支持,(3) 是最好的。如果在相同的硬件上编译和运行,(2) 是次佳的。(1) 可移植到其他编译器。

不幸的是,“256”是一个估计值,并且取决于硬件。最小值为 128,最大值为 512,具体取决于您的 CPU:RAM 速度。如果切换到_mm512*(),则将这些数字加倍。

如果您正在使用一系列处理器,我可以建议以涵盖所有情况的方式进行编译,然后测试 cpuid(ax=0)>=7,然后测试 cpuid(ax=7,cx=0):bx & 0x04000010 at运行时(AVX2 为 0x10,AVX512 为 0x04000000,包括预取)。

顺便说一句,如果您使用 gcc 并指定 -mavx 或 -msse2,编译器会为您定义内置宏 __AVX__ 或 __SSE2__ ;不需要-DAVX256。为了支持过时的 32 位处理器,-m32 不幸地禁用了 __SSE2__,因此有效地禁用了\#include <emmintrin.h>:-P

华泰