C++ 当使用g++;5.3.1使用g+编译的相同程序+;4.8.4,同一命令
最近,我开始在g++5.3.1中使用Ubuntu 16.04,并检查我的程序运行速度是否慢了3倍。 在此之前,我使用过Ubuntu 14.04、g++4.8.4。 我使用相同的命令构建它:C++ 当使用g++;5.3.1使用g+编译的相同程序+;4.8.4,同一命令,c++,performance,ubuntu,gcc5,C++,Performance,Ubuntu,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倍) 在我的程序中,我
CFLAGS=-std=c++11-Wall-O3
我的程序包含循环,充满了数学调用(sin、cos、exp)。
你可以找到它
我曾尝试使用不同的优化标志(O0、O1、O2、O3、Ofast)进行编译,但在所有情况下,问题都会重现(Ofast两种变体的运行速度更快,但第一种运行速度仍然慢3倍)
在我的程序中,我使用了libtinyxml-dev
,libgslcblas
。但它们在这两种情况下都有相同的版本,并且在性能方面(根据代码和callgrind评测)在程序中没有任何重要作用
我已经进行了分析,但它没有告诉我为什么会发生这种情况。
.
我只注意到现在程序使用的是libm-2.23
,而Ubuntu 14.04使用的是libm-2.19
我的处理器是i7-5820,哈斯韦尔
我不知道为什么它会变慢。你有什么想法吗
请注意,您可以找到最耗时的功能:
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;
}
}
}
}
}
使用其他优化标志不会更改比率
我怎样才能理解是谁,gcc还是libc,减慢了程序的速度?要获得真正准确的答案,您可能需要一名libm维护人员来查看您的问题。不过,这是我的初稿,如果我找到其他东西,我会把它添加到这个答案中 首先,看看GCC生成的asm,介于和之间。只有4个区别:
- 在开始时,对于相同的寄存器,
被转换为xorpd
pxor
- a
在从int转换为double之前添加(px或xmm1,xmm1
)cvtsi2sd
- 在转换之前移动了
movsd
- 添加(
)在比较(addsd
)之前移动ucomisd
sysdeps
中有17个不同的子文件夹(其中定义了sin),因此我选择了x86_64
一个
首先,处理器功能的处理方式发生了变化,例如,2.19中用于检查FMA/AVX的glibc/sysdeps/x86_64/fpu/multiarch/s_sin.c,但在2.23中是在外部完成的。可能存在未正确报告功能的错误,导致未使用FMA或AVX。然而,我认为这个假设不太可信
其次,在../x86_64/fpu/s_sinf.s
中,唯一的修改(版权更新除外)更改堆栈偏移量,将其对齐到16字节;同上。我不确定这是否会带来巨大的变化
然而,2.23为数学函数的矢量化版本添加了很多源代码,有些使用AVX512,您的处理器可能不支持AVX512,因为它确实是新的。也许libm会尝试使用这样的扩展,但既然您没有这些扩展,那个么可以使用通用版本吗
编辑:我尝试用GCC4.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 »
我将尝试解决这个问题,但事先请注意,这个符号很可能负责根据处理器选择正确的优化版本,这可能是性能影响的一部分。这是glibc中的一个bug,影响2.23版(在Ubuntu 16.04中使用)和2.24的早期版本(例如,Fedora和Debian已经包括不再受影响的修补版本,Ubuntu 16.10和17.04还没有) 增长放缓源于SSE到AVX寄存器的过渡惩罚。请参见此处的glibc错误报告: Oleg Strikov在他的Ubuntu bug报告中写了一个相当广泛的分析:
没有补丁,有各种可能的解决方法:您可以静态编译问题(即添加
-static
),也可以通过在程序执行期间设置环境变量LD\u BIND\u NOW
来禁用延迟绑定。同样,上面的错误报告中有更多详细信息。我怀疑这是libm本身(它实现了那些数学函数——是的,它们不是内联的)你看了生成的程序集输出了吗?另外,你确定这个函数没有错误,即没有未定义的行为吗?你有数组或类似数组的类型(比如F
,如果你问我的话,这是个坏名字),您正在使用未检查的索引访问它们,以查看它们是否在边界内。如果程序集输出相同或大致相等,请检查函数本身,因为UB可能会做奇怪的事情。@orbitcowboy,不,我还没有查看asm列表。源代码列表和主要计算。我发现了两个内存泄漏,但它不会影响程序的性能。事实上,我错过了两次删除。之后我有。这与问题无关!
g++ -std=c++11 -O3 main.cpp -o sum
/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 »