iOS-Trace: 自律型アプリケーションパフォーマンス最適化
iOS-Trace は、物理的な iPhone/iPad デバイスおよびローカルの iOS シミュレータ (SwiftUI、UIKit、Metal、CoreAudio / AVAudioEngine、URLSession ネットワーキング) 上で動作する iOS および iPadOS アプリケーション向けのクローズドループパフォーマンス最適化エンジンです。
中核的な目的は、手動による Instruments GUI 操作を排除することです。AI エージェントは、自律的に診断、ボトルネックの特定、コード変更の実装、差分ベンチマークによる再テストを行い、実証データによってパフォーマンス目標が検証されるまで反復できます。
+-------------------------------------------------------------------------+
| 自律最適化ループ |
| |
| 1. 目標調整 ──> 2. 診断トレース ──> 3. 対象を絞ったコード修正 |
| ^ │ |
| │ ▼ |
| └────── 目標未達の場合は反復 <── 4. 再テスト検証 |
+-------------------------------------------------------------------------+
フェーズ 1: ユーザー目標調整 (事前質問票)
携帯端末でのコード変更やトレース収集の前に、エージェントは最適化目標と成功基準についてユーザーと調整する必要があります。
モーダルツール vs チャット対話
- エージェントプラットフォームがインタラクティブな質問票/モーダルツール (例:
ask_question、入力ダイアログ、選択可能なオプションリスト) を提供している場合は、それを呼び出して、これらの選択肢をユーザーに明確に提示します。 - モーダルツールが利用できない場合は、構造化されたオプションと具体的な推奨値を用いて、会話内でユーザーに直接質問します。
ユーザーに質問する項目
-
最適化の主目的:
- オプション A: バッテリー消費、CPU 使用率、サーマルスロットリングの削減。
- オプション B: メモリフットプリント、一時的なアロケーションスパイクの低減、Jetsam OOM クラッシュの防止。
- オプション C: UI フレームのスタッタリングとアニメーションフレーム落ちの解消 (ProMotion 120Hz ヒッチ)。
- オプション D: モバイルアプリケーションのコールドローンチ時間の短縮。
- オプション E: ネットワーク無線オーバーヘッドとバッチリクエスト効率の最適化。
-
具体的なパフォーマンス目標 (推奨デフォルト値を提示):
- バッテリー & CPU 目標:
- アイドルベースライン目標: < 15 M/s 命令、CPU インパクト < 0.3。
- アクティブワークロード目標: < 80 M/s 命令 (または、30% - 50% 削減を指定)。
- メモリ & Jetsam 目標:
- 最大常駐 RAM: < 150 MB (標準ユーティリティ) または < 300 MB (メディア/リッチインタラクティブアプリ) に制限。
- アロケーションイベントレート: 安定状態のインタラクション中は < 400 イベント/秒。
- メモリリーク: 永続的なリークは正確に 0。
- UI スムーズネス & フレームレート目標:
- ヒッチレート: < 5.0 ms/s (許容範囲)、< 1.0 ms/s (滑らか / 120Hz ProMotion グレード)。
- 最大ヒッチ時間: < 16.6ms (60Hz) または < 8.33ms (120Hz)。
- 起動時間目標:
- 最初のフレームまでの時間: < 400 ms (優れている)、< 800 ms (許容範囲)。
- ネットワーク & 無線目標:
- 無線オーバーヘッド: 定期的な ping を単一のバーストリクエストにバッチ処理し、無線テールスタンバイ電力を回避。
- バッテリー & CPU 目標:
-
ベンチマークユーザーシナリオ:
- ベンチマークする特定の画面、ユーザーインタラクション、物理デバイス、またはシミュレータをユーザーに尋ねます。
目標が確認されたら、フェーズ 2 に進みます。
スコープと前提条件
- 対象プラットフォーム: USB またはローカルネットワーク経由で接続された物理 iPhone/iPad デバイス、またはローカルの iOS シミュレータで動作する iOS および iPadOS アプリケーション。 (macOS デスクトップアプリケーションの場合は、macOS-Trace を使用してください)。
- ホストシステム: Apple Silicon または Intel Mac 上で動作する macOS 12+ で、完全な Xcode または Xcode コマンドラインツールがインストールされていること (
xcode-select -p、xcrun xctrace version)。 - デバイスの準備:
- 物理 iPhone/iPad はロックが解除され、Mac ホストから信頼されている必要があります。
xcrun xctrace list devicesを実行したときに、デバイスが== Devices Offline ==ではなく== Devices ==の下に表示される必要があります。- 録画中に iOS がバックグラウンドプロセスを一時停止しないように、自動ロックを「しない」に設定するか、ディスプレイを起動したままにしておく必要があります。
- Python: ホスト Mac に Python 3.8+ が必要です (標準ライブラリのみ使用。外部 pip 依存関係はゼロ)。
- プロセス権限:
--attach <PID>を使用するには、get-task-allowエンタイトルメントを持つデバッグビルドまたは開発者プロビジョニングビルドが必要です。
エージェントのルール
自動プロファイリング中は、以下の不変のルールに従ってください。
- デバイスの接続状態を確認する: 録画前に必ず
xcrun xctrace list devicesを実行してください。== Devices Offline ==の下にリストされているデバイスに対して録画を試みないでください。 - 画面ロックとバックグラウンド化を防止する: iOS デバイスがロックされたりホーム画面に戻ったりすると、iOS はプロセスを一時停止またはスロットルし、無効な測定値が生成されます。デバイスを起動したまま、アプリをフォアグラウンドに保ってください。
- 最初にベースラインを確立する: アクティブワークロードのみを記録しないでください。アクティブ状態を記録する前に、必ずアイドルベースライン実行 (アプリがフォアグラウンド、デバイス画面オン、ワークロードが一時停止) をキャプチャしてください。
差分 = アクティブ - ベースラインを計算します。 - 同一のテストパラメータを使用する: 同一のサンプル時間 (デフォルト:
60s)、同一のデバイスバッテリー状態 (バッテリー残量 20% 未満または低電力モードでのプロファイリングを避ける)、同一のテスト入力データで実行を比較します。 - サードパーティの Python 依存関係を追加しない: バンドルされているすべてのスクリプト (
scripts/compare_elements.py、scripts/parse_power.py、scripts/top_categories.py) は、Python 3 標準ライブラリのみを使用します。 - 出力を
/tmp/ios-traces/に保存する: すべての.traceバンドルと.xmlエクスポートを、タイムスタンプとシナリオタグが付いたファイル名で/tmp/ios-traces/に保存します。 - 会話コンテキスト予算を保護する: トレースファイルとエクスポートされた生の XML ドキュメントは、数十から数百メガバイトになる可能性があります。生の
.trace出力、完全なコールツリー、または解析されていない Allocations XML をエージェントの会話コンテキストにダンプしないでください。バンドルされている Python スクリプトを使用して、データをストリーミング、フィルタリング、ランク付け、要約してから読み取ってください。 - 主要なボトルネックに集中する: 多数の無関係なユーティリティ関数にマイクロ最適化を分散しないでください。最初にプロファイリングして、支配的な原因 (例: 冗長なサーフェスインスタンス、高頻度タイマーの再評価、バッファリングされていない I/O) を確認し、最適化作業をその根本原因にのみ集中させてください。
- UI、視覚効果、または中核的な動作を黙って変更しない: パフォーマンスのボトルネックが視覚的な忠実度 (ブラー/マテリアル、フレームアニメーション、シャドウ、レイアウトトランジションなど) または必須のソフトウェア動作に関係する場合:
- 一方的に視覚機能を削除またはダウングレードしないでください。
- 正式にユーザーに許可を求めてください (インタラクティブプロンプトまたは明示的なチャットメッセージを使用)。
- トレードオフを明確に説明してください: 変更前と変更後の視覚的な変化を説明し、その機能がリソースを消費する理由を説明し、期待される具体的なパフォーマンス向上を提示してください (例: 「カードビューの動的シャドウとブラーを無効にすると、GPU の平均インパクトが 1.8 から 0.2 に減少し、120Hz ProMotion ヒッチが解消されます」)。
- 録画アーティファクトをクリーンアップする: すべての
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. ターゲットデバイスがオンラインでロックが解除されていることを確認 (オプションチェック;
# run_trace.sh は --device が省略された場合、最初に接続された iPhone/iPad を自動検出)
xcrun xctrace list devices
BUNDLE_ID="com.example.MyApp"
# SKILL_DIR = このスキルがインストールされているディレクトリ (インストール先に応じて調整)
SKILL_DIR="$HOME/.claude/skills/ios-trace"
# 2. 60秒のアイドルベースラインを記録 (デバイスロック解除、アプリフォアグラウンド、ワークロード一時停止)
"$SKILL_DIR/scripts/run_trace.sh" \
--bundle-id "$BUNDLE_ID" \
--template power \
--duration 60s \
--label "01-baseline"
# 3. アプリでターゲットワークロードをトリガーし、アクティブ状態を記録
"$SKILL_DIR/scripts/run_trace.sh" \
--process "MyApp" \
--template power \
--duration 60s \
--label "02-pre-opt"
# 4. 最適化前の差分を計算
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"
特殊なテンプレートを使用してボトルネックを特定します:
--template timeを実行して、ワーカースレッド上のホットコールツリー関数を特定します。scripts/top_categories.pyと共に--template allocを実行して、メモリプレッシャーを引き起こすスラッシングアロケーションを特定します。- スクロール中に
--template hitchesを実行して、ProMotion ディスプレイでのレンダリングとコミットの遅延を分離します。 --template networkを実行して、継続的なバッチ処理されていない無線ウェイクアップを検出します。
フェーズ 3: 対象を絞ったコード修正
調査結果に基づいて、最小限で外科的な修正を適用します:
- メモリスパイク & Jetsam: フルサイズの
UIImageをロードする代わりに、CGImageSourceCreateThumbnailAtIndexを使用して高解像度画像のダウンサンプリングを採用します。 - ProMotion ヒッチ: 複雑なシャドウとオフスクリーンブレンドパスを削除し、重いビューレイアウト計算をメインスレッドからオフロードします。
- 無線エネルギーオーバーヘッド: 定期的なネットワークリクエストを統合されたペイロードバーストにバッチ処理し、無線テールスタンバイ電力を排除します。
- リアルタイムオーディオ: CoreAudio レンダリングコールバック (
AVAudioEngineまたは RemoteIO) でのヒープアロケーションがゼロであることを確認します。
アプリケーションを再ビルドしてデバイスに展開します。
フェーズ 4: 再テスト、定量的レビュー、意思決定ゲート
同一の条件下でプロファイルを再実行し、差分を評価します:
# 1. 最適化後のアクティブワークロードを記録
"$SKILL_DIR/scripts/run_trace.sh" \
--process "MyApp" \
--template power \
--duration 60s \
--label "03-post-opt"
# 2. 最適化前と最適化後をベースラインと比較
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"
出力例:
シナリオ 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
---------------------------------------------------------------------------------------------------------
ベースラインに対する差分 [Idle Baseline]:
Active Pre-Opt +245.8 M/s 命令, CPU Avg 差分 +2.28, WiFi Tx 差分 +14.20MB
Active Post-Opt +55.8 M/s 命令, CPU Avg 差分 +0.43, WiFi Tx 差分 +2.10MB
最適化差分 (Post-Opt vs Pre-Opt):
命令スループット: -73.1% (70.0 vs 260.0 M/s)
CPU 平均インパクト: -77.1% (0.55 vs 2.40)
GPU 平均インパクト: -88.9% (0.20 vs 1.80)
WiFi 無線トラフィック: -85.2% (2.1MB vs 14.2MB)
意思決定ゲートロジック:
- 目標達成: 実証比較表をユーザーに提示し、終了します。
- 目標未達: 以前の最適化を維持し、次の残りのホットスポットを特定し、フェーズ 3 とフェーズ 4 を繰り返します。
レポート後のクリーンアップ: ユーザーが最終最適化レポートを受け入れた後、/tmp/ios-traces/ の下に蓄積された .trace バンドルを削除します (それぞれ数十 GB になる可能性があります)。ただし、ユーザーが明示的に保持を要求した場合はこの限りではありません。レポートに表示された最終的な比較表と .xml エクスポートで十分な証拠となります。
直接 CLI コマンド
run_trace.sh を使用せずに xctrace を直接実行する場合:
レコード
# デバイス上で実行中のアプリにアタッチ
xcrun xctrace record \
--device <DEVICE_UDID> \
--template 'Power Profiler' \
--time-limit 60s \
--output /tmp/ios-traces/power.trace \
--attach <PID>
# デバイス上でアプリをコールドローンチ
xcrun xctrace record \
--device <DEVICE_UDID> \
--template 'Time Profiler' \
--time-limit 30s \
--output /tmp/ios-traces/launch.trace \
--launch -- com.example.MyApp <LaunchArgs>
エクスポート
# Power Impact テーブルをエクスポート (CPU 命令、エネルギー、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
# 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
テンプレートリファレンス
iOS で scripts/run_trace.sh とヘッドレス xctrace を介してサポートされている Instruments テンプレート:
コンピュート、バッテリー、エネルギー
| テンプレート | 短縮名 | ターゲットメトリクスとエクスポートスキーマ | ユースケース |
|---|---|---|---|
Power Profiler | power | 命令/秒 (M/s)、CPU/GPU/Display/WiFi/Cellular エネルギーインパクト (ProcessSubsystemPowerImpact)。 | 包括的なバッテリー消費、サーマルスロットリング、A/B ベンチマーク。 |
Time Profiler | time | スレッド別 CPU サンプル重み、コールツリーホットスポット、メインスレッドブロッキングメソッド。 | 高い CPU 使用率、暴走するワーカースレッド、ホットな関数パス。 |
CPU Counters | cpu | サイクル、ストール、分岐予測ミス、キャッシュミスのパフォーマンスカウンター。 | マイクロアーキテクチャの非効率性、キャッシュミス、投機的実行の問題の特定。 |
Metal System Trace | metal | GPU シェーダー時間、バッファの待ち時間、レンダーパスの分解、フレームタイミング。 | 重いシェーダー、過剰な CPU-GPU 同期、GPU バインドパイプライン。 |
Hang Detection | hang | メインスレッドのブロッキング呼び出し、サスペンド時間 > 200ms。 | アプリが応答しない (ANR) 状態、UI フリーズ。 |
Core Animation | animation | コミット時間、ピクセルバッファのコピー、Offscreen レンダリングパス数。 | 60/120Hz でのフレーム落ち、オフスクリーンレンダリング、過剰なカラーミキシング。 |
Hitches | hitches | ヒッチレート (ms/s)、ディスプレイリンク期間、レンダーとコミットの詳細。 | ProMotion 120Hz ディスプレイでの知覚可能なヒッチ。 |
Core Data | data | フェッチカウント、フォールト数、永続ストアアクセス時間、キャッシュミス率。 | 非効率な Core Data クエリ、過剰なフェッチ、大きなオブジェクトグラフでの高いフォールト率。 |
メモリ
| テンプレート | 短縮名 | ターゲットメトリクスとエクスポートスキーマ | ユースケース |
|---|---|---|---|
Allocations | alloc | 割り当て/解放イベント、ライブバイト数、呼び出しスタック別カテゴリ (all-allocations-summary)。 | リーク、スラッシングアロケーション、永続的なメモリ成長。 |
Leaks | leaks | 到達可能および到達不可能なリークインスタンスの数とタイプ。 | 循環参照、失われた解放、未解放の Core Foundation オブジェクト。 |
VM Memory Profiler | vm | カテゴリ別仮想メモリ使用量、ページングアクティビティ。 | Jetsam OOM クラッシュ、環境設定による高 dirty メモリ、IOKit バッファ。 |
ネットワーク
| テンプレート | 短縮名 | ターゲットメトリクスとエクスポートスキーマ | ユースケース |
|---|---|---|---|
Network Profiler | network | 接続ライフサイクル、ペイロードサイズ、無線睡眠/アクティブサイクル (Connection)。 | 無線テールエネルギー、バッチ処理の機会の喪失、DNS 解決の遅延。 |
TCP Connections | tcp | 個々の TCP ストリームのスループット、RTT、パケット損失。 | 低速クライアント/サーバーネットワークリンク、再送信、パケット損失。 |
メディア
| テンプレート | 短縮名 | ターゲットメトリクスとエクスポートスキーマ | ユースケース |
|---|---|---|---|
Audio | audio | オーディオユニット時間、バッファアンダーラン、オーディオドライバー遅延。 | AVAudioEngine および CoreAudio レンダリングコールバックのグルッチ、オーディオドロップアウト。 |
Video | video | フレームエンコード/デコード時間、H264/HEVC ビットレート、フレーム落ち。 | ソフトウェアコーデックフレーム落ち、ハードウェアアクセラレーションのボトルネック。 |
インストール
エージェントのスキルディレクトリ
スキルリポジトリのクローンを作成するか、ファイルを手動でコピーします:
git clone https://github.com/kmgcc/ios-trace.git "$HOME/.claude/skills/ios-trace"
前提条件の確認
./install.sh # または、docs/requirements の指示に従ってください
アクティベーション
エージェントに対して、この SKILL.md を含むディレクトリを使用するように指示します。
CI/CD での使用
--headless フラグを使用して、ボトルネックが許容しきい値を超えた場合に特定の失敗コードで終了する、自動化パイプライン用のスクリプト呼び出しを可能にします:
./scripts/performance_gate.sh \
--bundle-id "com.example.MyApp" \
--max-instructions 100M \
--max-cpu-impact 1.0 \
--max-memory 200MB
トラブルシューティング
よくある問題
-
xctrace: error: device is not available.- デバイスが接続され、信頼され、ロックが解除されていることを確認してください。
- 使用可能なデバイスを確認するには
xcrun xctrace list devicesを実行し、デバイスが== Devices Offline ==の下にリストされていないことを確認してください。
-
Failed to launch processまたはLaunch failed: No such process- 指定されたバンドル ID がデバイスにインストールされていることを確認してください。
- Xcode から手動でアプリを起動し、これが機能することをテストしてください。
-
--attachが(os/kern) failureで失敗する- アプリのビルドに
get-task-allowエンタイトルメントがあることを確認してください。デバッグビルドにはデフォルトでこれが含まれていますが、Ad-Hoc またはリリースビルドには含まれていません。
- アプリのビルドに
-
低パフォーマンスの測定値
- デバイスのバッテリー残量が 20% 未満でないことを確認してください。
- 低電力モードが無効になっていることを確認してください。
- テストを開始する前に、デバイスが室温に達するまで待機してください (熱によるスロットルを防ぐため)。
-
ディスク領域の不足
xctrace記録は一時ファイルを使用して数 GB を消費する場合があります。$TMPDIRに十分な空き領域があることを確認してください。scripts/run_trace.shを使用している場合、一時ファイルはクリーンアップされます。xctraceを直接使用している場合は、手動で一時ファイルをクリーンアップする必要がある場合があります。
スクリプトリファレンス
scripts/run_trace.sh
プロファイリングセッションを実行するためのラッパースクリプト。
./scripts/run_trace.sh [options]
オプション:
--bundle-id <id> プロファイリングするアプリのバンドル ID (例: com.example.app)
--process <name> 実行者名 (アタッチ用)
--template <template> 使用する Instruments テンプレート (power, time, alloc, hitches, network など)
--duration <duration> 記録時間 (例: 60s, 30s)
--label <label> 出力に使用するラベル (例: 01-baseline)
--device <udid> デバイス UDID (指定しない場合は、最初の接続済みデバイスが使用される)
--output <dir> 出力ディレクトリ (デフォルト: /tmp/ios-traces/)
--headless CI スクリプトで使用するための非対話モード
scripts/compare_elements.py
複数の XML エクスポートを比較します。
python3 scripts/compare_elements.py <file1:label1> [<file2:label2> ...]
scripts/top_categories.py
Allocations XML エクスポートを解析し、最も多くのメモリを消費しているカテゴリを表示します。
python3 scripts/top_categories.py <alloc.xml>
scripts/parse_power.py
Power Profiler XML エクスポートを解析し、人間が読みやすい形式でフォーマットします。
python3 scripts/parse_power.py <power.xml>
サポート
- 問題/機能リクエスト: GitHub Issues
- macOS デスクトップアプリ: macOS-Trace
- ライセンス: MIT