SSkilltecabyclaudinhocode
Enviar skill
← Voltar para o catálogo

instruments-profiler

Desenvolvimento

xctrace CLIでiOS/macOSアプリをInstrumentsプロファイリングし、パフォーマンス問題を特定・修正するワークフロー。「Instrumentsで計測」「プロファイリング」「パフォーマンス計測」で使用。

9estrelas
Ver no GitHub ↗Autor: kyoya1123Licença: MIT

Instruments Profiler

Overview

xctrace CLIを使ってiOS/macOSアプリをInstrumentsでプロファイリングし、パフォーマンス問題を特定・修正する。

Core Workflow

1) デバイス選択

  1. デバイス一覧を取得

    # シミュレータ一覧
    xcrun simctl list devices available
    
    # 実機 + シミュレータ一覧(xctrace用UDID付き)
    xctrace list devices
    
  2. 具体的なデバイスをユーザーに確認(AskUserQuestionを使用)

    シミュレータと実機の両方を選択肢に含める:

    questions: [{
      question: "プロファイリングを実行するデバイスを選択してください(実機推奨)",
      header: "デバイス",
      options: [
        { label: "<実機名1>", description: "実機 - UDID: xxx(推奨)" },
        { label: "<実機名2>", description: "実機 - UDID: yyy(推奨)" },
        { label: "iPhone 17 Pro (Simulator)", description: "シミュレータ" }
      ],
      multiSelect: false
    }]
    

    ポイント: 実機を先頭に表示し推奨する。実機の方がシミュレータより安定した動作が期待できる。

  3. デバイスUDIDの取得

    xctrace list devicesの出力からUDIDを取得する:

    例: John's iPhone (26.0) (00008101-XXXXXXXXXXXX) → UDIDは 00008101-XXXXXXXXXXXX

2) Releaseビルド

重要: Debugビルドは最適化なしで計測不正確。必ずReleaseビルドを使用。

シミュレータの場合:

xcodebuild -scheme "<スキーム名>" \
  -configuration Release \
  -destination "id=<シミュレータUDID>" \
  -derivedDataPath /tmp/DerivedData \
  build

# appパスを取得
APP_PATH=$(find /tmp/DerivedData -name "*.app" -path "*/Release-iphonesimulator/*" | head -1)

# シミュレータにインストール
xcrun simctl install "<シミュレータUDID>" "$APP_PATH"

実機の場合:

xcodebuild -scheme "<スキーム名>" \
  -configuration Release \
  -destination "id=<実機UDID>" \
  -derivedDataPath /tmp/DerivedData \
  build

# appパスを取得
APP_PATH=$(find /tmp/DerivedData -name "*.app" -path "*/Release-iphoneos/*" | head -1)

# 実機にインストール
xcrun devicectl device install app --device "<実機UDID>" "$APP_PATH"

bundleIdの取得:

defaults read "$APP_PATH/Info.plist" CFBundleIdentifier

3) プロファイリングモード選択

ユーザーに計測モードを確認(AskUserQuestionを使用):

questions: [{
  question: "計測モードを選択してください(Leaks, Allocations, Animation Hitches, Energy Logはその他から入力)",
  header: "計測モード",
  options: [
    { label: "SwiftUI", description: "Time Profiler + View Body + Hangs + Hitches" },
    { label: "App Launch", description: "起動時間 + フェーズ分析" },
    { label: "Time Profiler", description: "CPU時間プロファイリング(汎用)" }
  ],
  multiSelect: false
}]

注意:

  • 選択肢にないモード(Leaks, Allocations, Animation Hitches, Energy Log)はユーザーが「その他」から入力して指定可能
  • Energy Logは実機でのみ正確なデータが取得可能。シミュレータでは意味のあるデータが得られない。

4) プロファイリング実行

トレースファイル名の生成(ファイル名衝突を防ぐためタイムスタンプを使用):

TIMESTAMP=$(date +%Y%m%d-%H%M%S)
TRACE_FILE="/tmp/profile_${TIMESTAMP}.trace"
TRACE_SYM_FILE="/tmp/profile_${TIMESTAMP}_sym.trace"
EXPORT_DIR="/tmp/exported_${TIMESTAMP}"

App Launchテンプレートの場合(全自動)

