我们有一个CFD求解器,运行模拟时发现在某些机器上运行特别慢,但在其他机器上没有这个问题。使用Intel VTune,发现以下代码行是问题所在(Fortran语言):
RHOV= RHO_INF*((1.0_wp - COEFF*EXP(F0)))**(1.0_wp/(GAMM - 1.0_wp))
通过使用 VTune 调试工具,问题被追踪到 call pow
汇编行,并且在跟踪堆栈时,显示它正在使用 __slowpow()
。经过一些搜索,发现了这个页面 抱怨同样的事情。在 libc 版本为 2.12 的计算机上,模拟需要 18 秒。在 libc 版本为 2.14 的计算机上,模拟只需 0 秒。
基于前面提到的网页信息,当底数接近 1.0 时,会出现问题。因此,我们进行了另一个简单的测试,在
pow()
之前将底数乘以任意数字,然后在调用 pow()
后将结果除以数字的指数幂。这将运行时间从 18 秒降至 0 秒,即使在 libc 2.12 上也是如此。但是,在所有使用
a**b
的代码中都这样做是不切实际的。有什么方法可以替换 libc 中的 pow()
函数吗?例如,我希望 Fortran 编译器生成的汇编行 call pow
调用我们编写的自定义 pow()
函数,该函数执行缩放、调用 libc 的 pow()
函数,然后除以缩放。如何创建一个中间层对编译器透明呢?
编辑
为澄清起见,我们正在寻找类似于以下的东西(伪代码):
double pow(a,b) {
a *= 5.0
tmp = pow_from_libc(a,b)
return tmp/pow_from_libc(5.0, b)
}
是否可以从libc中加载pow
并在我们的自定义函数中重命名它以避免命名冲突?如果customPow.o
文件可以将libc中的pow
重命名,那么如果libc仍然需要用于其他事情,会发生什么情况?这会在customPow.o
和libc中导致pow
的命名冲突吗?