我注意到编译器链接器的标志周围有一个有趣的现象,它以我无法理解的方式影响正在运行的代码。
我有一个库,它提供了相同算法的不同实现,以测试这些不同实现的运行速度。
最初,我用一对相同的实现测试了这种情况,以检查发生的正确事情(两者都以大致相同的速度运行)。我首先使用以下编译器标志编译对象(每个实现一个):
-g -funroll-loops -flto -Ofast -Werror
然后在链接期间传递了gcc以下标志:
-Ofast -flto=4 -fuse-linker-plugin
这给了一个快速运行的库,但奇怪的是,对于链接期间参数中包含的第一个对象,可靠且可重复地快了约7%(因此,如果首先链接,则实现速度更快)。
所以:
gcc -o libfoo.so -O3 -ffast-math -flto=4 -fuse-linker-plugin -shared support_obj.os obj1.os obj2.os -lm
VS
gcc -o libfoo.so -O3 -ffast-math -flto=4 -fuse-linker-plugin -shared support_obj.os obj2.os obj1.os -lm
第一种情况是obj1中的实现比obj2中的实现运行得更快。在第二种情况下,反过来是正确的。需要明确的是,除了函数入口名称外,代码在两种情况下都是相同的。
现在我通过在链接过程中删除-Ofast
标记来删除这个奇怪的链接参数顺序差异(实际上加了一点)。
我可以通过将-Ofast
更改为-O3 -ffast-math
来复制大致相同的情况,但在这种情况下,我需要在链接期间提供-ffast-math
,这又会导致奇怪的订购速度差异。我不确定为什么在-Ofast
期间保持加速,但在链接期间未传递-ffast-math
时{for} -ffast-math
不能保持加速,但我可以接受它可能会延迟到链接时间优化在一个案例中传递相关信息但不传递另一个案例。但这并不能解释速度差异。
删除-ffast-math
意味着它运行速度慢〜8倍。
是否有人能够了解可能导致这种影响的原因?我真的很想知道可能会发生什么导致这种有趣的行为,所以我不能不小心触发它。
运行速度测试是在python中使用库和timeit周围的包装器执行的,我很确定这是做正确的事情(我可以旋转命令和事物来显示python副作用可以忽略不计)。 / p>
我还测试了库的输出正确性,所以我也可以对此有合理的信心。
答案 0 :(得分:0)
太长了:
由于在数学运算中获得不正确结果的风险,我建议不要使用它。
使用-ffast_math
和/或-Ofast
会导致错误的结果,如gcc手册中的摘录所示:
选项:-ffast-math
设置选项:
此选项可以定义预处理器宏__FAST_MATH__
。
除-Ofast
之外的任何-O选项都不会打开此选项,因为它可能导致程序的输出不正确,这些程序依赖于IEEE或ISO规则/数学函数规范的精确实现。但是,对于不需要保证这些规范的程序,它可能会产生更快的代码。 "
选项:-Ofast
无视严格的标准合规性。 -Ofast
启用所有-O3
优化。它还支持对所有符合标准的程序无效的优化。它会启用-ffast-math
和特定于Fortran的-fno-protect-parens
和-fstack-arrays
。