std :: tan()在更新glibc后极其缓慢

我有一个C ++程序,调用大量的trig函数。 它已经运行了一年多了。 我最近安装了gcc-4.8,并在同样的地方更新了glibc。 这导致我的程序减慢了将近1000倍。 使用gdb我发现减速的原因是对std :: tan()的调用。 当参数是pi或pi / 2时,函数返回的时间很长。

如果编译时没有优化(真正的程序有和没有-O2标志都有相同的问题),这是一个MWE重现问题。

#include <cmath> int main() { double pi = 3.141592653589793; double approxPi = 3.14159; double ret = 0.; for(int i = 0; i < 100000; ++i) ret = std::tan(pi); //Very slow for(int i = 0; i < 100000; ++i) ret = std::tan(approxPi); //Not slow } 

下面是gdb的示例回溯(用Ctrl + c随机中断程序后获得)。 从打电话到晒黑,在MWE和我的真实程序中的回溯是相同的。

 #0 0x00007ffff7b1d048 in __mul (p=32, z=0x7fffffffc740, y=0x7fffffffcb30, x=0x7fffffffc890) at ../sysdeps/ieee754/dbl-64/mpa.c:458 #1 __mul (x=0x7fffffffc890, y=0x7fffffffcb30, z=0x7fffffffc740, p=32) at ../sysdeps/ieee754/dbl-64/mpa.c:443 #2 0x00007ffff7b1e348 in cc32 (p=32, y=0x7fffffffc4a0, x=0x7fffffffbf60) at ../sysdeps/ieee754/dbl-64/sincos32.c:111 #3 __c32 (x=<optimized out>, y=0x7fffffffcf50, z=0x7fffffffd0a0, p=32) at ../sysdeps/ieee754/dbl-64/sincos32.c:128 #4 0x00007ffff7b1e170 in __mptan (x=<optimized out>, mpy=0x7fffffffd690, p=32) at ../sysdeps/ieee754/dbl-64/mptan.c:57 #5 0x00007ffff7b45b46 in tanMp (x=<optimized out>) at ../sysdeps/ieee754/dbl-64/s_tan.c:503 #6 __tan_avx (x=<optimized out>) at ../sysdeps/ieee754/dbl-64/s_tan.c:488 #7 0x00000000004005b8 in main () 

