fortran 错误地调用子例程

Posted

技术标签:

【中文标题】fortran 错误地调用子例程【英文标题】:fortran erroneously calls a subroutine 【发布时间】:2013-01-08 20:35:14 【问题描述】:

我有一些用于有限元计算的 Fortran 90 代码。最近,我一直在尝试改进它解决块线性系统的方式。之前,我有一个用于稀疏矩阵向量乘法的子程序amux 和另一个使用amux 实现共轭梯度法的子程序cg。我写了一个新的矩阵向量子程序block_amux 和一个新的求解器block_cg。无论如何,新方法应该运行得更快,但它的运行速度却慢了 10 倍。

为了追踪问题,我使用分析器 gprof 来查看发生了什么。我发现我 92.5% 的代码都花在了运行 cg 子例程上——尽管我从未调用过它,并且完全依赖于 block_amux 和 block_cg。为了进一步搅浑水,我在实际的cg 例程中添加了一个打印语句,上面写着“Hello world”;它从未被打印出来。最后,我注意到 gprof 没有列出 amux 子例程的用途,即使真正调用 cg 会完成数百次普通的矩阵乘法。

我不知道这是怎么回事。有什么想法吗?如果这也有帮助,我可以附加 gprof 输出。

更新:我进行了以下更改,结果以某种方式或其他方式相同:

    更改子例程的名称,例如cg 变为conjugate_gradient。然后 Gprof 报告说我在新的 conjugate_gradient 例程中浪费时间。 将我实际使用的子例程移动到我的主程序中的“包含”语句下,而不是它们最初所在的模块linalg_mod,然后停止使用包含CG 例程的模块。相反,该程序将时间浪费在称为“frame_dummy”的东西上。这看起来很像this post,但我不能 将我使用的子例程从包含 CG 例程的 linalg_mod 移动到不包含它的新模块 linalg_mod_decoy。 gprof 没有在 CG 算法中浪费时间,而是说程序正在调用一个子程序,我用它来生成线性系统的右侧大约 3000 次而不是一次。 在另一台计算机上尝试。没有区别。

【问题讨论】:

如果将“cg”子程序重命名为“dontcallthissubroutine”之类的会发生什么?在这种情况下,我往往会发现 makefile 中存在问题,而我并没有像我想的那样编译和运行。 我想到了这个想法。我将它重命名为“conjugate_gradient”,删除所有可执行文件、对象和模块文件,然后以相同的结果重建所有内容。 gprof 报告在奇怪的子例程上花费了相同的时间,当然名称已更改。不过,我会尝试了解所有内容的编译方式。 您可能已经知道这一点,但请务必在重新编译之前清除旧的目标文件和您创建的所有库。 您的慢版本可执行文件有没有可能卡在缓存中?您是否尝试过从新的终端会话运行?还是开/关开关? 您使用哪个编译器以及哪些优化标志有效?您的问题听起来很像内联和/或过程间优化后发生的事情。每当编译经过检测的二进制文件时,都应禁用内联和 IPO。 【参考方案1】:

引用a comment by korrok,问题作者:

OpenMP 是罪魁祸首。我想如果我将线程数设置为 1,我将得到与完全没有 OMP 的分析相同的结果。当我停止使用 OpenMP 进行编译时,它的性能仍然很差,但正确地报告了所有工作的完成位置。

【讨论】:

以上是关于fortran 错误地调用子例程的主要内容,如果未能解决你的问题,请参考以下文章

由 R 调用时,Fortran 子例程不计算

从 C++ 调用带有可选参数的 Fortran 子例程

从 C++ 调用带有可选参数的 Fortran 子例程

如何在由 MPI 并行化的 fortran 中调用子例程?

从 c++ 调用 FORTRAN 子例程会产生非法参数值

从 Fortran 调用 C 函数,其中 C 函数名称最初是从 C 传入的