英特尔SIMD指令加速

时间:2015-02-20 19:10:54

标签: c++ performance intel simd

我有以下代码:

long a[1000];
long b[1000];
long c[1000];
long d[1000];
long e[10000000];

double start, end;
for(int i = 0; i < 1000; i++){
    a[i] = i;
    b[i] = i*2;
    c[i] = i%13;
}
start = clock();
for(int k = 0; k < 10; k++){
    for(int j = 0; j < 1000000; j++){
        for(int i = 0; i < 1000; i++){
            a[i] *= a[i];
            b[i] *= b[i];
            c[i] = a[i] + b[i];
            d[i] = a[i] * c[i];
        }

    }
    e[0] += a[k];
}
end = clock();
cout << end-start <<"\t"<< e[0];

测试配置:intel core i7-4702MQ CPU,Haswell(据我所知,我的处理器支持AVX-II),intel c ++编译器v.14,visual studio 2013,Windows 8.1。

当我运行显示的代码时,我得到时间3403毫秒,如果我添加#pragma novetor,那么时间是6934毫秒,即加速只是2倍。但是如果我将所有阵列的类型改为加倍,则时间分别为2067毫秒和7479毫秒,即SIMD加速超过3.5倍。为什么会这样?为什么整数类型如此小的加速?

2 个答案:

答案 0 :(得分:0)

因为向量运算(#pragma novector排除)是针对浮点值设计的。如果使用整数,则添加在两种类型之间进行转换的步骤。

答案 1 :(得分:0)

当允许矢量化时,双精度实现使用fma指令和vmulpd,其吞吐量为0.5。

profiling double precision

使用整数运算时,它使用vpmulld,其吞吐量为1(性能的一半)。

profiling integer

但是,我无法再现你提到的表演。

  • 使用矢量化 - 双倍:4.76秒; int:3.04秒
  • 没有矢量化 - 双倍:18.2秒; int:17.8秒

标量性能下降可以很容易地解释为double,因为编译器使用相同指令的标量版本,但是,对于整数,它使用imul指令。

使用英特尔C ++ 16.0,x64编译在i7-4712MQ上获得的结果。 单线程

你可能会说这只是int的x6改进,为什么不是x8。好吧,在多线程中,int版本的性能比双精度高2.6倍。由于超线程或缓存行为的大小不同,处理器可能会更好地覆盖各种指令的延迟。