mcpField
I
ios-ettrace-performance

ios-ettrace-performance

github.com/openai開発7.7k89 回インストール3 週間前に更新
リポジトリ

ios-ettrace-performance について

iOS シミュレーターアプリの処理を絞り、シンボル化した ETTrace プロファイルを取得・分析するスキルです。準備やトレースの保存から、注意点を含むボトルネックの報告までを扱います。

主な機能

  1. 01対象を絞ったアプリ操作の記録
  2. 02シミュレーター分析用 ETTrace のリンク
  3. 03対応する dSYM の収集と検証
  4. 04処理済みフレームグラフ JSON の保存
  5. 05ボトルネックと分析上の注意点の報告

活用シーン

  1. 01アプリ起動や初回描画の測定
  2. 02単一の実行時操作のプロファイリング
  3. 03シンボル化された自社コードのスタック確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/openai/plugins --skill ios-ettrace-performance

インストール後、Claude Code で/ios-ettrace-performanceを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

agents/
openai.yaml
scripts/
analyze_flamegraph_json.py
collect_ios_dsyms.sh

詳細

iOS ETTrace のパフォーマンス

このスキルを使って、iOS シミュレーターアプリの対象を絞ったシンボリケート済み ETTrace プロファイルを取得します。シミュレーターのビルド、インストール、起動、UI 操作、ログ、スクリーンショットも必要な場合は、../ios-debugger-agent/SKILL.md と併用してください。

基本的なワークフロー

  1. 対象を絞ったフローを 1 つ選び、開始点と終了点として想定する箇所を書き留めます。
  2. インストールしてプロファイルする対象のシミュレーターアプリを正確にビルドします。
  3. シミュレーター/デバッグプロファイル用に、ETTrace を一時的にアプリターゲットへリンクします。
  4. アプリ実行ファイルと組み込みの動的フレームワークについて、UUID が一致する dSYM を収集します。
  5. 起動時または実行時のトレースを 1 回取得します。
  6. 処理済みのフレームグラフ JSON を、実行直後に保存します。
  7. 処理済み JSON のみを分析し、対象フロー、成果物、ホットスポット、注意点を報告します。

「アプリをしばらく使う」といった範囲の広いキャプチャは避けてください。1 つのトレースが、ユーザーに見える 1 つのフローに対応するようにします。

セットアップ

プロファイリングセッションごとに、書き込み可能な実行フォルダーを使用します。

if [ -z "${RUN_DIR:-}" ]; then
  RUN_DIR="$(mktemp -d "${TMPDIR:-/tmp}/codex-ios-ettrace.XXXXXX")"
fi
mkdir -p "$RUN_DIR"

ETTrace ランナー CLI がまだ利用できない場合は、インストールします。

brew install emergetools/homebrew-tap/ettrace

ettrace はホスト側の macOS ランナーです。アプリは iOS シミュレーターのアーキテクチャに対応する ETTrace.xcframework もリンクする必要があります。 このワークフローは、トップレベルに nodes を持つ ETTrace v1.1.0 の処理済み output_<thread>.json ファイルで検証されています。

ETTrace をアプリにリンクする

プロファイル対象の正確なアプリターゲットに ETTrace を組み込みます。統合は一時的なパッチであることが明確に分かる形にし、ユーザーから明示的に保持するよう求められない限り、プロファイリング作業が終わったら削除します。

推奨される方法:

  • リポジトリにシミュレーター対応の ETTrace.xcframework がすでに含まれている場合は、それを再利用します。
  • 含まれていない場合は、上流の ETTrace パッケージからシミュレーター専用のコピーを RUN_DIR にビルドします。
  • フレームワークはアプリターゲットに直接リンクします。テスト、リソース、データファイル、またはネストされたランチャーターゲットだけにリンクしてはいけません。
  • 起動ログに Starting ETTrace と表示されることを確認します。
  • シミュレーターモードでは固定の localhost ポートで待ち受けるため、ETTrace を組み込んだシミュレーターアプリのプロファイルは一度に 1 つだけ実施します。

必要に応じてシミュレーターフレームワークをビルドします。

