GCC中不同的优化级别有什么区别?假设我不在乎有任何调试钩子,我为什么不只使用我可用的最高级别的优化呢?更高级别的优化是否必然(即可证明)生成更快的程序?
4 回答
是的,更高的级别有时可能意味着性能更好的程序。但是,根据您的代码,它可能会导致问题。例如,分支预测(在 -O1 和更高版本中启用)可以通过导致竞争条件来破坏编写不佳的多线程程序。优化实际上会决定比你写的更好的东西,这在某些情况下可能不起作用。
有时,更高的优化(-O3)并没有增加合理的好处,而是增加了很多额外的大小。您自己的测试可以确定这种大小权衡是否为您的系统带来了合理的性能增益。
最后一点,GNU 项目默认在 -O2编译他们的所有程序,而 -O2 在其他地方相当常见。
通常优化级别高于-O2
(仅-O3
针对 gcc,但其他编译器具有更高级别)包括可以增加代码大小的优化。这包括循环展开、大量内联、对齐填充(无论大小)等。其他编译器提供高于 的向量化和过程间优化-O3
,以及某些可以以正确性为代价大大提高速度的优化(例如,使用更快、不太准确的数学例程)。在使用这些东西之前检查文档。
至于性能,这是一个权衡。通常,编译器设计者会尝试调整这些东西,以免它们降低代码的性能,因此-O3
通常会有所帮助(至少在我的经验中),但您的里程可能会有所不同。真正激进的大小改变优化并不总是会提高性能(例如,真正激进的内联会导致缓存污染)。
我找到了一个网页,其中包含有关不同优化级别的一些信息。记得在某处听到的一件事是优化实际上可能会破坏您的程序,这可能是一个问题。但我不确定这个问题有多大。也许今天的编译器足够聪明来处理这些问题。
边注:
很难准确预测-O
gcc 命令行上针对不同版本和平台的全局指令打开了哪些标志,并且 GCC 站点上的所有文档可能很快就会过时,或者没有足够详细地涵盖编译器内部.
当您使用其中一个-O
标志和其他-f
标志和/或它们的组合时,这是一种简单的方法来准确检查特定设置中发生的情况:
- 在某处创建一个空的源文件:
touch dummy.c
- 尽管编译器通过了,但运行它,就像你通常会使用的那样,使用你通常使用的 all
-O
和-f
/或-m
标志,但添加-Q -v
到命令行:gcc -c -Q -v dummy.c
- 检查生成的输出,也许将其保存以供不同的运行。
- 根据自己的喜好更改命令行,删除生成的目标文件
rm -f dummy.o
并重新运行。
另外,请始终牢记,从纯粹主义者的角度来看,大多数非平凡优化会生成“损坏”代码(其中损坏定义为在极端情况下偏离最佳路径),因此选择是否启用某个一组优化机制有时归结为选择编译器输出的正确性级别。在任何编译器的优化器中总是存在(并且目前存在)错误 - 只需检查 GCC 邮件列表和 Bugzilla 以获取一些示例。编译器优化只能在实际执行测量后使用,因为
- 使用更好的算法所获得的收益将使编译器优化的任何收益相形见绌,
- 优化将在蓝月亮中运行一次的代码是没有意义的,
- 如果优化器引入了错误,那么您的代码运行速度有多快并不重要。