Ouvi de várias fontes (embora principalmente de um colega meu) que a compilação com um nível de otimização -O3
em g ++ é de alguma forma 'perigosa' e deve ser evitada em geral, a menos que seja necessário.
Isso é verdade? Se sim, por quê? Devo apenas estar aderindo -O2
?
c++
optimization
g++
compiler-flags
Dunnie
fonte
fonte
-O3
é considerado particularmente buggy? Eu acho que talvez possa piorar o comportamento indefinido, pois pode fazer coisas estranhas e maravilhosas com base em certas suposições, mas isso seria culpa sua. Então, geralmente, eu diria que está tudo bem.-O2
é ativado-fstrict-aliasing
e, se o seu código sobreviver a isso, provavelmente sobreviverá a outras otimizações, pois é uma que as pessoas erram repetidamente. Dito isto,-fpredictive-commoning
é apenas dentro-O3
e habilitar isso pode habilitar erros no seu código causados por suposições incorretas sobre simultaneidade. A menos errado seu código seja, a otimização menos perigoso é ;-)-Ofast
, ele desliga manuseio IEEE-compliant de Nans por exemploRespostas:
Nos primeiros dias do gcc (2.8 etc.) e nos tempos do egcs, e redhat 2.96 -O3 às vezes era bastante complicado. Mas isso foi há mais de uma década, e -O3 não é muito diferente de outros níveis de otimizações (em buggy).
No entanto, tende a revelar casos em que as pessoas confiam em comportamento indefinido, devido a confiar mais estritamente nas regras, e especialmente nos casos de canto, do (s) idioma (s).
Como observação pessoal, estou executando o software de produção no setor financeiro há muitos anos com o -O3 e ainda não encontrei um bug que não existiria se eu tivesse usado o -O2.
Pela demanda popular, aqui está uma adição:
-O3 e sinalizadores especialmente adicionais como -funroll-loops (não ativados por -O3) às vezes podem levar à geração de mais código de máquina. Sob certas circunstâncias (por exemplo, em uma CPU com cache de instrução L1 excepcionalmente pequeno), isso pode causar uma desaceleração devido a todo o código de, por exemplo, algum loop interno que agora não se encaixa mais no L1I. Geralmente, o gcc tenta bastante não gerar tanto código, mas como geralmente otimiza o caso genérico, isso pode acontecer. Opções especialmente propensas a isso (como desenrolar o loop) normalmente não são incluídas em -O3 e são marcadas de acordo na página de manual. Como tal, geralmente é uma boa ideia usar -O3 para gerar código rápido, e somente voltar a -O2 ou -Os (que tenta otimizar o tamanho do código) quando apropriado (por exemplo, quando um criador de perfil indica que L1I está ausente).
Se você quiser levar a otimização ao extremo, poderá ajustar o gcc via --param os custos associados a determinadas otimizações. Além disso, observe que o gcc agora tem a capacidade de colocar atributos em funções que controlam as configurações de otimização apenas para essas funções. Portanto, quando você encontrar um problema com -O3 em uma função (ou quiser experimentar sinalizadores especiais para essa função), você não precisa compilar o arquivo inteiro ou mesmo o projeto inteiro com o O2.
parece que é preciso ter cuidado ao usar -Ofast, que afirma:
o que me leva a concluir que o -O3 deve ser totalmente compatível com os padrões.
fonte
std::sort
funções provavelmente não ajudará. Usar algo como stackoverflow.com/questions/109710/… ajudaria, ou talvez escreva a fonte para tirar proveito da classificação: varra até ver> = 128 e comece a somar. Quanto ao código inchado, sim, pretendo denunciá-lo. : PNa minha experiência um tanto quadriculada, aplicar
-O3
a um programa inteiro quase sempre o torna mais lento (em relação a-O2
), porque ativa o desenrolar e o alinhamento agressivos de loop que tornam o programa não mais adequado ao cache de instruções. Para programas maiores, isso também pode ser verdade em-O2
relação a-Os
!O padrão de uso pretendido
-O3
é que, após criar um perfil do seu programa, você o aplica manualmente a um pequeno punhado de arquivos contendo loops internos críticos que realmente se beneficiam dessas trocas agressivas de espaço por velocidade. As versões mais recentes do GCC têm um modo de otimização guiado por perfil que pode (IIUC) aplicar seletivamente as-O3
otimizações a funções importantes - automatizando efetivamente esse processo.fonte
A opção -O3 ativa otimizações mais caras, como embutimento de funções, além de todas as otimizações dos níveis mais baixos '-O2' e '-O1'. O nível de otimização '-O3' pode aumentar a velocidade do executável resultante, mas também pode aumentar seu tamanho. Sob algumas circunstâncias em que essas otimizações não são favoráveis, essa opção pode tornar o programa mais lento.
fonte
Sim, o O3 é mais problemático. Sou desenvolvedor de compiladores e identifiquei erros claros e óbvios do gcc causados pelo O3, gerando instruções de montagem do SIMD com erros ao criar meu próprio software. Pelo que vi, a maioria dos softwares de produção vem com O2, o que significa que o O3 receberá menos atenção em testes e correções de erros.
Pense da seguinte maneira: o O3 adiciona mais transformações sobre o O2, o que adiciona mais transformações sobre o O1. Estatisticamente falando, mais transformações significam mais erros. Isso é verdade para qualquer compilador.
fonte
Recentemente, tive um problema ao usar a otimização com
g++
. O problema estava relacionado a uma placa PCI, onde os registradores (para comando e dados) eram representados por um endereço de memória. Meu driver mapeou o endereço físico para um ponteiro dentro do aplicativo e o entregou ao processo chamado, que funcionou assim:O cartão não funcionou como esperado. Quando eu vi a montagem entendi que o compilador só escreveu
someCommand[ the last ]
empciMemory
, omitindo todas as gravações anteriores.Em conclusão: seja preciso e atento à otimização.
fonte
pciMemory
comovolatile
.pciMemory
porque todas as outras gravações provavelmente não têm efeito. Para o otimizador, isso é incrível porque pode remover muitas instruções inúteis e demoradas.