优化的 SIMD 矢量库无法通过等效标量运算执行

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

本文关键字:标量 执行 运算 SIMD 优化      更新时间:2023-10-16

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

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 毫秒标量

使用 short 作为类型:54 毫秒特征与 1 毫秒标量

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

你的内心循环:

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

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

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

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

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