Skip to content

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

Open
Copilot wants to merge 2 commits intomainfrom
copilot/enable-graph-in-ci-dev-pr-builds
Open

Enable /graph in CI builds, dev builds, and PR builds#53607
Copilot wants to merge 2 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

  • Directory.Build.rsp — new file at the repo root containing /graph, which MSBuild automatically picks up for every invocation (dev, CI, and PR builds on all platforms)

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).

Agent-Logs-Url: https://github.com/dotnet/sdk/sessions/efc7cf71-2ee4-4f93-b888-494874161c1e

Co-authored-by: marcpopMSFT <12663534+marcpopMSFT@users.noreply.github.com>
@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.

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