Heartbeat.cs: Replace PowerShell process spawns with .NET APIs on Windows#15888
Draft
Heartbeat.cs: Replace PowerShell process spawns with .NET APIs on Windows#15888
Conversation
…indows - CPU: Use GetSystemTimes P/Invoke (kernel32.dll) instead of Get-CimInstance Win32_Processor - Memory: Use GlobalMemoryStatusEx P/Invoke (kernel32.dll) instead of Get-CimInstance Win32_OperatingSystem - DCP processes: Use Process.GetProcesses() filtered by name instead of PowerShell Get-Process - Top processes: Use Process.GetProcesses() sorted by CPU instead of PowerShell Get-Process - Disk: Use DriveInfo.GetDrives() instead of PowerShell Get-PSDrive - Share single Process.GetProcesses() call per cycle between DCP and Top metrics - Fix FILETIME.ToLong() to cast dwLowDateTime to long before bitwise OR (prevents overflow) - Apply consistent Math.Round to CPU% in GetTopProcesses to match GetDcpProcesses behavior Agent-Logs-Url: https://github.com/microsoft/aspire/sessions/980b8145-b029-436f-938b-b3f6da2078c7 Co-authored-by: radical <1472+radical@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Replace PowerShell process spawns with .NET APIs on Windows
Heartbeat.cs: Replace PowerShell process spawns with .NET APIs on Windows
Apr 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On Windows CI runners, the heartbeat monitor spawned 5 separate
powershell.exeprocesses per cycle — each loading the full PS runtime (~100MB, high CPU on init) — contributing to runner hangs on 2-corewindows-latestagents.Changes
All 5 Windows metric collection paths now use zero-spawn .NET equivalents:
Get-CimInstance Win32_ProcessorGetSystemTimesP/Invoke — idle/kernel/user time deltas (same approach as Linux/proc/stat)Get-CimInstance Win32_OperatingSystemGlobalMemoryStatusExP/Invoke — single syscallGet-Process -Name 'dcp*'Process.GetProcesses()filtered by name prefixGet-Process | Sort-Object CPUProcess.GetProcesses()call, sorted by CPU%Get-PSDrive -PSProvider FileSystemDriveInfo.GetDrives()Key optimizations:
Process.GetProcesses()is called once per cycle and shared between DCP and Top metrics, with process handles disposed after both reads complete.DllImportis used overLibraryImport(the script's auto-generated project doesn't haveAllowUnsafeBlocks); SYSLIB1054 suppressed via#pragma warning disable.FILETIME.ToLong()explicitly casts both fields tolongbefore bitwise OR to prevent sign-extension overflow.Checklist