Introducción: ¿por qué perfilar código Rust?
\n\nRust es famoso por su velocidad y seguridad, pero incluso el código más rápido puede funcionar lentamente si tiene cuellos de botella. El perfilado es el proceso de medir el rendimiento de un programa: tiempo de ejecución, carga de la CPU, memoria y otras métricas. Para los desarrolladores principiantes en Rust, esta es una habilidad indispensable que permite convertir código «que simplemente funciona» en código eficiente y rápido.
\n\nImagina que has escrito un analizador de registros o un juego en Rust. Todo compila, pero el programa tarda más de lo esperado. En lugar de adivinar qué parte del código está ralentizando, puedes usar perfiladores que mostrarán los «puntos calientes» (hotspots) exactos. En este artículo, analizaremos las herramientas principales de perfilado de Rust para principiantes: cargo-flamegraph, perf y mediciones simples con std::time::Instant.
1. La forma más simple: mediciones de tiempo con std::time::Instant
\n\nAntes de pasar a herramientas complejas, aprende a medir el tiempo de ejecución de secciones individuales de código. Este es un método básico pero efectivo para principiantes.
\n\nEjemplo: medir el tiempo de ejecución de una función
\n\nuse std::time::Instant;\n\nfn slow_function() {\n let mut sum = 0u64;\n for i in 0..1_000_000 {\n sum += i;\n }\n println!("Suma: {}", sum);\n}\n\nfn main() {\n let start = Instant::now();\n slow_function();\n let duration = start.elapsed();\n println!("Tiempo de ejecución: {:?}", duration);\n}\n\n\nEste código mostrará el tiempo exacto de ejecución de slow_function. Sin embargo, este enfoque no es conveniente para proyectos grandes: tendrías que colocar manualmente las mediciones en cada lugar sospechoso.
¿Cuándo es útil esto?
\n- \n
- Quieres verificar rápidamente una hipótesis sobre una función lenta. \n
- No es posible instalar herramientas adicionales. \n
- Estás trabajando con código de un solo hilo sin lógica compleja. \n
Desventaja: las mediciones manuales no muestran cuánto tiempo se gasta dentro de las funciones llamadas (por ejemplo, asignaciones de memoria o llamadas al sistema). Para eso se necesitan perfiladores.
\n\n2. Perfilado con perf (Linux)
\n\nLa utilidad perf es un potente perfilador para Linux que funciona a nivel de kernel. Recoge muestras (samples) de dónde pasa el tiempo el programa. Para empezar, asegúrate de que perf esté instalado:
sudo apt install linux-tools-common linux-tools-generic # Ubuntu/Debian\n\n\nPaso 1: Compilación con información de depuración
\nPara que perf pueda mostrar nombres de funciones y líneas de código, compila el proyecto en modo debug (o release con las banderas debuginfo):
cargo build\n# o\nRUSTFLAGS="-g" cargo build --release\n\n\nPaso 2: Iniciar el perfilado
\nperf record -g ./target/debug/tu_programa\nperf report\n\n\nLa bandera -g habilita la grabación de la pila de llamadas (call graph). Después de ejecutar perf report, verás una lista interactiva de funciones ordenadas por tiempo de ejecución.
Ejemplo de interpretación
\nSupongamos que ves que el 70% del tiempo lo ocupa la función Vec::push. Esto podría significar que estás reasignando memoria con frecuencia. Solución: reservar la capacidad del vector de antemano con Vec::with_capacity.
Consejo: Para principiantes, perf puede parecer complejo debido a la abundancia de datos. Comienza con perf top en tiempo real para ver qué funciones están «ardiendo» en este momento.
3. Visualización con cargo-flamegraph
\n\nSi necesitas una imagen visual, usa cargo-flamegraph. Esta herramienta construye flamegraphs — gráficos donde el ancho del rectángulo muestra el tiempo de ejecución de la función y la profundidad muestra la anidación de llamadas.