Introducción: ¿por qué perfilar código C++?
La optimización sin mediciones es una adivinanza. Incluso los desarrolladores experimentados a menudo se equivocan al suponer qué parte del código funciona más lentamente. El perfilado es la única forma científica de responder a la pregunta: «¿Dónde exactamente gasta el programa la mayor parte del tiempo?».
En este artículo, analizaremos herramientas prácticas para perfilar código C++ en Linux: gprof, perf y Valgrind (Callgrind). Aprenderá a ejecutar perfiladores, interpretar sus informes y encontrar cuellos de botella reales.
1. Perfilado con gprof
Preparación del código
gprof es el perfilador más simple y accesible. Para su funcionamiento, es necesario compilar el programa con la bandera -pg:
g++ -pg -O2 main.cpp -o my_programEjecutamos el programa. Se ejecutará un poco más lento de lo normal, pero creará un archivo gmon.out con los datos de perfilado. Luego ejecutamos gprof:
./my_programgprof my_program gmon.out > report.txtEjemplo de análisis
Consideremos un programa simple con dos funciones:
#include <iostream>#include <cmath>
void slowFunction() { double sum = 0.0; for (int i = 0; i < 100000000; ++i) { sum += std::sin(i) * std::cos(i); } std::cout << "Sum: " << sum << std::endl;}
void fastFunction() { int count = 0; for (int i = 0; i < 1000; ++i) { for (int j = 0; j < 1000; ++j) { count += (i * j) % 3; } } std::cout << "Count: " << count << std::endl;}
int main() { slowFunction(); fastFunction(); return 0;}Después de ejecutar gprof, en el informe veremos una tabla con el tiempo de ejecución de cada función:
Flat profile:
Each sample counts as 0.01 seconds. % cumulative self self total time seconds seconds calls ms/call ms/call name 99.0 1.98 1.98 1 1980.0 1980.0 slowFunction() 1.0 0.02 0.02 1 20.0 20.0 fastFunction()La conclusión es obvia: slowFunction() ocupa el 99% del tiempo. El cuello de botella es la llamada a las funciones trigonométricas sin y cos en el bucle.
Limitaciones de gprof
- Solo funciona con programas compilados con
-pg - No muestra el tiempo en funciones inline
- No es adecuado para aplicaciones multiproceso (sin configuraciones adicionales)
2. Perfilado con perf (Linux)
Ejecución básica
perf es una herramienta potente para el perfilado a nivel de kernel. No requiere recompilar el programa y funciona con cualquier binario (incluso con la optimización -O3):
# Instalación (si no está)sudo apt install linux-tools-common linux-tools-generic
# Perfilado con conteo de ciclos de CPUperf stat ./my_program
# Registro de eventos para análisis detalladoperf record ./my_programperf reportEjemplo con perf stat
Para el mismo programa, perf stat mostrará:
Performance counter stats for './my_program':
1,987.45 msec task-clock # 1.000 CPUs utilized 10 context-switches # 5.028 /sec 0 cpu-migrations # 0.000 /sec 105 page-faults # 52.832 /sec 5,234,567,890 cycles # 2.634 GHz 9,876,543,210 instructions # 1.89 insn per cycle 1,234,567,890 branches # 621.234 M/sec 10,000,000 branch-misses # 0.81% of all branches
1.987456789 seconds time elapsedMétricas cla