Nós já fizemos um vídeo sobre flags que servem tanto para o GCC quanto para o Clang, no entanto, aquelas dicas tem instruções gerais para compilação.
Nesse artigo vamos especificar mais o objetivo em “tempo de compilação” que influenciam diretamente do desempenho do binário tornando a velocidade em “tempo de execução”, melhor!
A flag -fsanitize=address
e todas as outras do sanitize(libasan
), do Google, que foi implementada nativamente pelo Projeto GNU serve para verificar memory leaks, violação de memória e entre outras falhas relacionadas.
Mas, ela deve ser usada somente durante o desenvolvimento, quando você for disponibilizar para produção, ou seja, a versão release o ideal é criar o Makefile, ou CMake ou qualquer outra ferramenta de compilação sem essa flag, aliás, é bom remover qualquer outra flag de debug, inclusive: -g
, -Wall
, -Werror
, -pedantic
, -Wpedantic
,…
Pois, elas, principalmente a -fsanitize=address
deixam a execução do binário muito lenta. Você pode substituir pelo otimizador, por exemplo, -O1
, -O2
ou -O3
:
-O1
(Otimização básica) - Ativa otimizações que melhoram a performance sem aumentar significativamente o tempo de compilação. Exemplos: eliminação de código morto, propagação de constantes, inlining limitado.
-O2
(Otimização moderada) - Inclui todas as otimizações de -O1
e adiciona mais agressivas que ainda mantêm a confiabilidade do código. Exemplos: desdobramento de loops (loop unrolling), eliminação de subexpressões comuns, melhor agendamento de instruções.
-O3
(Otimização agressiva)
- Inclui todas as otimizações de -O2
e adiciona novas ainda mais agressivas, como maior inlining e vetorização de loops. Pode aumentar o tamanho do código e, em alguns casos, reduzir a performance por over-otimização.
E ainda, existe também a -Ofast
, apesar dela ser a mais agressiva de todas e quase equivalente a -O3
, ela pode otimizar completamente o código o deixando ainda mais veloz, pois ela ainda inclui a flag -ffast-math
, isso pode ser bom, mas o ideal é fazer testes, pois alguns cálculos de precisão, principalmente para os tipos double
e float
podem ter resultado inesperados, pois ela pode diminuir a quantidade de dígitos significativos, além de poder quebrar com os padrões C e C++.
No entanto, na maioria dos casos, ela é indicada para o release, exemplo:
g++ -Ofast main.cpp
Se quiser uma fusão menos conflitante, use junto com
-ffp-contract=fast
: Permite fusão de operações de ponto flutuante, como FMA (Fused Multiply-Add).
Resumindo:
-Ofast
se precisão numérica exata não for crítica e quiser extrair o máximo de desempenho.A flag -march=native
permite que o compilador gere código otimizado para a arquitetura da sua CPU:
g++ -Ofast -march=native main.cpp
Usar em combinação com
-Ofast
pode ser uma ótima ideia para o desempenho.
Isso permite que o compilador use instruções avançadas do seu processador, como SSE, AVX, etc.
Se precisar distribuir o binário para outras máquinas, escolha um valor específico em vez de native, como -march=haswell
, -march=znver3
, etc.
Resumindo:
-march=native
, use, caso queira, para permitir que o compilador gere código otimizado para a arquitetura da sua CPU.Se o código for paralelizável, adicione suporte ao OpenMP para aproveitar múltiplos núcleos da CPU:
g++ -Ofast -march=native -fopenmp main.cpp
Também com combinação com as flags citadas acima.
Isso permite que loops e outras partes do código rodem em paralelo.
O OpenMP (do inglês Open Multi-Processing, ou Multi-processamento aberto) é uma interface de programação de aplicativo(API) para a programação multi-processo de memória compartilhada em múltiplas plataformas. Permite acrescentar simultaneidade aos programas escritos em C, C++ e Fortran sobre a base do modelo de execução fork-join.
As flags -funroll-loops
e -fprefetch-loop-arrays
ajudam a melhorar a execução de loops:
g++ -Ofast -march=native -funroll-loops -fprefetch-loop-arrays main.cpp
Também com combinação com as flags citadas acima.
Se usássemos elas no vídeo sobre Ranking das Linguagens de Programação, C++ e C deixaria as que ficaram atrás delas, ainda mais distantes! 😃
Lembrando, que um utilitário ainda melhor que essas flags é o ccache
que publicamos no artigo: Utilize o Ccache e compile muito mais rápido, no entanto, o foco dele é diminuir o “tempo de compilação” e não somente o desempenho do binário.
A flag -flto
(Link-Time Optimization) serve para permitir que o otimizador veja o código como um todo:
g++ -Ofast -march=native -flto main.cpp
É bom usá-la em conjunto com as duas primeiras flas citadas.
Use a flag -fno-rtti
se o código não usa exceções nem RTTI(Runtime Type Information), desative-os para ganhar desempenho:
g++ -Ofast -march=native -fno-exceptions -fno-rtti main.cpp
RTTI(Run-time Type Information) é uma técnica que armazena informações sobre o tipo de dado de um objeto durante a execução de um programa. RTTI está disponível em algumas linguagens de programação, como Delphi e C++.
Se puder rodar o programa antes da compilação final(E FAÇA ISSO!!!), use PGO com a flag -fprofile-generate
para otimizar baseado em dados reais de execução:
Não confunda ele com o tal: verificador de empréstimos!
Compile com instrumentação:
g++ -Ofast -march=native -fprofile-generate main.cpp
É bom usá-la em conjunto com as duas primeiras flas citadas.
Execute o programa normalmente para gerar dados de perfil e depois recompile usando os perfis gerados:
g++ -Ofast -march=native -fprofile-use main.cpp
A otimização guiada por perfil(PGO), também conhecida como feedback direcionado por perfil(PDF) ou otimização direcionada por feedback(FDO), é a técnica de otimização do compilador que usa análises anteriores de artefatos ou comportamentos de software(“ criação de perfil “) para melhorar o desempenho esperado do tempo de execução do programa.
Além de -march=native
, você pode usar -mtune
para ajustar a geração de código para melhor desempenho sem perder compatibilidade:
g++ -Ofast -march=native -mtune=native main.cpp
É bom usá-la em conjunto com as duas primeiras flas citadas.
Se precisar rodar em várias arquiteturas, use algo mais genérico, como -mtune=generic
.
Se quiser usar todas as flags que citamos em conjunto, fique à vontade:
g++ -Ofast -march=native -flto -funroll-loops -fprefetch-loop-arrays \
-fno-exceptions -fno-rtti -fopenmp main.cpp
Para mais informações consulte os links abaixo:
linguagemc cpp cppdaily gcc clang