矢量化 - 加速SSE,AVX和AVX2的预期

时间:2017-04-06 04:35:30

标签: c vectorization sse avx avx512

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

  

$ sysctl -n machdep.cpu.brand_string

Intel(R) Core(TM) i7-4960HQ CPU @ 2.60GHz

我的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

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
  

对于SSE矢量化,我希望Speedup等于2,因为我在128位上对齐数据= 16字节= 2 * sizeof(double)。

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

Results with SSE

所以,我认为这些结果是有效的,因为SpeedUp是因子2。

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

Results with AVX256

  

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

但正如您所看到的,我仍然可以获得factor 2而不是4来获取SpeedUp。

我不明白为什么我使用SSE和AVX获得与Speedup相同的结果 向量化。

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

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

对于SSE:

gcc-mp-4.9 -DSSE -O3 -msse main_benchmark.c -o vectorizedExe

对于AVX256:

gcc-mp-4.9 -DAVX256 -O3 -Wa,-q -mavx main_benchmark.c -o vectorizedExe

此外,使用我的处理器型号,我可以使用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指令。

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

2 个答案:

答案 0 :(得分:2)

你正在进行缓存 - &gt; ram传输。您的core7有一个64字节的缓存行。对于sse2,16字节存储需要64字节加载,更新和队列返回ram。按升序排列的16字节加载受益于自动预取预测,因此您可以获得一些负载优势。添加目标内存的mm_prefetch;比如,在下一个商店之前的256字节。这同样适用于avx2 32字节存储。

答案 1 :(得分:1)

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)&gt; = 7,然后cpuid(ax = 7,cx = 0): bx&amp;运行时为0x04000010(AVX2为0x10,AVX512为包含预取的为0x04000000)。

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

HTH