在G ++中,优化级别-O3危险吗?


232

我从各种来源(尽管大部分是我的同事发来的)都听说过,-O3用g ++ 的优化级别进行编译在某种程度上是“危险的”,除非被证明是必要的,否则通常应该避免编译。

这是真的吗?如果是这样,为什么?我应该坚持-O2吗?


38
仅当您依赖不确定的行为时,这才是危险的。即使到那时,如果是优化级别搞砸了我,我也会感到惊讶。
塞斯·卡内基

5
编译器仍然受约束以生成行为“好像”完全编译了您的代码的程序。我不知道那-O3是越野车吗?我认为这可能会使未定义的行为“更糟”,因为它可能会基于某些假设做出奇怪而美妙的事情,但这将是您自己的错。所以总的来说,我会说很好。
BoBTFish 2012年

5
确实,更高的优化级别更容易产生编译器错误。我本人也打过一些案件,但总的来说还是很少见。
Mysticial

21
-O2打开-fstrict-aliasing,并且如果您的代码得以保留,那么它可能也将保留其他优化,因为这是人们一遍又一遍的错误。也就是说,-fpredictive-commoning仅存在于中-O3,并且启用该功能可能会导致由于对并发性的错误假设导致的代码错误。您的代码错误越少,优化的危险就越小;-)
史蒂夫·杰索普

6
@PlasmaHH,我认为“ stricter”不是一个很好的描述,例如-Ofast,它关闭了IEEE兼容的NaN处理
Jonathan Wakely 2012年

Answers:


223

在gcc的早期(2.8等)和egcs时代,redhat 2.96 -O3有时是相当多的错误。但这是十年前的事了,-O3与其他级别的优化(在儿童车方面)没有太大不同。

但是,它确实倾向于揭示人们依赖未定义行为的情况,这是由于更严格地依赖一种或多种语言的规则,尤其是极端情况。

作为个人说明,我使用-O3在金融领域运行生产软件已有很多年了,并且还没有遇到过如果我使用-O2就不会出现的错误。

根据大众需求,这里有一个补充:

-O3尤其是诸如-funroll-loops之类的其他标志(未由-O3启用)有时会导致生成更多机器代码。在某些情况下(例如,在具有极小L1指令高速缓存的CPU上),这可能会导致速度变慢,这是因为某些内部循环的所有代码现在不再适合L1I。通常,gcc会尽力避免不生成太多代码,但是由于它通常会优化通用情况,因此可能会发生这种情况。-O3中通常不包括特别容易出现的选项(例如循环展开),并在手册页中进行了相应标记。因此,通常最好使用-O3来生成快速代码,并且仅在适当的时候(例如,当探查器指示L1I未命中时)回退到-O2或-Os(尝试对代码大小进行优化)。

如果您想将优化发挥到极致,则可以通过--param调整gcc与某些优化相关的成本。另外请注意,gcc现在可以将属性放在控制仅针对这些功能的优化设置的功能上,因此,当您发现一个功能中存在-O3问题时(或想尝试该功能的特殊标志),您无需使用O2编译整个文件甚至整个项目。

在使用-Ofast时,似乎必须小心,它指出:

-Ofast启用所有-O3优化。它还启用了并非对所有符合标准的程序都有效的优化。

这使我得出结论,-O3旨在完全符合标准。


2
我只使用相反的东西。我总是使用-Os或-O2(有时O2会生成一个较小的可执行文件)..分析后,我在代码上使用O3的部分代码会花费更多的执行时间,仅此一项就可以提高20%的速度。
CoffeDeveloper 2015年

3
我这样做是为了提高速度。O3通常会使事情变慢。不知道为什么,我怀疑它会污染指令缓存。
CoffeDeveloper 2015年

4
@DarioOO我觉得恳求“代码膨胀”是一件很受欢迎的事情,但是我几乎从来没有看到它有基准支持。这在很大程度上取决于体系结构,但是每次我看到已发布的基准测试(例如phoronix.com/…)时,都表明O3在大多数情况下都更快。我已经看到需要进行分析和仔细的分析,以证明代码膨胀实际上是一个问题,并且通常只在极端使用模板的人身上发生。
弗里德曼

1
@NirFriedman:当编译器的内联成本模型存在错误,或者针对与运行时完全不同的目标进行优化时,往往会遇到问题。有趣的是,这适用于所有优化级别...
PlasmaHH 2015年

