在更新到Ubuntu 14.04之后,重建的Fortran代码慢了两倍

时间:2014-11-04 09:38:55

标签: performance ubuntu fortran exponentiation

在将操作系统更新到Ubuntu 14.04并使用Gfortran 4.8.2重建后,我们的并行Fortran程序运行速度慢了两倍。遗憾的是,为了测量代码的哪些部分速度变慢(不是没有降级操作系统),因为在旧操作系统下编译时我没有为gprof保存任何分析信息。

因为程序执行了大量的矩阵求逆,我的猜测是在Ubuntu 12和14之间以一种减慢一切的方式更新了一个库(LAPACK?)或编程接口(OpenMP?)。我相信这是一个普遍的问题,这里的人可能已经知道了。除了降级到Ubuntu 12或13之外,哪个是快速恢复Fortran代码的解决方案?

所有库都是使用apg-get从存储库安装的,因此,当我使用apt-get dist-upgrade升级系统时,它们也应该升级,但我可以检查它们是否确实是最新版本和/或者从头开始构建它们。

我遵循了Steabert的建议并对当前代码进行了描述:我使用gfortran -pg重新编译并使用gprof检查了性能。当调用一些旧的F77子程序时,程序显得非常慢,我将其转换为f90而没有性能提升。我玩了建议的标志并比较了一个程序迭代的时间:标志-fno-aggressive-loop-optimizations-llapack-lblas没有产生任何显着的性能提升。标志-latlas-llapack_latlas-lf77blas未编译(/usr/bin/ld: cannot find -lf77blas等),即使这些库存在且位于正确的路径中。编译器标志播放和性能分析都表明我的第一个猜测(与矩阵反转相关的减速,LAPACK等)是错误的。似乎减速是在没有执行重线性代数的代码的一部分中。使用objdump my_exec -s我发现我的程序最初是在操作系统升级之前使用gfortran 4.6.3编译的。而不是使用现在的gfortran(4.8.2)。我现在可以尝试使用旧编译器编译代码。

2 个答案:

答案 0 :(得分:1)

这可能不是100%令人满意的答案,但它解决了我的性能问题。所以这就是:

我决定使用GDB(Valgrid对我不起作用):我用标志-g编译,用“gdb myprogramname”执行,在GDB提示符下输入“run”来执行程序,暂停用ctr + C ,检查线程用“信息线程”做什么,然后继续“继续”。我随机做了好几次这样做,以便在程序花费大部分时间的情况下进行某种统计。这很快证实了之前发现的gprof,即我的程序在我转换为f90的函数中投入了大量时间。但是,现在我还发现,在函数e_powf.c中调用的建议是,在函数内部需要特别长时间的数学运算是取幂。我的函数(海水状态方程)有许多高阶多项式,其中的术语如T**3T**4。为了避免调用e_powf.c并查看这是否改善了代码的性能,我将类型T**2的所有术语更改为T*T; T**3T*T*T等。以下是函数的摘录之前的内容:

!          RW =     999.842594 + 6.793952E-2*T - 9.095290E-3*T**2+ 1.001685E-4*T**3 - 1.120083E-6*T**4 + 6.536332E-9*T**5

以及它现在如何:

 RW =     999.842594 + 6.793952E-2*T - 9.095290E-3*T*T+ 1.001685E-4*T*T*T - 1.120083E-6*T*T*T*T + 6.536332E-9*T*T*T*T*T

结果,我的程序再次以两倍的速度运行(即,就像我升级操作系统之前一样)。虽然这解决了我的性能问题,但我无法100%确定它是否真的与操作系统升级或编译器从4.6.3更改为4.8.2有关。虽然目前的性能类似于操作系统前的升级,但它确实表明它应该是。

不幸的是,“locate e_powf”在我的系统中没有产生任何结果,好像该函数是gfortran编译器的二进制部分,但源代码没有给出。通过谷歌搜索,似乎e_powf.c本身似乎最近似乎没有更新(我想,在互联网上发生的这种情况,如http://koala.cs.pub.ro/lxr/#glibc/sysdeps/ieee754/flt-32/e_powf.c),所以如果从Ubuntu 12更改为14或从gfortran 4.6.3对于4.8.2,这个函数的使用方式似乎相当微妙。

因为我在互联网上发现了一些关于是否使用T*T代替T**2等的讨论会带来一些性能提升,而且大多数人似乎对此持怀疑态度(例如:http://computer-programming-forum.com/49-fortran/6b042075d8c77a4b.htm ;或者stackoverflow中的一个封闭的问题:Tips and tricks on improving Fortran code performance)我仔细检查了我的发现,所以我可以说我非常确定使用变量的产品(避免像这样调用e_powf.c)比取幂更快,至少与gfortran 4.8.2(这是有原因的)。

非常感谢所有评论过的人,当然这对我帮助很大,而且我学到了很多东西!

答案 1 :(得分:0)

RW =     999.842594 + 6.793952E-2*T - 9.095290E-3*T*T+ 1.001685E-4*T*T*T - 1.120083E-6*T*T*T*T + 6.536332E-9*T*T*T*T*T

如果您需要进一步改进,可以在上面写一行:

T2=T*T
T3=T2*T
T4=T3*T
T5=T4*T
RW=999.842594 + 6.793952E-2*T - 9.095290E-3*T2+ 1.001685E-4*T3 - 1.120083E-6*T4 + 6.536332E-9*T5