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