Skip to content

perf: stop recompiling every project on every build (release 1.3.0) - #46

Merged
kieronlanning merged 1 commit into
mainfrom
perf-updates
Nov 8, 2026
Merged

kieronlanning merged 1 commit into
mainfrom
perf-updates

Conversation

@kieronlanning

Copy link
Copy Markdown
Contributor

Why

A rebuild with no source changes on a 39-project solution took 67.7 s and ran 38 Csc invocations. Two files the SDK generates into every project were written with Overwrite="true" and no WriteOnlyWhenDifferent, and both are @(Compile) inputs - so CoreCompile could never be up to date. That also silently defeated AccelerateBuildsInVisualStudio=true.

Measured end to end

changeops (39 projects, net11.0, AnalysisMode=All), same machine, no source changes between runs:

1.2.0 1.3.0
Cold build 154.4 s 103.2 s
Warm rebuild, no changes 67.7 s 7.20 s
Csc on the warm rebuild 38 calls / 111.6 s 0

The first warm build after upgrading is 27.3 s, not 7.2 s - the upgrade invalidates analyzers, .editorconfig and compiler state at once. Steady state is the next no-change build.

Every Purview target in that steady-state build now sums to about 0.9 s of the 7.2 s, with none above 400 ms.

What changed

  • WriteOnlyWhenDifferent="true" on both generated-file writers.
  • The AfterTargets="Build" skill recommendation hook is gone. It read and regex-scanned every project assets file (~500 KB, 256 libraries) on every build to print advice. VerifyPurviewSkills replaces it as an explicit gate that escalates PRSKL0010/PRSKL0011 to errors.
  • ValidatePurviewStylePolicy reads each .editorconfig in the chain once, not twice (the SDK own copy is 2,714 lines / 95 KB).
  • Both repository-file bootstraps skip DesignTimeBuild, which was repeating the root probes and two 95 KB reads per project on every IDE edit.
  • The tracked .editorconfig version marker now syncs from package.json (just version-sync), a new just version-sync-check guards it, and a pre-commit hook runs it.

Breaking change

No skill work runs during a build. EnablePurviewSkillRecommendations, PurviewSkillRecommendationsInCI and PurviewSkillRecommendationStampPath are removed. Use -t:RecommendPurviewSkills to report, -t:VerifyPurviewSkills to fail a pipeline, -t:InstallPurviewSkills to install. Nothing in purview-dev/* sets any of the removed properties - checked with git grep across every repo.

Testing

  • just pipeline-local-release on 1.3.0 passed: 669 tests (47 + 69 + 73 + 480), CSharpier, pack, pack validation, local publish.
  • New IncrementalBuildTests pins both generated files: two builds of an unchanged project must leave their timestamps and content alone.
  • New DesignTimeBuild_DoesNotBootstrapTheRepositoryFiles.
  • AdoptionPin_MatchesPackageJson now covers .editorconfig; version-sync-check was verified to fail on a stale marker and pass on a clean one.
  • Verified against changeops on 1.3.0: zero Csc on a no-change rebuild, and just skills-verify returns 0 silently.

Deliberately not changed

ImportProjectReferencedBuildTransitiveAssets looked like the next target (~2 s in the target summary) but toggling it off on a steady-state build gave 7.99 s against 7.20 s with it on - no measurable cost. AnalysisMode=All is intentional policy. Both are recorded in docs/wiki/Performance.md so they are not re-litigated.

The SDK wrote GeneratedAssemblyInfo.cs and GeneratedAssemblyIdentifier.cs with
Overwrite="true" and no WriteOnlyWhenDifferent. Both files are @(Compile)
inputs, so CoreCompile could never be up to date and every build recompiled
every project. Measured on a 39-project solution: a rebuild with no source
changes ran 38 Csc invocations totalling 111.6 s of a 67.7 s build. It now
runs none, and that rebuild takes 7.2 s instead of 67.7 s.

Also in this release:

- remove the AfterTargets="Build" skill recommendation hook, which read and
  regex-scanned every project assets file (about 500 KB, 256 libraries each)
  on every build to print advice nobody on CI could act on; the explicit
  VerifyPurviewSkills gate replaces it and escalates PRSKL0010/0011 to errors
- read each .editorconfig in the style-policy chain once instead of twice
- skip both repository-file bootstraps on design-time builds, which repeated
  the repository-root probes and two 95 KB reads per project per IDE edit
- keep the tracked .editorconfig version marker in sync with package.json via
  just version-sync, checked by just version-sync-check in the pre-commit hook

BREAKING CHANGE: no skill work runs during a build any more, and
EnablePurviewSkillRecommendations, PurviewSkillRecommendationsInCI and
PurviewSkillRecommendationStampPath are removed. Use -t:RecommendPurviewSkills
to report, -t:VerifyPurviewSkills to fail a pipeline, and -t:InstallPurviewSkills
to install.
@kieronlanning
kieronlanning merged commit 84e8802 into main Nov 8, 2026
5 checks passed
@kieronlanning
kieronlanning deleted the perf-updates branch November 8, 2026 18:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant