К основному содержанию
скилл CX Codex

build-perf-diagnostics — скилл для Claude Code: разбор узких мест

Скилл разбирает binlog и Performance Summary, чтобы найти, почему сборка .NET идёт медленно. Нужен, когда причина тормозов непонятна.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add dotnet/skills --skill build-perf-diagnostics -a claude-code
Открыть на GitHub

Что делает build-perf-diagnostics

Скилл работает по замерам, которые уже сняты: сначала генерируется binlog командой dotnet build /bl:{} -m, потом он разбирается через binlog MCP-сервер Microsoft.AITools.BinlogMcp из пространства имён binlog. Если сервер не подключается, есть запасной путь — переиграть binlog в текстовый лог с performancesummary и читать сводку по целям и задачам через grep.

Дальше скилл сверяет цифры с порогами: RAR дольше 5 секунд, анализаторы больше 30% времени задачи Csc, одна цель больше половины сборки, загрузка узлов ниже 80%. Под каждую находку в нём расписаны причины и правки — условное отключение анализаторов через RunAnalyzers, DisableTransitiveProjectReferences для лишних транзитивных ссылок, хардлинки и SkipCopyUnchangedFiles для тяжёлых Copy. Отдельно разобраны накладные расходы на вычисление свойств и restore внутри сборки.

Важно: скилл не для первичных замеров и не для параллелизма — для этого есть соседние скиллы. И он про MSBuild, другие системы сборки он не трогает.

Какие задачи решает

  • понять, почему сборка .NET стала медленной без явной причины
  • найти задачу, которая съедает больше половины времени сборки
  • отделить время анализаторов Roslyn от времени компиляции
  • проверить загрузку узлов сборки и найти сериализацию
  • разобрать тяжёлые Copy и лишние транзитивные ссылки

Примеры запросов агенту

  • Собери проект с binlog и разбери, что тормозит: dotnet build /bl:{} -m
  • Посмотри Task Performance Summary и скажи, не занимают ли анализаторы больше 30% Csc
  • Почему RAR идёт дольше 5 секунд на этом проекте?

Как установить build-perf-diagnostics

1Через Skills CLI (Vercel)

npx skills add dotnet/skills --skill build-perf-diagnostics -a claude-code

2Вручную: положить файлы

~/.claude/skills/build-perf-diagnostics/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/build-perf-diagnostics/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о build-perf-diagnostics

Как установить build-perf-diagnostics в Claude?

Через установщик скиллов: npx skills add dotnet/skills --skill build-perf-diagnostics -a claude-code. После этого файл скилла лежит в ~/.claude/skills/build-perf-diagnostics/SKILL.md.

Что делает build-perf-diagnostics?

Разбирает binlog и сводки по производительности целей и задач MSBuild, находит узкие места и предлагает конкретные правки в проекте.

Нужен ли MCP-сервер для работы скилла?

Основной путь идёт через binlog MCP-сервер Microsoft.AITools.BinlogMcp. Если он не подключается, скилл переходит на переигрывание binlog в текстовый лог с performancesummary.

Исходный текст

SKILL.md · MIT
---
name: build-perf-diagnostics
description: "Diagnose MSBuild bottlenecks from binlog timelines and Target/Task Performance Summaries after build-perf-baseline establishes measurements. USE FOR: unknown build slowness, RAR >5s, analyzers >30% of Csc, one target >50% of build time, node utilization <80%, excessive Copy tasks, finding restore overhead. DO NOT USE FOR: known repeated-restore fixes (use eliminate-redundant-restores), initial baselines (use build-perf-baseline), incremental rebuilds (use incremental-build), parallelism tuning (use build-parallelism), non-MSBuild builds."
license: MIT
---

## Performance Analysis Methodology

1. **Generate a binlog**: `dotnet build /bl:{} -m`
2. Use the **binlog MCP server** (`Microsoft.AITools.BinlogMcp`, exposed under the `binlog` MCP namespace) which is bundled with this plugin

If the server cannot connect, use `troubleshoot-binlog-mcp` when startup repair is
wanted. If repair is blocked, declined, or unnecessary, use the replay flow below.

### Alternate flow when MCP is unavailable: binlog replay to text logs

