微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

用g ++ 5.3.1编译的程序运行速度要比用g ++ 4.8.4编译的同样的程序运行速度慢3倍,命令相同

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

我的程序包含充满math调用(sin,cos,exp)的循环。 你可以在这里find它。

我试着用不同的优化标志(O0,O1,O2,O3,Ofast)进行编译,但是在所有情况下,这个问题都被复制了(使用了Ofast,两个变种跑得更快,但是第一个跑得慢了3倍)。

在我的程序中,我使用libtinyxml-dev , libgslcblas 。 但是它们在这两种情况下都有相同的版本,并且在性能方面不会在程序(根据代码和callgrind分析)中占有重要的地位。

最好的方法来比较不同版本的库的性能

Netbeans发布模式C ++速度是Visual Studio 2012的两倍?

通过cmd获取网速(Windows)

数据库服务器中速率非常高的内存页面

为什么QueryPerformanceFrequency是由1024除以TSC频率,为什么不只是TSC?

我已经进行了分析,但是它并没有告诉我为什么会发生这种情况。 Kcachegrind比较(左边慢) 。 我只注意到,现在程序使用libm-2.23与Ubuntu 14.04的libm-2.19相比。

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

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

PS下面你可以find最耗时的function:

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(ry - props->r1.y + 2.0 * (double)(i) * props->sizes.y)) - exp(-M_PI * buf2 * fabs(ry + props->r1.y + 2.0 * (double)(i) * props->sizes.y)) ) * sin(M_PI * (double)(m) * rx / props->sizes.x) * cos(M_PI * (double)(l) * rz / 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; } } } } }

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

#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; }

我真的好奇,为什么这个简单的示例程序在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

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

我怎样才能了解gcc或libc这个程序的运行速度?

有效的线程数

如何获得当前进程的Windows性能计数器

我怎么知道为什么我的Perl代码在内核空间(上面的“sy”)花费了太多的时间?

一个是推荐的:使用静态库与dynamic库(共享对象)

在linux中使用opencv的c ++快速截图

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

放缓源于上证所对AVX寄存器的过渡惩罚。 查看glibc错误报告: https : //sourceware.org/bugzilla/show_bug.cgi? id = 20495

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

没有补丁程序,有各种可能的解决方法:您可以静态编译问题(即添加-static ),或者您可以通过在程序执行期间设置环境变量LD_BIND_Now来禁用延迟绑定。 再次,上述错误报告中的更多细节。

对于一个确切的答案,你可能需要一个libm维护者来看看你的问题。 但是,这里是我的承担 – 如果我找到其他的东西,我将它添加到这个答案。

首先看GCC生成的gcc,在gcc 4.8.2和gcc 5.3之间 。 只有4个区别:

在开始一个xorpd变成一个pxor ,为相同的寄存器

一个pxor xmm1,xmm1是在从int到double的转换之前添加的( cvtsi2sd )

在转换之前移动了一个movsd

在比较( ucomisd )之前添加( ucomisd )

所有这些可能都不足以降低性能。 有一个好的分析器(例如英特尔)可以允许更确定的,但我没有访问一个

现在,对sin的依赖,让我们看看有什么改变。 问题是首先确定你使用的是哪个平台…在glibc的sysdeps有17个不同的子文件夹(其中罪被定义),所以我去了x86_64之一。

首先,处理器功能的处理方式发生了变化,例如glibc/sysdeps/x86_64/fpu/multiarch/s_sin.c在2.19中用于检查FMA / AVX,而在2.23中则是在外部完成的。 可能有一个错误,其中的功能不正确的报告,导致不使用FMA或AVX。 然而,我不认为这个假设是非常合理的。

其次,在.../x86_64/fpu/s_sinf.S ,唯一的修改(除版权更新之外)改变堆栈偏移量,将其对齐到16字节; 为sincos同情。 不知道这会造成巨大的差异。

然而,2.23为数学函数的向量化版本添加了很多源,有些使用AVX512–你的处理器可能不支持,因为它是新的。 也许libm试图使用这样的扩展,并且因为你没有它们,在通用版本上回退?

编辑:我试着用gcc 4.8.5编译它,但为此我需要重新编译glibc-2.19。 目前我无法链接,因为这个:

/usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libm.a(s_sin.o): in function « __cos »: (.text+0x3542): undefined reference to « _dl_x86_cpu_features » /usr/lib/gcc/x86_64-linux-gnu/4.8/../../../x86_64-linux-gnu/libm.a(s_sin.o): in function « __sin »: (.text+0x3572): undefined reference to « _dl_x86_cpu_features »

我会尽力解决这个问题,但是事先注意到这个符号很可能是负责选择基于处理器的正确优化版本,这可能是性能的一部分。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