エンジニアリングガイド

クラウドMacでSwiftのコンパイル遅延を特定する

クラウドMacでSwiftのコンパイル遅延を特定する

Swiftモジュールのコンパイル時間が数十秒から数分へと徐々に延びてきた場合、すぐにコードを書き直したり並列度を上げたりするべきではありません。リモート環境では、依存関係の解決、ビルドスクリプト、リンク、型チェックの時間もすべてXcodeの合計時間に含まれます。効果的に調査するには、クラウドMacのツールチェーンと入力条件を固定し、工程別の根拠を収集してから、問題を具体的なソースファイルや式へ絞り込みます。

再現可能な計測ベースラインを作る

ほかのビルドタスクが動いていない時間帯を選び、コードのコミット、Scheme、Configuration、SDK、ターゲットアーキテクチャを固定します。xcodebuild -version、現在のコミット、実際に実行したコマンドを記録してください。クリーンビルド1回とインクリメンタルビルド1回をそのまま比較してはいけません。この2つは異なる問題を測定しています。

mkdir -p "$HOME/build-audit"
xcodebuild -version > "$HOME/build-audit/toolchain.txt"
git rev-parse HEAD > "$HOME/build-audit/commit.txt"

set -o pipefail
/usr/bin/time -l xcodebuild \
  -workspace MyApp.xcworkspace \
  -scheme MyApp \
  -configuration Release \
  -destination 'generic/platform=iOS' \
  -showBuildTimingSummary \
  build \
  2>&1 | tee "$HOME/build-audit/baseline.log"

まず通常のインクリメンタルビルドを3回連続で実行し、所要時間のばらつきが安定しているか確認します。クリーンビルドを計測する場合は、明示的にcleanを実行するか、専用のDerivedDataパスを使用し、最適化前後でクリーンアップ方法を完全に統一してください。

1回だけの最速値を結論にしてはいけません。同一条件で複数回実行した中央値を比較し、最も遅かった回のログも保存して、突発的なスクリプト実行、ネットワークリクエスト、リソース競合を確認します。

工程別サマリーから調査方針を決める

Build Timing Summaryには、コンパイル、リンク、リソース処理、スクリプトなどの工程が表示されます。最後の合計時間だけを見るのではなく、割合が大きく、繰り返し現れる項目を先に特定します。

現象 優先して確認する項目 よくある誤認
SwiftCompileが長時間にわたり首位 型チェック、単一ファイルのサイズ、バッチコンパイルの挙動 リンクが遅いと思い込む
Run Scriptが毎回実行される 入出力ファイル、スクリプト内部のスキャン範囲 マシンの並列度だけを上げる
依存関係の解決時間が不安定 ロックファイル、リポジトリアクセス、解決処理の重複 Swiftコンパイルの問題と判断する
Link工程が突出している リンク入力、デバッグシンボル、重複ライブラリ ビジネスロジックの式を書き直す

スクリプトに入力と出力が宣言されているかも確認してください。依存関係の境界が定義されていないスクリプトは、インクリメンタルビルドのたびに実行され、ソースコード最適化の効果を覆い隠す可能性があります。スクリプトにダウンロード処理が含まれる場合は、ネットワーク待機時間とローカル計算時間を分けて計測します。

遅い関数と式を特定する

ボトルネックがSwiftコンパイルにあると確認できたら、フロントエンドの診断オプションを一時的に追加します。チームの日常的な設定に影響させないよう、診断専用ConfigurationのOTHER_SWIFT_FLAGSに設定できます。

-Xfrontend -debug-time-function-bodies
-Xfrontend -debug-time-expression-type-checking

同じビルドコマンドを再実行し、標準エラーも含めて保存します。通常、ログには所要時間、ファイル位置、関数または式が出力されます。出力形式やしきい値はXcodeのツールチェーンによって変わる可能性があるため、解析スクリプトで列数が常に固定されていると仮定してはいけません。

何を優先して対処するか

まず所要時間で並べ替え、次にファイル単位で集約します。数百回繰り返しコンパイルされる中程度のホットスポットは、単発の極端に遅い関数よりも優先度が高い場合があります。コストが高くなりやすいコードには、長すぎるジェネリックチェーン、ネストしたクロージャ、多数の分岐を含む単一の式、複数の中間型をコンパイラに同時推論させるコレクション変換などがあります。

変更時は、式の分割、中間値への明示的な型指定、大きな関数の境界が明確な小さな関数への分割など、毎回1種類の問題だけを扱います。コンパイル設定とソースコードを同時に変更すると、どちらが改善に寄与したのか判断できなくなります。

最小限の変更で原因を検証する

フィルタリング、マッピング、辞書の構築、オプショナル値の処理を1つの式に連結しているコードがあるとします。まず中間結果に名前を付け、型を明示できます。目的はソースコードを短くすることではなく、型チェッカーが一度に解く必要のある制約を減らすことです。

let validItems: [Item] = items.filter { $0.isValid }
let identifiers: [String] = validItems.map(\.identifier)
let result: [String: Item] = Dictionary(
    uniqueKeysWithValues: zip(identifiers, validItems)
)

変更後は、同じコミットのベースラインに対して、その変更だけを含むブランチで再計測します。少なくとも、ホットスポットログ内で該当する式の時間が減ったか、SwiftCompile工程が短縮したか、複数回の実行で合計ビルド時間が安定して改善したか、という3点を確認してください。合計時間だけが変化し、ホットスポットが変わらない場合は、ソースコードの変更による効果と判断せず、キャッシュやバックグラウンドタスクを引き続き調査します。

診断を保守可能な検証プロセスにする

診断オプションをすべてのビルドへ恒久的に追加するのは適切ではありません。より堅実な方法は、独立したパフォーマンス検証タスクを用意し、必要に応じて実行して、ツールチェーン、コミット、コマンド、サマリーをアーカイブすることです。ログにはローカルパス、リポジトリ構造、展開後の環境変数が含まれる可能性があるため、アップロード前に機密情報を除去してください。

各調査では、次の内容を保存することを推奨します。

  1. XcodeとSwiftのバージョン。
  2. Gitコミットとビルド設定。
  3. クリーンビルドかインクリメンタルビルドかを示す明確な記録。
  4. 3回以上実行した生の所要時間。
  5. 工程別サマリーと主要なソースコードのホットスポット。
  6. 変更前後の唯一の差分とロールバック方法。

クラウドMac上で結果のばらつきが大きい場合は、並列ビルド、インデックス作成タスク、残存スクリプトが実行されていないかを先に確認してから、再計測してください。MiniRentが提供するのは専有物理ノードですが、同じデバイス上でユーザーが起動したタスク同士は、引き続きCPU、メモリ、ディスクを奪い合います。信頼できる結論は、一度だけ速く見えたビルドではなく、制御された入力、再現可能なコマンド、完全に保存された根拠から得られます。

よくある質問

Xcodeの合計ビルド時間だけでは不十分なのはなぜですか?

依存関係の解決、キャッシュ、スクリプト、リンク時間が混在するためです。コミットとXcodeバージョンを固定し、工程別の時間とSwiftコードの診断結果を確認します。

Swiftの時間診断オプションは常時有効にしてよいですか?

常時利用は推奨しません。ログ量が増え、ツールチェーンによって挙動も変わるため、調査時だけ有効にし、原因を確認したら設定から外します。

専用クラウドMac

専用物理ノードでビルドタスクを実行

MiniRents M4またはMiniRents M4 Proを日単位、週単位、月単位、四半期単位から選択し、チームとコードリポジトリの場所に合わせてノードを選べます。物理マシンを専有利用でき、仮想マシンではありません。

モデルを選んで注文