1. **Generate a binlog**: `dotnet build /bl:{} -m`
2. **Replay to diagnostic log with performance summary**:
   ```bash
   dotnet msbuild build.binlog -noconlog -fl "-flp:v=diag;logfile=full.log;performancesummary"
   ```
3. **Read the performance summary** (at the end of `full.log`):
   ```bash
   grep "Target Performance Summary\|Task Performance Summary" -A 50 full.log
   ```
4. **Find expensive targets and tasks**: The PerformanceSummary section lists all targets/tasks sorted by cumulative time
5. **Check for node utilization**: grep for scheduling and node messages
   ```bash
   grep -i "node.*assigned\|building with\|scheduler" full.log | head -30
   ```
6. **Check analyzers**: grep for analyzer timing
   ```bash
   grep -i "analyzer.*elapsed\|Total analyzer execution time\|CompilerAnalyzerDriver" full.log
   ```

## Key Metrics and Thresholds

- **Build duration**: what's "normal" — small project <10s, medium <60s, large <5min
- **Node utilization**: ideal is >80% active time across nodes. Low utilization = serialization bottleneck
- **Single target domination**: if one target is >50% of build time, investigate
- **Analyzer time vs compile time**: analyzers should be <30% of Csc task time. If higher, consider removing expensive analyzers
- **RAR time**: ResolveAssemblyReference >5s is concerning. >15s is pathological

## Common Bottlenecks

### 1. ResolveAssemblyReference (RAR) Slowness

