【问题标题】:g++ Optimization Flags: -fuse-linker-plugin vs -fwhole-programg++ 优化标志:-fuse-linker-plugin vs -fwhole-program
【发布时间】:2013-03-14 11:21:12
【问题描述】:

我正在阅读:
http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html

它首先表明:
不应使用此选项 (-fwhole-program) 与 -flto 结合使用。相反,依赖链接器插件应该提供更安全、更精确的信息。

然后,它建议:
如果程序不需要导出任何符号,则可以结合 -flto-fwhole-program 以允许过程间优化器使用更积极的假设,从而提高优化机会。当链接器插件处于活动状态时,不需要使用-fwhole-program(参见-fuse-linker-plugin)。

这是否意味着理论上,使用-fuse-linker-plugin-flto 总是比使用-fwhole-program-flto 获得更好的优化可执行文件?

我尝试使用ld分别链接-fuse-linker-plugin-fwhole-program,至少可执行文件的大小不同。

附:我在 CentOS 6 上使用 gcc 4.6.2 和 ld 2.21.53.0.1。

【问题讨论】:

  • fwiw,按照您的报价 - “链接器插件处于活动状态时不需要使用 -fwhole-program(请参阅 -fuse-linker-plugin)。” - 我们稍后会在文档中看到 - “当 GCC 中的 LTO 支持启用并且 GCC 配置为与支持插件的链接器一起使用(GNU ld 2.21 或更新版本或黄金)时,默认启用此选项 [-fuse-linker-plugin] ." - 所以我猜这涵盖了最合理的现代 gcc 安装。这意味着他们有一个默认选项,使-fwhole-program 变得不必要。但这只是我对这一切的解释!
  • @underscore_d 太好了!现在,我们如何关闭该死的东西?! (我的意思是 fuse-linker-plugin。)请参阅:stackoverflow.com/questions/68582122/…

标签: c++ linux g++ x86-64 ld


【解决方案1】:

更新:请参阅下面的@PeterCordes 评论。从本质上讲,不再需要 -fuse-linker-plugin

这些差异是微妙的。首先,了解 -flto 的实际作用。它本质上创建了一个可以稍后优化的输出(在“链接时”)。

-fwhole-program 所做的是假设“当前编译单元代表正在编译的整个程序”,无论实际情况是否如此。因此,GCC 将假定它知道调用特定函数的所有位置。正如它所说,它可能会使用更积极的过程间优化器。我会稍微解释一下。

最后,-fuse-linker-plugin 所做的实际上是在链接时执行优化,这通常会在执行每个编译单元时完成。所以,这个设计是为了与 -flto 配对,因为 -flto 意味着保存足够的信息以便以后进行优化,而 -fuse-linker-plugin意味着实际进行这些优化。

那么,它们有什么不同呢?好吧,正如 GCC 文档所建议的那样,使用 -fwhole-program 原则上没有任何优势,因为该选项假定您必须确保某些东西是真实的。要打破它,只需在一个 .cpp 文件中定义一个函数并在另一个文件中使用它。您将收到链接器错误。

-fwhole-program有什么优势吗?好吧,如果您只有一个编译单元,那么您可以使用它,但老实说,它不会更好。通过使用等效程序,我能够获得不同大小的可执行文件,但是在检查实际生成的机器代码时,它们是相同的。事实上,我看到的唯一区别是带有调试信息的行号不同。

【讨论】:

  • IIRC,与gcc -O3 -march=native ... -flto 链接这些天刚刚工作,并做了所有必要的链接器插件的东西。 (将与编译时相同的优化选项传递给链接命令。)
  • @PeterCordes 你知道gcc -O2 -march=native ... -flto 是否也这样做吗?很多时候,特别是对于热路径上的机器代码大于跟踪缓存的程序,O2 优于 O3O3 最适合用于选择函数。还有,感谢您的更新!
  • -O2 当然也“正常工作”。但只有-O3 启用自动矢量化。如果任何重要的循环都可以从自动矢量化中受益,那么它通常是值得的代码大小成本。现代 x86 CPU 不使用跟踪缓存,只有 Pentium 4。Sandybridge / Ryzen 中的 uop 缓存不是 trace 缓存。它不跟随跳跃。此外,传统解码带宽比 P4 中的要好得多,因此 uop 缓存未命中并不是灾难。但是,如果 L1i 未命中是一个问题,O2 对于一些大型程序总体上可能会更好。
  • 请注意,现代 GCC -O3 确实 启用 -funroll-loops;仅当您使用 -fprofile-generate /` -fprofile-use 执行 PGO 时,才会为热循环执行此操作。此外,GCC 8 及更高版本通常使用未对齐的加载/存储而不是完全展开的序言/尾声自动矢量化以达到对齐边界。那总是很糟糕而且超级臃肿,将大部分代码大小用于启动/清理上的自动矢量化循环,根本没有展开实际的重要部分!顺便说一句,clang -O2 自动矢量化,并默认展开小循环。
猜你喜欢
  • 2014-01-06
  • 1970-01-01
  • 2010-10-22
  • 1970-01-01
  • 2015-06-20
  • 1970-01-01
  • 2019-04-10
  • 1970-01-01
  • 2012-05-15
相关资源
最近更新 更多