优化的 SIMD 向量库是否由等效的标量运算执行?

Optimized SIMD vector library is out performed by equivalent scalar operations?

我编写此代码是为了测试特征加法与普通旧标量加法的性能。

int x, y;
cin >> x; cin >> y;
typedef int theType;
Array<theType, 8, 1> theArray; theArray << 0,0,0,0,0,0,0,0;
StopWatch sw;
sw.Start();
for(int k = 0; k < y*1000000; k++){
    theArray << 0,0,0,0,0,0,0,0;
    for (int i = 0; i < 10 *x; i++){
        theArray += 2;
    }
}
sw.Stop();
cout << theArray << " : " << sw.MilliSeconds() << endl;

theType f = 0;
sw.Start();
for(int k = 0; k < y*1000000; k++){
    f = f-1;
    for (int i = 0; i < 80 * x; i++){
        f += 2;
    }
}
sw.Stop();
cout << f << " : " << sw.MilliSeconds();

我是 运行 使用 g++ -O2 的代码。我使用命令行设置 x 和 y 并将它们用作 for 循环中的上限,因此编译器不会优化 for 循环。本征测试生成一个包含 8 个值的数组,并明智地添加一个常量分量。标量测试只是增加一个标量值,但它完成的是特征值测试的 8 倍。

结果(使用 x = 1,y=1):

使用 int 作为类型:52 毫秒本征与 1 毫秒标量

使用短作为类型:54 毫秒本征与 1 毫秒标量

为什么 Eigen 比较慢?由于在 eigen 中使用 SIMD,我预计它会更快一些。 eigen真的这么慢,还是我做错了什么?

你的内部循环:

for (int i = 0; i < 80 * x; i++){
    f += 2;
}

被编译器优化掉了。在 VC++ 上为 x86 编译整个循环折叠成一条汇编指令:

lea esi, DWORD PTR [esi+ecx*2]

其中ecx是80*x的值,esif变量的值。

您将需要一些方法来禁用循环优化。除此之外,对单个标量执行 8 次操作总是比对 8 元素数组执行一次操作快,因此我建议将您的 f 变量转换为数组 f[8],以实现与矢量代码的奇偶校验。执行此操作后,您会发现 Eigen 明显快于非矢量化代码。