使用g ++ 5.3.1编译时,程序运行速度比使用g ++ 4.8.4编译的相同程序慢3倍

Ale*_*kov 17 c++ ubuntu performance gcc5

最近,我开始使用带有g ++ 5.3.1的Ubuntu 16.04并检查我的程序运行速度慢了3倍.在此之前我使用过Ubuntu 14.04,g ++ 4.8.4.我使用相同的命令构建它:CFLAGS = -std=c++11 -Wall -O3.

我的程序包含循环,充满数学调用(sin,cos,exp).你可以在这里找到它.

我尝试使用不同的优化标志(O0,O1,O2,O3,Ofast)进行编译,但在所有情况下都会重现问题(使用Ofast,两种变体运行速度更快,但第一次运行速度仍然慢3倍).

在我使用的程序中libtinyxml-dev,libgslcblas.但是它们在两种情况下都具有相同的版本,并且在性能方面没有在程序中(根据代码和callgrind概要分析)占用任何重要部分.

我已经进行了分析,但它并没有让我知道它为什么会发生. Kcachegrind比较(左边比较慢).我只注意到现在程序使用与Ubuntu 14.04 libm-2.23相比libm-2.19.

我的处理器是i7-5820,Haswell.

我不知道为什么它会变慢.你有什么想法?

PS下面你可以找到最耗时的功能:

void InclinedSum::prepare3D()
{
double buf1, buf2;
double sum_prev1 = 0.0, sum_prev2 = 0.0;
int break_idx1, break_idx2; 
int arr_idx;

for(int seg_idx = 0; seg_idx < props->K; seg_idx++)
{
    const Point& r = well->segs[seg_idx].r_bhp;

    for(int k = 0; k < props->K; k++)
    {
        arr_idx = seg_idx * props->K + k;
        F[arr_idx] = 0.0;

        break_idx2 = 0;

        for(int m = 1; m <= props->M; m++)
        {
            break_idx1 = 0;

            for(int l = 1; l <= props->L; l++)
            {
                buf1 = ((cos(M_PI * (double)(m) * well->segs[k].r1.x / props->sizes.x - M_PI * (double)(l) * well->segs[k].r1.z / props->sizes.z) -
                            cos(M_PI * (double)(m) * well->segs[k].r2.x / props->sizes.x - M_PI * (double)(l) * well->segs[k].r2.z / props->sizes.z)) /
                        ( M_PI * (double)(m) * tan(props->alpha) / props->sizes.x + M_PI * (double)(l) / props->sizes.z ) + 
                            (cos(M_PI * (double)(m) * well->segs[k].r1.x / props->sizes.x + M_PI * (double)(l) * well->segs[k].r1.z / props->sizes.z) -
                            cos(M_PI * (double)(m) * well->segs[k].r2.x / props->sizes.x + M_PI * (double)(l) * well->segs[k].r2.z / props->sizes.z)) /
                        ( M_PI * (double)(m) * tan(props->alpha) / props->sizes.x - M_PI * (double)(l) / props->sizes.z )
                            ) / 2.0;

                buf2 = sqrt((double)(m) * (double)(m) / props->sizes.x / props->sizes.x + (double)(l) * (double)(l) / props->sizes.z / props->sizes.z);

                for(int i = -props->I; i <= props->I; i++)
                {   

                    F[arr_idx] += buf1 / well->segs[k].length / buf2 *
                        ( exp(-M_PI * buf2 * fabs(r.y - props->r1.y + 2.0 * (double)(i) * props->sizes.y)) - 
                        exp(-M_PI * buf2 * fabs(r.y + props->r1.y + 2.0 * (double)(i) * props->sizes.y)) ) *
                        sin(M_PI * (double)(m) * r.x / props->sizes.x) * 
                        cos(M_PI * (double)(l) * r.z / props->sizes.z);
                }

                if( fabs(F[arr_idx] - sum_prev1) > F[arr_idx] * EQUALITY_TOLERANCE )
                {
                    sum_prev1 = F[arr_idx];
                    break_idx1 = 0;
                } else
                    break_idx1++;

                if(break_idx1 > 1)
                {
                    //std::cout << "l=" << l << std::endl;
                    break;
                }
            }

            if( fabs(F[arr_idx] - sum_prev2) > F[arr_idx] * EQUALITY_TOLERANCE )
            {
                sum_prev2 = F[arr_idx];
                break_idx2 = 0;
            } else
                break_idx2++;

            if(break_idx2 > 1)
            {
                std::cout << "m=" << m << std::endl;
                break;
            }
        }
    }
}
}
Run Code Online (Sandbox Code Playgroud)

进一步调查.我写了以下简单的程序:

#include <cmath>
#include <iostream>
#include <chrono>

#define CYCLE_NUM 1E+7

using namespace std;
using namespace std::chrono;

int main()
{
    double sum = 0.0;

    auto t1 = high_resolution_clock::now();
    for(int i = 1; i < CYCLE_NUM; i++)
    {
        sum += sin((double)(i)) / (double)(i);
    }
    auto t2 = high_resolution_clock::now();

    microseconds::rep t = duration_cast<microseconds>(t2-t1).count();

    cout << "sum = " << sum << endl;
    cout << "time = " << (double)(t) / 1.E+6 << endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我真的很想知道为什么这个简单的示例程序在g ++ 4.8.4 libc-2.19(libm-2.19)下比在g ++ 5.3.1 libc-2.23(libm-2.23)下快2.5.

编译命令是:

g++ -std=c++11 -O3 main.cpp -o sum
Run Code Online (Sandbox Code Playgroud)

使用其他优化标志不会更改比率.

我如何理解谁,gcc或libc,减慢程序?

Mar*_*erg 1

这是 glibc 中的一个错误,影响版本 2.23(在 Ubuntu 16.04 中使用)和 2.24 的早期版本(例如 Fedora 和 Debian 已经包含不再受影响的修补版本,Ubuntu 16.10 和 17.04 尚未包含)。

速度减慢源于 SSE 到 AVX 寄存器转换的损失。请参阅此处的 glibc 错误报告:https://sourceware.org/bugzilla/show_bug.cgi?id=20495

Oleg Strikov 在他的 Ubuntu 错误报告中写了相当广泛的分析:https://bugs.launchpad.net/ubuntu/+source/glibc/+bug/1663280

如果没有补丁,有各种可能的解决方法:您可以静态编译问题(即 add -static),或者可以通过LD_BIND_NOW在程序执行期间设置环境变量来禁用延迟绑定。同样,上面的错误报告中有更多详细信息。