Conheça 8 flags para melhorar drasticamente a velocidade do seu software

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! 01. O básico 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: Use -Ofast se precisão numérica exata não for crítica e quiser extrair o máximo de desempenho. 02. Ajuste específico para a arquitetura do processador 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: A flag -march=native, use, caso queira, para permitir que o compilador gere código otimizado para a arquitetura da sua CPU. 03. Paralelismo com OpenMP 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. 04. Melhorar uso do cache da CPU 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!

Mar 12, 2025 - 17:54
 0
Conheça 8 flags para melhorar drasticamente a velocidade do seu software

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!

01. O básico

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:

Use -Ofast se precisão numérica exata não for crítica e quiser extrair o máximo de desempenho.

02. Ajuste específico para a arquitetura do processador

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:

A flag -march=native, use, caso queira, para permitir que o compilador gere código otimizado para a arquitetura da sua CPU.

03. Paralelismo com OpenMP

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.

04. Melhorar uso do cache da CPU

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!