Skip to content

Enable /graph in CI builds, dev builds, and PR builds#53607

Merged
baronfel merged 3 commits intomainfrom
copilot/enable-graph-in-ci-dev-pr-builds
Apr 3, 2026
Merged

Enable /graph in CI builds, dev builds, and PR builds#53607
baronfel merged 3 commits intomainfrom
copilot/enable-graph-in-ci-dev-pr-builds

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 27, 2026

Summary

Enables MSBuild's static graph build mode (/graph) for all build types to speed up builds.

Changes

  • eng/build.sh — adds /graph for developer builds on Linux/macOS
  • eng/build.ps1 — adds /graph for developer builds on Windows
  • eng/pipelines/templates/jobs/sdk-build.yml — adds /graph to both the Windows (eng/common/build.ps1) and Linux (eng/common/build.sh) build steps used in CI and PR pipelines

Why /graph?

MSBuild's static graph (/graph) mode pre-evaluates the project dependency graph before building, which allows for better scheduling and parallelism across projects. This speeds up builds, particularly in repos with many projects like the SDK.

MSBuild /graph Build Performance Analysis

Summary

Enabling MSBuild's /graph flag on the dotnet/sdk repo cuts no-op incremental build time by ~52% (8.5 min → 4.1 min wall-clock). Graph build pre-computes the project dependency graph statically, eliminating redundant recursive traversal of project references that dominates incremental build cost.

Test Setup

  • Repo: dotnet/sdk (main branch, March 2026)
  • Machine: Windows x64, local developer build
  • Command: build.cmd /bl (baseline) vs build.cmd /bl /graph
  • Scenario: No-op incremental rebuild (no source changes)
  • Analysis tool: Custom C# binlog analyzer using MSBuild.StructuredLogger (scripts/BinlogAnalyzer/)

Results

Wall-Clock Time

Build Mode Wall-Clock Sum of Project Times Parallelism Ratio
No /graph 8.5 min 602.1 min 71.1x
With /graph 4.1 min 82.6 min 20.1x
Improvement -52% -86%

Target-Level Comparison (Cumulative Time)

Target No /graph With /graph Reduction
ResolveProjectReferences 195.4 min (617 calls) 46.6 min (589 calls) 76%
MsCoverageReferencedPathMaps 187.5 min (61 calls) 3.2 min (61 calls) 98%
DispatchToInnerBuilds 112.2 min (50 calls) 9.7 min (50 calls) 91%
GetCopyToOutputDirectoryItems 22.9 min (855 calls) 2.1 min (858 calls) 91%
_GetProjectReferenceTargetFrameworkProperties 16.5 min (529 calls) 3.6 min (528 calls) 78%

Task-Level Comparison (Cumulative Time)

Task No /graph With /graph Reduction
MSBuild (recursive invocations) 561.0 min (2094 calls) 75.4 min (2028 calls) 87%
Csc (compilation) 10.9 min (692 calls) Not in top 20 (fully skipped) ~100%
Copy 24.7s (698 calls) 9.1s (598 calls) 63%

Key Observations

  1. /graph halved wall-clock time. The biggest gain comes from eliminating redundant project reference traversal. In standard mode, MSBuild recursively invokes ResolveProjectReferences on every project and its transitive dependencies. Graph build pre-computes the full dependency graph, building projects in topological order without redundant re-evaluation.

  2. MsCoverageReferencedPathMaps dropped from 187 min to 3 min cumulative. This code coverage instrumentation target was being invoked deeply in the recursive project graph traversal. With graph build, it no longer runs redundantly across transitive references.

  3. Zero compilations on no-op with /graph. The Csc task didn't even appear in the top 20 task list — graph build correctly determined every project was up-to-date. Without /graph, there were still 692 Csc invocations (10.9 min cumulative), suggesting the standard mode was triggering unnecessary recompilations due to timestamp changes from the recursive traversal itself.

  4. The build succeeded cleanly with /graph — zero errors, zero warnings. The pre-existing dotnet.Tests compilation error (RunFileTestBase not found) that occurs without /graph did not reproduce, likely due to different build ordering.

  5. Lower parallelism ratio is expected. The parallelism ratio dropped from 71x to 20x because there is dramatically less redundant work being scheduled across cores. The 71x ratio in the non-graph build reflects wasted parallel work (the same project references being evaluated simultaneously on multiple threads).

@baronfel
Copy link
Copy Markdown
Member

@copilot can this be added to a directory.build.rsp file in the root of the repo instead?

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 27, 2026

@copilot can this be added to a directory.build.rsp file in the root of the repo instead?

Done in ec698e7. Reverted the per-script additions and added a Directory.Build.rsp at the repo root with /graph — MSBuild automatically picks this file up for every invocation, covering dev, CI, and PR builds without touching any scripts or pipeline YAML.

Copilot AI requested a review from baronfel March 27, 2026 00:10
@marcpopMSFT marcpopMSFT marked this pull request as ready for review March 27, 2026 17:11
Copilot AI review requested due to automatic review settings March 27, 2026 17:11
@marcpopMSFT
Copy link
Copy Markdown
Member

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 1 pipeline(s).

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Enables MSBuild static graph mode across builds by introducing a repo-level response file intended to add /graph to MSBuild invocations.

Changes:

  • Add Directory.Build.rsp at the repo root containing /graph to enable static graph builds by default.

@marcpopMSFT
Copy link
Copy Markdown
Member

/azp run dotnet-sdk-public-ci

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines could not run because the pipeline triggers exclude this branch/path.

@marcpopMSFT
Copy link
Copy Markdown
Member

@baronfel it doesn't appear that Directory.Build.rsp is loaded when we build with build.cmd. I'm not clear if that's true of cibuild.cmd either. I confirmed it loads when using dotnet build. As such, I'm thinking we may need to go back to the prior fix for this.

@baronfel
Copy link
Copy Markdown
Member

baronfel commented Apr 1, 2026

Agree - though I want to log an issue and make copilot figure out why that is, because it break my mental model quite badly.

@marcpopMSFT
Copy link
Copy Markdown
Member

@copilot The .rsp file doesn't get loaded when I build locally using build.cmd. Let's go back to the prior solution you had for this.

Copilot AI requested a review from MiYanni as a code owner April 3, 2026 16:43
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 3, 2026

@copilot The .rsp file doesn't get loaded when I build locally using build.cmd. Let's go back to the prior solution you had for this.

Reverted in 30b66b4. Removed Directory.Build.rsp and restored /graph to eng/build.ps1, eng/build.sh, and eng/pipelines/templates/jobs/sdk-build.yml.

@marcpopMSFT
Copy link
Copy Markdown
Member

@baronfel confirmed this works for local build now. It isn't used in the PR build but I assume we're ok with that since /graph mostly helps with incremental builds. Holler if you think we should try to ensure /graph is used for PR and CI builds as well.

@baronfel baronfel enabled auto-merge (squash) April 3, 2026 18:39
@baronfel baronfel merged commit 8b1618b into main Apr 3, 2026
24 checks passed
@baronfel baronfel deleted the copilot/enable-graph-in-ci-dev-pr-builds branch April 3, 2026 22:24
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.

4 participants