- **Symptoms**: RAR taking >5s per project
- **Root causes**: too many assembly references, network-based reference paths, large assembly search paths
- **Fixes**: reduce reference count, use `<DesignTimeBuild>false</DesignTimeBuild>` for RAR-heavy analysis, set `<ResolveAssemblyReferencesSilent>true</ResolveAssemblyReferencesSilent>` for diagnostic
- **Advanced**: `<DesignTimeBuild>` and `<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>`
- **Key insight**: RAR runs unconditionally even on incremental builds because users may have installed targeting packs or GACed assemblies (see dotnet/msbuild#2015). With .NET Core micro-assemblies, the reference count is often very high.
- **Reduce transitive references**: Set `<DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences>` to avoid pulling in the full transitive closure (note: projects may need to add direct references for any types they consume). Use `ReferenceOutputAssembly="false"` on ProjectReferences that are only needed at build time (not API surface). Trim unused PackageReferences.

### 2. Roslyn Analyzers and Source Generators

- **Symptoms**: Csc task takes much longer than expected for file count (>2× clean compile time)
- **Diagnosis**: Check the Task Performance Summary in the replayed log for Csc task time; grep for analyzer timing messages; compare Csc duration with and without analyzers (`/p:RunAnalyzers=false`)
- **Fixes**:
  - Conditionally disable in dev: `<RunAnalyzers Condition="'$(ContinuousIntegrationBuild)' != 'true'">false</RunAnalyzers>`
  - Per-configuration: `<RunAnalyzers Condition="'$(Configuration)' == 'Debug'">false</RunAnalyzers>`
  - Code-style only: `<EnforceCodeStyleInBuild Condition="'$(ContinuousIntegrationBuild)' == 'true'">true</EnforceCodeStyleInBuild>`
  - Remove genuinely redundant analyzers from inner loop
  - Severity config in .editorconfig for less critical rules
- **Key principle**: Preserve analyzer enforcement in CI. Never just "remove" analyzers — configure them conditionally.
- **GlobalPackageReference**: Analyzers added via `GlobalPackageReference` in `Directory.Packages.props` apply to ALL projects. Consider if test projects need the same analyzer set as production code.
- **EnforceCodeStyleInBuild**: When set to `true` in `Directory.Build.props`, forces code-style analysis on every build. Should be conditional on CI environment (`ContinuousIntegrationBuild`) to avoid slowing dev inner loop.

### 3. Serialization Bottlenecks (Single-threaded targets)

- **Symptoms**: Performance summary shows most build time concentrated in a single project; diagnostic log shows idle nodes while one works
- **Common culprits**: targets without proper dependency declaration, single project on critical path
- **Fixes**: split large projects, optimize the critical path project, ensure proper `BuildInParallel`

### 4. Excessive File I/O (Copy tasks)

- **Symptoms**: Copy task shows high aggregate time
- **Root causes**: copying thousands of files, copying across network drives, Copy task unintentionally running once per item (per-file) instead of as a single batch (see dotnet/msbuild#12884)
- **Fixes**: use hardlinks (`<CreateHardLinksForCopyFilesToOutputDirectoryIfPossible>true</CreateHardLinksForCopyFilesToOutputDirectoryIfPossible>`), reduce CopyToOutputDirectory items, use `<UseCommonOutputDirectory>true</UseCommonOutputDirectory>` when appropriate, set `<SkipCopyUnchangedFiles>true</SkipCopyUnchangedFiles>`, consider `--artifacts-path` (.NET 8+) for centralized output layout
- **Dev Drive**: On Windows, switching to a Dev Drive (ReFS with copy-on-write and reduced Defender scans) can significantly reduce file I/O overhead for Copy-heavy builds. Recommend for both dev machines and self-hosted CI agents.

### 5. Evaluation Overhead

- **Symptoms**: build starts slow before any compilation
- **Root causes**: complex Directory.Build.props, wildcard globs scanning large directories, NuGetSdkResolver overhead (adds 180-400ms per project evaluation even when restored — see dotnet/msbuild#4025)
- **Fixes**: reduce Directory.Build.props complexity, use `<EnableDefaultItems>false</EnableDefaultItems>` for legacy projects with explicit file lists, avoid NuGet-based SDK resolvers if possible
- See: `eval-performance` skill for detailed guidance

### 6. NuGet Restore in Build

- **Symptoms**: restore runs every build even when unnecessary
- **Fixes**:
  - Separate restore from build: `dotnet restore` then `dotnet build --no-restore`
  - Enable static graph evaluation: `<RestoreUseStaticGraphEvaluation>true</RestoreUseStaticGraphEvaluation>` in Directory.Build.props — can save significant time in large builds (results are workload-dependent)
- See: `eliminate-redundant-restores` skill when several pipeline or script steps each restore, or before adding `--no-restore` (it fails with NETSDK1004/NETSDK1047 when no earlier restore covers the step)

### 7. Large Project Count and Graph Shape

- **Symptoms**: many small projects, each takes minimal time but overhead adds up; deep dependency chains serialize the build
- **Consider**: project consolidation, or use `/graph` mode for better scheduling
- **Graph shape matters**: a wide dependency graph (few levels, many parallel branches) builds faster than a deep one (many levels, serialized). Refactoring from deep to wide can yield significant improvements in both clean and incremental build times.
- **Actions**: look for unnecessary project dependencies, consider splitting a bottleneck project into two, or merging small leaf projects

## Using Binlog Replay for Performance Analysis

Step-by-step workflow using text log replay:

1. **Replay with performance summary**:
   ```bash
   dotnet msbuild build.binlog -noconlog -fl "-flp:v=diag;logfile=full.log;performancesummary"
   ```
2. **Read target/task performance summaries** (at the end of `full.log`):
   ```bash
   grep "Target Performance Summary\|Task Performance Summary" -A 50 full.log
   ```
   This shows all targets and tasks sorted by cumulative time — equivalent to finding expensive targets/tasks.
3. **Find per-project build times**:
   ```bash
   grep "done building project\|Project Performance Summary" full.log
   ```
4. **Check parallelism** (multi-node scheduling):
   ```bash
   grep -i "node.*assigned\|RequiresLeadingNewline\|Building with" full.log | head -30
   ```
5. **Check analyzer overhead**:
   ```bash
   grep -i "Total analyzer execution time\|analyzer.*elapsed\|CompilerAnalyzerDriver" full.log
   ```
6. **Drill into a specific slow target**:
   ```bash
   grep 'Target "CoreCompile"\|Target "ResolveAssemblyReferences"' full.log
   ```

## Quick Wins Checklist

- [ ] Use `/maxcpucount` (or `-m`) for parallel builds
- [ ] Separate restore from build (`dotnet restore` then `dotnet build --no-restore`)
- [ ] Enable static graph restore (`<RestoreUseStaticGraphEvaluation>true</RestoreUseStaticGraphEvaluation>`)
- [ ] Enable hardlinks for Copy (`<CreateHardLinksForCopyFilesToOutputDirectoryIfPossible>true</CreateHardLinksForCopyFilesToOutputDirectoryIfPossible>`)
- [ ] Disable analyzers conditionally in dev inner loop: `<RunAnalyzers Condition="'$(ContinuousIntegrationBuild)' != 'true'">false</RunAnalyzers>`
- [ ] Enable reference assemblies (`<ProduceReferenceAssembly>true</ProduceReferenceAssembly>`)
- [ ] Check for broken incremental builds (see `incremental-build` skill)
- [ ] Check for bin/obj clashes (see `check-bin-obj-clash` skill)
- [ ] Use graph build (`/graph`) for multi-project solutions
- [ ] Use `--artifacts-path` (.NET 8+) for centralized output layout
- [ ] Enable Dev Drive (ReFS) on Windows dev machines and self-hosted CI

## Impact Categorization

When reporting findings, categorize by impact to help prioritize fixes:

- 🔴 **HIGH IMPACT** (do first): Items consuming >10% of total build time, or a single target >50% of build time
- 🟡 **MEDIUM IMPACT**: Items consuming 2-10% of build time
- 🟢 **QUICK WINS**: Easy changes with modest impact (e.g., property flags in Directory.Build.props)

© dotnet · MIT · dotnet/skills

Похожие скиллы

Всё по теме «DevOps и инфраструктура» →
kotlin-tooling-native-build-performance JetBrains Разбирает, почему iOS-сборка в Kotlin Multiplatform идёт медленно, и предлагает безопасные правки с замером до и после. CX Codex +1 943установок container-publish codewithmukesh Собирает OCI-образы прямо из dotnet publish /t:PublishContainer, без Dockerfile. Пригодится, когда проект на .NET 10 надо упаковать в контейнер и запушить в реестр. CX Codex +1 2 800установок dotnet-project-structure Aaronontheweb Скилл подсказывает агенту, как разложить .NET-решение: .slnx, Directory.Build.props, центральные версии пакетов и SourceLink. CX Codex +1 658установок project-structure codewithmukesh Скилл задаёт агенту правила раскладки .NET-решения: центральные версии пакетов, общие свойства сборки, формат .slnx и именование проектов. CX Codex +1 2 800установок cargo-diagnostics getcargo Скилл разбирает, что именно сделал запуск или батч Cargo: проходит по узлам, рисует граф с упавшим шагом, группирует ошибки по причине и считает расход кредитов. CX Codex +1 8 700установок cmux-diagnostics manaflow-ai Скилл запускает проверку cmux: сокеты, хуки, восстановление сессий, настройки. Используй, когда уведомления не приходят, агент не возобновляется или нужна отчёт о здоровье системы. CX Codex +1 6 400установок

Из того же набора101

directory-build-organization Скилл решает, что вынести в Directory.Build.props, .targets и .rsp: несколько проектов перестают дублировать одну и ту же политику MSBuild. CX Codex +1 3 700установок coverage-analysis Скилл разбирает отчёты о покрытии .NET, находит пробелы и объясняет, что мешает росту показателей. Пригодится для анализа Cobertura и оценки рисков рефакторинга. CX Codex +1 3 600установок binlog-generation Скилл заставляет агента добавлять /bl:{} к каждой команде MSBuild, чтобы после сборки остался файл .binlog с полной трассировкой. Пригодится, когда сборка падает или тормозит. CX Codex +1 3 500установок dotnet-pinvoke Скилл учит агента вызывать функции C и C++ из .NET через DllImport и LibraryImport. Помогает переносить сигнатуры без повреждения памяти и настраивать маршалинг строк. CX Codex +1 3 500установок test-gap-analysis Разбирает, какие видимые вызывающему исходы в продакшн-коде могут измениться, а тесты этого не заметят. Пригодится перед правкой, когда надо понять, чего стоит текущий набор проверок. CX Codex +1 3 500установок crap-score Считает метрику риска изменений CRAP для методов, классов и файлов в .NET. Помогает найти сложный код с недостаточным тестовым покрытием. CX Codex +1 3 500установок assertion-quality Разбирает утверждения в готовых тестах и показывает, где проверка пустая: тест зелёный, а правильность кода он не подтверждает. CX Codex +1 3 600установок dotnet-aot-compat Разбирает предупреждения IL-анализатора по одному и доводит .NET-проект до совместимости с Native AOT и триммером. Пригодится после перехода на net8.0. CX Codex +1 3 600установок

Спонсоры проекта

Компании, которые помогают держать аналитику открытой