首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用gcc-4.9将矢量化检查为一个简单的例子。

用gcc-4.9将矢量化检查为一个简单的例子。
EN

Stack Overflow用户
提问于 2016-09-19 01:07:01
回答 2查看 727关注 0票数 0

我正在尝试将矢量化检查成一个简单的循环。我正在编写MacOS 19.5,我的代码是用gcc-mp-4.9编译的(安装自Macport)。为了获得更好的矢量化性能,我测量了经过的时间进入一个主循环,并将其与非矢量化版本进行了比较。

下面是这个简单的代码(我用"NOVEC""VEC" -D flag编译的):

代码语言:javascript
运行
复制
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define SIZE 1000000000

#ifdef NOVEC    
void addition_tab_novec(double *a, double *b, double *c)
{
 int i;

 for (i=0; i<SIZE; i++)
    c[i] = a[i] + b[i];
}
#endif

#ifdef VEC    
void addition_tab_vec(double * restrict a, double * restrict b, double * restrict c) 
{
 int i;

 double *x = __builtin_assume_aligned(a, 16);
 double *y = __builtin_assume_aligned(b, 16);
 double *z = __builtin_assume_aligned(c, 16);

 for (i=0; i<SIZE; i++)
    z[i] = x[i] + y[i];
}
#endif

int main(int argc, char *argv[])
{
  // Array index
  int i;

  // Two input arrays
  double *tab_x;
  double *tab_y;
  double *tab_z;

  // Time elapsed
  time_t time1, time2;

  // Allocation
  tab_x = (double*) malloc(SIZE*sizeof(double));
  tab_y = (double*) malloc(SIZE*sizeof(double));
  tab_z = (double*) malloc(SIZE*sizeof(double));

  // Initialization
  for (i=0; i<SIZE; i++)
     {
      tab_x[i] = i;
      tab_y[i] = 2*i;
      tab_z[i] = 0.0;
     }

#ifdef NOVEC
     // Start time for vectorization
     time(&time1);

     // Addition function
     addition_tab_novec(tab_x, tab_y, tab_z);

     // Compute elapsed time for vectorization
     time(&time2);

     printf("No Vectorization - Time elapsed = %f seconds\n", difftime(time2, time1));
#endif

#ifdef VEC    
     // Start time for vectorization
     time(&time1);

     // Addition function
     addition_tab_vec(tab_x, tab_y, tab_z);

     // Compute elapsed time for vectorization
     time(&time2);

     printf("Vectorization - Time elapsed = %f seconds\n", difftime(time2, time1));
#endif

  return 0;
}

我的问题是,与无矢量化版本相比,矢量化并没有得到更好的效果。

考虑到我使用的是"__builtin_assume_aligned(array, 16)",即16 bytes alignement,我希望在被测量的循环中获得一段更小两倍的运行时间(我使用带sizeof(double) = 8 bytes的双数组)

但实际上,我有60秒没有向量化和59秒与它:我如何解释这些相同的结果?

以下是两种情况下的编译命令行:

No-矢量化:

代码语言:javascript
运行
复制
gcc-mp-4.9 -DNOVEC -std=c99 -fno-tree-vectorize main_benchmark.c

矢量化:

代码语言:javascript
运行
复制
gcc-mp-4.9 -DVEC -std=c99 -Wa,-q -O3 -march=native -ftree-vectorize -fopt-info-vec main_benchmark.c

我不确定优化是否为非向量化编译所激活.如果是这样的话,该如何禁用呢?

谢谢你的帮忙

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-09-25 18:53:50

首先,可以删除__builtin_assume_aligned变量,因为矢量器会自动对齐数据,并使用专门针对未对齐数据的特殊变量。但是,您是对的,显式对齐和限制改进了代码。

gcc-mp-6 -g -DVEC -std=c99 -Wa,-q -O3 -march=native -ftree-fopt info-vec-ftree-verbose=2 vec-sample.c -o vec-vec2

代码语言:javascript
运行
复制
vec-sample.c:12:2: note: loop vectorized
vec-sample.c:12:2: note: loop versioned for vectorization because of possible aliasing
vec-sample.c:12:2: note: loop peeled for vectorization to enhance alignment
vec-sample.c:50:3: note: loop vectorized
vec-sample.c:50:3: note: loop peeled for vectorization to enhance alignment
vec-sample.c:12:2: note: loop vectorized
vec-sample.c:12:2: note: loop peeled for vectorization to enhance alignment

$ otool -tv vec vec 2

代码语言:javascript
运行
复制
...
0000000100000920    vmovupd (%r10,%rax), %ymm0
0000000100000926    vaddpd  (%r14,%rax), %ymm0, %ymm0
000000010000092c    addl    $0x1, %ecx
000000010000092f    vmovupd %ymm0, (%r8,%rax)
...

其次,循环中的添加代码是矢量化的(参见上面的vaddpd ),但是设置和malloc控制着循环。已经没有多少东西可以测量回路了。

为了测量循环(仅限osx),我使用了

代码语言:javascript
运行
复制
#include <mach/mach_time.h>
#define SIZE 1000000
...
  // Time elapsed
  uint64_t t1, t2;
...
  // Start time for vectorization
  t1 = mach_absolute_time();

  // Addition function
  addition_tab_vec(tab_x, tab_y, tab_z);

  // Compute elapsed time for vectorization
  t2 = mach_absolute_time();

  printf("Vectorization - Time elapsed = %ld ticks\n", t2-t1);

这为您提供了使用SSE代码的可测量的20%的开销,不使用-O0的62%的开销。

http://locklessinc.com/articles/vectorize/会更多地讨论细节。

票数 -1
EN

Stack Overflow用户

发布于 2016-09-24 06:57:55

看到汇编程序代码会很有趣。

通常情况下,您最多可以期望获得两倍的性能,但在这种情况下,考虑到数组的大小,您不会接近它,CPU只是处于空闲状态,等待数据进入缓存并从缓存中刷新,然后才能做任何事情,这可能就是没有收益的原因。

在处理大量数据时,还可能涉及内存管理开销,因此最好锁定内存,参见mlock手册。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39564073

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档