Agent Skills
› dotnet/skills
› build-parallelism
build-parallelism
GitHub分析 MSBuild 并行构建性能,诊断因串行依赖导致的瓶颈。通过检查 binlog 节点时间线和关键路径,识别不必要的 ProjectReference,推荐扁平化依赖以优化并发构建效率。
Trigger Scenarios
MSBuild 构建速度慢
-m 参数未提升并行度
存在串行项目引用链
需要分析多项目调度吞吐量
Install
npx skills add dotnet/skills --skill build-parallelism -g -y
SKILL.md
Frontmatter
{
"name": "build-parallelism",
"license": "MIT",
"description": "Analyze an MSBuild solution, solution filter, or Build.proj that schedules multiple project files. USE FOR: measured idle worker nodes, `-m` that does not scale, a serial ProjectReference critical path, graph builds, or an MSBuild task that builds a Projects list. Requires at least two distinct project files whose scheduling or throughput must be analyzed. DO NOT USE for non-MSBuild build systems."
}
Diagnose a slow parallel build (start here)
Work this checklist in order — it targets the usual root cause (a serial dependency chain that no number of cores can parallelize):
- Check how many worker nodes actually built the solution. Capture a
binlog with
dotnet build /bl:{}(PowerShell:dotnet build '-bl:{}') and inspect the node timeline to see whether more than one node ran. EverydotnetCLI command built on the SDK's MSBuild-forwarding path (build,msbuild,test,pack,publish, etc.) enables/maxcpucount(multiple nodes) by default;-m:1forces a single node. A directMSBuild.exeinvocation is sequential by default, so pass-mexplicitly to enable parallel worker nodes there. - Find the critical path. From the binlog, read per-project timings and the node timeline. If total build time ≈ the sum of the projects on one dependency chain, that chain — not CPU count — is the bottleneck.
- Name the chain explicitly, e.g.
Core → Api → Web → Tests. A long serial chain stays serial no matter how large-mis, because each project waits on its predecessor. - Look for unnecessary
ProjectReferenceedges that lengthen the chain — a reference that only needs build order (not the output assembly), or one that could be aPackageReference, forces serialization it doesn't need. - Recommend flattening: break false dependencies so independent projects
build concurrently, and consider
/graphfor better scheduling.
MSBuild Parallelism Model
/maxcpucount(or-m): number of worker nodes (processes)- Every
dotnetCLI command (build,msbuild,test,pack,publish, etc.) passes/maxcpucountby default via the SDK's shared MSBuild-forwarding path;-m:1overrides it with one node - A direct
MSBuild.exeinvocation is sequential by default and requires an explicit-m - Recommended:
-mwithout a number = use all logical processors - Each node builds one project at a time
- Projects are scheduled based on dependency graph
Project Dependency Graph
- MSBuild builds projects in dependency order (topological sort)
- Critical path: longest chain of dependent projects determines minimum build time
- Bottleneck: if project A depends on B, C, D and B takes 60s while C and D take 5s, B is the bottleneck
- Diagnosis: replay binlog to diagnostic log with
performancesummaryand check Project Performance Summary — shows per-project time; grep fornode.*assignedto check scheduling - Wide graphs (many independent projects) parallelize well; deep graphs (long chains) don't
Graph Build Mode (/graph)
dotnet build /graphormsbuild /graph- What it changes: MSBuild constructs the full project dependency graph BEFORE building
- Benefits: better scheduling, avoids redundant evaluations, enables isolated builds
- Limitations: all projects must use
<ProjectReference>(no programmatic MSBuild task references) - When to use: large solutions with many projects, CI builds
- When NOT to use: projects that dynamically discover references at build time
Optimizing Project References
- Reduce a
<ProjectReference>only after proving it is unnecessary; a slow but valid dependency must stay in the graph - Use
<ProjectReference ... SkipGetTargetFrameworkProperties="true">to avoid extra evaluations <ProjectReference ... ReferenceOutputAssembly="false">for build-order-only dependencies- Consider if a ProjectReference should be a PackageReference instead (pre-built NuGet)
- Use
solution filters(.slnf) to build subsets of the solution
BuildInParallel
<MSBuild Projects="@(ProjectsToBuild)" BuildInParallel="true" />in custom targets- Without
BuildInParallel="true", MSBuild task batches projects sequentially - Ensure
/maxcpucount> 1 for this to have effect
Multi-threaded MSBuild Tasks
- Individual tasks can run multi-threaded within a single project build
- Tasks implementing
IMultiThreadableTaskcan run on multiple threads - Tasks must declare thread-safety via
[MSBuildMultiThreadableTask]
Analyzing Parallelism with Binlog
Primary: binlog MCP (preferred)
Use the binlog MCP server (Microsoft.AITools.BinlogMcp, exposed under the binlog MCP namespace):
- Use expensive_projects tool → find the slowest projects and compare individual vs total build time
- Use expensive_targets tool → find bottleneck targets
- Use project_target_times tool → drill into a specific project's target-level timing
- Ideal: build time should be much less than sum of project times (parallelism)
- If build time ≈ sum of project times: too many serial dependencies, or one slow project blocking others
Fallback: text-log replay (when MCP is unavailable)
Step-by-step:
- Replay the binlog:
dotnet msbuild build.binlog -noconlog -fl "-flp:v=diag;logfile=full.log;performancesummary" - Check Project Performance Summary at the end of
full.log - Ideal: build time should be much less than sum of project times (parallelism)
- If build time ≈ sum of project times: too many serial dependencies, or one slow project blocking others
grep 'Target Performance Summary' -A 30 full.log→ find the bottleneck targets- Consider splitting large projects or optimizing the critical path
CI/CD Parallelism Tips
- Use
-min CI (many CI runners have multiple cores) - Consider splitting solution into build stages for extreme parallelism
- Use build caching (NuGet lock files, deterministic builds) to avoid rebuilding unchanged projects
dotnet build /graphworks well with structured CI pipelines
Version History
-
10d85e2
Current 2026-10-19 01:58
修正 maxcpucount 默认作用域说明,澄清节点数量检查描述,并优化技能指导内容。
-
5354047
2026-07-23 12:07
新增诊断慢并行构建的‘起点’关键路径检查清单;修正 PowerShell 环境下 dotnet build -m 命令的写法以确保并行标志正确传递。
- ce75c35 2026-07-06 00:31


