@cratis/pi 7.101.0 → 7.103.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package/corpus/harnesses/copilot/instructions/github-actions.instructions.md +17 -0
- package/package/corpus/harnesses/copilot/instructions/profiles.instructions.md +10 -1
- package/package/corpus/harnesses/copilot/instructions/pull-requests.instructions.md +2 -0
- package/package/corpus/harnesses/copilot/instructions/secrets.instructions.md +4 -0
- package/package/corpus/hooks/README.md +11 -1
- package/package/corpus/hooks/scripts/cratis-check-pr.mjs +12 -1
- package/package/corpus/hooks/scripts/cratis-guard-secrets.sh +79 -23
- package/package/corpus/hooks/scripts/cratis-guard-writes.sh +145 -40
- package/package/corpus/rules/github-actions.md +17 -0
- package/package/corpus/rules/profiles.md +10 -1
- package/package/corpus/rules/pull-requests.md +2 -0
- package/package/corpus/rules/secrets.md +4 -0
- package/package/corpus/skills/analyzing-dotnet-performance/LICENSE +23 -0
- package/package/corpus/skills/analyzing-dotnet-performance/NOTICE +36 -0
- package/package/corpus/skills/analyzing-dotnet-performance/SKILL.md +214 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/async-patterns.md +122 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/collections-and-linq.md +220 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/critical-patterns.md +291 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/io-and-serialization.md +135 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/memory-and-strings.md +219 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/regex-patterns.md +95 -0
- package/package/corpus/skills/analyzing-dotnet-performance/references/structural-patterns.md +38 -0
- package/package/corpus/skills/binlog-generation/LICENSE +23 -0
- package/package/corpus/skills/binlog-generation/NOTICE +22 -0
- package/package/corpus/skills/binlog-generation/SKILL.md +129 -0
- package/package/corpus/skills/check-bin-obj-clash/LICENSE +23 -0
- package/package/corpus/skills/check-bin-obj-clash/NOTICE +27 -0
- package/package/corpus/skills/check-bin-obj-clash/SKILL.md +127 -0
- package/package/corpus/skills/check-bin-obj-clash/references/common-causes-and-fixes.md +206 -0
- package/package/corpus/skills/coverage-analysis/LICENSE +23 -0
- package/package/corpus/skills/coverage-analysis/NOTICE +32 -0
- package/package/corpus/skills/coverage-analysis/SKILL.md +198 -0
- package/package/corpus/skills/coverage-analysis/references/guidelines.md +68 -0
- package/package/corpus/skills/coverage-analysis/references/output-format.md +91 -0
- package/package/corpus/skills/coverage-analysis/references/report-generation.md +58 -0
- package/package/corpus/skills/coverage-analysis/references/setup-discovery.md +307 -0
- package/package/corpus/skills/coverage-analysis/scripts/Compute-CrapScores.ps1 +80 -0
- package/package/corpus/skills/coverage-analysis/scripts/CoverageData.ps1 +272 -0
- package/package/corpus/skills/coverage-analysis/scripts/Extract-MethodCoverage.ps1 +65 -0
- package/package/corpus/skills/cratis-ci-pipeline-performance/LICENSE +2 -0
- package/package/corpus/skills/cratis-ci-pipeline-performance/SKILL.md +201 -0
- package/package/corpus/skills/cratis-ci-pipeline-performance/references/build-once-and-shard.md +158 -0
- package/package/corpus/skills/cratis-ci-pipeline-performance/references/caching.md +86 -0
- package/package/corpus/skills/cratis-ci-pipeline-performance/references/flaky-and-hung-jobs.md +70 -0
- package/package/corpus/skills/cratis-ci-pipeline-performance/references/publish-pipelines.md +67 -0
- package/package/corpus/skills/cratis-ci-pipeline-performance/references/required-checks-and-path-filters.md +117 -0
- package/package/corpus/skills/cratis-ci-pipeline-performance/references/runner-sizing-and-images.md +65 -0
- package/package/corpus/skills/cratis-ci-pipeline-performance/references/security-and-pinning.md +73 -0
- package/package/corpus/skills/cratis-ci-pipeline-performance/references/sources.md +33 -0
- package/package/corpus/skills/cratis-ci-pipeline-performance/references/test-setup-cost.md +82 -0
- package/package/corpus/skills/cratis-ci-pipeline-performance/scripts/ci-timings.sh +356 -0
- package/package/corpus/skills/cratis-ci-pipeline-performance/scripts/fixtures/jobs/1003.json +79 -0
- package/package/corpus/skills/cratis-ci-pipeline-performance/scripts/fixtures/jobs/1007.json +79 -0
- package/package/corpus/skills/cratis-ci-pipeline-performance/scripts/fixtures/jobs/1010.json +79 -0
- package/package/corpus/skills/cratis-ci-pipeline-performance/scripts/fixtures/runs.json +102 -0
- package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/LICENSE +2 -0
- package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/SKILL.md +244 -0
- package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/docker-images.md +86 -0
- package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/dotnet-nuget.md +87 -0
- package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/go-jvm-python-elixir.md +83 -0
- package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/npm-yarn.md +78 -0
- package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/other-environments.md +60 -0
- package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/worked-examples.md +97 -0
- package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/scripts/cratis-local-packages.sh +778 -0
- package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/scripts/npm-restore-check.cjs +109 -0
- package/package/corpus/skills/csharp-refactoring/LICENSE +23 -0
- package/package/corpus/skills/csharp-refactoring/NOTICE +22 -0
- package/package/corpus/skills/csharp-refactoring/SKILL.md +175 -0
- package/package/corpus/skills/csharp-refactoring/references/operation-catalog.md +37 -0
- package/package/corpus/skills/directory-build-organization/LICENSE +23 -0
- package/package/corpus/skills/directory-build-organization/NOTICE +21 -0
- package/package/corpus/skills/directory-build-organization/SKILL.md +205 -0
- package/package/corpus/skills/directory-build-organization/references/common-patterns.md +56 -0
- package/package/corpus/skills/directory-build-organization/references/multi-level-examples.md +167 -0
- package/package/corpus/skills/directory-build-organization/references/targetframework-props-pitfall.md +54 -0
- package/package/corpus/skills/dotnet-aot-compat/LICENSE +23 -0
- package/package/corpus/skills/dotnet-aot-compat/NOTICE +18 -0
- package/package/corpus/skills/dotnet-aot-compat/SKILL.md +265 -0
- package/package/corpus/skills/dotnet-aot-compat/references/polyfills.md +43 -0
- package/package/corpus/skills/dotnet-trace-collect/LICENSE +23 -0
- package/package/corpus/skills/dotnet-trace-collect/NOTICE +65 -0
- package/package/corpus/skills/dotnet-trace-collect/SKILL.md +116 -0
- package/package/corpus/skills/dotnet-trace-collect/references/dotnet-monitor.md +97 -0
- package/package/corpus/skills/dotnet-trace-collect/references/dotnet-trace-collect-linux.md +84 -0
- package/package/corpus/skills/dotnet-trace-collect/references/dotnet-trace-collect.md +91 -0
- package/package/corpus/skills/dotnet-trace-collect/references/perfcollect.md +200 -0
- package/package/corpus/skills/dotnet-trace-collect/references/perfview.md +141 -0
- package/package/corpus/skills/dotnet-trace-collect/references/tool-selection.md +160 -0
- package/package/corpus/skills/dump-collect/LICENSE +23 -0
- package/package/corpus/skills/dump-collect/NOTICE +40 -0
- package/package/corpus/skills/dump-collect/SKILL.md +97 -0
- package/package/corpus/skills/dump-collect/references/container-dumps.md +412 -0
- package/package/corpus/skills/dump-collect/references/coreclr-dumps.md +108 -0
- package/package/corpus/skills/dump-collect/references/nativeaot-dumps.md +280 -0
- package/package/corpus/skills/eliminate-redundant-restores/LICENSE +23 -0
- package/package/corpus/skills/eliminate-redundant-restores/NOTICE +19 -0
- package/package/corpus/skills/eliminate-redundant-restores/SKILL.md +112 -0
- package/package/corpus/skills/extension-points/LICENSE +23 -0
- package/package/corpus/skills/extension-points/NOTICE +18 -0
- package/package/corpus/skills/extension-points/SKILL.md +248 -0
- package/package/corpus/skills/filter-syntax/LICENSE +23 -0
- package/package/corpus/skills/filter-syntax/NOTICE +17 -0
- package/package/corpus/skills/filter-syntax/SKILL.md +179 -0
- package/package/corpus/skills/including-generated-files/LICENSE +23 -0
- package/package/corpus/skills/including-generated-files/NOTICE +17 -0
- package/package/corpus/skills/including-generated-files/SKILL.md +139 -0
- package/package/corpus/skills/microbenchmarking/LICENSE +23 -0
- package/package/corpus/skills/microbenchmarking/NOTICE +36 -0
- package/package/corpus/skills/microbenchmarking/SKILL.md +131 -0
- package/package/corpus/skills/microbenchmarking/references/bdn-internals-and-tuning.md +143 -0
- package/package/corpus/skills/microbenchmarking/references/comparison-strategies.md +200 -0
- package/package/corpus/skills/microbenchmarking/references/diagnosers-and-exporters.md +150 -0
- package/package/corpus/skills/microbenchmarking/references/project-setup-and-running.md +189 -0
- package/package/corpus/skills/microbenchmarking/references/writing-benchmarks.md +310 -0
- package/package/corpus/skills/msbuild/LICENSE +23 -0
- package/package/corpus/skills/msbuild/NOTICE +55 -0
- package/package/corpus/skills/msbuild/SKILL.md +117 -0
- package/package/corpus/skills/msbuild/references/antipatterns/additional-antipatterns.md +291 -0
- package/package/corpus/skills/msbuild/references/antipatterns/incremental-build-inputs-outputs.md +57 -0
- package/package/corpus/skills/msbuild/references/antipatterns/private-assets.md +29 -0
- package/package/corpus/skills/msbuild/references/binlog-failure-analysis.md +85 -0
- package/package/corpus/skills/msbuild/references/binlog-generation.md +69 -0
- package/package/corpus/skills/msbuild/references/build-perf-baseline.md +493 -0
- package/package/corpus/skills/msbuild/references/build-perf-diagnostics.md +268 -0
- package/package/corpus/skills/msbuild/references/copy-to-output-directory.md +183 -0
- package/package/corpus/skills/msbuild/references/eval-performance.md +190 -0
- package/package/corpus/skills/msbuild/references/extension-points.md +281 -0
- package/package/corpus/skills/msbuild/references/incremental-build.md +365 -0
- package/package/corpus/skills/msbuild/references/msbuild-antipatterns.md +401 -0
- package/package/corpus/skills/orleans/LICENSE +21 -0
- package/package/corpus/skills/orleans/NOTICE +64 -0
- package/package/corpus/skills/orleans/SKILL.md +140 -0
- package/package/corpus/skills/orleans/references/anti-patterns.md +660 -0
- package/package/corpus/skills/orleans/references/configuration-api.md +933 -0
- package/package/corpus/skills/orleans/references/examples.md +66 -0
- package/package/corpus/skills/orleans/references/grain-api.md +784 -0
- package/package/corpus/skills/orleans/references/grains.md +75 -0
- package/package/corpus/skills/orleans/references/hosting.md +71 -0
- package/package/corpus/skills/orleans/references/implementation.md +591 -0
- package/package/corpus/skills/orleans/references/official-docs-index.md +250 -0
- package/package/corpus/skills/orleans/references/patterns.md +811 -0
- package/package/corpus/skills/orleans/references/persistence-api.md +495 -0
- package/package/corpus/skills/orleans/references/primitive-selection.md +35 -0
- package/package/corpus/skills/orleans/references/scheduling-and-services.md +295 -0
- package/package/corpus/skills/orleans/references/serialization-api.md +299 -0
- package/package/corpus/skills/orleans/references/streaming-api.md +396 -0
- package/package/corpus/skills/orleans/references/testing-patterns.md +210 -0
- package/package/corpus/skills/platform-detection/LICENSE +23 -0
- package/package/corpus/skills/platform-detection/NOTICE +17 -0
- package/package/corpus/skills/platform-detection/SKILL.md +230 -0
- package/package/corpus/skills/platform-detection/references/command-mode.md +27 -0
- package/package/corpus/skills/profiling/LICENSE +21 -0
- package/package/corpus/skills/profiling/NOTICE +50 -0
- package/package/corpus/skills/profiling/SKILL.md +144 -0
- package/package/corpus/skills/profiling/references/commands.md +439 -0
- package/package/corpus/skills/profiling/references/patterns.md +586 -0
- package/package/corpus/skills/profiling/references/profiling.md +190 -0
- package/package/corpus/skills/run-tests/LICENSE +23 -0
- package/package/corpus/skills/run-tests/NOTICE +19 -0
- package/package/corpus/skills/run-tests/SKILL.md +305 -0
- package/package/corpus/skills/target-authoring/LICENSE +23 -0
- package/package/corpus/skills/target-authoring/NOTICE +17 -0
- package/package/corpus/skills/target-authoring/SKILL.md +165 -0
- package/package/corpus/skills/vectorization/LICENSE +23 -0
- package/package/corpus/skills/vectorization/NOTICE +17 -0
- package/package/corpus/skills/vectorization/SKILL.md +189 -0
- package/package/profile-catalog.json +87 -1
- package/package.json +3 -2
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Generate binary logs
|
|
2
|
+
|
|
3
|
+
Based on the original `binlog-generation` skill, reduced to capture, verification, and retention.
|
|
4
|
+
Capture a log for the build being investigated, not as an unconditional rule for every .NET task.
|
|
5
|
+
If a matching log already exists, use [MSBuild replay](binlog-failure-analysis.md#replay-a-binary-log)
|
|
6
|
+
instead of rerunning the build.
|
|
7
|
+
|
|
8
|
+
## Preserve the operation
|
|
9
|
+
|
|
10
|
+
Append the binary logger switch to the existing MSBuild invocation. Keep its entry point, working
|
|
11
|
+
directory, target, configuration, framework, runtime, restore behavior, and global properties.
|
|
12
|
+
Do not replace a repository wrapper with a bare `dotnet build` unless the wrapper's equivalent
|
|
13
|
+
invocation is known.
|
|
14
|
+
|
|
15
|
+
Choose an unused filename before each invocation. The examples below assume these paths do not
|
|
16
|
+
already exist:
|
|
17
|
+
|
|
18
|
+
```powershell
|
|
19
|
+
dotnet build App.sln -c Release --no-restore "-bl:build-01.binlog"
|
|
20
|
+
dotnet msbuild App.csproj -t:Pack "-bl:pack-01.binlog"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Retain the user's actual arguments rather than substituting these project names or adding
|
|
24
|
+
`--no-restore`. Every comparison or retry needs a different log path; do not use bare `-bl`,
|
|
25
|
+
which reuses `msbuild.binlog`.
|
|
26
|
+
|
|
27
|
+
Automatic `{}` filenames are optional and toolset-dependent. Do not assume every .NET 8 SDK
|
|
28
|
+
supports expansion. If support is confirmed, quote the complete argument in PowerShell, such as
|
|
29
|
+
`"-bl:build-{}.binlog"`, and verify that the resulting name actually expanded. Explicit unused
|
|
30
|
+
names avoid that compatibility issue and also work for CI uploaders needing a known path.
|
|
31
|
+
|
|
32
|
+
`dotnet build`, `restore`, `pack`, and `publish` accept MSBuild logger switches. Test runners and
|
|
33
|
+
wrapper scripts differ: only forward `-bl` through a supported MSBuild argument surface. A
|
|
34
|
+
Microsoft.Testing.Platform-native invocation or `dotnet test --no-build` is not automatically a
|
|
35
|
+
request to capture a new build.
|
|
36
|
+
|
|
37
|
+
## Verify the artifact, including on failure
|
|
38
|
+
|
|
39
|
+
Record the command's exit code and locate the newly created, nonempty `.binlog` before starting
|
|
40
|
+
analysis:
|
|
41
|
+
|
|
42
|
+
```powershell
|
|
43
|
+
Get-ChildItem -File *.binlog | Select-Object Name, Length, LastWriteTime
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
An intentional failing build can still produce a useful log. Failure before MSBuild starts
|
|
47
|
+
(missing SDK, invalid command-line arguments, wrapper rejection) may produce none. Report that
|
|
48
|
+
condition; do not invent a path or repeatedly rebuild without addressing it.
|
|
49
|
+
|
|
50
|
+
Keep the path, original exit code, and scenario together. For a capture-only request, this is the
|
|
51
|
+
deliverable. Otherwise continue to [failure analysis](binlog-failure-analysis.md) or
|
|
52
|
+
[performance diagnostics](build-perf-diagnostics.md).
|
|
53
|
+
|
|
54
|
+
## Privacy and retention
|
|
55
|
+
|
|
56
|
+
Binary logs can contain command lines, environment/property values, credentials, paths, and
|
|
57
|
+
embedded project/import contents. Replayed text logs can expose the same sensitive values.
|
|
58
|
+
Keep both local by default and out of commits. Preserve existing logs during any approved cleanup;
|
|
59
|
+
do not use a repository-wide clean to prepare capture.
|
|
60
|
+
|
|
61
|
+
If embedding imported files is inappropriate, use a quoted logger argument such as:
|
|
62
|
+
|
|
63
|
+
```powershell
|
|
64
|
+
dotnet build App.csproj "-bl:build-02.binlog;ProjectImports=None"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`ProjectImports=None` reduces embedded source coverage; it does **not** redact secrets from
|
|
68
|
+
properties, environment values, task arguments, or messages. Explain the diagnostic tradeoff,
|
|
69
|
+
and review/redact artifacts before any authorized sharing.
|
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
# Build Performance Baseline & Optimization
|
|
2
|
+
|
|
3
|
+
## Contents
|
|
4
|
+
|
|
5
|
+
- Overview
|
|
6
|
+
- Step 1: Establish a Performance Baseline
|
|
7
|
+
- Step 2: Artifacts Output Layout
|
|
8
|
+
- Step 3: Deterministic Builds
|
|
9
|
+
- Step 4: Dependency Graph Trimming
|
|
10
|
+
- Step 5: Static Graph Builds (`/graph`)
|
|
11
|
+
- Step 6: Parallel Build Tuning
|
|
12
|
+
- Step 7: Additional Quick Wins
|
|
13
|
+
- Optimization Decision Tree
|
|
14
|
+
- Validation and Results
|
|
15
|
+
|
|
16
|
+
Source: original build perf baseline skill.
|
|
17
|
+
|
|
18
|
+
## Overview
|
|
19
|
+
|
|
20
|
+
Before optimizing a build, you need a **baseline**. Without measurements,
|
|
21
|
+
optimization is guesswork. This reference covers establishing baselines and
|
|
22
|
+
applying systematic, measured optimization techniques.
|
|
23
|
+
|
|
24
|
+
**Related references:**
|
|
25
|
+
- [Build performance diagnostics](build-perf-diagnostics.md) - binlog-based bottleneck identification
|
|
26
|
+
- [Incremental builds](incremental-build.md) - Inputs/Outputs and up-to-date checks
|
|
27
|
+
- [Parallel build tuning](#step-6-parallel-build-tuning) - parallelism and critical paths
|
|
28
|
+
- [Evaluation performance](eval-performance.md) - glob and import-chain optimization
|
|
29
|
+
|
|
30
|
+
## Step 1: Establish a Performance Baseline
|
|
31
|
+
|
|
32
|
+
Measure three scenarios to understand where time is spent. Reuse matching existing
|
|
33
|
+
artifacts first; use [binlog generation](binlog-generation.md) for capture and
|
|
34
|
+
privacy guidance. Discover the repository's actual build entry point and retain
|
|
35
|
+
its configuration, TFM/RID, properties, SDK/toolset, node count, and restore policy
|
|
36
|
+
in the examples below.
|
|
37
|
+
|
|
38
|
+
The binlog filenames below are illustrative. Choose an unused explicit filename
|
|
39
|
+
for every capture; do not overwrite existing evidence.
|
|
40
|
+
|
|
41
|
+
Record those settings, source revision/local changes, machine resources, cache
|
|
42
|
+
state, and exact input edit. Compare successful builds of the same scenario, not
|
|
43
|
+
a failed build, a smaller solution, or differently instrumented runs.
|
|
44
|
+
|
|
45
|
+
### Cold Build (First Build)
|
|
46
|
+
|
|
47
|
+
No previous output exists for the selected build. An end-to-end cold-output
|
|
48
|
+
measurement includes restore, compilation, and all required work.
|
|
49
|
+
|
|
50
|
+
Use an agreed disposable workspace or explicitly authorized cleanup of known
|
|
51
|
+
generated paths. Inspect custom Clean behavior and shared outputs first. Do not
|
|
52
|
+
recursively delete every directory named `bin` or `obj`, clear shared NuGet caches,
|
|
53
|
+
or stop shared build servers. If safe preparation is unavailable, report the cold
|
|
54
|
+
scenario as unmeasured.
|
|
55
|
+
|
|
56
|
+
```powershell
|
|
57
|
+
# After preparing the agreed cold-output state
|
|
58
|
+
dotnet build -m "-bl:cold-build.binlog"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Record whether packages, compiler servers, and filesystem caches are already
|
|
62
|
+
warm. Removing build outputs does not make those caches cold.
|
|
63
|
+
|
|
64
|
+
### Warm Build (Incremental Build)
|
|
65
|
+
|
|
66
|
+
Build output exists and some files have changed. This measures how well
|
|
67
|
+
incremental building handles a specific change.
|
|
68
|
+
|
|
69
|
+
```powershell
|
|
70
|
+
dotnet build -m
|
|
71
|
+
if ($LASTEXITCODE -ne 0) { throw "Initial build failed; no valid warm baseline." }
|
|
72
|
+
|
|
73
|
+
# Make one recorded, reversible source/input change, then build normally
|
|
74
|
+
dotnet build -m "-bl:warm-build.binlog"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
A timestamp-only touch, implementation edit, and public-API edit can propagate
|
|
78
|
+
differently. Use the same kind of change before and after an optimization.
|
|
79
|
+
|
|
80
|
+
### No-Op Build (Nothing Changed)
|
|
81
|
+
|
|
82
|
+
Build output exists and nothing has changed. Expensive work whose inputs and
|
|
83
|
+
outputs are up to date should skip. A slow no-op can still be caused by
|
|
84
|
+
evaluation, restore checks, reference resolution, or orchestration rather than
|
|
85
|
+
broken compilation incrementality.
|
|
86
|
+
|
|
87
|
+
```powershell
|
|
88
|
+
dotnet build -m
|
|
89
|
+
if ($LASTEXITCODE -ne 0) { throw "Initial build failed; no valid no-op baseline." }
|
|
90
|
+
|
|
91
|
+
dotnet build -m "-bl:noop-build.binlog"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Label this **warm no-change** scenario separately from a warm changed-input build.
|
|
95
|
+
Do not use `Rebuild`, `-t:Rebuild`, or `--no-incremental` for the second build:
|
|
96
|
+
forced full work is a separate benchmark, not a no-op or proof of cold caches.
|
|
97
|
+
|
|
98
|
+
### What Good Looks Like
|
|
99
|
+
|
|
100
|
+
| Scenario | Expected behavior |
|
|
101
|
+
| --- | --- |
|
|
102
|
+
| Cold build | Complete required outputs, including compilation and required generation. This is the full-work baseline for the recorded cache state. |
|
|
103
|
+
| Warm build | Changed inputs and affected dependencies invalidate the appropriate work; unrelated recompilation needs explanation. |
|
|
104
|
+
| No-op build | Up-to-date expensive compilation/generation skips. Under roughly 5 seconds for small repositories or 30 seconds for large ones can be useful triage hints, not universal budgets. |
|
|
105
|
+
|
|
106
|
+
**Red flags to investigate, not automatic diagnoses:**
|
|
107
|
+
- No-op build over 30 seconds: distinguish evaluation, restore, copying, and
|
|
108
|
+
unexpected execution before applying [incremental fixes](incremental-build.md).
|
|
109
|
+
- Warm build recompiles everything: inspect the input/API change and dependency
|
|
110
|
+
chain; do not assume every downstream rebuild is unnecessary.
|
|
111
|
+
- Long cold restore: investigate feed/network work and cache state, not just
|
|
112
|
+
package-cache problems.
|
|
113
|
+
|
|
114
|
+
### Recording Baselines
|
|
115
|
+
|
|
116
|
+
Prefer repeated measurements, such as three runs per scenario, and report their
|
|
117
|
+
median and spread. Re-establish the correct cold or warm state before each run.
|
|
118
|
+
Do not mix cold and warmed timings or silently discard inconvenient outliers.
|
|
119
|
+
|
|
120
|
+
| Scenario | Before median [range] | After median [range] | Improvement |
|
|
121
|
+
| --- | --- | --- | --- |
|
|
122
|
+
| Cold build, restore included/excluded | Not measured | Not measured | Seconds and percent |
|
|
123
|
+
| Warm build, named input edit | Not measured | Not measured | Seconds and percent |
|
|
124
|
+
| No-op build, unchanged command | Not measured | Not measured | Seconds and percent |
|
|
125
|
+
|
|
126
|
+
Fill this table with actual results and artifact paths. Percentage improvement is
|
|
127
|
+
`(before - after) / before * 100`; a negative result is a regression. Change one
|
|
128
|
+
variable at a time and retain the same success/output checks. Use distinct log
|
|
129
|
+
names for each run and for before/after results so baseline evidence is not
|
|
130
|
+
overwritten.
|
|
131
|
+
|
|
132
|
+
## Step 2: Artifacts Output Layout
|
|
133
|
+
|
|
134
|
+
`UseArtifactsOutput`, introduced in **.NET SDK 8**, centralizes output layout.
|
|
135
|
+
It can address output-management and collision problems and simplify CI caching;
|
|
136
|
+
it does not itself make compilation faster or validate a cache.
|
|
137
|
+
|
|
138
|
+
### Enabling Artifacts Output
|
|
139
|
+
|
|
140
|
+
```xml
|
|
141
|
+
<!-- Directory.Build.props -->
|
|
142
|
+
<PropertyGroup>
|
|
143
|
+
<UseArtifactsOutput>true</UseArtifactsOutput>
|
|
144
|
+
</PropertyGroup>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Before vs After
|
|
148
|
+
|
|
149
|
+
Illustrative single-target layout:
|
|
150
|
+
|
|
151
|
+
```text
|
|
152
|
+
# Traditional layout
|
|
153
|
+
src\
|
|
154
|
+
MyLib\
|
|
155
|
+
bin\Debug\net8.0\MyLib.dll
|
|
156
|
+
obj\Debug\net8.0\...
|
|
157
|
+
MyApp\
|
|
158
|
+
bin\Debug\net8.0\MyApp.dll
|
|
159
|
+
|
|
160
|
+
# Artifacts layout
|
|
161
|
+
artifacts\
|
|
162
|
+
bin\MyLib\debug\MyLib.dll
|
|
163
|
+
bin\MyApp\debug\MyApp.dll
|
|
164
|
+
obj\MyLib\debug\...
|
|
165
|
+
obj\MyApp\debug\...
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Benefits
|
|
169
|
+
|
|
170
|
+
- **Separated outputs:** project/configuration pivots reduce accidental overlap;
|
|
171
|
+
check duplicate project names and custom path/pivot overrides.
|
|
172
|
+
- **Easier cache management:** a common artifacts root is easier to collect,
|
|
173
|
+
but cache keys must still cover the relevant inputs, options, SDK, and platform.
|
|
174
|
+
- **Simpler ignore rules:** the generated artifacts root can be ignored centrally.
|
|
175
|
+
- **Multi-targeting:** SDK pivots distinguish TFMs/RIDs where needed; inspect the
|
|
176
|
+
evaluated paths instead of assuming one fixed subdirectory pattern.
|
|
177
|
+
|
|
178
|
+
### Customizing
|
|
179
|
+
|
|
180
|
+
```xml
|
|
181
|
+
<PropertyGroup>
|
|
182
|
+
<ArtifactsPath>$(MSBuildThisFileDirectory)output</ArtifactsPath>
|
|
183
|
+
</PropertyGroup>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The CLI's `--artifacts-path` also requires SDK 8+. Keep restore, build, test,
|
|
187
|
+
pack/publish, scripts, and cleanup consistent with the new locations. Verify the
|
|
188
|
+
supported configuration/TFM/RID matrix and file ownership before adopting the
|
|
189
|
+
layout. A target framework change alone does not enable this SDK feature.
|
|
190
|
+
|
|
191
|
+
## Step 3: Deterministic Builds
|
|
192
|
+
|
|
193
|
+
Deterministic compilation produces identical compiler outputs for identical
|
|
194
|
+
compiler inputs. This supports caching and reproducibility, but does not make
|
|
195
|
+
every custom build step or package reproducible automatically.
|
|
196
|
+
|
|
197
|
+
### Enabling Deterministic Builds
|
|
198
|
+
|
|
199
|
+
```xml
|
|
200
|
+
<!-- Directory.Build.props -->
|
|
201
|
+
<PropertyGroup>
|
|
202
|
+
<!-- Already enabled by default in modern .NET SDK projects -->
|
|
203
|
+
<Deterministic>true</Deterministic>
|
|
204
|
+
<ContinuousIntegrationBuild Condition="'$(CI)' == 'true'">true</ContinuousIntegrationBuild>
|
|
205
|
+
</PropertyGroup>
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
Use the repository's actual CI signal; not every runner supplies `CI=true`.
|
|
209
|
+
|
|
210
|
+
### What Deterministic Affects
|
|
211
|
+
|
|
212
|
+
- Removes time-dependent variation from compiler output; it does not simply zero
|
|
213
|
+
every PE timestamp field.
|
|
214
|
+
- Makes compiler outputs repeatable for the same complete inputs.
|
|
215
|
+
- Works with source/path normalization for reproducible PDBs; deterministic
|
|
216
|
+
compilation alone does not normalize arbitrary machine-specific paths.
|
|
217
|
+
|
|
218
|
+
### Why It Matters for Performance
|
|
219
|
+
|
|
220
|
+
- **Build caching:** deterministic outputs can be reused when the complete cache
|
|
221
|
+
key and required artifacts are correct.
|
|
222
|
+
- **CI optimization:** correct input tracking can avoid rebuilding unchanged work.
|
|
223
|
+
- **Distributed builds:** cross-machine reuse also requires compatible toolsets,
|
|
224
|
+
paths, options, dependencies, and generated content.
|
|
225
|
+
|
|
226
|
+
Verify reproducibility of the required artifacts. Neither these properties nor
|
|
227
|
+
NuGet lock files create a compiled-output cache or excuse untracked inputs.
|
|
228
|
+
|
|
229
|
+
## Step 4: Dependency Graph Trimming
|
|
230
|
+
|
|
231
|
+
Removing genuinely unnecessary references can reduce graph/resolution work and,
|
|
232
|
+
when it removes a critical dependency, shorten the critical path.
|
|
233
|
+
|
|
234
|
+
### Audit the Dependency Graph
|
|
235
|
+
|
|
236
|
+
Inspect existing binlogs for project references, global-property variants, build
|
|
237
|
+
times, and waits. If a new capture is needed:
|
|
238
|
+
|
|
239
|
+
```powershell
|
|
240
|
+
dotnet build "-bl:graph.binlog"
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Use [local replay](binlog-failure-analysis.md#replay-a-binary-log) and
|
|
244
|
+
[performance diagnostics](build-perf-diagnostics.md) to follow the actual work.
|
|
245
|
+
Inclusive `ResolveProjectReferences` time includes waiting for dependencies; it
|
|
246
|
+
is not all reference-resolution CPU work.
|
|
247
|
+
|
|
248
|
+
### Techniques
|
|
249
|
+
|
|
250
|
+
#### Remove Redundant Transitive References
|
|
251
|
+
|
|
252
|
+
```xml
|
|
253
|
+
<!-- Before: Core also references Utils -->
|
|
254
|
+
<ItemGroup>
|
|
255
|
+
<ProjectReference Include="..\Core\Core.csproj" />
|
|
256
|
+
<ProjectReference Include="..\Utils\Utils.csproj" />
|
|
257
|
+
</ItemGroup>
|
|
258
|
+
|
|
259
|
+
<!-- Candidate only after proving the direct Utils edge is unnecessary -->
|
|
260
|
+
<ItemGroup>
|
|
261
|
+
<ProjectReference Include="..\Core\Core.csproj" />
|
|
262
|
+
</ItemGroup>
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Transitive reachability alone is insufficient. A direct reference may express
|
|
266
|
+
direct API use, repository policy, or important metadata. Verify compile/runtime
|
|
267
|
+
dependencies and pack/publish behavior across supported TFMs/configurations.
|
|
268
|
+
Removing `App -> Utils` does not necessarily shorten `App -> Core -> Utils`.
|
|
269
|
+
|
|
270
|
+
#### Build-Order-Only References
|
|
271
|
+
|
|
272
|
+
When a project must build first but its assembly is not a compiler reference:
|
|
273
|
+
|
|
274
|
+
```xml
|
|
275
|
+
<ProjectReference Include="..\CodeGen\CodeGen.csproj"
|
|
276
|
+
ReferenceOutputAssembly="false" />
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
This preserves the build-order dependency. It does **not** remove the scheduling
|
|
280
|
+
edge or make the projects independent.
|
|
281
|
+
|
|
282
|
+
#### Prevent Transitive Asset Flow
|
|
283
|
+
|
|
284
|
+
When a dependency is an implementation detail that should not be exposed through
|
|
285
|
+
the relevant NuGet asset/pack contract:
|
|
286
|
+
|
|
287
|
+
```xml
|
|
288
|
+
<ProjectReference Include="..\InternalHelpers\InternalHelpers.csproj"
|
|
289
|
+
PrivateAssets="all" />
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
Inspect restored assets, generated package dependencies, and consuming projects.
|
|
293
|
+
`PrivateAssets` is not a generic "do not build" or "remove the compiler reference"
|
|
294
|
+
switch, and this metadata alone does not establish a performance improvement.
|
|
295
|
+
|
|
296
|
+
#### Disable Transitive Project References
|
|
297
|
+
|
|
298
|
+
For deliberately explicit-only dependency management in supporting SDK builds:
|
|
299
|
+
|
|
300
|
+
```xml
|
|
301
|
+
<PropertyGroup>
|
|
302
|
+
<DisableTransitiveProjectReferences>true</DisableTransitiveProjectReferences>
|
|
303
|
+
</PropertyGroup>
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
**Caution:** this requires explicit references to consumed dependencies. Consider
|
|
307
|
+
it only for measured transitive-closure overhead, with consumer validation. It
|
|
308
|
+
does not eliminate required project build ordering.
|
|
309
|
+
|
|
310
|
+
## Step 5: Static Graph Builds (`/graph`)
|
|
311
|
+
|
|
312
|
+
Static graph mode constructs the project graph before building, allowing
|
|
313
|
+
scheduling from the declared dependencies.
|
|
314
|
+
|
|
315
|
+
### Enabling Graph Build
|
|
316
|
+
|
|
317
|
+
```powershell
|
|
318
|
+
dotnet build -graph
|
|
319
|
+
dotnet build -graph "-bl:graph-build.binlog"
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Benefits
|
|
323
|
+
|
|
324
|
+
- **Scheduling:** knowing the complete graph can improve parallel scheduling.
|
|
325
|
+
- **Isolation:** project isolation is a separate contract, selected with
|
|
326
|
+
`-isolateProjects`; `/graph` alone does not guarantee it.
|
|
327
|
+
- **Caching potential:** results-cache options are separate features with their
|
|
328
|
+
own isolation/correctness requirements, not an automatic graph-build cache.
|
|
329
|
+
|
|
330
|
+
### When to Use
|
|
331
|
+
|
|
332
|
+
| Scenario | Recommendation |
|
|
333
|
+
| --- | --- |
|
|
334
|
+
| Large multi-project solution, for example 20+ projects | Measure graph mode as a candidate; project count is not proof of a benefit. |
|
|
335
|
+
| Small solution, for example fewer than 5 projects | Extra graph construction may outweigh scheduling gains; measure rather than assume. |
|
|
336
|
+
| CI builds | Try when dependencies are statically discoverable and output isolation is sound. |
|
|
337
|
+
| Local development | Compare both modes in the same cold, changed-input, or no-change scenario. |
|
|
338
|
+
|
|
339
|
+
### Troubleshooting Graph Build
|
|
340
|
+
|
|
341
|
+
All relevant project dependencies must be statically discoverable. References
|
|
342
|
+
created inside targets or hidden in programmatic `MSBuild` calls can violate
|
|
343
|
+
that model. Inspect the actual emitted error rather than assuming one error code.
|
|
344
|
+
|
|
345
|
+
Declare `ProjectReference` items during evaluation where that preserves their
|
|
346
|
+
semantics. Do not move execution-dependent logic blindly, drop dependencies, or
|
|
347
|
+
disable dependency builds to make graph construction pass. If the graph cannot
|
|
348
|
+
represent the build correctly, retain the normal build.
|
|
349
|
+
|
|
350
|
+
## Step 6: Parallel Build Tuning
|
|
351
|
+
|
|
352
|
+
### MaxCpuCount
|
|
353
|
+
|
|
354
|
+
```powershell
|
|
355
|
+
# Permit up to the logical processor count
|
|
356
|
+
dotnet build -m
|
|
357
|
+
|
|
358
|
+
# Explicit budget, useful on shared CI agents
|
|
359
|
+
dotnet build -m:4
|
|
360
|
+
|
|
361
|
+
# MSBuild.exe syntax
|
|
362
|
+
msbuild -m:8 .\MySolution.sln
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Raw MSBuild defaults to one node without `-m`; the `dotnet build` driver can
|
|
366
|
+
supply switches itself. Inspect the actual invocation and record an explicit
|
|
367
|
+
budget when comparing runs. Respect memory limits, CPU quotas, and other users.
|
|
368
|
+
|
|
369
|
+
### Identifying Parallelism Bottlenecks
|
|
370
|
+
|
|
371
|
+
In recorded project-instance and scheduling evidence, look for:
|
|
372
|
+
- **Long sequential chains:** projects waiting on required predecessors.
|
|
373
|
+
- **Uneven load:** idle nodes while others remain busy.
|
|
374
|
+
- **Single-project bottleneck:** one long project on the critical path.
|
|
375
|
+
|
|
376
|
+
Name the chain with durations, for example `Core -> Api -> Web -> Tests`.
|
|
377
|
+
Aggregate target/task summaries alone cannot establish node utilization: totals
|
|
378
|
+
can overlap, nest, or include waits. If replay lacks sufficient scheduling detail,
|
|
379
|
+
report that gap rather than inventing utilization percentages.
|
|
380
|
+
|
|
381
|
+
For independent requests in a custom orchestration target, enable parallelism
|
|
382
|
+
on the `MSBuild` task as well as providing multiple nodes:
|
|
383
|
+
|
|
384
|
+
```xml
|
|
385
|
+
<MSBuild Projects="@(ProjectsToBuild)" Targets="Build" BuildInParallel="true" />
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
### Reducing the Critical Path
|
|
389
|
+
|
|
390
|
+
1. Split a measured large bottleneck only if the resulting work can run independently.
|
|
391
|
+
2. Remove proven unnecessary references using Step 4's compatibility checks.
|
|
392
|
+
3. Use `ReferenceOutputAssembly="false"` only for genuine build-order-only intent;
|
|
393
|
+
it can reduce assembly-reference work, not the dependency wait itself.
|
|
394
|
+
4. Consider a shared base library only if the resulting graph is better; a new
|
|
395
|
+
common prerequisite can also lengthen the serial chain.
|
|
396
|
+
|
|
397
|
+
More nodes cannot parallelize a required dependency chain and can worsen
|
|
398
|
+
memory- or I/O-bound workloads.
|
|
399
|
+
|
|
400
|
+
## Step 7: Additional Quick Wins
|
|
401
|
+
|
|
402
|
+
Treat these as candidates selected by evidence, not a list to apply wholesale.
|
|
403
|
+
|
|
404
|
+
### Separate Restore from Build
|
|
405
|
+
|
|
406
|
+
```powershell
|
|
407
|
+
dotnet restore
|
|
408
|
+
if ($LASTEXITCODE -ne 0) { throw "Restore failed; do not use stale assets." }
|
|
409
|
+
dotnet build --no-restore -m
|
|
410
|
+
if ($LASTEXITCODE -ne 0) { throw "Build failed; do not test stale outputs." }
|
|
411
|
+
dotnet test --no-build
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
Use matching configuration/TFM/RID and restore-affecting properties in each stage.
|
|
415
|
+
`--no-restore` requires current assets; `--no-build` requires successfully built
|
|
416
|
+
matching test outputs. Keep restore-inclusive and build-only timings separate.
|
|
417
|
+
|
|
418
|
+
### Skip Unnecessary Targets
|
|
419
|
+
|
|
420
|
+
For an explicitly agreed development scenario where these outputs/checks are
|
|
421
|
+
optional:
|
|
422
|
+
|
|
423
|
+
```powershell
|
|
424
|
+
dotnet build -p:GenerateDocumentationFile=false
|
|
425
|
+
dotnet build -p:RunAnalyzers=false
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Measure their actual cost first. Preserve required XML documentation in packages,
|
|
429
|
+
required analyzer diagnostics in CI, and generator-produced code.
|
|
430
|
+
[Analyzer diagnostics](build-perf-diagnostics.md#2-roslyn-analyzers-and-source-generators)
|
|
431
|
+
covers conditional policy and global analyzer references. Do not silently call
|
|
432
|
+
disabled validation behavior-preserving.
|
|
433
|
+
|
|
434
|
+
### Use Project-Level Filtering
|
|
435
|
+
|
|
436
|
+
```powershell
|
|
437
|
+
dotnet build .\src\MyApp\MyApp.csproj
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
Build the project and its dependencies when that is the intended inner loop.
|
|
441
|
+
Solution filters can similarly select a supported subset. A smaller selection
|
|
442
|
+
is a different scenario, not proof that the full solution became faster; retain
|
|
443
|
+
the required integration and test coverage.
|
|
444
|
+
|
|
445
|
+
### Binary Log for All Investigations
|
|
446
|
+
|
|
447
|
+
Start with an existing matching binlog or capture through
|
|
448
|
+
[binlog generation](binlog-generation.md):
|
|
449
|
+
|
|
450
|
+
```powershell
|
|
451
|
+
dotnet build -m "-bl:perf.binlog"
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
Then use [build performance diagnostics](build-perf-diagnostics.md) to identify
|
|
455
|
+
the bottleneck before applying a change.
|
|
456
|
+
|
|
457
|
+
## Optimization Decision Tree
|
|
458
|
+
|
|
459
|
+
```text
|
|
460
|
+
Is the no-op build slow?
|
|
461
|
+
YES -> Classify evaluation, restore, copies, and executed work first.
|
|
462
|
+
Unexpected execution -> incremental-build.md.
|
|
463
|
+
Slow evaluation -> eval-performance.md.
|
|
464
|
+
NO / after classification:
|
|
465
|
+
Is the cold build slow?
|
|
466
|
+
Restore -> investigate feeds/cache/inputs; compare restore separately.
|
|
467
|
+
Compilation -> diagnose analyzers/generators and critical-path work.
|
|
468
|
+
Other targets -> inspect their recorded reasons and task costs.
|
|
469
|
+
Is the warm changed-input build slow?
|
|
470
|
+
Unexpected propagation -> incremental-build.md and dependency analysis.
|
|
471
|
+
Required serial work -> inspect critical path and parallelism above.
|
|
472
|
+
Are all scenarios healthy for the actual workload?
|
|
473
|
+
Stop. Do not change healthy configuration just to apply a tuning flag.
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
Use the linked [incremental](incremental-build.md),
|
|
477
|
+
[evaluation](eval-performance.md), and [diagnostics](build-perf-diagnostics.md)
|
|
478
|
+
references for those branches.
|
|
479
|
+
|
|
480
|
+
## Validation and Results
|
|
481
|
+
|
|
482
|
+
Repeat the same scenario and input change with the same instrumentation. Verify
|
|
483
|
+
required outputs, downstream consumers, diagnostics, and relevant tests or
|
|
484
|
+
pack/publish behavior. For tracking changes, exercise input addition/change/removal
|
|
485
|
+
and missing outputs as described in [incremental builds](incremental-build.md).
|
|
486
|
+
For copy changes, verify [copy-mode semantics](copy-to-output-directory.md).
|
|
487
|
+
|
|
488
|
+
Report the command/environment, before/after median and spread, artifact paths,
|
|
489
|
+
one causal change, correctness checks, and unmeasured scenarios. Stop or revert
|
|
490
|
+
only your own experimental change if the benefit is within noise, the comparison
|
|
491
|
+
cannot succeed, or correctness regresses.
|
|
492
|
+
|
|
493
|
+
> **Cratis:** Only as a labelled timing experiment; restore analyzers and warnings-as-errors and run the real gate before finishing.
|