App Launchは起動完了を自動検出して終了するため、確認なしで直接実行する。

# 同期実行(自動終了を待つ)
xctrace record \
  --template "App Launch" \
  --device "<デバイス>" \
  --output $TRACE_FILE \
  --launch <bundleId>
  • バックグラウンド実行不要
  • ユーザーによる停止確認不要
  • 開始確認も不要
  • 起動完了後、自動的にシンボル化・解析へ進む

SwiftUIテンプレートの場合(ユーザー操作が必要)

起動方法の選択(AskUserQuestionを使用):

questions: [{
  question: "アプリの起動方法を選択してください",
  header: "起動方法",
  options: [
    { label: "起動中のアプリに接続", description: "既に起動中のアプリにアタッチ(--attach)" },
    { label: "アプリを起動して計測", description: "アプリを新規起動してプロファイリング(--launch)" }
  ],
  multiSelect: false
}]

「起動中のアプリに接続」を選択した場合:

# PIDを検索
ps aux | grep <アプリ名>
# または xcrun devicectl で実機のプロセス一覧を取得

実行フロー:

  1. run_in_background: trueでxctraceを実行(--time-limitなし)
  2. AskUserQuestionで停止を待つ
  3. ユーザーが停止を選択したら、xctraceプロセスをkill
  4. 通常通りシンボル化・解析を続行
# バックグラウンドで実行(time-limitなし)
Bash(run_in_background: true):
  # --attach の場合
  xctrace record --template "SwiftUI" --device "<デバイス>" --output $TRACE_FILE --attach <PID>
  # --launch の場合
  xctrace record --template "SwiftUI" --device "<デバイス>" --output $TRACE_FILE --launch <bundleId>
# → shell_idを控える

# ユーザーに停止タイミングを確認
AskUserQuestion:
  question: "アプリを操作してください。計測を終了する場合は停止を押してください"
  options: [
    { label: "停止", description: "計測を終了して解析を開始" },
    { label: "停止", description: "計測を終了して解析を開始" }
  ]

# 「停止」が選択されたら
pkill -INT -f "xctrace record"

# TaskOutputで完了を確認
TaskOutput(task_id: "<shell_id>", block: false)

Time Profilerテンプレートの場合

汎用CPUプロファイリング。SwiftUIテンプレートと同様のフローを使用。

Leaks / Allocationsテンプレートの場合

メモリ関連テンプレートはユーザー操作が必要で、SwiftUIテンプレートと同様のフローを使用。

注意: Leaks/Allocationsは十分なメモリ操作(画面遷移、データ読み込み等)を行ってから停止すること。

Animation Hitchesテンプレートの場合

フレームドロップ検出。スクロールやアニメーション操作が必要。SwiftUIテンプレートと同様のフローを使用。

Energy Logテンプレートの場合

重要: Energy Logは実機のみで正確なデータが取得可能。シミュレータでは意味のあるデータが得られない。

デバイス選択時にシミュレータが選択された場合は警告を表示し、実機を選択するよう促す。


xctrace recordコマンド(内部参照用)

--attach(起動中のアプリに接続):

xctrace record --template "<テンプレート>" --device "<デバイス名 or UDID>" --output $TRACE_FILE --attach <PID>

--launch(アプリを起動して計測):

xctrace record --template "<テンプレート>" --device "<デバイス名 or UDID>" --output $TRACE_FILE --launch <bundleId>

注意:

  • --launch--attach引数はコマンドの最後に配置
  • 実機・シミュレータ共通でbundleIdを使用可能

5) シンボル化(重要)

アプリコードのシンボルを解決するために、dSYMを使ってトレースをシンボル化:

xctrace symbolicate \
  --input $TRACE_FILE \
  --output $TRACE_SYM_FILE \
  --dsym ~/Library/Developer/Xcode/DerivedData/<project>/Build/Products/Release-iphoneos/

シンボル化しないと: アプリのコードがunknown<deduplicated_symbol>として表示される。

6) データエクスポート

<skill_dir>/scripts/export_trace.sh $TRACE_SYM_FILE $EXPORT_DIR

出力:

  • $EXPORT_DIR/toc.xml - テーブル一覧
  • $EXPORT_DIR/time-profile.xml - Time Profilerデータ
  • $EXPORT_DIR/report.md - 解析レポート

