macOS-Trace: Optimización Autónoma del Rendimiento de Aplicaciones
macOS-Trace es un motor de optimización de rendimiento en ciclo cerrado para aplicaciones nativas de macOS (SwiftUI, AppKit, Metal, CoreAudio, WebKit y binarios nativos).
El objetivo es eliminar la interacción manual con la GUI de Instruments. Un agente de IA puede diagnosticar de forma autónoma, localizar cuellos de botella, implementar cambios de código, volver a probar con evaluación comparativa diferencial e iterar hasta que los objetivos de rendimiento se verifiquen con datos empíricos.
+-------------------------------------------------------------------------+
| El Ciclo de Optimización Autónoma |
| |
| 1. Alineación de Objetivos ──> 2. Traza de Diagnóstico ──> 3. Corrección de Código Dirigida |
| ^ │ |
| │ ▼ |
| └────── Iterar si no se cumple el objetivo <── 4. Verificación de Re-evaluación |
+-------------------------------------------------------------------------+
Fase 1: Alineación de Objetivos con el Usuario (Cuestionario Previo)
Antes de modificar código o recopilar trazas, el agente debe alinearse con el usuario sobre los objetivos de optimización y los criterios de éxito.
Interacción con Herramienta Modal vs Chat
- Si tu plataforma de agente proporciona un cuestionario/herramienta modal interactiva (por ejemplo,
ask_question, diálogos de entrada o listas de opciones seleccionables), invócala para presentar estas opciones de manera limpia al usuario. - Si no hay una herramienta modal disponible, pregunta al usuario directamente en la conversación con opciones estructuradas y valores recomendados concretos.
Preguntas para Hacer al Usuario
- Objetivo Principal de Optimización:
- Opción A: Reducir el uso de CPU, el consumo de energía y el estrangulamiento térmico.
- Opción B: Reducir la huella de memoria, los picos de asignación transitorios o eliminar fugas.
- Opción C: Eliminar el tartamudeo de fotogramas de la UI y los cuadros de animación caídos (Hitches).
- Opción D: Acelerar el tiempo de inicio en frío de la aplicación.
- Objetivos de Rendimiento Específicos (Proporcionar Valores Predeterminados Recomendados):
- Objetivos de CPU / Energía:
- Objetivo de Línea Base Inactiva: < 20 M/s instrucciones, Impacto de CPU < 0.5.
- Objetivo de Carga de Trabajo Activa: < 100 M/s instrucciones (o especificar: reducir en un 30% - 50%).
- Objetivos de Memoria:
- RAM Residente Máxima: Límite en < 150 MB (utilidades/audio) o < 300 MB (multimedia/UI enriquecida).
- Tasa de Eventos de Asignación: < 500 eventos/seg durante la ejecución en estado estable.
- Fugas de Memoria: Exactamente 0 fugas persistentes.
- Objetivos de Suavidad de UI:
- Relación de Hitches: < 5.0 ms/s (aceptable), < 1.0 ms/s (fluido/sin fotogramas caídos).
- Objetivos de Tiempo de Inicio:
- Tiempo hasta el Primer Fotograma: < 400 ms (excelente), < 800 ms (aceptable).
- Objetivos de CPU / Energía:
- Escenario de Evaluación Comparativa del Usuario:
- Pregunta al usuario qué pantalla, interacción de usuario o carga de trabajo específica evaluar.
Una vez confirmados los objetivos, procede a la Fase 2.
Alcance y Requisitos Previos
- Plataforma objetivo: Solo aplicaciones de escritorio nativas de macOS (SwiftUI, AppKit, Metal, CoreAudio / AVAudioEngine, vistas host de WebKit, ejecutables CLI nativos). No es compatible con simuladores de iOS, dispositivos móviles remotos o aplicaciones web externas solo para navegador.
- Herramientas de Xcode: Requiere macOS 12+ y Xcode completo o Xcode Command Line Tools (
xcode-select -p,xcrun xctrace version). - Python: Python 3.8+ (preinstalado en macOS; cero dependencias pip externas).
- Permisos de proceso: Se requieren compilaciones de depuración o binarios con el entitlement
get-task-allowpara--attach <PID>bajo Hardened Runtime.
Reglas para Agentes
Sigue estas reglas no negociables durante la creación automatizada de perfiles:
- Establece una línea base primero: Nunca registres solo la carga de trabajo activa. Siempre captura una línea base inactiva (aplicación abierta en primer plano, carga de trabajo en pausa) antes de registrar el estado activo. Calcula:
Delta = Activo - Línea Base. - Verifica el estado objetivo antes de registrar: Comprueba que el proceso exista usando
pgrep -x <NombreDelProceso>y que la característica objetivo se esté ejecutando activamente durante la ventana de grabación. - Mantén la ventana en primer plano: macOS limita la renderización y los display links para ventanas ocluidas o minimizadas (
NSWindowOcclusionState). Una ventana ocluida producirá lecturas de GPU y CPU falsamente bajas. - Usa parámetros de prueba iguales: Compara ejecuciones con duraciones de muestra idénticas (predeterminado:
60s), escalas de visualización idénticas, tamaños de ventana idénticos y datos de entrada de prueba idénticos. Nunca compares una compilación Debug contra una compilación Release. - Sin dependencias de Python de terceros: Todos los scripts incluidos (
scripts/compare_elements.py,scripts/parse_power.py,scripts/top_categories.py) usan solo la biblioteca estándar de Python 3. No instales paquetes pip. - Guarda las salidas en
/tmp/macos-traces/: Almacena todos los paquetes.tracey exportaciones.xmlen/tmp/macos-traces/con nombres de archivo con marca de tiempo y etiqueta de escenario. - Protege el presupuesto de contexto de la conversación: Los archivos de traza y los documentos XML exportados sin procesar pueden tener decenas o cientos de megabytes. Nunca vuelques salidas
.tracesin procesar, árboles de llamadas completos o XML de Allocations sin analizar en el contexto de la conversación del agente. Siempre usa los scripts de Python incluidos para transmitir, filtrar, clasificar y resumir los datos antes de leerlos. - Concéntrate en los cuellos de botella principales: No disperses micro-optimizaciones en docenas de funciones de utilidad inocentes. Primero crea un perfil para confirmar el contribuyente dominante (por ejemplo, instancias de superficie redundantes, reevaluaciones de temporizadores de alta frecuencia, E/S sin búfer) y enfoca los esfuerzos de optimización exclusivamente en esa causa raíz.
- Nunca alteres silenciosamente la UI, los efectos visuales o el comportamiento central: Si un cuello de botella de rendimiento involucra fidelidad visual (como materiales de desenfoque/cristal, animaciones de fotogramas, sombras, transiciones de diseño) o comportamiento esencial del software:
- No elimines ni degrades unilateralmente la característica visual.
- Pide permiso al usuario formalmente primero (usando un mensaje interactivo o un mensaje de chat explícito).
- Articula claramente la compensación: Describe el cambio visual antes y después, explica por qué la característica consume recursos y presenta la ganancia de rendimiento concreta esperada (por ejemplo, "Deshabilitar el desenfoque de fondo dinámico reducirá el impacto de GPU activo de 1.5 a 0.2 y ahorrará ~50 M/s instrucciones de CPU").
- Limpia los artefactos de grabación: Cada grabación de
xctraceescribe varios GB de trazas de kernel transitorias (instruments*.ktrace) y un caché de CLI de Instruments (C/com.apple.dt.InstrumentsCLI) en la carpeta temporal del sistema por usuario ($TMPDIR).scripts/run_trace.shlos elimina automáticamente al salir (tanto en éxito como en fallo). Cuando ejecutesxctracedirectamente, límpialos tú mismo antes de concluir:Nunca termines una sesión dejando cientos de GB de datos de grabación transitorios atrás.find "${TMPDIR:-/tmp}" -maxdepth 1 -type f -name 'instruments*.ktrace' -delete 2>/dev/null || true
El Protocolo de Optimización de 4 Fases
Fase 2: Creación de Perfiles de Diagnóstico y Atribución
Antes de escribir código, mide el estado actual y aísla la causa raíz:
# 1. Verificación previa: la aplicación debe estar ejecutándose con su ventana visible
APP_NAME="TuApp"
pgrep -x "$APP_NAME" || { echo "[ERROR] $APP_NAME no se está ejecutando. Lánzala primero."; exit 1; }
# SKILL_DIR = directorio de instalación de esta habilidad (ajustar si está instalada en otro lugar)
SKILL_DIR="$HOME/.claude/skills/macos-trace"
# 2. Graba 60s de línea base inactiva (carga de trabajo en pausa, ventana visible)
# run_trace.sh resuelve el nombre del proceso a un PID por sí mismo
"$SKILL_DIR/scripts/run_trace.sh" --process "$APP_NAME" --template power --duration 60s --label "01-baseline"
# 3. Activar carga de trabajo en la aplicación, grabar estado activo
"$SKILL_DIR/scripts/run_trace.sh" --process "$APP_NAME" --template power --duration 60s --label "02-pre-opt"
# 4. Calcular delta previo a la optimización
python3 "$SKILL_DIR/scripts/compare_elements.py" \
/tmp/macos-traces/01-baseline-power.xml:"Línea Base Inactiva" \
/tmp/macos-traces/02-pre-opt-power.xml:"Activo Pre-Opt"
Usa las plantillas especializadas para atribuir el cuello de botella:
- Ejecuta
--template timepara aislar funciones activas en el árbol de llamadas. - Ejecuta
--template allocconscripts/top_categories.pypara identificar asignaciones problemáticas. - Ejecuta
--template hitchesdurante el desplazamiento para aislar retrasos de renderizado vs confirmación.
Fase 3: Modificación de Código Dirigida
Aplica correcciones mínimas y quirúrgicas basadas en los hallazgos:
- ¿Los hilos de audio en tiempo real asignan memoria del heap? Reemplázalos con búferes de anillo sin bloqueo preasignados.
- ¿IPC de WebKit saturado? Limita las actualizaciones de estado y cambia a animaciones CSS transform.
- ¿Sobredibujado del shader de fragmentos Metal en Retina? Agrega escalado de resolución dinámica o pausa los bucles de renderizado fuera de pantalla.
- ¿Picos de decodificación de imágenes de alta resolución? Adopta el submuestreo de
CGImageSourceCreateThumbnailAtIndex.
Reconstruye la aplicación.
Fase 4: Re-evaluación, Revisión Cuantitativa y Puerta de Decisión
Vuelve a ejecutar el perfil bajo condiciones idénticas y evalúa el delta:
# 1. Grabar carga de trabajo activa posterior a la optimización
"$SKILL_DIR/scripts/run_trace.sh" --process "$APP_NAME" --template power --duration 60s --label "03-post-opt"
# 2. Comparar Pre-Opt vs Post-Opt contra la Línea Base
python3 "$SKILL_DIR/scripts/compare_elements.py" \
/tmp/macos-traces/01-baseline-power.xml:"Línea Base Inactiva" \
/tmp/macos-traces/02-pre-opt-power.xml:"Activo Pre-Opt" \
/tmp/macos-traces/03-post-opt-power.xml:"Activo Post-Opt"
Ejemplo de Salida de Decisión:
Escenario Seg CPU Prom CPU Máx Pantalla GPU Prom Instr Totales Instr M/s
====================================================================================================
Línea Base Inactiva 60 0.15 0.80 0.05 0.00 1.02G 17.0
Activo Pre-Opt 60 2.40 4.80 1.10 1.50 16.20G 270.0
Activo Post-Opt 60 0.65 1.20 0.25 0.10 4.80G 80.0
----------------------------------------------------------------------------------------------------
Diferencial vs Línea Base [Línea Base Inactiva]:
Activo Pre-Opt +253.0 M/s instrucciones, Delta CPU Prom +2.25
Activo Post-Opt +63.0 M/s instrucciones, Delta CPU Prom +0.50
Puerta de Decisión:
- Si se cumple el objetivo (por ejemplo, la tasa de instrucciones bajó de 270 M/s a 80 M/s, cumpliendo el objetivo de < 100 M/s): Presenta el informe empírico antes/después al usuario y concluye.
- Si no se cumple el objetivo: Aísla el cuello de botella restante y comienza el siguiente ciclo de iteración.
Limpieza Posterior al Informe: Después de que el usuario acepte el informe de optimización final, elimina los paquetes .trace acumulados en /tmp/macos-traces/ (cada uno puede tener decenas de GB) a menos que el usuario solicite explícitamente mantenerlos. La tabla de comparación finalizada y las exportaciones .xml mostradas en el informe son evidencia suficiente.
Referencia Directa de CLI
# Adjuntar a un proceso en ejecución
xcrun xctrace record \
--template 'Power Profiler' \
--time-limit 60s \
--output /tmp/macos-traces/power.trace \
--attach $PID
# Exportar tabla de Impacto de Energía (instrucciones, CPU, GPU, pantalla)
xcrun xctrace export \
--input /tmp/macos-traces/power.trace \
--xpath "/trace-toc/run[@number='1']/data/table[@schema='ProcessSubsystemPowerImpact']" \
> /tmp/macos-traces/power.xml
# Exportar tabla de resumen de Asignaciones
xcrun xctrace export \
--input /tmp/macos-traces/alloc.trace \
--xpath "/trace-toc/run[@number='1']/data/table[@schema='all-allocations-summary']" \
> /tmp/macos-traces/alloc.xml
Referencia de Plantillas
Plantillas de Instruments compatibles con scripts/run_trace.sh y xctrace sin interfaz:
Cómputo y Energía
| Plantilla | Nombre Corto | Métricas Objetivo y Esquema de Exportación | Caso de Uso |
|---|---|---|---|
Power Profiler | power | Instrucciones/seg (M/s), impactos de energía de CPU/GPU/Pantalla (ProcessSubsystemPowerImpact). | Evaluación comparativa A/B objetiva y pruebas de eficiencia energética. |
Time Profiler | time | Pesos de muestras de CPU por hilo, puntos calientes en el árbol de llamadas, métodos bloqueantes del hilo principal. | Alto uso de CPU, hilos descontrolados y rutas de funciones activas. |
CPU Counters | counters | IPC (instrucciones por ciclo), fallos de caché L1/L2, predicciones erróneas de rama. | Cuellos de botella de rendimiento computacional y de algoritmos DSP de bajo nivel. |
Capacidad de Respuesta y Suavidad de UI
| Plantilla | Nombre Corto | Métricas Objetivo y Esquema de Exportación | Caso de Uso |
|---|---|---|---|
Animation Hitches | hitches | Duración de hitches (ms), relación de hitches (ms/s), fotogramas caídos, latencia de fase de app vs render. | Tartamudeo al desplazar, fotogramas de animación caídos y retrasos de confirmación de CoreAnimation. |
SwiftUI | swiftui | Evaluaciones del body de la vista, conteos de invalidación de State, frecuencia de actualización de vistas. | Reevaluaciones innecesarias de vistas y cascadas de invalidación de estado. |
Metal System Trace | metal | Tiempo de codificador de GPU, duraciones de shaders de vértices/fragmentos, latencia de límite de fotograma. | Cuellos de botella de ejecución de shaders, sobrecarga de efectos de partículas y estancamientos en la tubería de renderizado. |
Memoria y Asignaciones
| Plantilla | Nombre Corto | Métricas Objetivo y Esquema de Exportación | Caso de Uso |
|---|---|---|---|
Allocations | alloc | Asignaciones del heap, memoria transitoria vs persistente, tasas de eventos por categoría (all-allocations-summary). | Asignaciones temporales de alta frecuencia, picos de memoria y thrashing de búferes. |
Leaks | leaks | Fugas de memoria retenidas que sobreviven al ciclo de vida del padre, ciclos de referencia. | Memoria abandonada, fugas de captura en clausuras y ciclos de delegados no liberados. |
Inicio y Concurrencia
| Plantilla | Nombre Corto | Métricas Objetivo y Esquema de Exportación | Caso de Uso |
|---|---|---|---|
App Launch | launch | Tiempo hasta el primer fotograma, tiempo de carga de dyld, inicializadores estáticos, configuración del runloop. | Optimización de inicio en frío (--launch -- <ruta_del_binario>). |
Swift Concurrency | concurrency | Tareas Swift (creadas/ejecutadas/suspendidas), reentrada de Actores, uso del pool cooperativo. | Inanición de async/await, contención de actores y tareas suspendidas por largo tiempo. |
System Trace | sys | Transiciones de estado de hilos (En ejecución... |