ETTRACE_TAG="${ETTRACE_TAG:-v1.1.0}" # Override to match the installed runner when Homebrew updates.
ETTRACE_SRC="$RUN_DIR/ETTrace-src"
if [ ! -d "$ETTRACE_SRC" ]; then
  git clone --depth 1 --branch "$ETTRACE_TAG" https://github.com/EmergeTools/ETTrace "$ETTRACE_SRC"
fi

rm -rf "$RUN_DIR/ETTrace-iphonesimulator.xcarchive" "$RUN_DIR/ETTrace.xcframework"
pushd "$ETTRACE_SRC" >/dev/null
xcodebuild archive \
  -scheme ETTrace \
  -archivePath "$RUN_DIR/ETTrace-iphonesimulator.xcarchive" \
  -sdk iphonesimulator \
  -destination 'generic/platform=iOS Simulator' \
  BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
  INSTALL_PATH='Library/Frameworks' \
  SKIP_INSTALL=NO \
  CLANG_CXX_LANGUAGE_STANDARD=c++17

xcodebuild -create-xcframework \
  -framework "$RUN_DIR/ETTrace-iphonesimulator.xcarchive/Products/Library/Frameworks/ETTrace.framework" \
  -output "$RUN_DIR/ETTrace.xcframework"
popd >/dev/null

Bazel アプリでは、通常、一時的なインポートは次のようになります。

load("@rules_apple//apple:apple.bzl", "apple_dynamic_xcframework_import")

package(default_visibility = ["//visibility:public"])

apple_dynamic_xcframework_import(
    name = "ETTrace",
    xcframework_imports = glob(["ETTrace.xcframework/**"]),
)

Xcode プロジェクトでは、プロファイル対象のデバッグ用シミュレータービルドのアプリターゲットにある Link Binary With Libraries/Embed Frameworks フェーズへシミュレーター用 ETTrace.xcframework を一時的に追加し、プロファイリング後にその設定を削除します。

シンボリケーションの確認

シンボリケートされていないフレームグラフから結論を導き出してはいけません。キャプチャの前に、アプリの dSYM と組み込みのファーストパーティ製動的フレームワークの dSYM を含む dSYM フォルダーを準備します。

インストールしたアプリを生成した最終ビルドの後に、dSYM を収集します。

SKILL_DIR="<absolute path to this loaded skill folder>"
APP="<path-to-built-simulator-App.app>"
DSYMS="$RUN_DIR/dsyms"

"$SKILL_DIR/scripts/collect_ios_dsyms.sh" \
  --app "$APP" \
  --out-dir "$DSYMS" \
  --search-root "$(dirname "$APP")" \
  --search-root "$PWD" \
  --extra-dsym "$RUN_DIR/ETTrace-iphonesimulator.xcarchive/dSYMs/ETTrace.framework.dSYM"

シンボリケートが必要なアプリ所有の動的フレームワークには --require-framework <FrameworkName> を追加します。--require-all-frameworks は、組み込みのすべてのフレームワークがアプリ所有であるか、シンボルが存在すると想定される場合に限って使用します。ヘルパーが必須のアプリまたはフレームワークの dSYM がないと報告した場合は、トレースの前に、dSYM を生成する設定で正確なシミュレーターアプリを再ビルドするか、該当する dSYM を含むビルド出力ディレクトリを別の --search-root として追加します。

報告内容に疑わしい点がある場合は、トレースの前に重要な UUID を確認します。

dwarfdump --uuid "$APP/$(/usr/libexec/PlistBuddy -c 'Print :CFBundleExecutable' "$APP/Info.plist")"
find "$DSYMS" -maxdepth 1 -type d -name '*.dSYM' -print -exec dwarfdump --uuid {} \;

ETTrace の終了後に、シンボリケーションの概要を確認します。重要なファーストパーティ製コードについて「ライブラリはあるがシンボルがない」という行が出ている場合、ごくわずかなノイズでない限り、そのトレースは失敗と見なします。シンボリケートされていないシステムフレームワークや ETTrace 内部のバケットは、通常は問題ありません。

キャプチャ

起動トレースの場合:

cd "$RUN_DIR"
CAPTURE_MARKER="$RUN_DIR/.ettrace-capture-start"
: > "$CAPTURE_MARKER"
find "$RUN_DIR" -maxdepth 1 \( -name 'output.json' -o -name 'output_*.json' \) -delete
ettrace --simulator --launch --verbose --dsyms "$DSYMS"

