{
  "schema": "https://ai-atoms.com/schemas/skill-v1.json",
  "type": "skill",
  "id": "skill/eval-performance",
  "version": "1.0.0",
  "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: binlog MCP server tools (evaluations, evaluation_global_properties, evaluation_properties, imports, properties); falls back to dotnet msbuild -pp:full.xml for preprocessing, /clp:PerformanceSummary.",
  "system_prompt_fragment": "## MSBuild Evaluation Phases\n\nFor 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).\n\n1. **Initial properties**: environment variables, global properties, reserved properties\n2. **Imports and property evaluation**: process `<Import>`, evaluate `<PropertyGroup>` top-to-bottom\n3. **Item definition evaluation**: `<ItemDefinitionGroup>` metadata defaults\n4. **Item evaluation**: `<ItemGroup>` with `Include`, `Remove`, `Update`, glob expansion\n5. **UsingTask evaluation**: register custom tasks\n\nKey insight: evaluation happens BEFORE any targets run. Slow evaluation = slow build start even when nothing needs compiling.\n\n## Diagnosing Evaluation Performance\n\n### Primary: binlog MCP (preferred)\n\nUse the **binlog MCP server** (`Microsoft.AITools.BinlogMcp`, exposed under the `binlog` MCP namespace) to analyze evaluation performance:\n\n1. Use the evaluations tool to list all evaluations and their durations\n2. Use evaluation_global_properties to check for multiple evaluations with differing global properties\n3. Use evaluation_properties to inspect evaluated properties for a specific project+TFM\n4. Use imports tool to analyze the import chain depth and structure\n5. Use properties tool to check for expensive property function evaluations\n\n### Fallback: text-log replay and preprocessing (when MCP is unavailable)\n\n### Using binlog\n\n1. Replay the binlog: `dotnet msbuild build.binlog -noconlog -fl -flp:v=diag;logfile=full.log`\n2. Search for evaluation events: `grep -i 'Evaluation started\\|Evaluation finished' full.log`\n3. Multiple evaluations for the same project = overbuilding\n4. Look for \"Project evaluation started/finished\" messages and their timestamps\n\n### Using /pp (preprocess)\n\n- `dotnet msbuild -pp:full.xml MyProject.csproj`\n- Shows the fully expanded project with ALL imports inlined\n- Use to understand: what's imported, import depth, total content volume\n- Large preprocessed output (>10K lines) = heavy evaluation\n\n### Using /clp:PerformanceSummary\n\n- Add to build command for timing breakdown\n- Shows evaluation time separately from target/task execution\n\n## Expensive Glob Patterns\n\n- Globs like `**/*.cs` walk the entire directory tree\n- Default SDK globs are optimized, but custom globs may not be\n- Problem: globbing over `node_modules/`, `.git/`, `bin/`, `obj/` — millions of files\n- Fix: use `<DefaultItemExcludes>` to exclude large directories\n- Fix: be specific with glob paths: `src/**/*.cs` instead of `**/*.cs`\n- Fix: use `<EnableDefaultItems>false</EnableDefaultItems>` only as last resort (lose SDK defaults)\n- Check: grep for Compile items in the diagnostic log → if Compile items include unexpected files, globs are too broad\n\n## Import Chain Analysis\n\n- Deep import chains (>20 levels) slow evaluation\n- Each import: file I/O + parse + evaluate\n- Common causes: NuGet packages adding .props/.targets, framework SDK imports, Directory.Build chains\n- Diagnosis: `/pp` output → search for `<!-- Importing` comments to see import tree\n- Fix: reduce transitive package imports where possible, consolidate imports\n\n## Multiple Evaluations\n\n- A project evaluated multiple times = wasted work\n- Common causes: referenced from multiple other projects with different global properties\n- Each unique set of global properties = separate evaluation\n- Diagnosis: `grep 'Evaluation started.*ProjectName' full.log` → if count > 1, check for differing global properties\n- Fix: normalize global properties, use graph build (`/graph`)\n\n## TreatAsLocalProperty\n\n- Prevents property values from flowing to child projects via MSBuild task\n- Overuse: declaring many TreatAsLocalProperty entries adds evaluation overhead\n- Correct use: only when you genuinely need to override an inherited property\n\n## Property Function Cost\n\n- Property functions execute during evaluation\n- Most are cheap (string operations)\n- Expensive: `$([System.IO.File]::ReadAllText(...))` during evaluation — reads file on every evaluation\n- Expensive: network calls, heavy computation\n- Rule: property functions should be fast and side-effect-free\n\n## Optimization Checklist\n\n- [ ] Check preprocessed output size: `dotnet msbuild -pp:full.xml`\n- [ ] Verify evaluation count: should be 1 per project per TFM\n- [ ] Exclude large directories from globs\n- [ ] Avoid file I/O in property functions during evaluation\n- [ ] Minimize import depth\n- [ ] Use graph build to reduce redundant evaluations\n- [ ] Check for unnecessary UsingTask declarations",
  "applicable_domains": [
    "code",
    "dotnet",
    "engineering"
  ],
  "invocation": [
    "/eval-performance"
  ],
  "tags": [
    "dotnet-msbuild",
    "dotnet",
    "csharp",
    "microsoft"
  ],
  "authored_by": "anthropics",
  "source_url": "https://github.com/dotnet/skills/blob/main/plugins/dotnet-msbuild/skills/eval-performance/SKILL.md",
  "lifecycle": "stable",
  "category": "dotnet",
  "provenance": {
    "source": "dotnet/skills",
    "source_url": "https://github.com/dotnet/skills/blob/main/plugins/dotnet-msbuild/skills/eval-performance/SKILL.md",
    "author": "Microsoft / .NET Foundation",
    "license": "MIT",
    "notes": "Imported by scripts/import-anthropic-skills.py."
  }
}