macOS-Trace: Autonome Anwendungsleistungsoptimierung
macOS-Trace ist eine Engine zur geschlossenen Leistungsoptimierung für native macOS-Anwendungen (SwiftUI, AppKit, Metal, CoreAudio, WebKit und native Binärdateien).
Das Ziel ist es, die manuelle Interaktion mit dem Instruments-GUI zu eliminieren. Ein KI-Agent kann autonom Leistungsengpässe diagnostizieren, Codeänderungen umsetzen, mit differentiellem Benchmarking nachtesten und iterieren, bis Leistungsziele mit empirischen Daten verifiziert sind.
+-------------------------------------------------------------------------+
| Der Autonome Optimierungszyklus |
| |
| 1. Zielabstimmung ──> 2. Diagnostisches Tracing ──> 3. Gezielte Code-Korrektur |
| ^ │ |
| │ ▼ |
| └────── Iteration, falls Ziel nicht erreicht <── 4. Erneuter Test (Verifizierung) |
+-------------------------------------------------------------------------+
Phase 1: Benutzerzielabstimmung (Fragebogen vor der Aufnahme)
Bevor Code geändert oder Traces erfasst werden, muss sich der Agent mit dem Benutzer über Optimierungsziele und Erfolgskriterien abstimmen.
Modales Tool vs. Chat-Interaktion
- Wenn Ihre Agentenplattform ein interaktives Fragebogen-/Modaltool bereitstellt (z. B.
ask_question, Eingabedialoge oder auswählbare Optionslisten), verwenden Sie es, um diese Auswahlmöglichkeiten sauber darzustellen. - Wenn kein modales Tool verfügbar ist, fragen Sie den Benutzer direkt im Gespräch mit strukturierten Optionen und konkreten empfohlenen Werten.
Fragen an den Benutzer
- Primäres Optimierungsziel:
- Option A: CPU-Auslastung, Stromverbrauch und thermische Drosselung reduzieren.
- Option B: Speicher-Fußabdruck, vorübergehende Allokationsspitzen senken oder Lecks beseitigen.
- Option C: UI-Frame-Ruckler und verworfene Animationsframes (Hitches) beseitigen.
- Option D: Kaltstartzeit der Anwendung beschleunigen.
- Spezifische Leistungsziele (mit empfohlenen Standardwerten):
- CPU-/Energieziele:
- Leerlauf-Baseline-Ziel: < 20 M/s Anweisungen, CPU-Auswirkung < 0,5.
- Aktives Workload-Ziel: < 100 M/s Anweisungen (oder angeben: Reduzierung um 30% - 50%).
- Speicherziele:
- Maximaler Resident-RAM: Begrenzung auf < 150 MB (Dienstprogramme/Audio) oder < 300 MB (Medien/reichhaltige UI).
- Allokationsrate: < 500 Ereignisse/Sek. während des stationären Betriebs.
- Speicherlecks: Genau 0 permanente Lecks.
- UI-Glätteziele:
- Hitch-Verhältnis: < 5,0 ms/s (akzeptabel), < 1,0 ms/s (flüssig/keine verworfenen Frames).
- Startzeitziele:
- Zeit bis zum ersten Frame: < 400 ms (ausgezeichnet), < 800 ms (akzeptabel).
- CPU-/Energieziele:
- Benchmark-Benutzerszenario:
- Fragen Sie den Benutzer, welcher spezifische Bildschirm, welche Benutzerinteraktion oder welcher Workload gemessen werden soll.
Sobald die Ziele bestätigt sind, fahren Sie mit Phase 2 fort.
Umfang und Voraussetzungen
- Zielplattform: Nur native macOS-Desktop-Anwendungen (SwiftUI, AppKit, Metal, CoreAudio / AVAudioEngine, WebKit-Host-Views, native CLI-Executables). Unterstützt keine iOS-Simulatoren, entfernte Mobilgeräte oder reine Browser-Web-Apps.
- Xcode-Tooling: Erfordert macOS 12+ und vollständiges Xcode oder Xcode-Befehlszeilentools (
xcode-select -p,xcrun xctrace version). - Python: Python 3.8+ (vorinstalliert auf macOS; keine externen pip-Abhängigkeiten).
- Prozessberechtigungen: Debug-Builds oder Binärdateien mit der Berechtigung
get-task-allowsind für--attach <PID>unter Hardened Runtime erforderlich.
Regeln für Agenten
Befolgen Sie diese nicht verhandelbaren Regeln während des automatisierten Profilings:
- Zuerst eine Baseline erstellen: Nehmen Sie niemals nur den aktiven Workload auf. Erfassen Sie immer eine Leerlauf-Baseline (App im Vordergrund geöffnet, Workload pausiert), bevor Sie den aktiven Zustand aufzeichnen. Berechnung:
Delta = Aktiv - Baseline. - Zielzustand vor der Aufnahme verifizieren: Überprüfen Sie, dass der Prozess mit
pgrep -x <Prozessname>existiert und dass die Zielfunktion während des Aufzeichnungsfensters aktiv ausgeführt wird. - Fenster im Vordergrund halten: macOS drosselt Rendering und Display-Links für verdeckte oder minimierte Fenster (
NSWindowOcclusionState). Ein verdecktes Fenster erzeugt fälschlich niedrige GPU- und CPU-Werte. - Gleiche Testparameter verwenden: Vergleichen Sie Läufe mit identischer Beispieldauer (Standard:
60s), identischen Anzeigeskalierungen, identischen Fenstergrößen und identischen Testeingabedaten. Vergleichen Sie niemals einen Debug-Build mit einem Release-Build. - Keine Python-Abhängigkeiten von Drittanbietern: Alle gebündelten Skripte (
scripts/compare_elements.py,scripts/parse_power.py,scripts/top_categories.py) verwenden nur die Python 3-Standardbibliothek. Installieren Sie keine pip-Pakete. - Ausgaben in
/tmp/macos-traces/speichern: Speichern Sie alle.trace-Bündel und.xml-Exporte in/tmp/macos-traces/mit Zeitstempel- und Szenario-gekennzeichneten Dateinamen. - Konversationskontext-Budget schützen: Trace-Dateien und rohe exportierte XML-Dokumente können dutzende oder hunderte Megabyte groß sein. Geben Sie niemals rohe
.trace-Ausgaben, vollständige Call-Trees oder ungeparste Allocations-XML in den Kontext der Agentenkonversation. Verwenden Sie immer die gebündelten Python-Skripte, um die Daten zu streamen, zu filtern, zu ordnen und zusammenzufassen, bevor Sie sie lesen. - Auf primäre Engpässe konzentrieren: Streuen Sie keine Mikrooptimierungen über dutzende harmlose Hilfsfunktionen. Erstellen Sie zuerst ein Profil, um den dominanten Beitrag (z. B. redundante Surface-Instanzen, Timer-Neuauswertungen mit hoher Frequenz, ungepufferte E/A) zu bestätigen, und konzentrieren Sie Optimierungen ausschließlich auf diese Grundursache.
- UI, visuelle Effekte oder Kernverhalten niemals stillschweigend ändern: Wenn ein Leistungsengpass die visuelle Wiedergabetreue (wie Unschärfe/Glas-Materialien, Frame-Animationen, Schatten, Layout-Übergänge) oder wesentliches Softwareverhalten betrifft:
- Entfernen oder verschlechtern Sie die visuelle Funktion nicht einseitig.
- Fragen Sie den Benutzer zuerst formell um Erlaubnis (mit einer interaktiven Eingabeaufforderung oder expliziten Chat-Nachricht).
- Artikulieren Sie den Kompromiss klar: Beschreiben Sie die visuelle Änderung vorher und nachher, erklären Sie, warum die Funktion Ressourcen verbraucht, und präsentieren Sie den konkreten erwarteten Leistungsgewinn (z. B. „Das Deaktivieren der dynamischen Hintergrundunschärfe reduziert die aktive GPU-Auswirkung von 1,5 auf 0,2 und spart ~50 M/s CPU-Anweisungen“).
- Aufnahme-Artefakte bereinigen: Jede
xctrace-Aufnahme schreibt mehrere GB an transienten Kernel-Traces (instruments*.ktrace) und einen Instruments-CLI-Cache (C/com.apple.dt.InstrumentsCLI) in den systemweiten Benutzer-Temp-Ordner ($TMPDIR).scripts/run_trace.shentfernt diese automatisch beim Beenden (sowohl bei Erfolg als auch bei Fehler). Wenn Siexctracedirekt ausführen, bereinigen Sie diese selbst vor dem Abschluss:Beenden Sie niemals eine Sitzung, während hunderte GB an transienten Aufnahmedaten zurückbleiben.find "${TMPDIR:-/tmp}" -maxdepth 1 -type f -name 'instruments*.ktrace' -delete 2>/dev/null || true
Das 4-Phasen-Optimierungsprotokoll
Phase 2: Diagnostisches Profiling und Ursachenanalyse
Bevor Sie Code schreiben, messen Sie den aktuellen Zustand und isolieren Sie die Grundursache:
# 1. Vorab-Check: Die App muss mit sichtbarem Fenster laufen
APP_NAME="IhreApp"
pgrep -x "$APP_NAME" || { echo "[FEHLER] $APP_NAME läuft nicht. Starten Sie sie zuerst."; exit 1; }
# SKILL_DIR = das Installationsverzeichnis dieser Fähigkeit (anpassen, falls anderswo installiert)
SKILL_DIR="$HOME/.claude/skills/macos-trace"
# 2. 60s Leerlauf-Baseline aufnehmen (Workload pausiert, Fenster sichtbar)
# run_trace.sh löst den Prozessnamen selbst in eine PID auf
"$SKILL_DIR/scripts/run_trace.sh" --process "$APP_NAME" --template power --duration 60s --label "01-baseline"
# 3. Workload in der App auslösen, aktiven Zustand aufnehmen
"$SKILL_DIR/scripts/run_trace.sh" --process "$APP_NAME" --template power --duration 60s --label "02-pre-opt"
# 4. Vor-Optimierungs-Delta berechnen
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"
Verwenden Sie die spezialisierten Vorlagen, um den Engpass zu identifizieren:
- Führen Sie
--template timeaus, um heiße Call-Tree-Funktionen zu isolieren. - Führen Sie
--template allocmitscripts/top_categories.pyaus, um übermäßige Allokationen zu identifizieren. - Führen Sie
--template hitcheswährend des Scrollens aus, um Verzögerungen bei Render- vs. Commit-Phasen zu isolieren.
Phase 3: Gezielte Code-Modifikation
Wenden Sie minimale, chirurgische Korrekturen basierend auf den Ergebnissen an:
- Echtzeit-Audio-Threads, die Heap-Speicher allokieren? Ersetzen Sie sie durch vorallozierte lockfreie Ringpuffer.
- WebKit-IPC gesättigt? Drosseln Sie Zustandsaktualisierungen und wechseln Sie zu CSS-Transform-Animationen.
- Metal-Fragment-Shader auf Retina überzeichnend? Fügen Sie dynamische Skalierung hinzu oder pausieren Sie Offscreen-Render-Loops.
- Spitzen bei der Dekodierung hochauflösender Bilder? Verwenden Sie
CGImageSourceCreateThumbnailAtIndex-Downsampling.
Erstellen Sie die Anwendung neu.
Phase 4: Erneuter Test, quantitative Überprüfung und Entscheidungstor
Führen Sie das Profil unter identischen Bedingungen erneut aus und bewerten Sie das Delta:
# 1. Aktiven Workload nach der Optimierung aufnehmen
"$SKILL_DIR/scripts/run_trace.sh" --process "$APP_NAME" --template power --duration 60s --label "03-post-opt"
# 2. Vor-Optimierung vs. Nach-Optimierung gegen Baseline vergleichen
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"
Beispiel für Entscheidungsausgabe:
Szenario Sek. CPU Avg CPU Max Display GPU Avg Gesamt-Instr. Instr. M/s
============================================================================================
Idle Baseline 60 0,15 0,80 0,05 0,00 1,02 G 17,0
Active Pre-Opt 60 2,40 4,80 1,10 1,50 16,20 G 270,0
Active Post-Opt 60 0,65 1,20 0,25 0,10 4,80 G 80,0
--------------------------------------------------------------------------------------------
Differential vs. Baseline [Idle Baseline]:
Active Pre-Opt +253,0 M/s Anweisungen, CPU Avg Delta +2,25
Active Post-Opt +63,0 M/s Anweisungen, CPU Avg Delta +0,50
Entscheidungstor:
- Wenn Ziel erreicht (z. B. Anweisungsrate von 270 M/s auf 80 M/s gesunken, was das < 100 M/s-Ziel erfüllt): Präsentieren Sie dem Benutzer den Vorher/Nachher-empirischen Bericht und schließen Sie ab.
- Wenn Ziel nicht erreicht: Isolieren Sie den verbleibenden Engpass und beginnen Sie den nächsten Iterationszyklus.
Bereinigung nach dem Bericht: Nachdem der Benutzer den endgültigen Optimierungsbericht akzeptiert hat, löschen Sie die angesammelten .trace-Bündel unter /tmp/macos-traces/ (jedes kann dutzende GB groß sein), es sei denn, der Benutzer bittet explizit darum, sie zu behalten. Die im Bericht gezeigte finalisierte Vergleichstabelle und die .xml-Exporte sind ausreichende Nachweise.
Direkte CLI-Referenz
# An einen laufenden Prozess anhängen
xcrun xctrace record \
--template 'Power Profiler' \
--time-limit 60s \
--output /tmp/macos-traces/power.trace \
--attach $PID
# Tabelle der Energieauswirkungen exportieren (Anweisungen, CPU, GPU, Display)
xcrun xctrace export \
--input /tmp/macos-traces/power.trace \
--xpath "/trace-toc/run[@number='1']/data/table[@schema='ProcessSubsystemPowerImpact']" \
> /tmp/macos-traces/power.xml
# Zusammenfassungstabelle der Allokationen exportieren
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
Vorlagen-Referenz
Von scripts/run_trace.sh und xctrace im Headless-Modus unterstützte Instruments-Vorlagen:
Berechnung & Energie
| Vorlage | Kurzname | Zielmetriken & Exportschema | Anwendungsfall |
|---|---|---|---|
Power Profiler | power | Anweisungen/Sek. (M/s), CPU/GPU/Display-Energieauswirkungen (ProcessSubsystemPowerImpact). | Objektives A/B-Benchmarking und Energieeffizienztests. |
Time Profiler | time | CPU-Sample-Gewichte nach Thread, Call-Tree-Hotspots, Main-Thread-blockierende Methoden. | Hohe CPU-Auslastung, entlaufene Threads und heiße Funktionspfade. |
CPU Counters | counters | IPC (Anweisungen pro Takt), L1/L2-Cache-Fehlzugriffe, falsche Sprungvorhersagen. | Leistungsengpässe auf niedriger Ebene bei Berechnungs- und DSP-Algorithmen. |
UI-Reaktionsfähigkeit & Glätte
| Vorlage | Kurzname | Zielmetriken & Exportschema | Anwendungsfall |
|---|---|---|---|
Animation Hitches | hitches | Hitch-Dauer (ms), Hitch-Verhältnis (ms/s), Frame-Drops, App- vs. Render-Phasen-Latenz. | Scroll-Ruckler, verworfene Animationsframes und CoreAnimation-Commit-Verzögerungen. |
SwiftUI | swiftui | View-Body-Auswertungen, State-Invalidierungszahlen, View-Aktualisierungshäufigkeit. | Unnötige View-Neuauswertungen und State-Invalidierungskaskaden. |
Metal System Trace | metal | GPU-Encoder-Zeit, Vertex-/Fragment-Shader-Dauern, Frame-Grenzlatenz. | Shader-Ausführungsengpässe, Particle-FX-Overhead und Render-Pipeline-Staus. |
Speicher & Allokationen
| Vorlage | Kurzname | Zielmetriken & Exportschema | Anwendungsfall |
|---|---|---|---|
Allocations | alloc | Heap-Allokationen, transientes vs. persistentes Speicher, Kategorie-Ereignisraten (all-allocations-summary). | Hochfrequente temporäre Allokationen, Speicherspitzen und Pufferüberlastung. |
Leaks | leaks | Behaltene Speicherlecks, die den übergeordneten Lebenszyklus überdauern, Referenzzyklen. | Verlassener Speicher, Closure-Capture-Lecks und nicht freigegebene Delegate-Zyklen. |
Start & Nebenläufigkeit
| Vorlage | Kurzname | Zielmetriken & Exportschema | Anwendungsfall |
|---|---|---|---|
App Launch | launch | Zeit bis zum ersten Frame, dyld-Ladezeit, statische Initialisierer, Runloop-Setup. | Kaltstartoptimierung (--launch -- <binary_path>). |
Swift Concurrency | concurrency | Swift Tasks (erstellt/laufend/ausgesetzt), Actor-Reentranz, Nutzung des kooperativen Pools. | async/await-Aushungerung, Actor-Konflikte und lang ausgesetzte Tasks. |
System Trace | sys | Thread-Zustandsübergänge (Running, Woken, Suspended), Systemaufrufe, Interrupts, Dispatch-Queue- und IO-Throttling. |