Análisis de rendimiento del código con Rprof y profvis
Identifique qué funciones consumen más tiempo en sus scripts.
Análisis de rendimiento del código con Rprof y profvis es una lección gratuita de R Academy en CoddyKit. Esta es la lección 2 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de R Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de R Academy incluye 4 lecciones en total.
¿Qué es la creación de perfiles?
Medir el tiempo le indica cuánto tarda en ejecutarse el código. La creación de perfiles le indica dónde se invierte el tiempo dentro de ese código. El profiler de R toma muestras de la pila de llamadas a intervalos regulares para crear una visión estadística de qué funciones son costosas.
Las dos herramientas principales son Rprof(), integrada en R, y el paquete interactivo profvis.
Iniciar y detener Rprof()
Rprof('output.prof', interval = 0.01) inicia el profiler. Escribe muestras de la pila de llamadas en un archivo cada 10 ms. Ejecute el código lento y, después, llame a Rprof(NULL) para detener la grabación.
El argumento interval controla la frecuencia de muestreo en segundos: los valores más pequeños ofrecen mayor resolución, pero generan archivos de salida más grandes.
# Pattern — do not run Rprof inside knitr/Quarto
# Rprof('my_profile.prof', interval = 0.01)
#
# slow_function <- function(n) {
# x <- numeric(n)
# for (i in seq_len(n)) x[i] <- sqrt(i)
# sum(x)
# }
# slow_function(500000)
#
# Rprof(NULL) # stop profilingLectura de resultados con summaryRprof()
summaryRprof('output.prof') analiza el archivo de profiling y devuelve una lista con dos data frames:
- by.self — tiempo invertido en cada función por sí misma (sin incluir las funciones llamadas)
- by.total — tiempo total, incluidas todas las funciones llamadas por esa función
Ordene por self.pct para encontrar los puntos críticos.
# After Rprof() run:
# prof <- summaryRprof('my_profile.prof')
# head(prof$by.self)
#
# Example output columns:
# self.time self.pct total.time total.pct
# slow_fn 1.22 61.0 1.98 99.0
# sqrt 0.76 38.0 0.76 38.0
# sum 0.02 1.0 0.02 1.0Tiempo propio frente a tiempo total
Comprender la diferencia entre el tiempo propio y el tiempo total es fundamental para crear perfiles:
- Tiempo propio — tiempo que la función empleó ejecutando sus propias líneas (sin esperar a las funciones llamadas)
- Tiempo total — tiempo propio más todo el tiempo empleado en las funciones que llamó
Una función con un tiempo total alto, pero un tiempo propio bajo, es lenta por lo que llama, no por su propia lógica. Optimice la función llamada, no la que realiza la llamada.
# Conceptual example:
# wrapper() -> process_data() -> slow_sort()
#
# total.pct: wrapper=100, process_data=90, slow_sort=85
# self.pct: wrapper=5, process_data=5, slow_sort=85
#
# => slow_sort is the real bottleneck to fix.
cat('High total + low self => the culprit is a callee function
')Introducción a profvis
profvis envuelve Rprof() y proporciona un gráfico de llama HTML interactivo en RStudio o en un navegador. Es mucho más fácil de leer que la salida sin procesar de summaryRprof().
Instálelo una vez con install.packages('profvis') y, después, envuelva el código con profvis({...}).
# library(profvis)
#
# profvis({
# n <- 200000
# x <- numeric(n)
# for (i in seq_len(n)) x[i] <- log(i)
# total <- sum(x)
# sorted <- sort(x)
# })Lectura del gráfico de llama de profvis
La salida de profvis tiene dos paneles:
- Gráfico de llama — barras horizontales cuyo ancho representa el tiempo; las barras anidadas representan la profundidad de la pila de llamadas
- Tabla de datos — vista ordenable del tiempo propio y total por función y línea de código fuente
Las barras anchas situadas en la parte inferior del gráfico de llama corresponden a las funciones que realizan las llamadas más costosas. Las pilas altas indican cadenas de llamadas profundas.
# Reading the flame graph:
# - Each horizontal bar = one function on the call stack
# - Width proportional to time spent
# - Bottom = outermost caller, top = deepest callee
# - Click a bar to zoom in
# - 'Memory' tab shows allocation by line
cat('profvis shows self time per source line — invaluable for tight loops
')Identificación de puntos críticos
Después de visualizar la salida de profvis, identifique los puntos críticos buscando funciones que sean anchas en el gráfico de llama y tengan un tiempo propio elevado. Algunos culpables habituales en R son:
- Bucles no vectorizados que realizan operaciones elemento por elemento
- Uso repetido de
rbind()oc()que hace crecer objetos dentro de un bucle - Análisis repetido de expresiones regulares o cadenas en bucles estrechos
# Before fix — growing vector in loop (common hot spot)
# profvis reveals repeated reallocations:
# result <- c()
# for (i in 1:50000) result <- c(result, i^2)
#
# After fix — pre-allocated:
# result <- numeric(50000)
# for (i in 1:50000) result[i] <- i^2
cat('Pre-allocation eliminates the most common loop hot spot
')Creación de perfiles de asignaciones de memoria
Rprof también puede realizar un seguimiento de las asignaciones de memoria con memory.profiling = TRUE. profvis muestra un panel de memoria junto con la medición del tiempo, lo que permite detectar funciones que asignan objetos temporales grandes, una fuente clave de pausas por la recolección de basura.
# Memory profiling with Rprof:
# Rprof('mem.prof', interval = 0.01, memory.profiling = TRUE)
# ... slow code ...
# Rprof(NULL)
# prof <- summaryRprof('mem.prof', memory = 'both')
# head(prof$by.self)
#
# profvis also shows mem delta per line automatically
cat('Memory profiling pinpoints allocation hot spots causing GC pauses
')Creación de perfiles de un pipeline real
Aplique la creación de perfiles de forma sistemática a un pipeline de datos: envuelva todo el pipeline en profvis({}), identifique la etapa más lenta, optimícela y vuelva a crear el perfil para confirmar la mejora. No optimice nunca a ciegas.
# Workflow:
# 1. profvis({ full_pipeline() }) => identify Stage 3 is 80% of time
# 2. Rewrite Stage 3 (vectorize / use data.table)
# 3. profvis({ full_pipeline() }) => confirm Stage 3 now < 10%
# 4. system.time({ full_pipeline() }) => confirm overall speedup
cat('Profile -> identify -> fix -> re-profile is the correct cycle
')Limitaciones del muestreo de Rprof
Rprof utiliza muestreo estadístico, por lo que las funciones muy rápidas (más rápidas que el intervalo de muestreo) pueden no aparecer. Para microevaluaciones de expresiones pequeñas, use el paquete microbenchmark.
Además, Rprof no crea perfiles del código C/C++ situado por debajo de la interfaz de R; solo se pueden ver las pilas de llamadas del nivel de R.
# Rprof interval = 0.01s => functions faster than 10ms may not appear
# For sub-millisecond work use microbenchmark:
# microbenchmark(expr1, expr2, times = 1000L)
#
# For C-level profiling use external tools:
# - Instruments (macOS)
# - perf (Linux)
cat('Rprof is for R-level profiling; use microbenchmark for micro-timing
')Prácticas recomendadas para crear perfiles en R
Siga estas prácticas para obtener resultados fiables al crear perfiles:
- Cree perfiles con tamaños de datos realistas; las entradas pequeñas ocultan el cuello de botella real
- Ejecute iteraciones de calentamiento antes de crear el perfil para excluir los costes de configuración inicial
- Cree el perfil en una sesión de R limpia para evitar interferencias de los paquetes cargados
- Use
profvispara explorar ysummaryRprofpara informes de CI o automatizados
# Clean session profiling checklist:
# 1. Restart R (Ctrl+Shift+F10 in RStudio)
# 2. Load only required packages
# 3. Run once to warm up
# 4. profvis({ ... }) on second run
# 5. Compare before/after with system.time()
cat('Always profile with realistic data in a clean R session
')Comprobación rápida: tiempo propio frente a total en Rprof
Una función muestra total.pct = 95%, pero self.pct = 3% en la salida de summaryRprof(). ¿Qué le indica esto?
Resumen de las herramientas de profiling
R le ofrece un conjunto de herramientas de profiling de dos niveles:
Rprof('file.prof', interval=0.01)+Rprof(NULL)+summaryRprof()— integrado, ejecutable mediante scripts y adecuado para CIprofvis({...})— gráfico de llama interactivo con anotaciones de las líneas de código fuente y seguimiento de memoria
El flujo de trabajo correcto es siempre: medir primero, identificar el punto más costoso, optimizar únicamente ese punto y volver a medir para confirmar la mejora.
Preguntas frecuentes
¿La lección «Análisis de rendimiento del código con Rprof y profvis» es gratis?
Sí — el texto completo de «Análisis de rendimiento del código con Rprof y profvis» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de R Academy, actualiza a CoddyKit PRO. El curso de R Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Análisis de rendimiento del código con Rprof y profvis»?
Identifique qué funciones consumen más tiempo en sus scripts. Practicas R Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar R Academy?
No se requiere experiencia previa. R Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 2 de 4.
¿Cuánto tiempo toma la lección «Análisis de rendimiento del código con Rprof y profvis»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de R Academy?
Sí. Cada lección de R Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- system.time() y proc.time()
- Análisis de rendimiento del código con Rprof y profvis
- Vectorización para acelerar el código
- Evaluación comparativa con microbenchmark