build-parallelism について
binlogを使ってクリティカルパスや直列依存を特定し、MSBuildの並列化改善を提案する、.NET開発者向けのビルド診断スキルです。
主な機能
- 01ビルドノードとプロジェクト時間の確認
- 02クリティカルパスと依存チェーンの分析
- 03不要なプロジェクト参照の特定
- 04binlog MCPによるビルド時間の分析
- 05グラフビルドとCI並列化の提案
活用シーン
- 01マルチコア環境でも遅いビルドの調査
- 02ビルドを直列化する依存関係の特定
- 03binlogによる遅いプロジェクトとターゲットの検出
MCP 対応
Microsoft.AITools.BinlogMcpのbinlog MCPツールを使い、プロジェクト、ターゲット、並列ビルド時間を調べる手順を案内します。
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ dotnet/ skills --skill build-parallelismインストール後、Claude Code で/build-parallelismを入力して読み込まれたか確認します。
詳細
低速な並列ビルドを診断する(まずはこちら)
次のチェックリストを順番に確認してください。よくある根本原因である、どれだけコアを増やしても並列化できない直列の依存関係を対象としています。
- ソリューションのビルドを実際に実行したワーカーノードの数を確認します。
dotnet build /bl:{}(PowerShell の場合:dotnet build '-bl:{}')で binlog を取得し、ノードのタイムラインを調べて、複数のノードが実行されたか確認します。SDK の MSBuild 転送経路を使うすべてのdotnetCLI コマンド(build、msbuild、test、pack、publishなど)では、既定で/maxcpucount(複数ノード)が有効になります。-m:1を指定すると、単一ノードに固定されます。MSBuild.exeを直接呼び出す場合、既定では逐次実行されるため、複数のワーカーノードを有効にするには-mを明示的に指定します。 - クリティカルパスを特定します。 binlog から、プロジェクトごとの所要時間とノードのタイムラインを確認します。ビルド全体の所要時間が、1 つの依存関係チェーン上にあるプロジェクトの所要時間の合計にほぼ等しい場合、ボトルネックは CPU 数ではなく、そのチェーンです。
- チェーンを明示します。 例:
Core → Api → Web → Tests。各プロジェクトが前のプロジェクトの完了を待つため、-mをどれだけ大きくしても、長い直列チェーンは直列のままです。 - チェーンを長くする、不要な
ProjectReferenceの依存関係を探します。ビルド順序だけが必要で、出力アセンブリは必要ない参照や、PackageReferenceに置き換えられる参照は、不要な直列化を引き起こします。 - 依存関係のフラット化を推奨します。 偽の依存関係を取り除いて、独立したプロジェクトを並行してビルドできるようにし、より効率的なスケジューリングには
/graphの使用を検討してください。
MSBuild の並列処理モデル
/maxcpucount(または-m):ワーカーノード(プロセス)の数- すべての
dotnetCLI コマンド(build、msbuild、test、pack、publishなど)は、SDK の共有 MSBuild 転送経路を通じて、既定で/maxcpucountを渡します。-m:1を指定すると、1 つのノードに上書きされます MSBuild.exeを直接呼び出す場合、既定では逐次実行されるため、-mの明示的な指定が必要です- 推奨:数字を付けずに
-mを指定すると、すべての論理プロセッサーが使用されます - 各ノードは一度に 1 つのプロジェクトをビルドします
- プロジェクトは依存関係グラフに基づいてスケジュールされます
プロジェクト依存関係グラフ
- MSBuild は依存関係の順序(トポロジカルソート)でプロジェクトをビルドします
- クリティカルパス:依存するプロジェクトの最長チェーンによって、最短のビルド時間が決まります
- ボトルネック:プロジェクト A が B、C、D に依存しており、B に 60 秒、C と D に 5 秒かかる場合、B がボトルネックです
- 診断:binlog を
performancesummaryを使って診断ログに再生し、Project Performance Summary を確認します。プロジェクトごとの所要時間が表示されます。スケジューリングの確認にはnode.*assignedを検索します - 幅の広いグラフ(独立したプロジェクトが多数ある場合)は並列化しやすく、深いグラフ(長いチェーンがある場合)は並列化しにくくなります
グラフビルドモード(/graph)
dotnet build /graphまたはmsbuild /graph- 変更点:MSBuild はビルド前にプロジェクトの依存関係グラフ全体を構築します
- メリット:スケジューリングの改善、重複した評価の回避、分離ビルドの有効化
- 制限事項:すべてのプロジェクトが
<ProjectReference>を使用する必要があります(プログラムから参照する MSBuild タスクは使用できません) - 使用する場面:プロジェクト数の多い大規模なソリューション、CI ビルド
- 使用しない場面:ビルド時に参照を動的に検出するプロジェクト
プロジェクト参照の最適化
<ProjectReference>は不要だと証明できた場合にのみ削除してください。遅くても有効な依存関係は、グラフに残す必要があります<ProjectReference ... SkipGetTargetFrameworkProperties="true">を使用して、余分な評価を回避します- ビルド順序だけの依存関係には
<ProjectReference ... ReferenceOutputAssembly="false">を使用します - ProjectReference を、事前ビルド済みの NuGet パッケージを使用する PackageReference に置き換えるべきか検討します
solution filters(.slnf)を使用して、ソリューションの一部をビルドします
BuildInParallel
- カスタムターゲットで
<MSBuild Projects="@(ProjectsToBuild)" BuildInParallel="true" />を使用します BuildInParallel="true"を指定しない場合、MSBuild タスクはプロジェクトを逐次バッチ処理します- 効果を得るには
/maxcpucountを 1 より大きく設定してください
マルチスレッド MSBuild タスク
- 個々のタスクは、単一のプロジェクトビルド内でマルチスレッド実行できます
IMultiThreadableTaskを実装するタスクは、複数のスレッドで実行できます- タスクでは
[MSBuildMultiThreadableTask]を使用してスレッドセーフであることを宣言する必要があります
Binlog による並列処理の分析
優先:binlog MCP(推奨)
binlog MCP サーバー(binlog MCP 名前空間で公開される Microsoft.AITools.BinlogMcp)を使用します。
- expensive_projects ツールを使用 → 最も遅いプロジェクトを見つけ、個別のビルド時間と合計のビルド時間を比較します
- expensive_targets ツールを使用 → ボトルネックとなっているターゲットを見つけます
- project_target_times ツールを使用 → 特定のプロジェクトのターゲットレベルの所要時間を詳しく調べます
- 理想的には、ビルド時間はプロジェクトの所要時間の合計を大幅に下回ります(並列処理)
- ビルド時間 ≈ プロジェクトの所要時間の合計の場合、直列依存関係が多すぎるか、1 つの遅いプロジェクトがほかのプロジェクトを妨げています
フォールバック:テキストログの再生(MCP を利用できない場合)
手順:
- binlog を再生します:
dotnet msbuild build.binlog -noconlog -fl "-flp:v=diag;logfile=full.log;performancesummary" full.logの末尾にある Project Performance Summary を確認します- 理想的には、ビルド時間はプロジェクトの所要時間の合計を大幅に下回ります(並列処理)
- ビルド時間 ≈ プロジェクトの所要時間の合計の場合、直列依存関係が多すぎるか、1 つの遅いプロジェクトがほかのプロジェクトを妨げています
grep 'Target Performance Summary' -A 30 full.log→ ボトルネックとなっているターゲットを見つけます- 大規模なプロジェクトを分割するか、クリティカルパスを最適化することを検討します
CI/CD の並列処理に関するヒント
- CI では
-mを使用します(多くの CI ランナーは複数のコアを搭載しています) - 極端な並列処理が必要な場合は、ソリューションをビルドステージに分割することを検討します
- ビルドキャッシュ(NuGet のロックファイル、決定論的ビルド)を使用して、変更されていないプロジェクトの再ビルドを避けます
dotnet build /graphは、構造化された CI パイプラインで効果的に機能します
コメント
Markdown 対応