macOS-Trace : Optimisation Autonome des Performances d'Applications
macOS-Trace est un moteur d'optimisation de performances en boucle fermée pour les applications macOS natives (SwiftUI, AppKit, Metal, CoreAudio, WebKit et binaires natifs).
L'objectif est d'éliminer l'interaction manuelle avec l'interface graphique d'Instruments. Un agent IA peut diagnostiquer de manière autonome, localiser les goulots d'étranglement, implémenter des modifications de code, re-tester avec des benchmarks différentiels et itérer jusqu'à ce que les cibles de performances soient vérifiées avec des données empiriques.
+-------------------------------------------------------------------------+
| La Boucle d'Optimisation Autonome |
| |
| 1. Alignement des Objectifs ──> 2. Trace Diagnostique ──> 3. Correction de Code Ciblée |
| ^ │ |
| │ ▼ |
| └────── Itérer si la Cible n'est pas Atteinte <── 4. Vérification par Re-Test |
+-------------------------------------------------------------------------+
Phase 1 : Alignement des Objectifs Utilisateur (Questionnaire Pré-Vol)
Avant de modifier du code ou de collecter des traces, l'agent doit s'aligner avec l'utilisateur sur les cibles d'optimisation et les critères de succès.
Outil Modal vs Interaction en Chat
- Si votre plateforme agent fournit un outil/questionnaire interactif modal (par ex.,
ask_question, boîtes de dialogue de saisie ou listes d'options sélectionnables), invoquez-le pour présenter ces choix proprement à l'utilisateur. - Si aucun outil modal n'est disponible, demandez directement à l'utilisateur dans la conversation avec des options structurées et des valeurs recommandées concrètes.
Questions à Poser à l'Utilisateur
- Objectif d'Optimisation Principal :
- Option A : Réduire l'utilisation du CPU, la consommation d'énergie et le throttling thermique.
- Option B : Diminuer l'empreinte mémoire, les pics d'allocation transitoires ou éliminer les fuites.
- Option C : Éliminer les saccades de trames de l'interface utilisateur et les images d'animation perdues (Hitches).
- Option D : Accélérer le temps de lancement à froid de l'application.
- Cibles de Performances Spécifiques (Fournir les Valeurs Par Défaut Recommandées) :
- Cibles CPU / Énergie :
- Cible de Base au Repos : < 20 M/s instructions, Impact CPU < 0,5.
- Cible de Charge de Travail Active : < 100 M/s instructions (ou spécifier : réduire de 30% à 50%).
- Cibles Mémoire :
- RAM Résidente Maximale : Limiter à < 150 Mo (utilitaires/audio) ou < 300 Mo (média/interface riche).
- Taux d'Événements d'Allocation : < 500 événements/s en régime permanent.
- Fuites Mémoire : Exactement 0 fuite persistante.
- Cibles de Fluidité de l'Interface :
- Ratio de Saccades : < 5,0 ms/s (acceptable), < 1,0 ms/s (fluide/aucune image perdue).
- Cibles de Temps de Lancement :
- Temps jusqu'à la Première Trame : < 400 ms (excellent), < 800 ms (acceptable).
- Cibles CPU / Énergie :
- Scénario de Benchmark Utilisateur :
- Demandez à l'utilisateur quel écran, interaction utilisateur ou charge de travail spécifique il souhaite benchmarker.
Une fois les cibles confirmées, passez à la Phase 2.
Périmètre et Prérequis
- Plateforme cible : Applications de bureau macOS natives uniquement (SwiftUI, AppKit, Metal, CoreAudio / AVAudioEngine, vues hôtes WebKit, exécutables CLI natifs). Ne prend pas en charge les simulateurs iOS, les appareils mobiles distants ou les applications web externes uniquement basées sur un navigateur.
- Outillage Xcode : Nécessite macOS 12+ et Xcode complet ou les outils en ligne de commande Xcode (
xcode-select -p,xcrun xctrace version). - Python : Python 3.8+ (pré-installé sur macOS ; zéro dépendance pip externe).
- Permissions de processus : Les builds de débogage ou les binaires avec l'entitlement
get-task-allowsont requis pour--attach <PID>sous Runtime Renforcé.
Règles pour les Agents
Suivez ces règles non négociables lors du profilage automatisé :
- Établir d'abord une ligne de base : N'enregistrez jamais uniquement la charge de travail active. Capturez toujours une ligne de base au repos (application ouverte au premier plan, charge de travail en pause) avant d'enregistrer l'état actif. Calculez :
Delta = Actif - Base. - Vérifier l'état cible avant l'enregistrement : Assurez-vous que le processus existe en utilisant
pgrep -x <NomProcessus>et que la fonctionnalité cible est activement en cours d'exécution pendant la fenêtre d'enregistrement. - Garder la fenêtre au premier plan : macOS limite le rendu et les liaisons d'affichage pour les fenêtres masquées ou minimisées (
NSWindowOcclusionState). Une fenêtre masquée produira des relevés CPU et GPU faussement bas. - Utiliser des paramètres de test égaux : Comparez les exécutions avec des durées d'échantillonnage identiques (par défaut :
60s), des échelles d'affichage identiques, des tailles de fenêtre identiques et des données d'entrée de test identiques. Ne comparez jamais une build Debug à une build Release. - Pas de dépendances Python tierces : Tous les scripts fournis (
scripts/compare_elements.py,scripts/parse_power.py,scripts/top_categories.py) utilisent uniquement la bibliothèque standard Python 3. N'installez pas de paquets pip. - Sauvegarder les sorties dans
/tmp/macos-traces/: Stockez tous les bundles.traceet les exportations.xmldans/tmp/macos-traces/avec des noms de fichiers horodatés et étiquetés par scénario. - Protéger le budget de contexte de conversation : Les fichiers de trace et les documents XML bruts exportés peuvent peser des dizaines ou des centaines de mégaoctets. Ne déversez jamais les sorties
.tracebrutes, les arbres d'appels complets ou le XML d'Allocations non analysé dans le contexte de conversation de l'agent. Utilisez toujours les scripts Python fournis pour diffuser, filtrer, classer et résumer les données avant de les lire. - Se concentrer sur les goulots d'étranglement principaux : Ne dispersez pas les micro-optimisations sur des dizaines de fonctions utilitaires innocentes. Profilez d'abord pour confirmer le contributeur dominant (par exemple, instances de surface redondantes, réévaluations de temporisateurs à haute fréquence, E/S non mises en mémoire tampon) et concentrez les efforts d'optimisation exclusivement sur cette cause racine.
- Ne jamais modifier silencieusement l'interface utilisateur, les effets visuels ou le comportement principal : Si un goulot d'étranglement de performance implique la fidélité visuelle (comme les matériaux de flou/verre, les animations d'images, les ombres, les transitions de disposition) ou un comportement logiciel essentiel :
- Ne supprimez pas ou ne dégradez pas unilatéralement la fonctionnalité visuelle.
- Demandez formellement l'autorisation à l'utilisateur d'abord (en utilisant une invite interactive ou un message de chat explicite).
- Articulez clairement le compromis : Décrivez le changement visuel avant et après, expliquez pourquoi la fonctionnalité consomme des ressources et présentez le gain de performance concret attendu (par exemple, « La désactivation du flou d'arrière-plan dynamique réduira l'impact GPU actif de 1,5 à 0,2 et économisera environ 50 M/s d'instructions CPU »).
- Nettoyer les artefacts d'enregistrement : Chaque enregistrement
xctraceécrit plusieurs Go de traces de noyau transitoires (instruments*.ktrace) et un cache CLI d'Instruments (C/com.apple.dt.InstrumentsCLI) dans le dossier temporaire système par utilisateur ($TMPDIR).scripts/run_trace.shles supprime automatiquement à la sortie (en cas de succès comme d'échec). Lorsque vous exécutezxctracedirectement, nettoyez-les vous-même avant de conclure :Ne terminez jamais une session en laissant des centaines de Go de données d'enregistrement transitoires derrière vous.find "${TMPDIR:-/tmp}" -maxdepth 1 -type f -name 'instruments*.ktrace' -delete 2>/dev/null || true
Le Protocole d'Optimisation en 4 Phases
Phase 2 : Profilage Diagnostique et Attribution
Avant d'écrire du code, mesurez l'état actuel et isolez la cause racine :
# 1. Vérification pré-vol : l'application doit être en cours d'exécution avec sa fenêtre visible
APP_NAME="VotreApp"
pgrep -x "$APP_NAME" || { echo "[ERREUR] $APP_NAME n'est pas en cours d'exécution. Lancez-la d'abord."; exit 1; }
# SKILL_DIR = le répertoire d'installation de cette compétence (ajustez si installée ailleurs)
SKILL_DIR="$HOME/.claude/skills/macos-trace"
# 2. Enregistrer 60s de ligne de base au repos (charge de travail en pause, fenêtre visible)
# run_trace.sh résout lui-même le nom du processus en un PID
"$SKILL_DIR/scripts/run_trace.sh" --process "$APP_NAME" --template power --duration 60s --label "01-baseline"
# 3. Déclencher la charge de travail dans l'application, enregistrer l'état actif
"$SKILL_DIR/scripts/run_trace.sh" --process "$APP_NAME" --template power --duration 60s --label "02-pre-opt"
# 4. Calculer le delta pré-optimisation
python3 "$SKILL_DIR/scripts/compare_elements.py" \
/tmp/macos-traces/01-baseline-power.xml:"Idle Baseline" \
/tmp/macos-traces/02-pre-opt-power.xml:"Active Pre-Opt"
Utilisez les modèles spécialisés pour attribuer le goulot d'étranglement :
- Exécutez
--template timepour isoler les fonctions chaudes de l'arbre d'appels. - Exécutez
--template allocavecscripts/top_categories.pypour identifier les allocations incontrôlées. - Exécutez
--template hitchespendant le défilement pour isoler les retards de rendu par rapport aux retards de commit.
Phase 3 : Modification de Code Ciblée
Appliquez des corrections minimales et chirurgicales basées sur les résultats :
- Threads audio en temps réel allouant de la mémoire tas ? Remplacez par des tampons en anneau sans verrou pré-alloués.
- IPC WebKit saturé ? Limitez les mises à jour d'état et passez aux animations CSS transform.
- Fragment shader Metal surdessinant sur Retina ? Ajoutez un changement d'échelle de résolution dynamique ou mettez en pause les boucles de rendu hors écran.
- Pics de décodage d'images haute résolution ? Adoptez le sous-échantillonnage
CGImageSourceCreateThumbnailAtIndex.
Reconstruisez l'application.
Phase 4 : Re-Test, Revue Quantitative et Porte de Décision
Relancez le profil dans des conditions identiques et évaluez le delta :
# 1. Enregistrer la charge de travail active post-optimisation
"$SKILL_DIR/scripts/run_trace.sh" --process "$APP_NAME" --template power --duration 60s --label "03-post-opt"
# 2. Comparer Pré-Opt vs Post-Opt par rapport à la Ligne de Base
python3 "$SKILL_DIR/scripts/compare_elements.py" \
/tmp/macos-traces/01-baseline-power.xml:"Idle Baseline" \
/tmp/macos-traces/02-pre-opt-power.xml:"Active Pre-Opt" \
/tmp/macos-traces/03-post-opt-power.xml:"Active Post-Opt"
Exemple de Sortie de Décision :
Scénario Sec CPU Avg CPU Max Affichage GPU Avg Instr Total Instr M/s
============================================================================================
Idle Baseline 60 0.15 0.80 0.05 0.00 1.02G 17.0
Active Pre-Opt 60 2.40 4.80 1.10 1.50 16.20G 270.0
Active Post-Opt 60 0.65 1.20 0.25 0.10 4.80G 80.0
--------------------------------------------------------------------------------------------
Delta vs Ligne de Base [Idle Baseline] :
Active Pre-Opt +253.0 M/s d'instructions, Delta CPU Moyen +2.25
Active Post-Opt +63.0 M/s d'instructions, Delta CPU Moyen +0.50
Porte de Décision :
- Si la cible est atteinte (par exemple, le taux d'instructions est passé de 270 M/s à 80 M/s, satisfaisant l'objectif < 100 M/s) : Présentez le rapport avant/après empirique à l'utilisateur et concluez.
- Si la cible n'est pas atteinte : Isolez le goulot d'étranglement restant et commencez le cycle d'itération suivant.
Nettoyage Post-Rapport : Après que l'utilisateur a accepté le rapport d'optimisation final, supprimez les bundles .trace accumulés sous /tmp/macos-traces/ (chacun peut faire des dizaines de Go) sauf si l'utilisateur demande explicitement de les conserver. Le tableau de comparaison finalisé et les exportations .xml montrés dans le rapport sont une preuve suffisante.
Référence CLI Directe
# Attacher à un processus en cours d'exécution
xcrun xctrace record \
--template 'Power Profiler' \
--time-limit 60s \
--output /tmp/macos-traces/power.trace \
--attach $PID
# Exporter la table d'Impact d'Alimentation (instructions, CPU, GPU, affichage)
xcrun xctrace export \
--input /tmp/macos-traces/power.trace \
--xpath "/trace-toc/run[@number='1']/data/table[@schema='ProcessSubsystemPowerImpact']" \
> /tmp/macos-traces/power.xml
# Exporter la table récapitulative des Allocations
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
Référence des Modèles
Modèles Instruments pris en charge par scripts/run_trace.sh et xctrace sans tête :
Calcul et Énergie
| Modèle | Nom Court | Métriques Cibles & Schéma d'Exportation | Cas d'Utilisation |
|---|---|---|---|
Power Profiler | power | Instructions/s (M/s), impacts énergétiques CPU/GPU/Affichage (ProcessSubsystemPowerImpact). | Benchmarking A/B objectif et tests d'efficacité énergétique. |
Time Profiler | time | Poids des échantillons CPU par thread, points chauds de l'arbre d'appels, méthodes bloquantes du thread principal. | Utilisation CPU élevée, threads incontrôlés et chemins de fonctions chaudes. |
CPU Counters | counters | IPC (instructions par cycle), échecs de cache L1/L2, prédictions de branchement erronées. | Goulots d'étranglement de performance de calcul et d'algorithmes DSP de bas niveau. |
Réactivité et Fluidité de l'Interface Utilisateur
| Modèle | Nom Court | Métriques Cibles & Schéma d'Exportation | Cas d'Utilisation |
|---|---|---|---|
Animation Hitches | hitches | Durée des saccades (ms), ratio de saccades (ms/s), images perdues, latence de phase application vs rendu. | Saccades de défilement, images d'animation perdues et retards de commit CoreAnimation. |
SwiftUI | swiftui | Évaluations du corps de la vue, comptes d'invalidation d'État, fréquence de mise à jour de la vue. | Réévaluations de vue inutiles et cascades d'invalidation d'État. |
Metal System Trace | metal | Temps de l'encodeur GPU, durées des shaders de vertex/fragment, latence de limite de trame. | Goulots d'étranglement d'exécution du shader, surcharge des effets de particules et blocages du pipeline de rendu. |
Mémoire et Allocations
| Modèle | Nom Court | Métriques Cibles & Schéma d'Exportation | Cas d'Utilisation |
|---|---|---|---|
Allocations | alloc | Allocations tas, mémoire transitoire vs persistante, taux d'événements par catégorie (all-allocations-summary). | Allocations temporaires à haute fréquence, pics de mémoire et gaspillage de tampons. |
Leaks | leaks | Fuites mémoire retenues qui survivent au cycle de vie parent, cycles de référence. | Mémoire abandonnée, fuites de capture de fermeture et cycles de délégué non libérés. |
Démarrage et Concurrence
| Modèle | Nom Court | Métriques Cibles & Schéma d'Exportation | Cas d'Utilisation |
|---|---|---|---|
App Launch | launch | Temps jusqu'à la première trame, temps de chargement dyld, initialiseurs statiques, configuration de la boucle d'exécution. | Optimisation du démarrage à froid (--launch -- <chemin_binaire>). |
Swift Concurrency | concurrency | Tâches Swift (créées/en cours d'exécution/suspendues), réentrance d'acteur, utilisation du pool coopératif. | Famine async/await, contention d'acteur et tâches longtemps suspendues. |
System Trace | sys | Transitions d'état de thread (Running |