macOS-Trace: 自律型アプリケーションパフォーマンス最適化
macOS-Traceは、ネイティブmacOSアプリケーション(SwiftUI、AppKit、Metal、CoreAudio、WebKit、ネイティブバイナリ)向けのクローズドループパフォーマンス最適化エンジンです。
目的は、InstrumentsのGUI操作を排除することです。AIエージェントが自律的に診断、ボトルネックの特定、コード変更の実装、差分ベンチマークによる再テストを行い、パフォーマンス目標が経験データで検証されるまで反復します。
+-------------------------------------------------------------------------+
| 自律最適化ループ |
| |
| 1. 目標調整 ──> 2. 診断トレース ──> 3. 対象を絞ったコード修正 |
| ^ │ |
| │ ▼ |
| └────── 目標未達成の場合は反復 <── 4. 再テストによる検証 |
+-------------------------------------------------------------------------+
フェーズ1: ユーザー目標調整(事前質問)
コードの変更やトレースの収集を行う前に、エージェントは最適化目標と成功基準についてユーザーと合意する必要があります。
モーダルツール vs チャットでの対話
- エージェントプラットフォームがインタラクティブな質問/モーダルツールを提供している場合(例:
ask_question、入力ダイアログ、選択可能なオプションリスト)、それを呼び出してこれらの選択肢を整理してユーザーに提示します。 - モーダルツールが利用できない場合、構造化されたオプションと具体的な推奨値とともに、会話内で直接ユーザーに質問します。
ユーザーに質問する内容
- 最適化の主要目的:
- オプションA: CPU使用率、消費電力、サーマルスロットリングの削減。
- オプションB: メモリフットプリントの低減、一時的なアロケーションスパイクの抑制、リークの解消。
- オプションC: UIフレームのスタッタリングとドロップされたアニメーションフレーム(ヒッチ)の解消。
- オプションD: アプリケーションのコールド起動時間の短縮。
- 具体的なパフォーマンス目標(推奨デフォルト値を提示):
- CPU / エネルギーの目標:
- アイドルベースライン目標: < 20 M/s 命令、CPU インパクト < 0.5。
- アクティブワークロード目標: < 100 M/s 命令(または指定: 30%~50%削減)。
- メモリの目標:
- 最大常駐RAM: < 150 MB(ユーティリティ/オーディオ)または < 300 MB(メディア/リッチUI)に制限。
- アロケーションイベントレート: 定常状態実行中 < 500 イベント/秒。
- メモリリーク: 永続的なリークは正確に0。
- UIの滑らかさの目標:
- ヒッチ比: < 5.0 ms/s(許容範囲)、< 1.0 ms/s(流動的/フレーム落ちなし)。
- 起動時間の目標:
- 最初のフレームが表示されるまでの時間: < 400 ms(優秀)、< 800 ms(許容範囲)。
- CPU / エネルギーの目標:
- ベンチマークユーザーシナリオ:
- ベンチマーク対象の特定の画面、ユーザー操作、またはワークロードをユーザーに尋ねます。
目標が確認されたら、フェーズ2に進みます。
スコープと前提条件
- 対象プラットフォーム: macOSネイティブデスクトップアプリケーションのみ(SwiftUI、AppKit、Metal、CoreAudio / AVAudioEngine、WebKitホストビュー、ネイティブCLI実行可能ファイル)。iOSシミュレーター、リモートモバイルデバイス、外部ブラウザ専用Webアプリはサポートしません。
- Xcodeツール: macOS 12+ およびフルXcodeまたはXcodeコマンドラインツールが必要(
xcode-select -p、xcrun xctrace version)。 - Python: Python 3.8+(macOSにプリインストール済み、外部pip依存関係は不要)。
- プロセス権限: Hardened Runtime下で
--attach <PID>を使用するには、get-task-allowエンタイトルメントを持つデバッグビルドまたはバイナリが必要です。
エージェント向けルール
自動プロファイリング中は、以下の譲歩できないルールに従ってください:
- 最初にベースラインを確立する: アクティブワークロードのみを記録しないでください。アクティブ状態を記録する前に、常にアイドルベースライン(アプリをフォアグラウンドで開き、ワークロードを一時停止した状態)をキャプチャしてください。計算:
差分 = アクティブ - ベースライン。 - 記録前にターゲット状態を確認する:
pgrep -x <プロセス名>を使用してプロセスが存在すること、および記録ウィンドウ中にターゲット機能がアクティブに実行されていることを確認します。 - ウィンドウをフォアグラウンドに保つ: macOSは、隠蔽または最小化されたウィンドウ(
NSWindowOcclusionState)のレンダリングとディスプレイリンクを抑制します。隠蔽されたウィンドウは、誤って低いGPUおよびCPUの読み取り値を生成します。 - 同一のテストパラメータを使用する: 同一のサンプル期間(デフォルト:
60s)、同一の表示スケール、同一のウィンドウサイズ、同一のテスト入力データで実行を比較します。デバッグビルドとリリースビルドを比較しないでください。 - サードパーティのPython依存関係は使用しない: 同梱のスクリプト(
scripts/compare_elements.py、scripts/parse_power.py、scripts/top_categories.py)はPython 3標準ライブラリのみを使用します。pipパッケージをインストールしないでください。 - 出力を
/tmp/macos-traces/に保存する: すべての.traceバンドルと.xmlエクスポートを、タイムスタンプとシナリオタグ付きのファイル名で/tmp/macos-traces/に保存します。 - 会話コンテキストの予算を保護する: トレースファイルと生のエクスポートXMLドキュメントは、数十から数百メガバイトになる可能性があります。生の
.trace出力、完全なコールツリー、または未解析のAllocations XMLをエージェントの会話コンテキストにダンプしないでください。データを読み取る前に、常に同梱のPythonスクリプトを使用してストリーミング、フィルタリング、ランキング、サマリ化を行ってください。 - 主要なボトルネックに集中する: 多くの無関係なユーティリティ関数にマイクロ最適化を分散させないでください。最初にプロファイリングして主要な原因(例:冗長なサーフェスインスタンス、高頻度タイマーの再評価、バッファリングされていないI/O)を確認し、最適化の努力をその根本原因にのみ集中させてください。
- UI、視覚効果、またはコア動作を黙って変更しない: パフォーマンスのボトルネックが視覚的忠実度(ブラー/ガラスマテリアル、フレームアニメーション、シャドウ、レイアウトトランジションなど)または重要なソフトウェア動作に関係する場合:
- 一方的に視覚機能を削除またはダウングレードしないでください。
- まず正式にユーザーに許可を求めてください(インタラクティブプロンプトまたは明示的なチャットメッセージを使用)。
- トレードオフを明確に説明してください: 変更前後の視覚的変化を説明し、なぜその機能がリソースを消費するのかを説明し、具体的な期待されるパフォーマンス向上を示してください(例:「動的な背景ブラーを無効にすると、アクティブなGPUインパクトが1.5から0.2に低下し、約50 M/sのCPU命令が節約されます」)。
- 記録アーティファクトをクリーンアップする: すべての
xctrace記録は、数GBの一時的なカーネルトレース(instruments*.ktrace)とInstruments CLIキャッシュ(C/com.apple.dt.InstrumentsCLI)をユーザーごとのシステム一時フォルダ($TMPDIR)に書き込みます。scripts/run_trace.shは終了時に(成功時も失敗時も)これらを自動的に削除します。xctraceを直接実行する場合は、終了前に自分でクリーンアップしてください:数百GBの一時的な記録データを残したままセッションを終了しないでください。find "${TMPDIR:-/tmp}" -maxdepth 1 -type f -name 'instruments*.ktrace' -delete 2>/dev/null || true
4フェーズ最適化プロトコル
フェーズ2: 診断プロファイリングと原因特定
コードを書く前に、現在の状態を測定し、根本原因を特定します:
# 1. 事前チェック: アプリが実行中で、ウィンドウが表示されている必要があります
APP_NAME="YourApp"
pgrep -x "$APP_NAME" || { echo "[ERROR] $APP_NAME が実行されていません。最初に起動してください。"; exit 1; }
# SKILL_DIR = このスキルがインストールされているディレクトリ(別の場所にインストールされている場合は調整)
SKILL_DIR="$HOME/.claude/skills/macos-trace"
# 2. 60秒のアイドルベースラインを記録(ワークロードを一時停止、ウィンドウを表示)
# run_trace.sh はプロセス名からPIDを自動解決します
"$SKILL_DIR/scripts/run_trace.sh" --process "$APP_NAME" --template power --duration 60s --label "01-baseline"
# 3. アプリでワークロードをトリガーし、アクティブ状態を記録
"$SKILL_DIR/scripts/run_trace.sh" --process "$APP_NAME" --template power --duration 60s --label "02-pre-opt"
# 4. 最適化前の差分を計算
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"
特化されたテンプレートを使用してボトルネックを特定します:
- ホットなコールツリー関数を分離するには
--template timeを実行します。 - スラッシングアロケーションを特定するには
scripts/top_categories.pyとともに--template allocを実行します。 - スクロール中のレンダリング対コミット遅延を分離するには
--template hitchesを実行します。
フェーズ3: 対象を絞ったコード修正
発見に基づいて、最小限の外科的修正を適用します:
- リアルタイムオーディオスレッドがヒープメモリをアロケートしている?事前にアロケートされたロックフリーリングバッファに置き換えます。
- WebKit IPCが飽和している?状態更新をスロットルし、CSS Transformアニメーションに切り替えます。
- MetalフラグメントシェーダーがRetinaでオーバードローしている?動的解像度スケーリングを追加するか、オフスクリーンレンダリングループを一時停止します。
- 高解像度画像デコードのスパイク?
CGImageSourceCreateThumbnailAtIndexダウンサンプリングを採用します。
アプリケーションを再ビルドします。
フェーズ4: 再テスト、定量的レビュー、判定ゲート
同一条件下でプロファイルを再実行し、差分を評価します:
# 1. 最適化後のアクティブワークロードを記録
"$SKILL_DIR/scripts/run_trace.sh" --process "$APP_NAME" --template power --duration 60s --label "03-post-opt"
# 2. ベースラインに対する最適化前と最適化後を比較
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"
出力例:
Scenario Sec CPU Avg CPU Max Display GPU Avg Total Instr 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
--------------------------------------------------------------------------------------------
Differential vs Baseline [Idle Baseline]:
Active Pre-Opt +253.0 M/s instructions, CPU Avg Delta +2.25
Active Post-Opt +63.0 M/s instructions, CPU Avg Delta +0.50
判定ゲート:
- 目標達成の場合(例:命令レートが270 M/sから80 M/sに低下し、< 100 M/sの目標を満たした場合):変更前後の経験レポートをユーザーに提示し、終了します。
- 目標未達成の場合:残りのボトルネックを特定し、次の反復サイクルを開始します。
レポート後のクリーンアップ: ユーザーが最終的な最適化レポートを受け入れた後、/tmp/macos-traces/ に蓄積された .trace バンドルを削除します(各バンドルは数十GBになる可能性があります)。ただし、ユーザーが明示的に保持を要求した場合は除きます。レポートに表示された最終的な比較表と .xml エクスポートで十分な証拠となります。
直接CLIリファレンス
# 実行中のプロセスにアタッチ
xcrun xctrace record \
--template 'Power Profiler' \
--time-limit 60s \
--output /tmp/macos-traces/power.trace \
--attach $PID
# Power Impactテーブルをエクスポート(命令、CPU、GPU、ディスプレイ)
xcrun xctrace export \
--input /tmp/macos-traces/power.trace \
--xpath "/trace-toc/run[@number='1']/data/table[@schema='ProcessSubsystemPowerImpact']" \
> /tmp/macos-traces/power.xml
# 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
テンプレートリファレンス
scripts/run_trace.sh およびヘッドレス xctrace でサポートされているInstrumentsテンプレート:
計算とエネルギー
| テンプレート | 短縮名 | 対象メトリクスとエクスポートスキーマ | 使用例 |
|---|---|---|---|
Power Profiler | power | 命令/秒 (M/s)、CPU/GPU/ディスプレイエネルギーインパクト (ProcessSubsystemPowerImpact)。 | 目的のA/Bベンチマークと電力効率テスト。 |
Time Profiler | time | スレッド別CPUサンプル重み、コールツリーホットスポット、メインスレッドブロッキングメソッド。 | 高いCPU使用率、暴走スレッド、ホットな関数パス。 |
CPU Counters | counters | IPC(サイクルあたりの命令数)、L1/L2キャッシュミス、ブランチミス予測。 | 低レベルの計算およびDSPアルゴリズムのパフォーマンスボトルネック。 |
UI応答性と滑らかさ
| テンプレート | 短縮名 | 対象メトリクスとエクスポートスキーマ | 使用例 |
|---|---|---|---|
Animation Hitches | hitches | ヒッチ継続時間 (ms)、ヒッチ比 (ms/s)、フレームドロップ、アプリ対レンダリングフェーズのレイテンシ。 | スクロールのスタッタリング、ドロップされたアニメーションフレーム、CoreAnimationコミット遅延。 |
SwiftUI | swiftui | ビュー本文評価数、State無効化カウント、ビュー更新頻度。 | 不要なビュー再評価とState無効化カスケード。 |
Metal System Trace | metal | GPUエンコーダー時間、頂点/フラグメントシェーダー実行時間、フレーム境界レイテンシ。 | シェーダー実行ボトルネック、パーティクルFXオーバーヘッド、レンダリングパイプラインの停止。 |
メモリとアロケーション
| テンプレート | 短縮名 | 対象メトリクスとエクスポートスキーマ | 使用例 |
|---|---|---|---|
Allocations | alloc | ヒープアロケーション、一時的 vs 永続的メモリ、カテゴリ別イベントレート (all-allocations-summary)。 | 高頻度の一時的なアロケーション、メモリスパイク、バッファのスラッシング。 |
Leaks | leaks | 親ライフサイクルを超えて保持されるメモリリーク、参照サイクル。 | 放棄されたメモリ、クロージャキャプチャリーク、解放されていないデリゲートサイクル。 |
起動と並行性
| テンプレート | 短縮名 | 対象メトリクスとエクスポートスキーマ | 使用例 |
|---|---|---|---|
App Launch | launch | 最初のフレームまでの時間、dyld ロード時間、静的初期化子、Runloopセットアップ。 | コールドスタートの最適化(--launch -- <バイナリパス>)。 |
Swift Concurrency | concurrency | Swiftタスク(作成済み/実行中/一時停止)、アクターの再入可能性、協調プール使用率。 | async/await の枯渇、アクターの競合、長時間一時停止されたタスク。 |
System Trace | sys | スレッド状態遷移(実行中、一時停止中、プリエンプション)、vnode操作、システムコール。 | スレッド調整の問題、I/O待ち、プロセス間通信。 |
スクリプトリファレンス
run_trace.sh
指定されたInstrumentsテンプレートを使用して、実行中のプロセスのxctraceトレースを記録します。
"$SKILL_DIR/scripts/run_trace.sh" --process <アプリ名> --template <テンプレート> [--duration <秒数>] [--label <ラベル>] [--launch <バイナリパス>]
引数:
--process: アタッチする実行中のmacOSアプリケーションプロセス名(必須)--template: Instrumentsテンプレート短縮名:power、time、alloc、hitches、launch、swiftui、metal、counters、concurrency、sys、vm、leaks(必須)--duration: 記録時間(例:60s、30s)。デフォルト:60s--label: 出力ファイルのシナリオタグ(例:01-baseline)。デフォルト:unnamed-scenario--launch:--attachの代わりにアプリケーションを起動するためのバイナリパス。デフォルト:launchテンプレートはこのフラグを必要とします
出力:
.traceバンドル:/tmp/macos-traces/<タイムスタンプ>-<ラベル>-<テンプレート>.trace.xmlエクスポート:/tmp/macos-traces/<タイムスタンプ>-<ラベル>-<テンプレート>.xml
compare_elements.py
2つまたは3つの Power Profiler XMLエクスポートを比較し、ベースラインからの差分を示す表を出力します。
python3 "$SKILL_DIR/scripts/compare_elements.py" \
/path/to/baseline.xml:"ラベル" \
/path/to/pre-opt.xml:"ラベル" \
[/path/to/post-opt.xml:"ラベル"]
top_categories.py
Allocations XMLエクスポートを解析し、平均アロケーションレートでソートされたランキングカテゴリリストを出力します。
python3 "$SKILL_DIR/scripts/top_categories.py" \
/tmp/macos-traces/<タイムスタンプ>-<ラベル>-alloc.xml
インストール
必要条件
- macOS: 12モントレー以降
- Xcode:
xcode-select --installでインストールされたXcodeコマンドラインツール。xcrun xctrace versionを実行して、xctraceが利用可能であることを確認してください。 - Python:
/usr/bin/python3でPython 3.8以降。 - ディスク容量: 各トレース記録で一時的に最大50GBの空き容量(最終的なエクスポートは分析に十分な証拠となる微小なXMLファイルです)。
インストール手順(手動)
# スキルディレクトリを作成
mkdir -p ~/.claude/skills/macos-trace/scripts
# GitHubリポジトリからこのREADME.mdとスクリプトをダウンロード
# (例: curl または git clone)
cd ~/.claude/skills/macos-trace
# ... README.md と scripts/ の内容をここにコピー ...
# スクリプトが実行可能であることを確認
chmod +x scripts/run_trace.sh
インストール手順(Claude Codeプロジェクト)
CLAUDE.md またはプロジェクトルートに、以下を含めることができます:
このプロジェクトは、macOS-Trace パフォーマンス最適化スキル(`~/.claude/skills/macos-trace/` にインストール)を使用できます。
適切な場合は、`SKILL.md` の指示に従って自律的なパフォーマンスプロファイリングと最適化を実行します。
パフォーマンス最適化の実践例
例1: 高いCPU使用率(暴走タイマー)
# シナリオ: AudioEngineアプリケーションがアイドル時に20%のCPUを使用
# フェーズ2: 診断
"$SKILL_DIR/scripts/run_trace.sh" --process AudioApp --template time --duration 30s --label "01-idle"
# コールツリーで、0.01秒ごとに実行されるホットな Timer.fire() を発見
# フェーズ3: コード修正
# Timer.scheduledTimer(withTimeInterval: 0.01, ...) を 0.1 に変更し、
# アクティブなワークロード中のみタイマーをスケジュールする
# フェーズ4: 再テスト
"$SKILL_DIR/scripts/run_trace.sh" --process AudioApp --template power --duration 60s --label "02-post-opt"
python3 "$SKILL_DIR/scripts/compare_elements.py" \
/tmp/macos-traces/*-01-idle-power.xml:"Idle Baseline" \
/tmp/macos-traces/*-02-post-opt-power.xml:"Post-Opt Idle"
# 予想: CPU インパクトが 0.8 から 0.1 に低下
例2: UIヒッチ(スクロール中のフレームドロップ)
# シナリオ: メッセージリストスクロール時のヒッチ率 12ms/s
# フェーズ2: 診断
# アクティブにスクロールしながら記録
"$SKILL_DIR/scripts/run_trace.sh" --process MessagesApp --template hitches --duration 30s --label "01-scroll"
# SwiftUI テンプレートも記録して、ビュー評価を確認
"$SKILL_DIR/scripts/run_trace.sh" --process MessagesApp --template swiftui --duration 30s --label "01-swiftui"
# 発見: 各セルが高解像度のAvatar画像全体をデコードしている
# フェーズ3: コード修正
# キャッシュからサムネイルダウンサンプリングを採用
# AsyncImage に CGImageSourceCreateThumbnailAtIndex で置き換え
# フェーズ4: 再テスト
"$SKILL_DIR/scripts/run_trace.sh" --process MessagesApp --template hitches --duration 30s --label "02-post-opt"
# ヒッチ率が 2ms/s に低下したことを確認
トラブルシューティング
| 問題 | 考えられる原因と解決策 |
|---|---|
xcrun: error: unable to find utility "xctrace" | Xcodeコマンドラインツールがインストールされていません。xcode-select --install を実行してください。 |
トレースのアタッチに失敗しました: アクセスが拒否されました | 対象のアプリケーションは Hardened Runtime で実行されています。これには get-task-allow エンタイトルメントを持つデバッグビルドが必要です。または、xcode-select --install を使用して、コマンドラインツールをインストールした場所を確認してください。 |
出力が空のXMLです | ほとんどの場合、対象のアプリケーションが予想されたワークロードを実行していなかったことを意味します(そして xctrace は何も記録しませんでした)。ユーザーにアプリケーションでアクションをトリガーするように促すか、pgrep でプロセスが存在することを確認し、アプリケーションがフォアグラウンドで作業中であることを確認してください。 |
pyenv: python3: command not found | pyenv環境の場合、python3 がデフォルトのパスにない可能性があります。scripts/run_trace.sh は /usr/bin/python3 を直接呼び出します。/usr/bin/python3 --version が機能することを確認してください。 |
サポートプラットフォーム
このスキルは、エージェントが bash スクリプト xcrun および python3 を実行できる任意のAIエージェントプラットフォームで動作するように設計されています:
- Claude Code
- Codex CLI
- Cursor エージェントモード
- Antigravity
- その他
ライセンス
このプロジェクトはMITライセンスの下で提供されています。