Skip to content

Move NuGet caches to the temp drive on Windows runners - #5991

Open
danielmarbach wants to merge 1 commit into
masterfrom
cache
Open

danielmarbach wants to merge 1 commit into
masterfrom
cache

Conversation

@danielmarbach

@danielmarbach danielmarbach commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Why

The Windows jobs spend a lot more time in dotnet restore than the Linux ones do for the same work. On GitHub-hosted Windows runners the checkout and RUNNER_TEMP are on D:, but the default NuGet package and HTTP caches live in the user profile on C:. @bording pointed at this write-up, which points at exactly that, and wanted to see whether it applies to us.

What changes

A small composite action, .github/actions/nuget-cache-location, points NUGET_PACKAGES and NUGET_HTTP_CACHE_PATH at RUNNER_TEMP. It only does anything on GitHub-hosted Windows runners. It runs right after checkout in the Windows build and compile jobs in ci.yml and in build-windows.yml. I made it an action so we have one copy of the logic instead of three.

Measurements

I ran a throwaway workflow (not part of this PR) on windows-latest that does dotnet restore src followed by dotnet build src --configuration Release --no-restore -graph. Averages over six runs per variant, three for the SDK one:

Variant Restore Extra step time Job total
Linux 21s 0s 194s
Windows, today 95s 0s 271s
Windows, caches on temp drive (this PR) 27s 1s 206s
Windows, temp drive + actions/cache, warm 18s 19s 208s
Windows, temp drive + SDK installed to D: 24s 17s 217s

Restore is about 3.5 times faster and the job is roughly a minute shorter. Windows ends up about 12s behind Linux instead of over a minute. The build step itself doesn't change. It also varies a lot between runs (120s to 177s on every variant, Linux included), so the job totals carry about 30s of noise. The restore gap is well outside that.

What I tried that didn't help

  • actions/cache on top of the temp drive saves about 9s of restore, but restoring the cache costs about 15s. A cold run pays around 50s to save it. I dropped it.
  • Installing the SDK to D: doesn't help here, because windows-latest already ships the SDK and setup-dotnet takes about 2s. dotnet-install.ps1 into D:\dotnet took about 17s.
  • Building on the temp drive isn't something we can improve, since the workspace is already on D:.

Open points

  • The numbers come from the throwaway workflow, so the CI run on this PR is the first time the action runs inside the real jobs. It would be worth comparing the restore timings in the Windows jobs here against a few recent runs on master.
  • I haven't touched the runtime installs into C:\Program Files\dotnet in ci.yml. They're small and I haven't measured them, so I can't say whether they're worth moving.
  • The runner.environment == 'github-hosted' guard is there because I don't know how our self-hosted or larger runners are laid out. Happy to drop it if that's not a concern.

@danielmarbach

Copy link
Copy Markdown
Contributor Author

I think we can always move this into some centralized action but the biggest benefit is certainly here

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