我试过在四个不同的系统上运行代码(包括MWE和真正的程序)。 其中两个是在我运行我的代码的集群。 两个是我的笔记本电脑。 MWE在其中一个集群和一台笔记本电脑上运行时没有问题。 我检查了每个系统在相关情况下使用的libm.so.6的版本。 以下列表显示系统描述(取自cat /etc/*-release ),CPU是32位还是64位,MWE是否缓慢,最后是运行/lib/libc.so.6cat /proc/cpuinfo的输出cat /proc/cpuinfo

  • SUSE Linux Enterprise Server 11(x86_64),64位,使用libm-2.11.1.so(MWE很快)
 GNU C Library stable release version 2.11.1 (20100118), by Roland McGrath et al. Copyright (C) 2009 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Configured for x86_64-suse-linux. Compiled by GNU CC version 4.3.4 [gcc-4_3-branch revision 152973]. Compiled on a Linux 2.6.32 system on 2012-04-12. Available extensions: crypt add-on version 2.1 by Michael Glad and others GNU Libidn by Simon Josefsson Native POSIX Threads Library by Ulrich Drepper et al BIND-8.2.3-T5B For bug reporting instructions, please see: <http://www.gnu.org/software/libc/bugs.html>. processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 63 model name : Intel(R) Xeon(R) CPU E5-2680 v3 @ 2.50GHz stepping : 2 microcode : 53 cpu MHz : 1200.000 cache size : 30720 KB physical id : 0 siblings : 24 core id : 0 cpu cores : 12 apicid : 0 initial apicid : 0 fpu : yes fpu_exception : yes cpuid level : 15 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm abm ida arat epb xsaveopt pln pts dts tpr_shadow vnmi flexpriority ept vpid fsgsbase bmi1 avx2 smep bmi2 erms invpcid bogomips : 5000.05 clflush size : 64 cache_alignment : 64 address sizes : 46 bits physical, 48 bits virtual power management: 
  • CentOS发行版本6.7(Final),64位,使用libm-2.12.so(MWE很慢)
 GNU C Library stable release version 2.12, by Roland McGrath et al. Copyright (C) 2010 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Compiled by GNU CC version 4.4.7 20120313 (Red Hat 4.4.7-16). Compiled on a Linux 2.6.32 system on 2015-09-22. Available extensions: The C stubs add-on version 2.1.2. crypt add-on version 2.1 by Michael Glad and others GNU Libidn by Simon Josefsson Native POSIX Threads Library by Ulrich Drepper et al BIND-8.2.3-T5B RT using linux kernel aio libc ABIs: UNIQUE IFUNC For bug reporting instructions, please see: <http://www.gnu.org/software/libc/bugs.html>. processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 26 model name : Intel(R) Xeon(R) CPU E5507 @ 2.27GHz stepping : 5 cpu MHz : 1596.000 cache size : 4096 KB physical id : 0 siblings : 4 core id : 0 cpu cores : 4 apicid : 0 initial apicid : 0 fpu : yes fpu_exception : yes cpuid level : 11 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology nonstop_tsc aperfmperf pni dtes64 monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr pdcm dca sse4_1 sse4_2 popcnt lahf_lm tpr_shadow vnmi flexpriority ept vpid bogomips : 4533.16 clflush size : 64 cache_alignment : 64 address sizes : 40 bits physical, 48 bits virtual power management: 
  • Ubuntu精确(12.04.5 LTS),64位,使用libm-2.15.so(我的第一台笔记本电脑,MWE很慢)
 GNU C Library (Ubuntu EGLIBC 2.15-0ubuntu10.15) stable release version 2.15, by Roland McGrath et al. Copyright (C) 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Compiled by GNU CC version 4.6.3. Compiled on a Linux 3.2.79 system on 2016-05-26. Available extensions: crypt add-on version 2.1 by Michael Glad and others GNU Libidn by Simon Josefsson Native POSIX Threads Library by Ulrich Drepper et al BIND-8.2.3-T5B libc ABIs: UNIQUE IFUNC For bug reporting instructions, please see: <http://www.debian.org/Bugs/>. processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 42 model name : Intel(R) Core(TM) i7-2620M CPU @ 2.70GHz stepping : 7 microcode : 0x1a cpu MHz : 800.000 cache size : 4096 KB physical id : 0 siblings : 4 core id : 0 cpu cores : 2 apicid : 0 initial apicid : 0 fpu : yes fpu_exception : yes cpuid level : 13 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx lahf_lm ida arat epb xsaveopt pln pts dtherm tpr_shadow vnmi flexpriority ept vpid bogomips : 5387.59 clflush size : 64 cache_alignment : 64 address sizes : 36 bits physical, 48 bits virtual power management: 
  • Ubuntu精确(12.04.5 LTS),32位,使用libm-2.15.so(我的第二台笔记本电脑,MWE速度很快)
 GNU C Library (Ubuntu EGLIBC 2.15-0ubuntu10.12) stable release version 2.15, by Roland McGrath et al. Copyright (C) 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Compiled by GNU CC version 4.6.3. Compiled on a Linux 3.2.68 system on 2015-03-26. Available extensions: crypt add-on version 2.1 by Michael Glad and others GNU Libidn by Simon Josefsson Native POSIX Threads Library by Ulrich Drepper et al BIND-8.2.3-T5B libc ABIs: UNIQUE IFUNC For bug reporting instructions, please see: <http://www.debian.org/Bugs/>. processor : 0 vendor_id : GenuineIntel cpu family : 6 model : 15 model name : Intel(R) Core(TM)2 Duo CPU T5800 @ 2.00GHz stepping : 13 microcode : 0xa3 cpu MHz : 800.000 cache size : 2048 KB physical id : 0 siblings : 2 core id : 0 cpu cores : 2 apicid : 0 initial apicid : 0 fdiv_bug : no hlt_bug : no f00f_bug : no coma_bug : no fpu : yes fpu_exception : yes cpuid level : 10 wp : yes flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx lm constant_tsc arch_perfmon pebs bts aperfmperf pni dtes64 monitor ds_cpl est tm2 ssse3 cx16 xtpr pdcm lahf_lm dtherm bogomips : 3989.79 clflush size : 64 cache_alignment : 64 address sizes : 36 bits physical, 48 bits virtual power management: 

我希望我能够提供足够的背景信息。 这些是我的问题。

  1. 为什么std :: tan()变慢?
  2. 有没有办法将其恢复到正常速度?

我会非常喜欢一个不需要安装/replace一堆库的解决scheme。 这可能适用于我的笔记本电脑,但我没有在群集节点上的必要权限。

更新#1:我删除了关于将常量传递给tan的观察,正如Sam Varshavchik所解释的那样。 我将运行/lib/libc.so.6的输出添加到我的系统列表中。 还增加了第四个系统。 至于时机,下面是运行time ./mwe的输出time ./mwepi循环( approxPi注释掉)。

 real 0m11.483s user 0m11.465s sys 0m0.004s 

在这里是与approxPi循环( pi注释掉)。

 real 0m0.011s user 0m0.008s sys 0m0.000s 

更新#2:对于每个系统,添加CPU是32位还是64位以及第一个内核的cat /proc/cpuinfo的输出。

超越函数的准确性(如三角函数和指数等)一直存在问题1

为什么一些trig函数调用比其他的慢

对于三角函数的许多论据来说,有一个快速的近似值可以为大多数论证产生一个高精度的结果。 然而,对于某些论点来说,近似可能是非常严重的错误。 因此,需要采用更精确的方法,但是这需要更长的时间(正如你所注意到的)。

为什么新图书馆现在可能会变慢

长期以来,英特尔就三角函数的浮点版本的准确性做出了误导性的声明,称它们比实际的准确得多2 。 那么,那个glibc过去只是把sin(double)作为fsin(float) 3的包装。 你可能升级到一个glibc版本,纠正了这个错误。 我不能说AMD的libm,但它仍然可能仍然依赖于三角函数4,5的浮点版本的精确度的不正确声明。

该怎么办

如果你想要速度,而不是精确度太高,那么就使用tan( ftan )的float版本。 否则,如果你需要准确性,那么你就被困在较慢的方法中。 最好你可以做的就是缓存tan(pi )和tan(pi/2) ,当你认为你可能需要的时候使用预先计算的值。