【问题标题】:Curious result from the gcc linker behaviour around -ffast-math来自 -ffast-math 的 gcc 链接器行为的奇怪结果
【发布时间】:2016-03-25 08:35:51
【问题描述】:

我注意到编译器链接器的标志以我无法理解的方式影响正在运行的代码的一个有趣现象。

我有一个库,它提供相同算法的不同实现,以便测试这些不同实现的运行速度。

最初,我使用一对相同的实现来测试情况,以检查是否发生了正确的事情(两者的运行速度大致相同)。我首先使用以下编译器标志编译对象(每个实现一个):

-g -funroll-loops -flto -Ofast -Werror

然后在链接过程中传递了以下标志:

-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

对

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,这再次导致奇怪的订购速度差异。我不确定为什么在链接期间未传递-ffast-math 时为-Ofast 而不是-ffast-math 保持加速,但我可以接受它可能归结为传递相关信息的链接时间优化一种情况,但不是另一种情况。但这并不能解释速度差异。

删除 -ffast-math 意味着它的运行速度慢了约 8 倍。

有没有人能解释一下导致这种效果的原因?我真的很想知道是什么导致了这种有趣的行为,所以我不能不小心触发它。

运行速度测试是在 python 中使用库和 timeit 的包装器执行的,我相当确定这是在做正确的事情(我可以​​旋转订单和显示 python 副作用的东西可以忽略不计)。

我还测试了库的输出正确性,因此我对此也有相当的信心。

【问题讨论】:

  • 您能发一个minimal reproducible example 或向我们展示您图书馆的代码吗?如果没有机会查看包含它的代码,就很难找到奇怪行为的根源。
  • 您使用哪个版本的 GCC 观察到这一点?
  • 请注意,尽管-Ofast 确实启用了-O3 和-ffast-math 涵盖的所有优化,但文档并没有排除它还启用其他未涵盖的优化的可能性——甚至可能是其他任何方式都无法获得的。如果您的问题是“为什么 -Ofast 的行为与 -O3 -ffast-math 的行为不同”,这可能与它有关。
  • GNU 编译器集合不包含链接器,但使用系统链接器(通常是 GNU ld 来自binutils 的一个
  • 看看生成的汇编代码。由于 LTO 如何内联函数、如何组织内存(例如缓存对齐)、寄存器分配等,这很有可能。完整的分析是 imo OT 这里,因为它可能需要代码审查。

标签: c gcc optimization linker fast-math


【解决方案1】:

评论太长,因此作为答案发布:

由于在数学运算中得到错误结果的风险,我建议不要使用它。

使用-ffast_math 和/或-Ofast 可能会导致不正确的结果,如gcc 手册的以下摘录所示:

option:-ffast-math 设置选项:

  1. -fno-math-errno,
  2. -funsafe-数学优化,
  3. -仅有限数学,
  4. -fno-rounding-math,
  5. -fno-signaling-nans 和
  6. -fcx-有限范围。

此选项导致定义预处理器宏__FAST_MATH__。

除-Ofast 之外的任何 -O 选项都不会打开此选项,因为它可能导致依赖于数学函数的 IEEE 或 ISO 规则/规范的精确实现的程序的输出不正确。但是,对于不需要这些规范保证的程序,它可能会产生更快的代码。 "

选项:-Ofast

无视严格的标准合规性。 -Ofast 启用所有 -O3 优化。它还支持并非对所有符合标准的程序都有效的优化。它打开-ffast-math 和特定于Fortran 的-fno-protect-parens 和-fstack-arrays。

【讨论】:

  • 好吧,如果理解它们,所有问题都可以合理地接受 - 许多算法可以安全地忽略 IEEE 浮点的许多极端情况,但这仍然需要-funsafe-math-optimizations。
  • “不安全”表示不严格遵守标准。
猜你喜欢
  • 1970-01-01
  • 2018-02-20
  • 2021-11-26
  • 1970-01-01
  • 2011-11-17
  • 1970-01-01
  • 1970-01-01
  • 2019-09-22
  • 1970-01-01
相关资源
最近更新 更多