我正在尝试将矢量化检查成一个简单的循环。我正在编写MacOS 19.5,我的代码是用gcc-mp-4.9
编译的(安装自Macport)。为了获得更好的矢量化性能,我测量了经过的时间进入一个主循环,并将其与非矢量化版本进行了比较。
下面是这个简单的代码(我用"NOVEC"
或"VEC" -D flag
编译的):
#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-矢量化:
gcc-mp-4.9 -DNOVEC -std=c99 -fno-tree-vectorize main_benchmark.c
矢量化:
gcc-mp-4.9 -DVEC -std=c99 -Wa,-q -O3 -march=native -ftree-vectorize -fopt-info-vec main_benchmark.c
我不确定优化是否为非向量化编译所激活.如果是这样的话,该如何禁用呢?
谢谢你的帮忙
发布于 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
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
...
0000000100000920 vmovupd (%r10,%rax), %ymm0
0000000100000926 vaddpd (%r14,%rax), %ymm0, %ymm0
000000010000092c addl $0x1, %ecx
000000010000092f vmovupd %ymm0, (%r8,%rax)
...
其次,循环中的添加代码是矢量化的(参见上面的vaddpd
),但是设置和malloc控制着循环。已经没有多少东西可以测量回路了。
为了测量循环(仅限osx),我使用了
#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/会更多地讨论细节。
发布于 2016-09-24 06:57:55
看到汇编程序代码会很有趣。
通常情况下,您最多可以期望获得两倍的性能,但在这种情况下,考虑到数组的大小,您不会接近它,CPU只是处于空闲状态,等待数据进入缓存并从缓存中刷新,然后才能做任何事情,这可能就是没有收益的原因。
在处理大量数据时,还可能涉及内存管理开销,因此最好锁定内存,参见mlock
手册。
https://stackoverflow.com/questions/39564073
复制相似问题