iOS-Trace : Optimisation Autonome des Performances d'Applications
iOS-Trace est un moteur d'optimisation de performances en boucle fermée pour les applications iOS et iPadOS fonctionnant sur des appareils physiques iPhone/iPad et des simulateurs iOS locaux (SwiftUI, UIKit, Metal, CoreAudio / AVAudioEngine, et réseau URLSession).
L'objectif principal 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 objectifs de performance soient vérifiés par des données empiriques.
+-------------------------------------------------------------------------+
| La Boucle d'Optimisation Autonome |
| |
| 1. Alignement des Objectifs ──> 2. Trace Diagnostique ──> 3. Correction de Code Ciblée |
| ^ │ |
| │ ▼ |
| └────── Itération si l'Objectif n'est pas Atteint <── 4. Vérification par Re-test |
+-------------------------------------------------------------------------+
Phase 1 : Alignement des Objectifs Utilisateur (Questionnaire Pré-Vol)
Avant de modifier le code ou de collecter des traces sur des appareils mobiles, l'agent doit s'aligner avec l'utilisateur sur les cibles d'optimisation et les critères de succès.
Interaction avec Outil Modal vs Conversation
- Si votre plateforme d'agent fournit un outil de questionnaire/modal interactif (par exemple,
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, posez directement la question à 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 la décharge de la batterie, l'utilisation du CPU et le throttling thermique.
- Option B : Réduire l'empreinte mémoire, les pics d'allocation transitoires, ou prévenir les crashs Jetsam OOM.
- Option C : Éliminer le bégaiement des trames UI et les animations perdues (Hitches ProMotion 120Hz).
- Option D : Accélérer le temps de lancement à froid de l'application mobile.
- Option E : Optimiser la surcharge radio réseau et l'efficacité des requêtes par lots.
-
Cibles de Performance Spécifiques (Fournir des Valeurs par Défaut Recommandées) :
- Cibles Batterie et CPU :
- Cible de Référence au Repos : < 15 M/s d'instructions, Impact CPU < 0,3.
- Cible de Charge de Travail Active : < 80 M/s d'instructions (ou spécifier : réduire de 30% à 50%).
- Cibles Mémoire et Jetsam :
- RAM Résidente Maximale : Limiter à < 150 Mo (utilitaires standard) ou < 300 Mo (applications multimédia/interactives riches).
- Taux d'Événements d'Allocation : < 400 événements/s pendant une interaction stable.
- Fuites Mémoire : Exactement 0 fuites persistantes.
- Cibles de Fluidité UI et Taux de Trames :
- Ratio de Hitch : < 5,0 ms/s (acceptable), < 1,0 ms/s (fluide / grade ProMotion 120Hz).
- Durée Maximale de Hitch : < 16,6 ms (60 Hz) ou < 8,33 ms (120 Hz).
- Cibles de Temps de Lancement :
- Temps jusqu'à la Première Trame : < 400 ms (excellent), < 800 ms (acceptable).
- Cibles Réseau et Radio :
- Surcharge Radio : Regrouper les pings périodiques en requêtes par lots uniques pour éviter la puissance de veille de la queue radio.
- Cibles Batterie et CPU :
-
Scénario Utilisateur de Benchmark :
- Demandez à l'utilisateur quel écran spécifique, quelle interaction utilisateur, quel appareil physique ou simulateur benchmarker.
Une fois les cibles confirmées, passez à la Phase 2.
Portée et Prérequis
- Plateformes cibles : Applications iOS et iPadOS fonctionnant sur des appareils physiques iPhone/iPad connectés via USB ou réseau local, ou des simulateurs iOS locaux. (Pour les applications de bureau macOS, utilisez macOS-Trace).
- Système hôte : macOS 12+ fonctionnant sur Apple Silicon ou Intel Mac avec Xcode complet ou les outils en ligne de commande Xcode (
xcode-select -p,xcrun xctrace version). - Préparation de l'appareil :
- L'iPhone/iPad physique doit être déverrouillé et approuvé par le Mac hôte.
- L'appareil doit apparaître sous
== Devices ==(pas== Devices Offline ==) lors de l'exécution dexcrun xctrace list devices. - Le verrouillage automatique doit être réglé sur "Jamais" ou l'écran maintenu allumé pendant les enregistrements pour empêcher iOS de suspendre les processus en arrière-plan.
- Python : Python 3.8+ sur le Mac hôte (utilise uniquement la bibliothèque standard ; zéro dépendance pip externe).
- Entitlements de processus : Les builds de débogage ou les builds provisionnés par le développeur avec l'entitlement
get-task-allowsont requis pour--attach <PID>.
Règles pour les Agents
Suivez ces règles non négociables lors du profilage automatisé :
- Vérifier l'état de connexion de l'appareil : Exécutez toujours
xcrun xctrace list devicesavant d'enregistrer. Ne tentez jamais d'enregistrer sur un appareil listé sous== Devices Offline ==. - Empêcher le verrouillage de l'écran et la mise en arrière-plan : Si l'appareil iOS se verrouille ou retourne à l'écran d'accueil, iOS suspend ou réduit le processus, produisant des mesures invalides. Gardez l'appareil allumé et l'application au premier plan.
- Établir une référence d'abord : N'enregistrez jamais seulement la charge de travail active. Capturez toujours une exécution de référence au repos (application au premier plan, écran allumé, charge de travail en pause) avant d'enregistrer l'état actif. Calculez :
Delta = Actif - Référence. - Utiliser des paramètres de test égaux : Comparez les exécutions avec des durées d'échantillonnage identiques (par défaut :
60s), des états de batterie identiques (évitez le profilage en dessous de 20% de batterie ou en mode faible consommation), et des données d'entrée de test identiques. - Aucune dépendance Python tierce : Tous les scripts fournis (
scripts/compare_elements.py,scripts/parse_power.py,scripts/top_categories.py) utilisent uniquement la bibliothèque standard de Python 3. - Enregistrer les sorties dans
/tmp/ios-traces/: Stockez tous les bundles.traceet les exports.xmldans/tmp/ios-traces/avec des noms de fichiers horodatés et tagués par scénario. - Protéger le budget de contexte de la conversation : Les fichiers de trace et les documents XML bruts exportés peuvent faire des dizaines ou des centaines de mégaoctets. Ne jetez jamais les sorties
.tracebrutes, les arbres d'appels complets, ou les XML d'allocations non parsés dans le contexte de la 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 minuterie à haute fréquence, E/S non tamponnées) 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 flou/matériaux, animations de trames, ombres, transitions de mise en page) ou un comportement logiciel essentiel :
- Ne supprimez pas ou ne dégradez pas unilatéralement la fonctionnalité visuelle.
- Demandez formellement la permission à l'utilisateur d'abord (en utilisant une invite interactive ou un message de discussion 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 de l'ombre dynamique et du flou sur les vues de carte réduira l'impact GPU moyen de 1,8 à 0,2 et éliminera les accrocs ProMotion 120Hz").
- 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 derrière vous des centaines de Go de données d'enregistrement transitoires.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 sur l'appareil et isolez la cause racine :
# 1. Confirmer que l'appareil cible est en ligne et déverrouillé (vérification optionnelle ;
# run_trace.sh détecte automatiquement le premier iPhone/iPad connecté lorsque --device est omis)
xcrun xctrace list devices
BUNDLE_ID="com.example.MyApp"
# SKILL_DIR = répertoire d'installation de cette compétence (ajuster si installé ailleurs)
SKILL_DIR="$HOME/.claude/skills/ios-trace"
# 2. Enregistrer 60s de référence au repos (appareil déverrouillé, application au premier plan, charge de travail en pause)
"$SKILL_DIR/scripts/run_trace.sh" \
--bundle-id "$BUNDLE_ID" \
--template power \
--duration 60s \
--label "01-baseline"
# 3. Déclencher la charge de travail cible dans l'application, enregistrer l'état actif
"$SKILL_DIR/scripts/run_trace.sh" \
--process "MyApp" \
--template power \
--duration 60s \
--label "02-pre-opt"
# 4. Calculer le delta pré-optimisation
python3 "$SKILL_DIR/scripts/compare_elements.py" \
/tmp/ios-traces/01-baseline-power.xml:"Idle Baseline" \
/tmp/ios-traces/02-pre-opt-power.xml:"Active Pre-Opt"
Utilisez les templates spécialisés pour attribuer le goulot d'étranglement :
- Exécutez
--template timepour isoler les fonctions chaudes de l'arbre d'appels sur les threads de travail. - Exécutez
--template allocavecscripts/top_categories.pypour identifier les allocations excessives provoquant une pression mémoire. - Exécutez
--template hitchespendant le défilement pour isoler les retards de rendu par rapport aux retards de validation sur les écrans ProMotion. - Exécutez
--template networkpour détecter les réveils radio continus non regroupés.
Phase 3 : Modification de Code Ciblée
Appliquez des corrections minimales et chirurgicales basées sur les résultats :
- Pics de Mémoire et Jetsam : Adoptez le sous-échantillonnage pour les images haute résolution avec
CGImageSourceCreateThumbnailAtIndexau lieu de charger desUIImageen taille réelle. - Accrocs ProMotion : Supprimez les ombres complexes et les passes de composition hors écran ; déchargez les calculs de mise en page lourds de la vue du thread principal.
- Surcharge Énergétique Radio : Regroupez les requêtes réseau périodiques en rafales de charge utile unifiées pour éliminer la puissance de veille de la queue radio.
- Audio Temps Réel : Assurez zéro allocation de tas dans les callbacks de rendu CoreAudio (
AVAudioEngineou RemoteIO).
Reconstruisez l'application et déployez-la sur l'appareil.
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 "MyApp" \
--template power \
--duration 60s \
--label "03-post-opt"
# 2. Comparer Pré-Opt vs Post-Opt par rapport à la Référence
python3 "$SKILL_DIR/scripts/compare_elements.py" \
/tmp/ios-traces/01-baseline-power.xml:"Idle Baseline" \
/tmp/ios-traces/02-pre-opt-power.xml:"Active Pre-Opt" \
/tmp/ios-traces/03-post-opt-power.xml:"Active Post-Opt"
Exemple de Tableau de Décision :
Scénario Sec CPU Avg CPU Max Display GPU Avg Total Instr Instr M/s WiFi Tx/Rx
=========================================================================================================
Idle Baseline 60 0.12 0.60 0.05 0.00 0.85G 14.2 0.0/0.0MB
Active Pre-Opt 60 2.40 4.80 1.10 1.80 15.60G 260.0 14.2/1.8MB
Active Post-Opt 60 0.55 1.10 0.15 0.20 4.20G 70.0 2.1/0.4MB
---------------------------------------------------------------------------------------------------------
Différentiel vs Référence [Idle Baseline]:
Active Pre-Opt +245.8 M/s instructions, CPU Avg Delta +2.28, WiFi Tx Delta +14.20MB
Active Post-Opt +55.8 M/s instructions, CPU Avg Delta +0.43, WiFi Tx Delta +2.10MB
Delta d'Optimisation (Post-Opt vs Pré-Opt):
Débit d'instructions : -73.1% (70.0 vs 260.0 M/s)
Impact CPU Moyen : -77.1% (0.55 vs 2.40)
Impact GPU Moyen : -88.9% (0.20 vs 1.80)
Trafic Radio WiFi : -85.2% (2.1MB vs 14.2MB)
Logique de la Porte de Décision :
- Objectif Atteint : Présentez le tableau de comparaison empirique à l'utilisateur et concluez.
- Objectif Non Atteint : Conservez l'optimisation précédente, isolez le prochain point chaud restant, et répétez les Phases 3 et 4.
Nettoyage Post-Rapport : Une fois que l'utilisateur a accepté le rapport d'optimisation final, supprimez les bundles .trace accumulés sous /tmp/ios-traces/ (chacun peut faire des dizaines de Go) à moins que l'utilisateur ne demande explicitement de les conserver. Le tableau de comparaison finalisé et les exports .xml montrés dans le rapport sont une preuve suffisante.
Commandes CLI Directes
Si vous exécutez xctrace directement sans run_trace.sh :
Enregistrement
# Attacher à une application en cours d'exécution sur l'appareil
xcrun xctrace record \
--device <DEVICE_UDID> \
--template 'Power Profiler' \
--time-limit 60s \
--output /tmp/ios-traces/power.trace \
--attach <PID>
# Lancer à froid une application sur l'appareil
xcrun xctrace record \
--device <DEVICE_UDID> \
--template 'Time Profiler' \
--time-limit 30s \
--output /tmp/ios-traces/launch.trace \
--launch -- com.example.MyApp <LaunchArgs>
Export
# Exporter le tableau d'impact énergétique (instructions CPU, énergie, GPU, Display, WiFi/Cellular)
xcrun xctrace export \
--input /tmp/ios-traces/power.trace \
--xpath "/trace-toc/run[@number='1']/data/table[@schema='ProcessSubsystemPowerImpact']" \
> /tmp/ios-traces/power.xml
# Exporter le tableau récapitulatif des allocations
xcrun xctrace export \
--input /tmp/ios-traces/alloc.trace \
--xpath "/trace-toc/run[@number='1']/data/table[@schema='all-allocations-summary']" \
> /tmp/ios-traces/alloc.xml
Référence des Templates
Templates Instruments supportés sur iOS via scripts/run_trace.sh et xctrace sans tête :
Calcul, Batterie et Énergie
| Template | Nom Court | Métriques Cibles et Schéma d'Export | Cas d'Utilisation |
|---|---|---|---|
Power Profiler | power | Instructions/s (M/s), impacts énergétiques CPU/GPU/Display/WiFi/Cellular (ProcessSubsystemPowerImpact). | Décharge complète de la batterie, throttling thermique, et benchmarks A/B complets. |
Time Profiler | time | Poids d'échantillonnage CPU par thread, points chauds de l'arbre d'appels, méthodes bloquantes du thread principal. | Utilisation CPU élevée, threads de travail incontrôlés, et chemins de fonction chauds. |
CPU Counters | cpu | Compteurs de performance du processeur (cycles, instructions, échecs de cache). | Analyse approfondie de l'efficacité du pipeline CPU et des goulots d'étranglement du microprocesseur. |
Metal System Trace | metal | Charge de travail GPU, étapes de rendu, encodage de commandes, configuration du pipeline de shaders. | Optimisation du rendu Metal, identification des surcharges de shaders, et goulots d'étranglement du pipeline de trames. |
Mémoire
| Template | Nom Court | Métriques Cibles et Schéma d'Export | Cas d'Utilisation |
|---|---|---|---|
Allocations | alloc | Événements d'allocation mémoire par classe et catégorie (all-allocations-summary). | Pics de mémoire Jetsam, allocations fréquentes et fuites persistantes. |
Leaks | leaks | Diagnostics de fuite mémoire (leaks-snapshot, leaks-log). | Fuites mémoire de longue durée dans les applications à état stable. |
VM Tracker | vm | Cartographie de la mémoire virtuelle, pages sales, et pression mémoire au niveau du système. | Fragmentation de la mémoire VM, surcharge de dirty memory, et empreinte mémoire partagée. |
UI et Expérience Utilisateur
| Template | Nom Court | Métriques Cibles et Schéma d'Export | Cas d'Utilisation |
|---|---|---|---|
Core Animation Hitches | hitches | Ratio d'accrocs, durée maximale d'accroc, catégories de causes (hitches-timeline). | Stuttering UI, défilement ProMotion 120Hz, et retards d'animation de trame. |
Animation Hitches | anim | Accrocs d'animation CoreAnimation, retards de commit vs rendu. | Diagnostics des accrocs d'animation dans SwiftUI et UIKit. |
Hang Tracing | hang | Diagnostics de blocage de l'interface utilisateur et phénomènes de spinning. | Blocages UI, applications sans réponse, et opérations bloquantes du thread principal. |
Réseau
| Template | Nom Court | Métriques Cibles et Schéma d'Export | Cas d'Utilisation |
|---|---|---|---|
Network | network | Paquets radio WiFi/Cellular, transferts de données, et durée de la queue radio (network-activity). | Surcharge de la radio réseau, consommation de données en arrière-plan, et regroupement de requêtes. |
Connection Logging | conn | Connexions TCP/UDP, résolutions DNS, et établissements TLS. | Diagnostics de connexion réseau et optimisation des latences. |
Audio
| Template | Nom Court | Métriques Cibles et Schéma d'Export | Cas d'Utilisation |
|---|---|---|---|
Audio Trace | audio | Profilage audio à haute résolution, chronogrammes des signaux audio, et suivi des sessions audio. | Optimisation de la latence du pipeline audio, allocations dans les callbacks de rendu, et saturation du moteur audio. |
Référence des Scripts
Tous les scripts sont situés sous le répertoire scripts/ de cette compétence.
scripts/run_trace.sh
Enregistre, exporte et nettoie les traces en une seule commande de commodité.
Utilisation :
# Enregistrer en utilisant le bundle-id
./scripts/run_trace.sh \
--bundle-id com.example.MyApp \
--template "power" \
--duration 60s \
--label "mon-scenario"
# Enregistrer en utilisant le nom du processus
./scripts/run_trace.sh \
--process "MyApp" \
--template "alloc" \
--duration 30s \
--device <DEVICE_UDID>
scripts/compare_elements.py
Analyse les fichiers XML exportés pour produire un tableau de comparaison et des deltas d'optimisation.
Utilisation :
# Comparer deux ou plusieurs exécutions
python3 scripts/compare_elements.py \
/tmp/ios-traces/baseline.xml:"Repos" \
/tmp/ios-traces/opt1.xml:"Optimisation 1" \
/tmp/ios-traces/opt2.xml:"Optimisation 2"
scripts/top_categories.py
Analyse le XML d'allocations pour identifier les catégories avec le volume d'allocations le plus élevé.
Utilisation :
python3 scripts/top_categories.py /tmp/ios-traces/alloc.xml
scripts/parse_power.py
Parse et affiche les métriques détaillées d'impact énergétique (par sous-système).
Utilisation :
python3 scripts/parse_power.py /tmp/ios-traces/power.xml
Dépannage et FAQ
Q : xcrun xctrace échoue avec "Failed to locate device" ?
R : Vérifiez la connexion USB, l'appairage WiFi, et que l'appareil est déverrouillé. Exécutez xcrun xctrace list devices et confirmez que l'UDID apparaît sous == Devices == (pas == Devices Offline ==).
Q : "Process not found" lors de la tentative d'attachement ?
R : Assurez-vous que l'application est en cours d'exécution (sur le simulateur ou l'appareil physique). Pour les builds de débogage, assurez-vous que l'entitlement get-task-allow est présent. Pour les builds de test, utilisez --launch -- com.example.MyApp pour lancer à froid depuis Instruments.
Q : Les mesures de l'appareil physique sont nettement plus élevées que sur le simulateur ?
R : C'est attendu et normal. Les simulateurs fonctionnent sur le matériel Mac et ne reflètent pas les coûts CPU et énergétiques réels de iOS. Profitez toujours sur des appareils physiques pour la validation finale. Utilisez run_trace.sh avec --template power et comparez les deltas.
Q : Comment empêcher l'appareil iOS de se verrouiller pendant un enregistrement long ?
R : Définissez Verrouillage automatique sur "Jamais" (Réglages > Affichage & Luminosité > Verrouillage automatique). Sinon, maintenez l'interaction tactile ou utilisez un outil comme caffeinate sur l'hôte pour maintenir l'éveil (bien que cela n'affecte pas directement iOS). Note : sur iOS, les sessions xctrace maintiennent automatiquement l'éveil de l'appareil, mais une interaction supplémentaire avec l'écran peut être nécessaire pour les enregistrements les plus longs.
Q : scripts/run_trace.sh ne génère pas de fichier .xml ?
R : Vérifiez que vous avez exécuté xcode-select --install ou que le chemin Xcode complet est défini. Confirmez que le modèle Instruments sélectionné dispose du schéma d'export attendu. Par exemple, le Power Profiler comprend le schéma ProcessSubsystemPowerImpact. Utilisez le chemin explicite --xpath pour exporter des schémas non standard.
Licence
MIT