【问题标题】:Optimized SIMD vector library is out performed by equivalent scalar operations?优化的 SIMD 向量库是否由等效的标量操作执行?
【发布时间】:2015-03-14 00:40:28
【问题描述】:

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

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 ms Eigen vs. 1ms scalar

使用 short 作为类型:54 ms Eigen vs. 1ms scalar

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

【问题讨论】:

    标签: c++ eigen simd


    【解决方案1】:

    你的内循环:

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

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

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

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

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

    【讨论】:

    • “在单个标量上执行 8 次操作总是比在 8 个元素的数组上执行一次操作更快”......只有当它们可以优化为更少的操作时才是正确的(例如 8 加到乘法和添加)。例如,将一个标量与 8 个常数进行比较比将 8 个元素的 SIMD 向量与一个常数进行比较要慢得多。
    猜你喜欢
    • 2011-11-04
    • 2017-12-10
    • 1970-01-01
    • 1970-01-01
    • 2017-08-12
    • 2020-07-24
    • 2015-12-14
    • 2012-02-23
    • 2019-05-29
    相关资源
    最近更新 更多