g ++中的优化级别-O3是否危险?
我已经从各种来源(尽pipe大部分来自我的一位同事)得知,在g++
中编译-O3
的优化级别是某种“危险的”,除非certificate是必要的,否则应该避免。
这是真的吗?如果是这样,为什么? 我应该坚持-O2
吗?
在海湾合作委员会(2.8等)的早期和在egcs的时代,红帽2.96 -O3有时是相当错误的。 但是,这已经是十多年前了,-O3与其他优化级别没有多大区别。
然而,它倾向于揭示人们依赖未定义行为的情况,因为更严格地依赖规则,尤其是angular落案例中的语言。
作为一个个人笔记,我使用-O3在财务部门运行多年的生产软件,并且还没有遇到如果我使用-O2就不会出现的错误。
按照大众的需求,这里增加了一个:
-O3,尤其是像-funroll-loops这样的附加标志(不能由-O3启用)有时会导致生成更多的机器码。 在某些情况下(例如,在L1指令caching非常小的CPU上),由于某些内部循环的所有代码现在不再适合L1I,可能会导致速度下降。 通常,gcc很难不产生这么多的代码,但是由于它通常会优化generics情况,所以这可能会发生。 特别容易出现的选项(如循环展开)通常不包含在-O3中,并在联机帮助页中相应标记。 因此,使用-O3生成快速代码通常是一个好主意,并且在适当时(例如,当分析器指示L1I未命中时),只回退到-O2或-Os(其试图优化代码大小)。
如果你想把优化带入极限,你可以通过调整与某些优化相关的成本来调整gcc。 另外需要注意的是,gcc现在可以将属性放在控制优化设置的函数中,因此当你在一个函数中发现-O3有问题时(或者想为这个函数试试特殊的标志)时,你不需要使用O2编译整个文件甚至整个项目。
oth似乎必须小心使用-Ofast,其中规定:
-Ofast启用所有-O3优化。 它也支持对所有符合标准的程序无效的优化。
这使我得出结论-O3意在完全符合标准。
Neel的回答已经说过了,但是不够清楚或者不够强烈:
在我有点格格化的经验中,在整个程序中应用-O3
几乎总是会使其变慢(相对于-O2
),因为它开启了积极的循环展开和内联,使程序不再适合指令caching。 对于更大的程序来说,对于-O2
相对于-Os
也是如此。
-O3
的预期使用模式是,在分析程序之后,手动将其应用于一小撮包含关键内部循环的文件,这些文件实际上受益于这些激进的空间 – 速度折衷。 对于最近的GCC,我认为shiny的新链接时间configuration文件引导优化模式可以select性地将-O3
优化应用于热门function – 有效地自动执行此过程。
-O3选项可以启用更昂贵的优化,比如函数内联,除了所有对“-O2”和“-O1”的优化。 “-O3”优化级别可能会增加生成的可执行文件的速度,但也会增加其大小。 在某些情况下,这些优化是不利的,这个选项实际上可能会使程序变慢。
前段时间,我和优化碰撞了。 有一个PCI卡,它表示它的存储单元寄存器(命令和数据)。 我的驱动程序只是将该内存的物理地址映射到应用程序级别的指针,并将其提供给被调用的进程,如下所示:
unsigned int * pciMemory; askDriverForMapping( & pciMemory ); ... pciMemory[ 0 ] = someCommandIdx; pciMemory[ 0 ] = someCommandLength; for ( int i = 0; i < sizeof( someCommand ); i++ ) pciMemory[ 0 ] = someCommand[ i ];
我很惊讶,为什么卡没有按预期行事。 只有当我看到汇编程序,我明白,编译器只写了一些someCommand[ the last ]
到pciMemory
,省略了所有前面的写道。
总之:准确和周到的优化)))
是的,O3是buggier。 我是一名编译器开发人员,在构build我自己的软件时,我发现了由O3生成有问题的SIMD汇编指令所导致的清晰明显的gcc错误。 从我看到的情况来看,大多数生产软件都附带O2,这意味着O3在testing和错误修复方面将会受到较less的关注。
可以这样想:O3在O2的基础上增加了更多的变换,在O1上增加了更多的变换。 统计上讲,更多的转换意味着更多的错误。 对于任何编译器都是如此。