--- name: eval-performance description: "Guide for diagnosing and improving MSBuild project evaluation performance. Only activate in MSBuild/.NET build context. USE FOR: builds slow before any compilation starts, high evaluation time in binlog analysis, expensive glob patterns walking large directories (node_modules, .git, bin/obj), deep import chains (>20 levels), preprocessed output >10K lines indicating heavy evaluation, property functions with file I/O ($([System.IO.File]::ReadAllText(...))), multiple evaluations per project. Covers the 5 MSBuild evaluation phases, glob optimization via DefaultItemExcludes, import chain analysis with /pp preprocessing. DO NOT USE FOR: compilation-time slowness (use build-perf-diagnostics), incremental build issues (use incremental-build), non-MSBuild build systems. INVOKES: dotnet msbuild -pp:full.xml for preprocessing, /clp:PerformanceSummary." license: MIT --- ## MSBuild Evaluation Phases For a comprehensive overview of MSBuild's evaluation and execution model, see [Build process overview](https://learn.microsoft.com/en-us/visualstudio/msbuild/build-process-overview). 1. **Initial properties**: environment variables, global properties, reserved properties 2. **Imports and property evaluation**: process ``, evaluate `` top-to-bottom 3. **Item definition evaluation**: `` metadata defaults 4. **Item evaluation**: `` with `Include`, `Remove`, `Update`, glob expansion 5. **UsingTask evaluation**: register custom tasks Key insight: evaluation happens BEFORE any targets run. Slow evaluation = slow build start even when nothing needs compiling. ## Diagnosing Evaluation Performance ### Using binlog 1. Replay the binlog: `dotnet msbuild build.binlog -noconlog -fl -flp:v=diag;logfile=full.log` 2. Search for evaluation events: `grep -i 'Evaluation started\|Evaluation finished' full.log` 3. Multiple evaluations for the same project = overbuilding 4. Look for "Project evaluation started/finished" messages and their timestamps ### Using /pp (preprocess) - `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 ### Using /clp:PerformanceSummary - Add to build command for timing breakdown - Shows evaluation time separately from target/task execution ## Expensive Glob Patterns - Globs like `**/*.cs` walk the entire directory tree - Default SDK globs are optimized, but custom globs may not be - Problem: globbing over `node_modules/`, `.git/`, `bin/`, `obj/` — millions of files - Fix: use `` to exclude large directories - Fix: be specific with glob paths: `src/**/*.cs` instead of `**/*.cs` - Fix: use `false` only as last resort (lose SDK defaults) - Check: grep for Compile items in the diagnostic log → if Compile items include unexpected files, globs are too broad ## 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: `/pp` output → search for `