1
@PlasmaHH:在一般情况下,using-cmov问题很难解决。通常,您并不仅仅是对数据进行排序,所以当gcc试图确定分支是否可预测时,寻找std::sort函数调用的静态分析不太可能会有所帮助。使用诸如stackoverflow.com/questions/109710/…之类的方法将有所帮助,或者编写源代码以利用排序的优势:扫描直到看到> = 128,然后开始求和。至于code肿的代码,是的,我打算进行报告。:P
彼得·科德斯

42

根据我的经验,应用-O3到整个程序几乎总是会使它变慢(相对于-O2),因为应用程序会打开积极的循环展开和内联程序,从而使程序不再适合指令高速缓存。对于较大的程序,-O2相对于-Os!也是如此。

预期的使用模式-O3是,在对程序进行性能分析后,将其手动应用于少量文件,这些文件包含一些关键的内部循环,而这些循环实际上可以从这些积极的速度比空间取舍中受益。较新版本的GCC具有配置文件引导的优化模式,该模式可以(IIUC)有选择地将-O3优化应用于热功能-有效地使此过程自动化。


10
“几乎总是”?将其设置为“ 50-50”,我们会达成交易;-)。
No-Bugs野兔

12

除较低级别“ -O2”和“ -O1”的所有优化外,-O3选项还会启用更昂贵的优化,例如函数内联。'-O3'优化级别可以提高生成的可执行文件的速度,但也可以增加其大小。在某些情况下,这些优化不令人满意,此选项实际上会使程序变慢。


3
我了解某些“明显的优化”可能会使程序变慢,但是您是否有消息称GCC -O3使程序变慢了?
Mooing Duck 2012年

1
@MooingDuck:虽然我无法引用消息来源,但我记得遇到了一些旧的AMD处理器,这种情况具有相当小的L1I缓存(约1万条指令)。我确信google有更多兴趣感兴趣的对象,但是特别是诸如循环展开之类的选项不是O3的一部分,并且这些选项会增加很多大小。-Os是您想将可执行文件最小化的一种方法。甚至-O2也会增加代码大小。gcc资源管理器是一个很好的工具,可以处理不同优化级别的结果。
PlasmaHH 2012年

@PlasmaHH:实际上,很小的缓存大小是编译器可能搞砸的,这很不错。这是一个很好的例子。请把它放在答案中。
Mooing Duck 2012年

1
@PlasmaHH Pentium III具有16KB代码缓存。AMD的K6及更高版本实际上具有32KB指令缓存。P4的起始容量约为96KB。Core I7实际上具有32KB L1代码缓存。如今,指令解码器非常强大,因此您的L3足以在几乎任何循环中恢复运行。
doug65536

1
每当在循环中调用一个函数时,您都会看到巨大的性能提升,并且它可以执行显着的公共子表达式消除,并将不必要的重新计算从函数中提升到循环之前。
doug65536

8

是的,O3令人讨厌。我是一名编译器开发人员,而且我已经确定由O3引起的清晰明显的gcc错误,这些错误是由O3在构建自己的软件时生成错误的SIMD汇编指令引起的。据我所知,大多数生产软件都附带O2,这意味着O3在测试和错误修复方面的关注度会降低。

这样想:O3在O2之上添加了更多的转换,在O1之上添加了更多的转换。从统计上讲,更多的转换意味着更多的错误。对于任何编译器都是如此。


3

最近,我在使用优化时遇到了一个问题g++。问题与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,而忽略了之前的所有写入。

结论:准确,专心于优化。


38
但是这里的要点是,您的程序只是具有未定义的行为。优化器没有做错任何事情。特别是您需要声明pciMemoryvolatile
康拉德·鲁道夫

11
它实际上不是UB,但是编译器有权删除所有文件,但最后一次写入将被省略,pciMemory因为其他所有写入均无作用。对于优化器而言,它很棒,因为它可以删除许多无用且耗时的指令。
康拉德·鲁道夫2013年

4
我在标准中(超过10年后才发现)))- 易失性声明可用于描述与内存映射的输入/输出端口相对应的对象或由异步中断功能访问的对象。如此声明的对象上的操作不得通过实现“优化”或重新排序,除非评估表达式的规则允许。
鲍里斯堡

2
@borisbn有点偏离主题,但是您如何知道设备在发送新命令之前已经接受了该命令?
user877329 2014年

3
@ user877329我是通过设备的行为看到它的,但这是一个很棒的追求
borisbn 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.