Repository navigation
Add Windows CI resource telemetry to test and extension E2E jobs - #21644
David Fowler (davidfowl) wants to merge 4 commits into
Conversation
Windows test and extension E2E jobs freeze or lose their runner without any record of machine load (#21570). Add a below-normal-priority background sampler that records CPU, processor queue, available memory, commit charge, page file, paging, disk queue, free disk, and top processes every 20 seconds. The samples land in directories the existing if: always() uploads already collect, and a Stop step writes a peak/minimum summary to the job summary. Every mode exits 0 and the steps are continue-on-error, so telemetry never changes test behavior, timeouts, or retries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Processes that started during a sampling interval are now ranked by their accumulated CPU time instead of being skipped. Stop emits a warning when core counter columns are empty in every sample so a collection failure is visible on each Windows job, and the tests cover that warning and validate the sample row columns (core counters required on Windows). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Non-terminating Get-Counter errors were swallowed by -ErrorAction SilentlyContinue, so an empty counter column had no recorded cause. Capture them with -ErrorVariable and log each distinct failure once. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The launch profile test sliced from the run step to the diagnostics upload, so the new always() resource monitor Stop step (continue-on-error) fell inside the slice and tripped the run step's continue-on-error check. Slice to the next step instead, matching how the upload step is sliced. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tests selectorSelects the full PR test matrix + all PR-gated jobs (ALL) — a rule matching '.github/workflows/run-tests.yml' selects ALL Selection computed for commit |
|
🚀 Dogfood this PR with:
curl -fsSL https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.sh | bash -s -- 21644Or
iex "& { $(irm https://raw.githubusercontent.com/microsoft/aspire/main/eng/scripts/get-aspire-cli-pr.ps1) } 21644" |
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
🟡 Changes recommended
CPU rankings omit newly observed processes that may dominate an interval, and tests allow empty performance-counter fields without validating Windows counter collection, mapping, or unit conversions.
2 open issues
What changed in this PR
Adds Windows resource telemetry to help investigate CI slowdowns and runner losses tracked in #21570, using existing diagnostic artifacts.
Changes:
- Adds a background PowerShell sampler for machine pressure and top-process usage, with a shutdown summary.
- Starts and stops monitoring in Windows .NET test jobs and extension E2E shards.
- Adds behavioral tests for summary calculations, empty output, and sampler lifecycle.
| File | Description |
|---|---|
tests/Infrastructure.Tests/PowerShellScripts/CiResourceMonitorTests.cs |
Tests summaries and sampler startup/shutdown. |
eng/scripts/ci-resource-monitor.ps1 |
Collects resource metrics and generates diagnostic summaries. |
.github/workflows/run-tests.yml |
Adds Windows monitoring to .NET test jobs. |
.github/workflows/extension-e2e-tests.yml |
Adds Windows monitoring to extension E2E shards. |
Review effort: Balanced
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
🟡 Changes recommended
Non-terminating Get-Counter errors are suppressed without being logged, leaving users with missing counter values and no underlying diagnostics in sampler.log.
1 open issue
2 resolved since last review
Review effort: Balanced
This comment has been minimized.
This comment has been minimized.
|
Retrying the failed CI jobs for this pull request from the CI run attempt. The rerun is being tracked in the rerun attempt. |
|
CI attempt 1 on head d0358d4 (run 41291481771) had 8 failed jobs, all unrelated to this PR:
The repository's auto-rerun workflow started attempt 2. That is the single rerun for this head; I won't trigger another. 🤖 Posted by AspireAgent (AI Agent) |

Description
Windows runner loss and hangs are the largest flake family in #21600: Windows extension E2E and .NET test jobs freeze at 47–59 minutes against a 3–9 minute baseline, then lose their runner (#21570). We can't currently answer whether the machines are overloaded on CPU, memory or disk, because nothing records machine load in a form that survives the job.
This PR adds a lightweight background resource sampler to:
run-tests.yml)extension-e2e-tests.yml)What it records (
eng/scripts/ci-resource-monitor.ps1): a detached, below-normal-prioritypwshprocess starts right after checkout. Every 20s it writes:resources.csv: CPU %, processor queue length, available MB, commit charge % / committed GB / commit limit, paging pages/s, page file usage %, disk queue length, disk % time, free GB on the system and workspace drives, and process count.processes.log: the top 5 processes by CPU (since the previous sample) and by working set (with private bytes).Where it goes: the sampler writes into directories that the existing
if: always()uploads already collect, so there are no new artifacts:artifacts/log/test-logs/resource-monitor/insidelogs-<test>-windows-latest.extension/.test-results/resource-monitor/insideextension-e2e-diagnostics-win-x64-<shard>-attempt<N>.A
Stop resource monitor (Windows)step (if: always()) kills the sampler before the upload. It prints a peak/minimum table, including the largest gap between samples (a stall indicator), to the log and the job summary. This covers passing, failing, cancelled and timed-out jobs.Safety:
continue-on-error.Get-Counterand oneGet-Processcall every 20s at below-normal priority.Limitation: a runner that loses communication uploads nothing and keeps no logs. This telemetry can't capture the final minutes of a lost runner. It can show whether pressure builds on the slow jobs that survive and on the shards that typically get lost. That is still more than we have today: the existing console Heartbeat (60s, .NET tests only) vanishes with the log.
Contributes to #21570. It complements #21608 (Docker pin), which adds no telemetry.
Existing evidence (before this PR)
On main, the last 16 completed
ci.ymlpush runs had 1,551 Windows jobs. All 20 jobs that ran 45 minutes or longer were runner-lost; job logs returnBlobNotFound, so there's no Heartbeat data from any of them. Examples: extension E2E resource-debug-tools, 110m and Hosting-4, 59m.Surviving Windows Hosting-6 jobs on main (example) show the following in Heartbeat:
None of this shows exhaustion, but it doesn't cover commit charge, page file or disk queue.
Validation
tests/Infrastructure.Tests/PowerShellScripts/CiResourceMonitorTests.cs:actionlintis clean on both workflows.Observed in this PR's CI
The data comes from three CI runs of this PR on Windows hosted runners: 41289502805, 41290605859 (both partly cancelled by later pushes) and 41291481771 (head
d0358d42). It covers 331 Windows jobs with 2,923 samples: 312 .NET test jobs and 19 VS Code extension E2E shards. The sampler emitted no missing-counter warnings.Examples:
discovery-configuration: CPU 35% average (66% peak), at least 10.9 GB available, commit at most 26.7%, disk queue at most 11.6. The diagnostics artifactextension-e2e-diagnostics-win-x64-discovery-configuration-attempt1containsresource-monitor/resources.csvandprocesses.log.logs-Hosting.Dotnet-windows-latestartifact containsresource-monitor/. Itsprocesses.logshowsVBCSCompiler,dotnetandMSBuildas the top CPU consumers, i.e. the test-driven project builds.pwshuses about 1% CPU inprocesses.log.Runner loss was reproduced in this run, and those jobs stayed dark. On head
d0358d42, three .NET jobs froze inRun tests (Windows)at about 09:15Z: Hosting.Java (2-minute baseline), Hosting.Browsers (3-minute baseline) and Hosting-4 (8-minute baseline). MTP's--timeout 20mnever fired. All three were declared lost about 46 minutes after job start: "The hosted runner lost communication with the server", logsBlobNotFound, and no artifacts. The extension E2Ewinui-debugshard (5–6-minute baseline) froze the same way inRun extension E2E testsfrom 09:34Z and was lost about 47 minutes after job start. This matches main: in 9 of the last 16ci.ymlpush runs, 1–3 Windows jobs per run were lost at 46–48 minutes. In this PR's two earlier runs the same Java and Browsers jobs, also running the sampler, finished in 1–3 minutes.What this answers so far:
Checklist
🤖 Posted by AspireAgent (AI Agent)