Perfilado de código C++: encontramos cuellos de botella en la práctica

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

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_program


Ejecutamos 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.txt


Ejemplo 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 report


Ejemplo 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 elapsed


Métricas cla

Blogs

Book Recommendations