Perfilamento de C++ no Linux: guia para quem quer acelerar o código

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Seu código C++ está lento? Hora de olhar sob o capô

\n\n

Você escreveu um código C++ que parece perfeito à primeira vista. A compilação ocorreu sem erros, o programa inicia... mas funciona de forma lenta. Familiar? A mão já quer reescrever tudo em assembly ou adicionar multithreading com urgência. Não se apresse. Provavelmente, o problema não está na arquitetura, mas em algumas funções "quentes" que consomem 90% do tempo da CPU.

\n\n

No mundo Linux, temos um arsenal poderoso de ferramentas para perfilamento de código C++. Isso não é mágica, é ciência. Não adivinhamos, medimos. Neste guia, mostrarei quatro abordagens práticas: desde uma rápida "visão geral" até micro-benchmarking. Você aprenderá como perfilar C++ no Linux como um verdadeiro profissional.

\n\n

Por que palpites são ruins e o perfilamento é bom

\n\n

Antes de mergulhar no código, lembre-se da regra de ouro da otimização: "Não otimize o que não foi medido". Sua intuição é um mau conselheiro. Frequentemente, passamos horas otimizando uma função que é chamada uma vez por minuto e ignoramos um loop banal de 10 milhões de iterações.

\n\n

O perfilamento responde a três perguntas principais:

\n
    \n
  • Onde o programa gasta mais tempo?
  • \n
  • Por que isso acontece (algoritmo ineficiente, muitas operações de E/S, falhas de cache)?
  • \n
  • O que mudou após suas correções?
  • \n
\n\n

Hoje, vamos analisar quatro ferramentas que cobrirão 99% das suas necessidades. Vamos lá!

\n\n

Ferramenta nº1: gprof — o clássico do gênero

\n\n

gprof é o bom e velho profiler GNU integrado. Ele funciona em duas etapas: coleta de estatísticas durante a execução do programa e sua análise. Vantagens: não precisa instalar nada extra, está presente em todas as distribuições. Desvantagens: fornece resultados aproximados e não funciona com programas multithread prontos para uso.

\n\n

Como usar o gprof

\n\n

Passo 1. Compile o programa com a flag especial -pg:

\n
g++ -pg -O2 my_program.cpp -o my_program
\n\n

Observe: usamos -O2. Perfilar uma compilação de depuração sem otimizações é inútil; você obterá uma imagem distorcida.

\n\n

Passo 2. Execute o programa. Ele será um pouco mais lento, pois o gprof coleta dados.

\n
./my_program
\n\n

Passo 3. Na pasta atual, aparecerá o arquivo gmon.out. Analise-o:

\n
gprof my_program gmon.out > analysis.txt
\n\n

Abra analysis.txt e veja algo como:

\n
Flat profile:\nEach sample counts as 0.01 seconds.\n  %   cumulative   self              self     total\n time   seconds   seconds    calls  us/call  us/call  name\n 60.00      0.06     0.06    10000     6.00     6.00  slow_function\n 20.00      0.08     0.02     5000     4.00     4.00  fast_function\n 10.00      0.09     0.01                             main
\n\n

Voilà! Vemos que slow_function ocupou 60% do tempo. Este é nosso candidato para otimização.

\n\n

Exemplo de código para perfilamento

\n\n

Vamos escrever um programa simples que será perfilado com todas as ferramentas:

\n\n
#include <iostream>\n#include <cmath>\n\nvoid slow_function(int n) {\n    volatile double sum = 0.0; // volatile para o compilador não otimizar para zero\n    for (int i = 0; i < n; ++i) {\n        for (int j = 0; j < 1000; ++j) {\n            sum += std::sin(i) * std::cos(j);\n        }\n    }\n    std::cout << sum << std::endl;\n}\n\nvoid fast_function(int n) {\n    volatile int count = 0;\n    for (int i = 0; i < n; ++i) {\n        count += i % 2;\n    }\n    std::cout << count << std::endl;\n}\n\nint main() {\n    slow_function(10000);\n    fast_function(50000);\n    return 0;\n}
\n\n

Compile com a flag -pg e execute

Blogs

Book Recommendations