7) 解析・診断

# 基本的な解析
<skill_dir>/scripts/parse_trace.py $EXPORT_DIR

# アプリ固有コードをフィルタリング
<skill_dir>/scripts/parse_trace.py $EXPORT_DIR --app "MyApp"

# Flame Graph用データのみ出力
<skill_dir>/scripts/parse_trace.py $EXPORT_DIR --collapsed-only

出力内容:

  • Summary - サンプル数、合計時間
  • Hot Frames - Total Time - 関数の総実行時間(呼び出し先含む)
  • Hot Frames - Self Time - 関数自身の実行時間(リーフフレーム)
  • SwiftUI / AttributeGraph Frames - SwiftUI関連の処理
  • App Code - アプリ固有のコード(--app指定時)
  • SwiftUI View Body Updates - View更新統計(SwiftUIテンプレート使用時)
  • Potential Hangs - ハング検出(SwiftUIテンプレート使用時)
  • Animation Hitches - フレームドロップ(SwiftUIテンプレート使用時)
  • Flame Graph Data - collapsed stack形式

解析観点:

パターン意味対処
Self Time高その関数自体が重いアルゴリズム改善、キャッシュ
Total Time高 / Self Time低呼び出し先に問題呼び出し先を調査
SwiftUI関連が多いView更新が頻繁状態スコープ縮小

重要: 報告のフィルタリング

  • パフォーマンスに実質的な影響がない軽微な問題は報告しない
  • 例: 数ms以下のホットフレーム、発生頻度が極めて低いヒッチ、ユーザー体験に影響しないレベルのメモリ使用量
  • ユーザーが実際にアクションを取るべき問題のみを報告する

8) 改善計画の確認

解析結果を表示した後、ユーザーに改善計画を立てるかどうかを確認する(AskUserQuestionを使用):

questions: [{
  question: "解析が完了しました。改善計画を立てますか?",
  header: "次のステップ",
  options: [
    { label: "改善計画を立てる", description: "問題箇所を特定し、具体的な修正プランを作成" },
    { label: "結果の確認のみ", description: "今回は計測結果の確認だけで終了" }
  ],
  multiSelect: false
}]

「改善計画を立てる」を選択した場合:

  1. 解析結果から問題の優先度を特定
  2. 各問題に対する具体的な修正方針を提案
  3. 影響範囲と修正のリスクを説明
  4. 必要に応じて EnterPlanMode で詳細な実装計画を作成

「結果の確認のみ」を選択した場合:

  • 解析結果のサマリーを表示して終了
  • 後から /instruments-profiler で再度計測可能であることを伝える

9) Flame Graph生成(オプション)

git clone https://github.com/brendangregg/FlameGraph
./FlameGraph/flamegraph.pl $EXPORT_DIR/collapsed.txt > flamegraph.svg

10) 修正提案

注意: パフォーマンスに実質的な影響がある問題のみ提案する。無視できるレベルの小さな問題には言及しない。

問題特定後、以下のパターンを適用:

問題解決策
ループ内のData.appendwithUnsafeMutableBytesで直接書き込み
Array.removeFirst (O(n))リングバッファまたはインデックス管理
View invalidation storms状態スコープの縮小
Heavy work in body事前計算・キャッシュ
Large imagesダウンサンプリング

Troubleshooting

エラー原因対処
Permission denied開発者ツールアクセス未許可システム設定で許可
Device not foundデバイス名/UDIDが不正xctrace list devicesで確認
Template not foundテンプレート名が不正xctrace list templatesで確認
Empty trace操作なし/すぐ停止した十分にアプリを操作してから停止
シンボルがunknowndSYMがないxctrace symbolicateでシンボル化
Cannot find processプロセス検索失敗--launchオプションを使用
Leaks/Allocationsが空track-based exportが必要export_trace.shが最新か確認
Energy Logデータなしシミュレータ非対応実機で計測(シミュレータでは取得不可)
No en

Como adicionar

/plugin marketplace add kyoya1123/instruments-profiler

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Comentários · Nenhum comentário

Entre para comentar. Entrar

  • Ainda não há comentários. Seja o primeiro.