eval-performance
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMSBuild Evaluation Phases
MSBuild 评估阶段
For a comprehensive overview of MSBuild's evaluation and execution model, see Build process overview.
- Initial properties: environment variables, global properties, reserved properties
- Imports and property evaluation: process , evaluate
<Import>top-to-bottom<PropertyGroup> - Item definition evaluation: metadata defaults
<ItemDefinitionGroup> - Item evaluation: with
<ItemGroup>,Include,Remove, glob expansionUpdate - UsingTask evaluation: register custom tasks
Key insight: evaluation happens BEFORE any targets run. Slow evaluation = slow build start even when nothing needs compiling.
如需全面了解MSBuild的评估和执行模型,请参阅构建流程概述。
- 初始属性:环境变量、全局属性、保留属性
- 导入与属性评估:处理,从上到下评估
<Import><PropertyGroup> - 项定义评估:元数据默认值
<ItemDefinitionGroup> - 项评估:包含、
Include、Remove、glob展开的Update<ItemGroup> - UsingTask评估:注册自定义任务
核心要点:评估发生在所有目标运行之前。评估缓慢 = 即使没有任何内容需要编译,构建启动也会很慢。
Diagnosing Evaluation Performance
诊断评估性能
Using binlog
使用binlog
- Replay the binlog:
dotnet msbuild build.binlog -noconlog -fl -flp:v=diag;logfile=full.log - Search for evaluation events:
grep -i 'Evaluation started\|Evaluation finished' full.log - Multiple evaluations for the same project = overbuilding
- Look for "Project evaluation started/finished" messages and their timestamps
- 重放binlog:
dotnet msbuild build.binlog -noconlog -fl -flp:v=diag;logfile=full.log - 搜索评估事件:
grep -i 'Evaluation started\|Evaluation finished' full.log - 同一个项目多次评估 = 过度构建
- 查找“Project evaluation started/finished”消息及其时间戳
Using /pp (preprocess)
使用/pp(预处理)
dotnet msbuild -pp:full.xml MyProject.csproj- Shows the fully expanded project with ALL imports inlined
- Use to understand: what's imported, import depth, total content volume
- Large preprocessed output (>10K lines) = heavy evaluation
dotnet msbuild -pp:full.xml MyProject.csproj- 展示完全展开的项目,所有导入都已内联
- 用于了解:导入内容、导入深度、总内容量
- 预处理输出过大(>10K行)= 评估负担重
Using /clp:PerformanceSummary
使用/clp:PerformanceSummary
- Add to build command for timing breakdown
- Shows evaluation time separately from target/task execution
- 添加到构建命令中以获取耗时拆分
- 单独展示评估时间,与目标/任务执行时间区分开
Expensive Glob Patterns
高开销Glob模式
- Globs like walk the entire directory tree
**/*.cs - Default SDK globs are optimized, but custom globs may not be
- Problem: globbing over ,
node_modules/,.git/,bin/— millions of filesobj/ - Fix: use to exclude large directories
<DefaultItemExcludes> - Fix: be specific with glob paths: instead of
src/**/*.cs**/*.cs - Fix: use only as last resort (lose SDK defaults)
<EnableDefaultItems>false</EnableDefaultItems> - Check: grep for Compile items in the diagnostic log → if Compile items include unexpected files, globs are too broad
- 类似的glob会遍历整个目录树
**/*.cs - 默认SDK的glob已经过优化,但自定义glob可能没有
- 问题场景:对、
node_modules/、.git/、bin/等包含数百万文件的目录做glob匹配obj/ - 修复方案:使用排除大体积目录
<DefaultItemExcludes> - 修复方案:使用更明确的glob路径:用代替
src/**/*.cs**/*.cs - 修复方案:仅万不得已时使用(会丢失SDK默认配置)
<EnableDefaultItems>false</EnableDefaultItems> - 检查方法:在诊断日志中搜索Compile项 → 如果Compile项包含预期外的文件,说明glob范围过宽
Import Chain Analysis
导入链分析
- Deep import chains (>20 levels) slow evaluation
- Each import: file I/O + parse + evaluate
- Common causes: NuGet packages adding .props/.targets, framework SDK imports, Directory.Build chains
- Diagnosis: output → search for
/ppcomments to see import tree<!-- Importing - Fix: reduce transitive package imports where possible, consolidate imports
- 深层导入链(>20层)会拖慢评估速度
- 每次导入都需要:文件I/O + 解析 + 评估
- 常见原因:NuGet包添加.props/.targets文件、框架SDK导入、Directory.Build链
- 诊断方法:查看/pp输出 → 搜索注释查看导入树
<!-- Importing - 修复方案:尽可能减少传递包导入,合并导入
Multiple Evaluations
多次评估
- A project evaluated multiple times = wasted work
- Common causes: referenced from multiple other projects with different global properties
- Each unique set of global properties = separate evaluation
- Diagnosis: → if count > 1, check for differing global properties
grep 'Evaluation started.*ProjectName' full.log - Fix: normalize global properties, use graph build ()
/graph
- 一个项目被多次评估 = 无用开销
- 常见原因:被多个使用不同全局属性的其他项目引用
- 每组唯一的全局属性 = 单独的一次评估
- 诊断方法:→ 如果计数>1,检查是否存在不同的全局属性
grep 'Evaluation started.*ProjectName' full.log - 修复方案:统一全局属性,使用图构建()
/graph
TreatAsLocalProperty
TreatAsLocalProperty
- Prevents property values from flowing to child projects via MSBuild task
- Overuse: declaring many TreatAsLocalProperty entries adds evaluation overhead
- Correct use: only when you genuinely need to override an inherited property
- 防止属性值通过MSBuild任务传递到子项目
- 过度使用:声明大量TreatAsLocalProperty条目会增加评估开销
- 正确用法:仅当你确实需要覆盖继承的属性时才使用
Property Function Cost
属性函数开销
- Property functions execute during evaluation
- Most are cheap (string operations)
- Expensive: during evaluation — reads file on every evaluation
$([System.IO.File]::ReadAllText(...)) - Expensive: network calls, heavy computation
- Rule: property functions should be fast and side-effect-free
- 属性函数在评估阶段执行
- 大部分开销很低(字符串操作)
- 高开销场景:评估阶段执行→ 每次评估都会读取文件
$([System.IO.File]::ReadAllText(...)) - 高开销场景:网络调用、大量计算
- 规则:属性函数应该快速且无副作用
Optimization Checklist
优化清单
- Check preprocessed output size:
dotnet msbuild -pp:full.xml - Verify evaluation count: should be 1 per project per TFM
- Exclude large directories from globs
- Avoid file I/O in property functions during evaluation
- Minimize import depth
- Use graph build to reduce redundant evaluations
- Check for unnecessary UsingTask declarations
- 检查预处理输出大小:
dotnet msbuild -pp:full.xml - 验证评估次数:每个项目每个TFM应为1次
- 从glob中排除大体积目录
- 评估阶段避免在属性函数中执行文件I/O
- 最小化导入深度
- 使用图构建减少冗余评估
- 检查不必要的UsingTask声明