Comandos de py-spy
py-spy es un perfilador por muestreo para programas Python escrito en Rust. Puede perfilar procesos Python en ejecución sin modificar código ni reiniciarlos, produciendo flame graphs y vistas top en tiempo real con mínima sobrecarga.
Instalación
Linux/Ubuntu
# Install via pip
pip install py-spy
# Install via cargo (Rust)
cargo install py-spy
# Install via package manager (Arch Linux)
pacman -S py-spy
# Verify installation
py-spy --version
# py-spy requires root to attach to processes you don't own
# Or set ptrace permissions:
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
py-spy record — Generar perfiles
# Grabar un flame graph SVG desde un script
py-spy record -o profile.svg -- python my_script.py
# Grabar desde un proceso en ejecución por PID
sudo py-spy record -o profile.svg --pid 1234
# Grabar durante una duración específica (segundos)
sudo py-spy record -o profile.svg --pid 1234 --duration 60
# Establecer tasa de muestreo (predeterminado 100 Hz)
py-spy record -o profile.svg --rate 200 -- python my_script.py
# Grabar solo hilos inactivos (esperando/durmiendo)
py-spy record -o profile.svg --idle --pid 1234
# Grabar incluyendo marcos nativos de extensiones C/C++
py-spy record -o profile.svg --native -- python my_script.py
# Grabar subprocesos (seguir forks)
py-spy record -o profile.svg --subprocesses -- python my_script.py
# Grabar solo hilos que mantienen el GIL
py-spy record -o profile.svg --gil -- python my_script.py
# Grabar con números de línea de funciones
py-spy record -o profile.svg --function -- python my_script.py
# Modo no bloqueante (puede perder algunas muestras)
py-spy record -o profile.svg --nonblocking --pid 1234
Formatos de salida
# Flame graph SVG (predeterminado)
py-spy record -o profile.svg --format flamegraph -- python my_script.py
# Formato speedscope (ver en https://speedscope.app)
py-spy record -o profile.speedscope.json --format speedscope -- python my_script.py
# Salida de muestras sin procesar
py-spy record -o profile.raw --format raw -- python my_script.py
# Formato Chrome trace (ver en chrome://tracing)
py-spy record -o profile.json --format chrometrace -- python my_script.py
# Formato pprof (compatible con herramientas Go pprof)
py-spy record -o profile.pb.gz --format pprof -- python my_script.py
py-spy top — Perfilado en vivo
# Vista top en vivo de un proceso en ejecución
sudo py-spy top --pid 1234
# Vista en vivo de un script
py-spy top -- python my_script.py
# Incluir marcos nativos en vista top
sudo py-spy top --native --pid 1234
# Mostrar hilos inactivos
sudo py-spy top --idle --pid 1234
# Incluir subprocesos
py-spy top --subprocesses -- python my_script.py
# Tasa de muestreo personalizada
sudo py-spy top --rate 50 --pid 1234
py-spy dump — Volcado de hilos
# Volcar trazas de pila actuales de todos los hilos
sudo py-spy dump --pid 1234
# Volcar con variables locales
sudo py-spy dump --locals --pid 1234
# Volcar en formato JSON
sudo py-spy dump --json --pid 1234
# Volcar incluyendo marcos nativos
sudo py-spy dump --native --pid 1234
Perfilado de escenarios específicos
Aplicaciones web
# Perfilar una aplicación Django
py-spy record -o django_profile.svg -- python manage.py runserver
# Perfilar una aplicación Flask
py-spy record -o flask_profile.svg -- python app.py
# Perfilar un worker de Gunicorn (adjuntar al PID del worker específico)
sudo py-spy record -o gunicorn_profile.svg --pid $(pgrep -f 'gunicorn.*worker')
# Perfilar uvicorn (ASGI)
py-spy record -o uvicorn_profile.svg --subprocesses -- uvicorn main:app --workers 4
Procesamiento de datos
# Perfilar una carga de trabajo pandas/numpy con extensiones nativas
py-spy record -o data_profile.svg --native -- python etl_pipeline.py
# Perfilar con subprocesos (multiprocessing)
py-spy record -o multiproc_profile.svg --subprocesses -- python parallel_job.py
Servicios de larga ejecución
# Adjuntar a un demonio en ejecución durante 5 minutos
sudo py-spy record -o daemon_profile.svg --pid 1234 --duration 300
# Perfilado periódico vía cron (instantáneas de 30 segundos)
# Add to crontab: */5 * * * * sudo py-spy record -o /tmp/profile_$(date +\%s).svg --pid $(cat /var/run/myapp.pid) --duration 30
Docker y contenedores
# Perfilar un proceso Python en un contenedor Docker
# 1. Encontrar el PID del contenedor en el host
CONTAINER_PID=$(docker inspect --format '{{.State.Pid}}' my_container)
# 2. Adjuntar py-spy al namespace PID del contenedor
sudo py-spy record -o container_profile.svg --pid $CONTAINER_PID
# O ejecutar py-spy dentro del contenedor
docker exec -it my_container py-spy top --pid 1
# Docker run con capacidad SYS_PTRACE para py-spy
docker run --cap-add SYS_PTRACE my_image
Kubernetes
# Perfilar un pod Python
# 1. Encontrar el nodo y PID
kubectl exec -it my-pod -- pgrep -f python
# 2. Usar kubectl exec con py-spy instalado en el contenedor
kubectl exec -it my-pod -- py-spy record -o /tmp/profile.svg --pid 1 --duration 30
# 3. Copiar el perfil fuera
kubectl cp my-pod:/tmp/profile.svg ./profile.svg
# Para contenedores de depuración efímeros
kubectl debug -it my-pod --image=py-spy-debug --target=my-container -- py-spy top --pid 1
Interpretación de la salida
Flame Graph (SVG)
# Lectura del flame graph:
# - Eje X: proporción del tiempo total de CPU (más ancho = más CPU)
# - Eje Y: profundidad de la pila (abajo = punto de entrada, arriba = función hoja)
# - Cada caja: una llamada a función
# - Clic para ampliar, Ctrl+F para buscar
# - El color es aleatorio (no significativo por defecto)
Columnas de la vista Top
# Explicación de columnas en py-spy top:
# %Own — Tiempo de CPU solo en esta función (tiempo propio)
# %Total — Tiempo de CPU en esta función + llamadas
# OwnTime — Tiempo propio absoluto
# TotalTime — Tiempo total absoluto
# Function — Módulo y nombre de función
# Line — Archivo fuente y número de línea
Combinación con otras herramientas
# Generar pilas plegadas para las herramientas FlameGraph de Brendan Gregg
py-spy record -o profile.raw --format raw -- python my_script.py
# El formato raw ya es compatible con pilas plegadas
# Convertir a speedscope para análisis interactivo
py-spy record -o profile.speedscope.json --format speedscope -- python my_script.py
# Abrir en https://speedscope.app
# Convertir salida pprof para uso con go tool pprof
py-spy record -o profile.pb.gz --format pprof -- python my_script.py
go tool pprof -http=:8080 profile.pb.gz
Solución de problemas
# Permiso denegado — se necesita root o acceso ptrace
sudo py-spy top --pid 1234
# Or: echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
# "Error: Failed to find python version" — especificar ruta de Python
sudo py-spy record --pid 1234 --python-program /usr/bin/python3
# Símbolos faltantes en modo nativo — instalar paquetes de depuración
sudo apt install python3-dbg
# Proceso no encontrado en contenedor — usar PID del host
docker inspect --format '{{.State.Pid}}' my_container
Referencia rápida
| Comando | Propósito |
|---|---|
py-spy record | Generar flame graph o archivo de perfil |
py-spy top | Vista de perfilado de CPU en vivo tipo top |
py-spy dump | Volcado único de pilas de hilos |
--pid PID | Adjuntar a proceso en ejecución |
--native | Incluir marcos de extensiones C/C++ |
--subprocesses | Seguir procesos hijos |
--gil | Solo perfilar hilos que mantienen el GIL |
--rate N | Establecer frecuencia de muestreo (Hz) |
--format | Formato de salida (flamegraph, speedscope, raw, chrometrace, pprof) |