swift-performance について
swift-performanceは、Swiftアプリの性能改善と診断のためのワークフローです。開発者向けに、負荷のモデル化、ホットパス分析、処理の抑制、測定と検証を案内します。
主な機能
- 01規模別のワークロードモデル作成
- 02ホットパスの実行頻度分析
- 03描画と反復処理の抑制
- 04性能コストの測定と切り分け
- 05ベースラインとの比較による修正検証
活用シーン
- 01機能の性能リスクをレビュー
- 02アプリの遅い操作を診断
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ yahyabedirhan/ skills --skill swift-performanceインストール後、Claude Code で/swift-performanceを入力して読み込まれたか確認します。
同梱ファイルscripts/MainThreadMeter.swiftscripts/sample-busy.py
詳細
Swift のパフォーマンス
コストとは、1 回あたりの処理量に実行頻度を掛けたものです。ビルドモードでは、コードを書きながら、コストの高い処理がホットパスに入らないようにします。診断モードでは、ホットパスに入り込んだ処理を特定し、その修正をビルドモードに反映します。
アプリごとに必要なものは異なるため、それぞれのアプリ用にフィクスチャ、シナリオ、カウンターを用意してください。
ビルドモード
新機能ではすべての手順を実行します。レビューでは、差分に対して手順 4 から 6 を実行します。
- ワークロードモデル。 各ビューの項目数を、現在、×10、×100 の場合について記録します。最も規模の大きいビューは、通常、ほかのビューを統合するビューです。
- ホットパス分析。 各計算に、実行頻度(フレームごと、入力イベントごと、アクションごと、データ変更ごと、または 1 回のみ)を付けます。
- パフォーマンス予算。 120 Hz ではフレームごとのメインスレッド時間は 8 ms、60 Hz では 16 ms です。アクションは 100 ms 未満で完了します。何も操作していないウィンドウの CPU 使用率は約 0%です。
- 各ホットパスのコストが ×10 の規模でも予算内に収まるか、問題ありと判定されていれば完了です。
- 処理量の上限設定。
- 増加するコレクションは、
LazyVStack、List、またはTableで遅延描画します。VStackはすべての項目を構築します。 - アニメーション、シンボルエフェクト、
TimelineView、タイマー、ポーリングは、表示中かつ変化中の間だけ実行します。エフェクトを繰り返すと、ウィンドウはすべてのフレームで描画され続けます。 - 大きなサブツリーの
.idは安定させます。新しい.idを設定すると、サブツリーが再構築されます。
- 増加するコレクションは、
- 再利用と無効化。
- 派生コレクションはソースが変更されたときに計算し、
bodyでは保存済みの結果を読み取ります。 - ホバーや選択など、頻繁に変化する状態は、それを必要とする最小のビューに置きます。リストのルートに状態を置くと、すべての行が再描画されます。
- ツールチップのテキストなど、項目ごとの追加情報は、表示するときだけ構築します。
- 項目のジオメトリは必要に応じて読み取るか、スクロールしない座標空間で読み取ります。
- 派生コレクションはソースが変更されたときに計算し、
- 並行処理と I/O。 メインスレッドは描画と入力に使います。扱いやすい並行処理を備えた Swift 6.2 では、CPU 負荷の高い非同期関数に
@concurrentを付けます。通常のnonisolated async関数は、呼び出し元のアクターで実行されるためです。 - 計測。 問題ありと判定した各パスを、それぞれのデータ量で変更前と変更後に計測します。
診断モード
- 症状。 何が、どこで、どの程度遅いのか、またどのデータ量で発生するのかを記録します。
- 再現。 アプリのコピーと専用データを使い、ユーザーと同じデータ量で再現します。これにより、ユーザーのアプリとデータは変更されずに済みます。
- 計測。 ユーザーがたどるパスで、アイドル時、遅い操作時、比較用の速いケースを計測します。
- 遅いケースと速いケースに数値上の差があれば完了です。
- 切り分け。 コストがなくなるまで、要素を 1 つずつ無効にします。プロファイルにフレームワークのコードしか表示されない場合は、必ずこの手順を行います。プロファイラーは時間のかかる箇所を示しますが、その理由までは示さないためです。
- 根本原因。 メカニズム、発生頻度、ファイルと行、違反しているビルドルールを特定します。
- 原因を取り除くとコストもなくなれば完了です。
- 検証。 変更していないベースラインと並べて、修正を計測します。
各シナリオのメインスレッド使用率、最長の停止時間、最も遅いアクションを表にまとめ、その後に根本原因を記載します。
信頼できる計測
- メインスレッドの CPU 使用率と停止時間を計測します。CPU 使用率の合計やフレームレートだけでは、時間の使われ方は分かりません。
- 本体とハンドラーの実行回数を数えます。実行頻度がコストの大半を説明するためです。
- 計測中の状態を確認します。ウィンドウが開いていること、データが読み込まれていること、同じメインスレッド上でほかの描画が行われていないことを確認してください。
- 使用するツールがコストの原因になっていないか確認します。自動化やスクリーンショットは、アプリの描画内容を変える場合があります。
- リリースビルド同士を比較し、各ケースを少なくとも 2 回繰り返します。1 回の実行につき、変更する要素は 1 つだけにします。
スクリプト
scripts/MainThreadMeter.swift:ビルド可能なアプリ内で、メインスレッドの CPU 使用率と停止時間を計測します。8 ms の ping がメインスレッドを起こすため、アイドル時はsampleで計測してください。scripts/sample-busy.py:実行中の任意のアプリについて、sample <pid> <seconds> -mayDie -file <path>の出力からメインスレッドのビジー率を算出します。--frames <binary>を指定すると、そのバイナリで最も負荷の高いフレームを一覧表示します。
コメント
Markdown 対応