【问题标题】:Rebuilt Fortran code is twice as slow after updating to Ubuntu 14.04更新到 Ubuntu 14.04 后重建的 Fortran 代码速度是原来的两倍
【发布时间】:2014-11-04 09:38:54
【问题描述】:

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

因为该程序进行了大量的矩阵求逆,我猜想一个库(LAPACK?)或编程接口(OpenMP?)已经在 Ubuntu 12 和 14 之间进行了更新,从而减慢了一切。我相信这是一个普遍的问题,这里的人可能已经知道了。除了降级到 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)。我现在可以尝试用旧的编译器编译代码。

【问题讨论】:

  • 如果没有代码,这将很难回答。您是否测量过瓶颈在哪里以及代码的哪些部分变慢了?如果没有,请立即执行。
  • 当然,没有什么能阻止您构建自己的 LAPACK 和 BLAS。确保使用一些优化的 BLAS 库,例如 ATLAS 或 OpenBLAS。它们甚至可能存在于您的存储库中。
  • 关于您的编辑:您使用哪些库?最重要的是,您使用哪种 BLAS 实现?在你的包管理器中搜索“BLAS”,会有更多。
  • 另外,即使你无法确定是什么变慢了,你仍然可以确定在新编译的代码中什么最耗时。
  • 我会先询问您是否使用 MPI,并且处理器数量错误。而且,正如@steabert 所说,您仍然可以确定什么时间最长。如果您使用的是 gprof,它可能不会告诉您太多信息。 This explains the method I use. 在像 BLAS 和 LAPACK 这样的包中,对大矩阵的少量操作可能很快,但对小矩阵的大量操作可能会将大部分时间花在可避免的杂项上,例如检查参数。

标签: performance ubuntu fortran exponentiation


【解决方案1】:

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

我决定使用 GDB(Valgrid 不适合我):我使用标志 -g 编译,使用“gdb myprogramname”执行,在 GDB 提示符下键入“run”以执行程序,使用 ctr+C 暂停,使用“信息线程”检查线程在做什么,然后按“继续”继续。我随机地做了几次,以在程序大部分时间花费的地方进行某种统计。这很快证实了 gprof 之前的发现,即我的程序在我翻译成 f90 的函数上投入了大量时间。但是,现在我还发现,在这个函数中花费特别长时间的数学运算是求幂,正如对 C 函数 e_powf.c 的调用所暗示的那样。我的函数(海水状态方程)有很多高阶多项式,如T**3T**4。为了避免调用 e_powf.c 并查看这是否提高了代码的性能,我将 T**2 类型的所有术语更改为 T*TT**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 这样在 Internet 上出现的情况),所以如果从 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 中(无论是什么原因)。

非常感谢所有评论的人,这对我很有帮助,我学到了很多!

【讨论】:

  • 这很奇怪。编译器绝对应该自己优化它。您启用了哪些优化?见goo.gl/T5Fm0p
  • 我是这样编译的:gfortran -v -g -fbounds-check -fopenmp -o ahoi ahoi_load_data.f90 ahoi_globalvars.f90 ahoi_globalvarsOI.f90 ahoi_funcs.f90 woa_funcs.f90 ahoi_readcofile.f90 ahoi_main.f90 ahoi_paralind.f90 woa_basis.f90 ahoi_eta.f90 ahoi_dist.f90 ahoi_inverse.f90 ahoi_opest.f90 ahoi_corrclim.f90 ahoi_freezt.f90 ahoi_mapping.f90 ahoi_chnetcdf.f90 woa_adjust.f90 densitychange.f90 dgradcheck.f90 findsal.f findtemp.f ptemptotemp.f roundoff.f90 salest.f -I/usr/include/ -lnetcdff -lnetcdf
  • 你根本没有优化!立即阅读gcc.gnu.org/onlinedocs/gcc/Optimize-Options.htmlen.wikipedia.org/wiki/Optimizing_compiler!一定要尝试从-O1-O5 的所有级别!
  • 弗拉基米尔,谢谢!这真是太好了!我检查了 5 个优化标志,确实提高了速度。但是,有和没有指数仍然存在显着差异。我测量了一个程序迭代的时间。 “正常”代码:2:55 分钟。没有指数:1:03。 -O1 正常:1:00。 -O1 没有指数:30 秒。 O2 正常:56 秒。 -O2 没有指数:25 秒。进一步的水平没有显示出显着的变化(我尝试了没有指数的 O5)。看起来避免幂运算仍然可以加快相同 O 级别的代码。
【解决方案2】:
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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-16
    • 2011-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多