@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.
Files changed (168) hide show
  1. package/package/corpus/harnesses/copilot/instructions/github-actions.instructions.md +17 -0
  2. package/package/corpus/harnesses/copilot/instructions/profiles.instructions.md +10 -1
  3. package/package/corpus/harnesses/copilot/instructions/pull-requests.instructions.md +2 -0
  4. package/package/corpus/harnesses/copilot/instructions/secrets.instructions.md +4 -0
  5. package/package/corpus/hooks/README.md +11 -1
  6. package/package/corpus/hooks/scripts/cratis-check-pr.mjs +12 -1
  7. package/package/corpus/hooks/scripts/cratis-guard-secrets.sh +79 -23
  8. package/package/corpus/hooks/scripts/cratis-guard-writes.sh +145 -40
  9. package/package/corpus/rules/github-actions.md +17 -0
  10. package/package/corpus/rules/profiles.md +10 -1
  11. package/package/corpus/rules/pull-requests.md +2 -0
  12. package/package/corpus/rules/secrets.md +4 -0
  13. package/package/corpus/skills/analyzing-dotnet-performance/LICENSE +23 -0
  14. package/package/corpus/skills/analyzing-dotnet-performance/NOTICE +36 -0
  15. package/package/corpus/skills/analyzing-dotnet-performance/SKILL.md +214 -0
  16. package/package/corpus/skills/analyzing-dotnet-performance/references/async-patterns.md +122 -0
  17. package/package/corpus/skills/analyzing-dotnet-performance/references/collections-and-linq.md +220 -0
  18. package/package/corpus/skills/analyzing-dotnet-performance/references/critical-patterns.md +291 -0
  19. package/package/corpus/skills/analyzing-dotnet-performance/references/io-and-serialization.md +135 -0
  20. package/package/corpus/skills/analyzing-dotnet-performance/references/memory-and-strings.md +219 -0
  21. package/package/corpus/skills/analyzing-dotnet-performance/references/regex-patterns.md +95 -0
  22. package/package/corpus/skills/analyzing-dotnet-performance/references/structural-patterns.md +38 -0
  23. package/package/corpus/skills/binlog-generation/LICENSE +23 -0
  24. package/package/corpus/skills/binlog-generation/NOTICE +22 -0
  25. package/package/corpus/skills/binlog-generation/SKILL.md +129 -0
  26. package/package/corpus/skills/check-bin-obj-clash/LICENSE +23 -0
  27. package/package/corpus/skills/check-bin-obj-clash/NOTICE +27 -0
  28. package/package/corpus/skills/check-bin-obj-clash/SKILL.md +127 -0
  29. package/package/corpus/skills/check-bin-obj-clash/references/common-causes-and-fixes.md +206 -0
  30. package/package/corpus/skills/coverage-analysis/LICENSE +23 -0
  31. package/package/corpus/skills/coverage-analysis/NOTICE +32 -0
  32. package/package/corpus/skills/coverage-analysis/SKILL.md +198 -0
  33. package/package/corpus/skills/coverage-analysis/references/guidelines.md +68 -0
  34. package/package/corpus/skills/coverage-analysis/references/output-format.md +91 -0
  35. package/package/corpus/skills/coverage-analysis/references/report-generation.md +58 -0
  36. package/package/corpus/skills/coverage-analysis/references/setup-discovery.md +307 -0
  37. package/package/corpus/skills/coverage-analysis/scripts/Compute-CrapScores.ps1 +80 -0
  38. package/package/corpus/skills/coverage-analysis/scripts/CoverageData.ps1 +272 -0
  39. package/package/corpus/skills/coverage-analysis/scripts/Extract-MethodCoverage.ps1 +65 -0
  40. package/package/corpus/skills/cratis-ci-pipeline-performance/LICENSE +2 -0
  41. package/package/corpus/skills/cratis-ci-pipeline-performance/SKILL.md +201 -0
  42. package/package/corpus/skills/cratis-ci-pipeline-performance/references/build-once-and-shard.md +158 -0
  43. package/package/corpus/skills/cratis-ci-pipeline-performance/references/caching.md +86 -0
  44. package/package/corpus/skills/cratis-ci-pipeline-performance/references/flaky-and-hung-jobs.md +70 -0
  45. package/package/corpus/skills/cratis-ci-pipeline-performance/references/publish-pipelines.md +67 -0
  46. package/package/corpus/skills/cratis-ci-pipeline-performance/references/required-checks-and-path-filters.md +117 -0
  47. package/package/corpus/skills/cratis-ci-pipeline-performance/references/runner-sizing-and-images.md +65 -0
  48. package/package/corpus/skills/cratis-ci-pipeline-performance/references/security-and-pinning.md +73 -0
  49. package/package/corpus/skills/cratis-ci-pipeline-performance/references/sources.md +33 -0
  50. package/package/corpus/skills/cratis-ci-pipeline-performance/references/test-setup-cost.md +82 -0
  51. package/package/corpus/skills/cratis-ci-pipeline-performance/scripts/ci-timings.sh +356 -0
  52. package/package/corpus/skills/cratis-ci-pipeline-performance/scripts/fixtures/jobs/1003.json +79 -0
  53. package/package/corpus/skills/cratis-ci-pipeline-performance/scripts/fixtures/jobs/1007.json +79 -0
  54. package/package/corpus/skills/cratis-ci-pipeline-performance/scripts/fixtures/jobs/1010.json +79 -0
  55. package/package/corpus/skills/cratis-ci-pipeline-performance/scripts/fixtures/runs.json +102 -0
  56. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/LICENSE +2 -0
  57. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/SKILL.md +244 -0
  58. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/docker-images.md +86 -0
  59. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/dotnet-nuget.md +87 -0
  60. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/go-jvm-python-elixir.md +83 -0
  61. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/npm-yarn.md +78 -0
  62. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/other-environments.md +60 -0
  63. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/references/worked-examples.md +97 -0
  64. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/scripts/cratis-local-packages.sh +778 -0
  65. package/package/corpus/skills/cratis-engineering-local-cross-repo-verification/scripts/npm-restore-check.cjs +109 -0
  66. package/package/corpus/skills/csharp-refactoring/LICENSE +23 -0
  67. package/package/corpus/skills/csharp-refactoring/NOTICE +22 -0
  68. package/package/corpus/skills/csharp-refactoring/SKILL.md +175 -0
  69. package/package/corpus/skills/csharp-refactoring/references/operation-catalog.md +37 -0
  70. package/package/corpus/skills/directory-build-organization/LICENSE +23 -0
  71. package/package/corpus/skills/directory-build-organization/NOTICE +21 -0
  72. package/package/corpus/skills/directory-build-organization/SKILL.md +205 -0
  73. package/package/corpus/skills/directory-build-organization/references/common-patterns.md +56 -0
  74. package/package/corpus/skills/directory-build-organization/references/multi-level-examples.md +167 -0
  75. package/package/corpus/skills/directory-build-organization/references/targetframework-props-pitfall.md +54 -0
  76. package/package/corpus/skills/dotnet-aot-compat/LICENSE +23 -0
  77. package/package/corpus/skills/dotnet-aot-compat/NOTICE +18 -0
  78. package/package/corpus/skills/dotnet-aot-compat/SKILL.md +265 -0
  79. package/package/corpus/skills/dotnet-aot-compat/references/polyfills.md +43 -0
  80. package/package/corpus/skills/dotnet-trace-collect/LICENSE +23 -0
  81. package/package/corpus/skills/dotnet-trace-collect/NOTICE +65 -0
  82. package/package/corpus/skills/dotnet-trace-collect/SKILL.md +116 -0
  83. package/package/corpus/skills/dotnet-trace-collect/references/dotnet-monitor.md +97 -0
  84. package/package/corpus/skills/dotnet-trace-collect/references/dotnet-trace-collect-linux.md +84 -0
  85. package/package/corpus/skills/dotnet-trace-collect/references/dotnet-trace-collect.md +91 -0
  86. package/package/corpus/skills/dotnet-trace-collect/references/perfcollect.md +200 -0
  87. package/package/corpus/skills/dotnet-trace-collect/references/perfview.md +141 -0
  88. package/package/corpus/skills/dotnet-trace-collect/references/tool-selection.md +160 -0
  89. package/package/corpus/skills/dump-collect/LICENSE +23 -0
  90. package/package/corpus/skills/dump-collect/NOTICE +40 -0
  91. package/package/corpus/skills/dump-collect/SKILL.md +97 -0
  92. package/package/corpus/skills/dump-collect/references/container-dumps.md +412 -0
  93. package/package/corpus/skills/dump-collect/references/coreclr-dumps.md +108 -0
  94. package/package/corpus/skills/dump-collect/references/nativeaot-dumps.md +280 -0
  95. package/package/corpus/skills/eliminate-redundant-restores/LICENSE +23 -0
  96. package/package/corpus/skills/eliminate-redundant-restores/NOTICE +19 -0
  97. package/package/corpus/skills/eliminate-redundant-restores/SKILL.md +112 -0
  98. package/package/corpus/skills/extension-points/LICENSE +23 -0
  99. package/package/corpus/skills/extension-points/NOTICE +18 -0
  100. package/package/corpus/skills/extension-points/SKILL.md +248 -0
  101. package/package/corpus/skills/filter-syntax/LICENSE +23 -0
  102. package/package/corpus/skills/filter-syntax/NOTICE +17 -0
  103. package/package/corpus/skills/filter-syntax/SKILL.md +179 -0
  104. package/package/corpus/skills/including-generated-files/LICENSE +23 -0
  105. package/package/corpus/skills/including-generated-files/NOTICE +17 -0
  106. package/package/corpus/skills/including-generated-files/SKILL.md +139 -0
  107. package/package/corpus/skills/microbenchmarking/LICENSE +23 -0
  108. package/package/corpus/skills/microbenchmarking/NOTICE +36 -0
  109. package/package/corpus/skills/microbenchmarking/SKILL.md +131 -0
  110. package/package/corpus/skills/microbenchmarking/references/bdn-internals-and-tuning.md +143 -0
  111. package/package/corpus/skills/microbenchmarking/references/comparison-strategies.md +200 -0
  112. package/package/corpus/skills/microbenchmarking/references/diagnosers-and-exporters.md +150 -0
  113. package/package/corpus/skills/microbenchmarking/references/project-setup-and-running.md +189 -0
  114. package/package/corpus/skills/microbenchmarking/references/writing-benchmarks.md +310 -0
  115. package/package/corpus/skills/msbuild/LICENSE +23 -0
  116. package/package/corpus/skills/msbuild/NOTICE +55 -0
  117. package/package/corpus/skills/msbuild/SKILL.md +117 -0
  118. package/package/corpus/skills/msbuild/references/antipatterns/additional-antipatterns.md +291 -0
  119. package/package/corpus/skills/msbuild/references/antipatterns/incremental-build-inputs-outputs.md +57 -0
  120. package/package/corpus/skills/msbuild/references/antipatterns/private-assets.md +29 -0
  121. package/package/corpus/skills/msbuild/references/binlog-failure-analysis.md +85 -0
  122. package/package/corpus/skills/msbuild/references/binlog-generation.md +69 -0
  123. package/package/corpus/skills/msbuild/references/build-perf-baseline.md +493 -0
  124. package/package/corpus/skills/msbuild/references/build-perf-diagnostics.md +268 -0
  125. package/package/corpus/skills/msbuild/references/copy-to-output-directory.md +183 -0
  126. package/package/corpus/skills/msbuild/references/eval-performance.md +190 -0
  127. package/package/corpus/skills/msbuild/references/extension-points.md +281 -0
  128. package/package/corpus/skills/msbuild/references/incremental-build.md +365 -0
  129. package/package/corpus/skills/msbuild/references/msbuild-antipatterns.md +401 -0
  130. package/package/corpus/skills/orleans/LICENSE +21 -0
  131. package/package/corpus/skills/orleans/NOTICE +64 -0
  132. package/package/corpus/skills/orleans/SKILL.md +140 -0
  133. package/package/corpus/skills/orleans/references/anti-patterns.md +660 -0
  134. package/package/corpus/skills/orleans/references/configuration-api.md +933 -0
  135. package/package/corpus/skills/orleans/references/examples.md +66 -0
  136. package/package/corpus/skills/orleans/references/grain-api.md +784 -0
  137. package/package/corpus/skills/orleans/references/grains.md +75 -0
  138. package/package/corpus/skills/orleans/references/hosting.md +71 -0
  139. package/package/corpus/skills/orleans/references/implementation.md +591 -0
  140. package/package/corpus/skills/orleans/references/official-docs-index.md +250 -0
  141. package/package/corpus/skills/orleans/references/patterns.md +811 -0
  142. package/package/corpus/skills/orleans/references/persistence-api.md +495 -0
  143. package/package/corpus/skills/orleans/references/primitive-selection.md +35 -0
  144. package/package/corpus/skills/orleans/references/scheduling-and-services.md +295 -0
  145. package/package/corpus/skills/orleans/references/serialization-api.md +299 -0
  146. package/package/corpus/skills/orleans/references/streaming-api.md +396 -0
  147. package/package/corpus/skills/orleans/references/testing-patterns.md +210 -0
  148. package/package/corpus/skills/platform-detection/LICENSE +23 -0
  149. package/package/corpus/skills/platform-detection/NOTICE +17 -0
  150. package/package/corpus/skills/platform-detection/SKILL.md +230 -0
  151. package/package/corpus/skills/platform-detection/references/command-mode.md +27 -0
  152. package/package/corpus/skills/profiling/LICENSE +21 -0
  153. package/package/corpus/skills/profiling/NOTICE +50 -0
  154. package/package/corpus/skills/profiling/SKILL.md +144 -0
  155. package/package/corpus/skills/profiling/references/commands.md +439 -0
  156. package/package/corpus/skills/profiling/references/patterns.md +586 -0
  157. package/package/corpus/skills/profiling/references/profiling.md +190 -0
  158. package/package/corpus/skills/run-tests/LICENSE +23 -0
  159. package/package/corpus/skills/run-tests/NOTICE +19 -0
  160. package/package/corpus/skills/run-tests/SKILL.md +305 -0
  161. package/package/corpus/skills/target-authoring/LICENSE +23 -0
  162. package/package/corpus/skills/target-authoring/NOTICE +17 -0
  163. package/package/corpus/skills/target-authoring/SKILL.md +165 -0
  164. package/package/corpus/skills/vectorization/LICENSE +23 -0
  165. package/package/corpus/skills/vectorization/NOTICE +17 -0
  166. package/package/corpus/skills/vectorization/SKILL.md +189 -0
  167. package/package/profile-catalog.json +87 -1
  168. 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.