Perfilamento de código C++: encontrando gargalos na prática

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

Introdução: por que o perfilamento não é um luxo, mas uma necessidade

\n

Todo desenvolvedor C++ já passou pela situação em que o programa funciona, mas o faz lentamente. Palpites intuitivos sobre qual parte do código está "lenta" muitas vezes se mostram errados. Sem dados precisos, você corre o risco de otimizar o que já funciona rápido, perdendo de vista os verdadeiros "gargalos". O perfilamento é a única maneira científica de medir o desempenho e encontrar gargalos.

\n

Neste artigo, abordaremos três ferramentas poderosas para perfilamento de código C++: gprof (estatístico), Perf (hardware) e Valgrind/Callgrind (simulação). Você aprenderá como aplicá-las na prática, interpretar os resultados e encontrar rapidamente as áreas problemáticas.

\n\n

1. Perfilamento estatístico com gprof: início rápido

\n

gprof é o profilador clássico do GNU, que funciona com base em amostragem estatística. Ele não requer privilégios especiais e é ideal para uma primeira análise.

\n\n

Como preparar o código

\n

Para usar o gprof, você precisa compilar o programa com as flags -pg e -g:

\n
g++ -pg -g main.cpp -o my_program\n./my_program
\n

Após a execução do programa, um arquivo gmon.out será criado na pasta atual. Para obter um relatório legível, execute:

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

Exemplo: encontrando o algoritmo lento

\n

Considere um programa simples que ordena um array de duas maneiras:

\n
#include <iostream>\n#include <vector>\n#include <algorithm>\n#include <chrono>\n\nvoid bubble_sort(std::vector<int>& arr) {\n    for (size_t i = 0; i < arr.size(); ++i)\n        for (size_t j = 0; j < arr.size() - i - 1; ++j)\n            if (arr[j] > arr[j+1])\n                std::swap(arr[j], arr[j+1]);\n}\n\nvoid quick_sort_wrapper(std::vector<int>& arr) {\n    std::sort(arr.begin(), arr.end());\n}\n\nint main() {\n    std::vector<int> data(50000);\n    std::generate(data.begin(), data.end(), std::rand);\n    \n    auto copy1 = data;\n    auto copy2 = data;\n    \n    bubble_sort(copy1);\n    quick_sort_wrapper(copy2);\n    \n    return 0;\n}
\n

Execute o perfilamento. No relatório do gprof, você verá uma tabela de chamadas. A bubble_sort ocupará 95-99% do tempo. Este é um gargalo óbvio — substituir a ordenação bolha por std::sort trará um ganho imediato.

\n\n

Interpretação dos resultados

\n

No relatório, procure a coluna % time — ela mostra a proporção de tempo gasto na função. Funções com alta porcentagem são suas candidatas à otimização.

\n\n

2. Perfilamento de hardware com Perf: precisão de ciclo

\n

Perf é uma ferramenta moderna para Linux que usa contadores de hardware da CPU. Ela tem sobrecarga mínima e permite medir não apenas o tempo, mas também cache misses, branch misses e outras métricas.

\n\n

Instalação e uso básico

\n
sudo apt install linux-tools-common linux-tools-generic  # Ubuntu/Debian\nperf stat ./my_program   # Estatísticas gerais\nperf record ./my_program # Gravação do perfil\nperf report              # Visualização do relatório
\n\n

Exemplo: encontrando cache misses

\n

Suponha que temos uma função que processa uma matriz linha por linha:

\n
const int N = 4096;\nint matrix[N][N];\n\nvoid process_rows() {\n    for (int i = 0; i < N; ++i)\n        for (int j = 0; j < N; ++j)\n            matrix[i][j] *= 2;\n}\n\nvoid process_cols() {\n    for (int j = 0; j < N; ++j)\n        for (int i = 0; i < N; ++i)\n            matrix[i][j] *= 2;\n}
\n

Execute perf stat para cada função. Você verá que process_cols tem uma ordem de grandeza a mais de cache-misses. A razão

Blogs

Book Recommendations