ios-ettrace-performance について
ETTrace を使った、範囲を限定したシンボリケーション済みサンプリング実験のための iOS 性能分析スキルです。取得条件と対応する dSYM を証拠として管理し、同じ条件で複数回検証します。
主な機能
- 01再現可能なフローと取得境界の定義
- 02ビルド成果物と dSYM の照合
- 03処理済みフレームグラフの取得と検証
- 04排他的時間と包括的時間の区別
- 05条件をそろえた再取得による変更検証
活用シーン
- 01単一のユーザー操作におけるアプリ処理の分析
- 02排他的サンプリング時間が長いアプリコードの特定
- 03シンボリケーション不足による証拠の欠落確認
- 04最適化前後で同じ性能フローを比較
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ dpearson2699/ swift-ios-skills --skill ios-ettrace-performanceインストール後、Claude Code で/ios-ettrace-performanceを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
evals/evals.jsonscripts/analyze_ettrace.pycollect_dsyms.py詳細
iOS ETTrace のパフォーマンス
ETTrace を使用して、範囲を限定したシンボリケーション済みサンプリング実験を行います。キャプチャ条件とシンボリケーションは、単なる準備作業ではなく、証拠の一部として扱ってください。
目次
対象範囲
このスキルでは、ETTrace のフレームワーク/CLI によるキャプチャ、正確なビルドに対応する dSYM、処理済みのフレームグラフ JSON、および条件をそろえた検証を扱います。CPU、ハング、エネルギー、並行処理を広くトリアージする場合は Instruments を使用してください。ビューの ID、無効化、レイアウトの改善には、SwiftUI のパフォーマンスガイダンスを使用してください。
ETTrace はスレッドのスタックを定期的にサンプリングします。時間はそのサンプリング間隔からサンプルに基づく帰属を再構成したものであり、本番環境の実時間として示したり、設定の異なるプロファイラーの結果と直接比較したりしないでください。
キャプチャの条件
キャプチャ前に、次の項目を記録してください。
- 具体的なユーザーフローと、その開始/終了の境界。
- 起動時のキャプチャか、実行中のランタイムキャプチャか。
- アプリのコミット、ビルド設定、最適化設定、アーキテクチャ。
- ETTrace のランナーとフレームワークのバージョン、およびシングルスレッド/マルチスレッドのモード。
- シミュレーター/デバイスのモデルと OS ビルド。
- 起動方法、データの状態、キャッシュの状態、繰り返し回数。
これらのいずれかに実質的な差異がある場合は、前後比較の主張を退けてください。代わりに、条件を統一して再ビルドし、再計測してください。
ワークフロー
1. 計測の前にトリアージする
ETTrace のサンプリングフレームチャートが次に適したツールかどうかを確認してください。遅い区間が不明な場合、複数のサブシステムにまたがる場合、またはシステムレベルのブロッキング、I/O、ハング、並行処理の状況を把握する必要がある場合は、まず Instruments を使用してください。
繰り返しやすい小さなフローを 1 つ選んでください。起動、最初の画面の構築、ドキュメントを 1 つ開く、編集を 1 つ適用する、といった操作が適切な境界です。「アプリを使う」では範囲が広すぎます。
2. ETTrace のバージョンを記録し、固定する
公式タップからランナーをインストールし、計測対象のアプリターゲットに ETTrace パッケージのプロダクトをリンクしてください。ランナーのバージョンとフレームワークのリビジョンまたはタグは別々に記録し、比較するキャプチャ間で両方を固定してください。同梱のアナライザーがサポートするのは、検証済みの v1.1.1 処理済み出力形式です。異なる形式を使う前に、上流の仕様とパーサーを再確認してください。
brew install emergetools/homebrew-tap/ettrace
計測対象のアプリを一度実行し、Starting ETTrace ログを確認してください。このメッセージがない場合、キャプチャの証拠は信頼できません。プロジェクトが意図的にそのトレードオフを受け入れている場合を除き、この設定を製品版の構成に含めないでください。
3. 先にビルドし、そのビルドに対応する dSYM を収集する
キャプチャと dSYM の収集の両方で、最終的な計測対象ビルドを使用してください。ファイル名、更新日時、Derived Data 内での近さを基準に dSYM を選ばないでください。
mkdir -p /tmp/myapp-ettrace
python3 scripts/collect_dsyms.py \
--app /path/to/Build/Products/Release-iphonesimulator/MyApp.app \
--search-root /path/to/Build/Products \
--search-root /path/to/Archives \
--output /tmp/myapp-ettrace/dsyms \
--pretty > /tmp/myapp-ettrace/dsym-report.json
このヘルパーは、アプリの実行ファイルと埋め込みバイナリについて、dwarfdump --uuid の出力を比較します。UUID の一致が見つからない場合、または一致が曖昧な場合、デフォルトでは実行を中止します。コピーされたシンボルファイルがすべて関連するとは限らないため、dsym-report.json を読み、保存してください。UUID が一致するファイルを、ETTrace 1.1.1 が検出できる一意なフラット形式の保存先名でコピーできない場合、このヘルパーは失敗します。
4. クリーンなアーティファクトディレクトリからキャプチャする
処理済みファイルは現在の作業ディレクトリに書き込まれるため、空のディレクトリから ETTrace を実行してください。Simulator には --simulator、正確な dSYM ディレクトリには --dsyms を使用します。起動時の計測を行う場合に限り --launch を追加し、ランナーの2回起動に関する指示に正確に従ってください。
mkdir -p /tmp/myapp-ettrace
mkdir /tmp/myapp-ettrace/run-01
cd /tmp/myapp-ettrace/run-01
ettrace --simulator --dsyms /tmp/myapp-ettrace/dsyms
2つ目の mkdir は、その実行用ディレクトリがすでに存在する場合に失敗する必要があります。再試行で処理済みキャプチャが混在しないよう、新しい実行名を選んでください。
ランナーに求められたら、ホーム画面でアプリをタップして起動します。Xcode から起動すると、起動経路やタイミングが変わる可能性があります。デバイスをキャプチャする場合は --simulator を省略し、それ以外の実験条件はすべて固定してください。
制限したフローの終了後、ただちに停止し、キャプチャ契約に沿って新しく生成された output_<threadId>.json をすべて保持してください。ETTrace 1.1.1 はシンボル化後にこれらの処理済みファイルを作成します。内部の生ランナー出力である output.json は別のアーティファクトであり、以下のアナライザーでは受け付けられません。
5. 処理済み出力を検証して要約する
python3 scripts/analyze_ettrace.py \
/tmp/myapp-ettrace/run-01/output_*.json \
--top 25 --pretty > /tmp/myapp-ettrace/run-01/summary.json
このヘルパーは v1.1.1 の処理済みノード形式を検証し、重複した入力や osBuild/device/isSimulator のメタデータが混在する入力を拒否し、シリアライザーの children フィールドがオブジェクトまたは配列のどちらでも処理し、決定的な JSON を出力します。キャプチャファイルは書き換えません。元のファイルは要約とともに保持してください。
重要なアプリのフレームが <unknown>、生のアドレス、または誤ったバイナリに由来すると示されている場合は、停止してシンボル化を修正してください。シンボル化されていないホットアドレスは証拠の欠落であり、コードの推奨事項ではありません。ETTrace 1.1.1 のアドレスを含むノードは unresolved_frames に列挙され、通常のホットスポットから除外されます。
6. 原因を1つ変更して繰り返す
ホットスポットとなっているアプリ所有のパスに裏付けられた、最小限のコードまたは設定変更を行ってください。再ビルドし、UUID が一致する dSYM を再収集して、同じフローを少なくとも2回キャプチャします。結果とともに、ばらつきとキャプチャ契約全体を報告してください。
レポートの解釈
- 排他的秒数は、直接の子の実行時間を差し引いた後に、シンボルへ直接割り当てられるサンプリング時間の概算です。まず、排他的な処理時間が長いアプリ所有の処理に注目してください。
- 包括的秒数は、呼び出しサブツリー全体の重みを示します。高コストなエントリーパスを見つけるために使用し、親フレームすべてを原因とみなさないでください。
- 再帰や入れ子になった出現では各フレームが数えられるため、包括時間の合計はルートの時間を超えることがあります。排他的な割合はルートの時間を使用します。
<unattributed>は別個に報告されます。この値が大きい場合、欠落した時間帯に何が起きたかについての結論の確度が下がります。- フレームワークのホットスポットでも、アプリの呼び出し頻度、データの形状、または設定が原因の場合があります。上流をたどり、最初に制御可能なアプリ所有の呼び出し元を探してください。
- マルチスレッドのファイルは、実時間の遅延ではなくスレッドの実行時間を合算します。合算したルート時間を経過時間として説明しないでください。
よくある間違い
- 制限のないセッションをプロファイリングしてから、どのサンプルがバグに該当するか推測する。
- あるビルドをキャプチャし、別のビルドやアーキテクチャの dSYM を使用する。
- ETTrace の生ランナー JSON を処理済みフレームグラフとして扱う。
- 起動時のキャプチャと実行時のキャプチャ、またはシングルスレッドとマルチスレッドのキャプチャを比較する。
- 排他的な処理時間や子のパスを調べず、包括時間が最も長い親だけを最適化する。
- ノイズのある1回の実行だけで改善を主張する。
- 誤って ETTrace の計測を本番環境に残す。
レビューチェックリスト
- 再現可能なフローと開始/停止の境界が記録されています。
- 起動時/実行時のキャプチャモード、シングル/マルチスレッドモード、ランナーのバージョン、フレームワークのリビジョンが一致しています。
- ビルド設定、アーキテクチャ、ターゲット/OS、起動方法、アプリのデータ/キャッシュの状態が一致しています。
- すべてのキャプチャは、実行ごとに新しく作成された空の成果物ディレクトリから開始しています。
- アプリおよび組み込みバイナリの UUID が、提供された dSYM と一致しています。
- dSYM 収集の JSON レポートが、ソース/宛先と、不足、曖昧さ、衝突、不整合を示す証拠とともに保持されています。
- 処理済みの
output_<threadId>.jsonファイルが変更されずに保持されています。 - アプリの重要なフレームがシンボリケートされています。
- 排他的、包括的、未帰属、マルチスレッドの各セマンティクスが明確です。
- 推奨事項に、アプリが制御するパスと、それを裏付ける証拠が記載されています。
- 検証では同じ契約を繰り返し、複数回の実行結果が報告されています。
- 一時的な計測処理が削除されているか、意図した範囲に限定されています。