起動や初回描画を測定する場合に限り、--launch を使用してください。初回の起動接続によってアプリが強制終了されることがあります。プロンプトが表示された場合は、Xcode からではなくシミュレーターのホーム画面から再起動してください。インストール後の初回起動トレースでは、アプリの Info.plist で一時的に ETTraceRunAtStartup=YES を設定してから、ettrace --simulator を実行し、ホーム画面から起動してください。

実行時のフロートレースの場合:

cd "$RUN_DIR"
CAPTURE_MARKER="$RUN_DIR/.ettrace-capture-start"
: > "$CAPTURE_MARKER"
find "$RUN_DIR" -maxdepth 1 \( -name 'output.json' -o -name 'output_*.json' \) -delete
ettrace --simulator --verbose --dsyms "$DSYMS"

安定した画面から開始し、ETTrace を起動して、対象を絞ったフローを正確に 1 つ実行します。表示される処理が完了するまで待ってから、ランナーを停止してください。より広範囲のアトリビューションを行う場合は --multi-thread を追加してください。それ以外の場合は、まずメインスレッドから開始してください。

Codex では、TTY を使って ettrace を実行し、write_stdin でプロンプトに応答してください。TTY がない場合、ランナーは有用なトレースを出力せずに終了することがあります。

出力の保存

次回の ETTrace 実行によって処理済みのフレームグラフファイルが上書きされることがあるため、新しく生成された output_<thread-id>.json ファイルはすぐに保存してください。保存済みの output.json は分析しないでください。ETTrace では同じ名前のビューアルートも提供されます。また、生の emerge-output/output.json ファイルは、このワークフローで必要とする処理済みフレームグラフの成果物ではありません。

PRESERVED_DIR="$(mktemp -d "$RUN_DIR/run-$(date +%Y%m%d-%H%M%S).XXXXXX")"
: > "$PRESERVED_DIR/summary.txt"
if [ ! -e "$CAPTURE_MARKER" ]; then
  echo "error: capture marker missing; start a fresh ETTrace capture before preserving outputs" >&2
  exit 1
fi
find "$RUN_DIR" -maxdepth 1 -name 'output_*.json' -newer "$CAPTURE_MARKER" -print | while IFS= read -r json; do
  preserved="$PRESERVED_DIR/${json##*/}"
  cp "$json" "$preserved"
  {
    echo "## ${preserved##*/}"
    python3 "$SKILL_DIR/scripts/analyze_flamegraph_json.py" "$preserved"
  } >> "$PRESERVED_DIR/summary.txt"
done
if [ ! -s "$PRESERVED_DIR/summary.txt" ]; then
  echo "error: no fresh processed ETTrace output JSON found in $RUN_DIR" >&2
  exit 1
fi

RUN_DIR 内の処理済み output_*.json ファイルのみを分析してください。ETTrace 自体のデバッグを行う場合を除き、output.json と生の emerge-output/output.json ファイルは無視してください。アナライザーが JSON の形式を受け付けない場合は、却下されたファイルの解釈を試みるのではなく、Homebrew の ETTrace ランナーと、それに対応するアプリ側の ETTrace.xcframework タグを使って再度キャプチャしてください。

プロファイルの確認

まず run-*/summary.txt を確認し、必要に応じて処理済み JSON を直接調べてください。

以下を報告してください。

  • 正確なフロー、アプリのビルド、シミュレーターのモデル/ランタイム、実行回数
  • 処理済みフレームグラフ JSON のパス
  • アクティブ時間が長い末端ノードと、サンプルの重みまたは割合を含むファーストパーティーのインクルーシブスタック
  • アプリ所有のバイナリについてシンボルが完全だったかどうか
  • 初回セットアップ、シミュレーター限定のコスト、ネットワークの変動、サンプル数の少なさなどの注意事項
  • 比較可能な設定で同じフローをキャプチャした場合に限り、変更前後の差分

クリーンアップ

プロファイリングが完了したら、一時的な ETTrace のアプリ連携を削除してください。ただし、ユーザーから保持するよう依頼された場合は除きます。実行成果物は、現在のタスクに応じて保持または破棄してください。

コメント