perf(server): fix N+1 PowerShell process query and reduce sampling frequency - #4829

Closed
UtkarshUsername wants to merge 5 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/perf-resource-monitor-n-plus-1
Closed

perf(server): fix N+1 PowerShell process query and reduce sampling frequency#4829
UtkarshUsername wants to merge 5 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/perf-resource-monitor-n-plus-1

Conversation

@UtkarshUsername

@UtkarshUsernameUtkarshUsername commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What Changed

Eliminated two sources of excessive CPU usage in the Windows process resource monitor:

  1. N+1 PowerShell CIM query to bulk query (ProcessDiagnostics.ts): The Windows process reader was querying Win32_PerfFormattedData_PerfProc_Process individually for each process via an IDProcess filter inside a ForEach-Object loop. Changed to query all perf counter data once into a hashtable, then join with the process list. Reduced from 1+N CIM queries to exactly 2.
  2. Sampling interval 5s to 15s (ProcessResourceMonitor.ts): Tripled the interval between resource samples, reducing overhead 3x while maintaining adequate granularity for multi-second bucket aggregation.

Why

On Windows machines with 200+ processes, ProcessResourceMonitor was spawning powershell.exe every 5 seconds with an N+1 WMI query pattern. Each cycle issued 1+N CIM queries (e.g., 206 queries for 205 processes). The old command consistently timed out after 60 seconds on a typical development machine, pegging CPU indefinitely.

MetricBeforeAfterImprovement
Per-query time>60s (timed out)~2.7s≥22x+
CIM queries per cycle1+N (e.g., 206)2~100x
Sampling interval5s15s3x
Effective overhead100% CPU (never finishes)~18% for 2.7s≥66x

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Low Risk
Diagnostics-only changes on Windows sampling path; behavior is coarser metrics (15s) but lower server CPU load, with no auth or data-path impact.

Overview
Reduces Windows process diagnostics overhead by fixing how PowerShell loads CPU perf data and by sampling less often.

Windows process query:readWindowsProcessRows no longer runs a filtered Win32_PerfFormattedData_PerfProc_Process CIM call inside the per-process loop. It loads all perf rows once into a hashtable keyed by IDProcess, then walks Win32_Process and joins in memory—two CIM queries per cycle instead of 1+N.

Resource monitor:SAMPLE_INTERVAL_MS moves from 5s to 15s, so the background sampler runs three times less often. Approximate CPU-second rollups use the new interval; tests now expect 6 instead of 2 for the same two-sample scenario.

Reviewed by Cursor Bugbot for commit 9d9363e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix N+1 PowerShell process query and increase sampling interval to 15s

  • Rewrites readWindowsProcessRows in ProcessDiagnostics.ts to preload all Win32_PerfFormattedData_PerfProc_Process entries into a hashtable keyed by IDProcess, eliminating a per-process WMI query.
  • Increases SAMPLE_INTERVAL_MS in ProcessResourceMonitor.ts from 5,000 ms to 15,000 ms to reduce polling overhead.
  • Behavioral Change: process CPU metrics are now refreshed every 15s instead of every 5s.

Macroscope summarized 9d9363e.

…agnostics
The readWindowsProcessRows function spawned powershell.exe with an N+1
WMI query pattern: for each process (via Get-CimInstance Win32_Process),
it queried Win32_PerfFormattedData_PerfProc_Process individually using a
-IDProcess filter. On machines with 200+ processes, this created 1+N
CIM queries per sampling cycle.
The old command timed out after 60s on a machine with ~205 processes.
Fix: query all performance counter data once into a hashtable
(IDProcess -> perf object), then join it with the process list in
PowerShell memory. This reduces 1+N queries to exactly 2 queries
regardless of process count.
Measured improvement (~205 processes):
- Old: >60s (timed out)
- New: ~2.7s average per query
- Speedup: ~22x+ per sampling cycle
The ProcessResourceMonitor was sampling process resources every 5
seconds. Combined with the PowerShell CIM query overhead, this caused
excessive CPU usage on Windows.
Increasing to 15s reduces sampling frequency by 3x while still
providing adequate granularity for the resource history visualization
(which aggregates into multi-second buckets).
Test: update cpuSecondsApprox expectation from 2 to 6 to match the new
interval (the calculation is SAMPLE_INTERVAL_MS / 1000 * cpuPercent/100,
so tripling the interval triples the per-sample approximation).
@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 97fb8722-bcb4-4dfc-b5c7-48c11a50685b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Jul 29, 2026
@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved 2db1250

Performance optimization fixing N+1 PowerShell process query and reducing diagnostic sampling frequency from 5s to 15s. Self-contained changes to monitoring code with corresponding test updates.

You can customize Macroscope's approvability policy. Learn more.

@UtkarshUsername
UtkarshUsernameforce-pushed the fix/perf-resource-monitor-n-plus-1 branch from 8713172 to a8e541aCompareJuly 29, 2026 11:23
@UtkarshUsername
UtkarshUsername deleted the fix/perf-resource-monitor-n-plus-1 branch July 29, 2026 14:42
@UtkarshUsername

Copy link
Copy Markdown
ContributorAuthor

Superseded by #2679

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@UtkarshUsername
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

perf(server): fix N+1 PowerShell process query and reduce sampling frequency - #4829

Closed
UtkarshUsername wants to merge 5 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/perf-resource-monitor-n-plus-1
Closed

perf(server): fix N+1 PowerShell process query and reduce sampling frequency#4829
UtkarshUsername wants to merge 5 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/perf-resource-monitor-n-plus-1

Conversation

@UtkarshUsername

@UtkarshUsernameUtkarshUsername commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What Changed

Eliminated two sources of excessive CPU usage in the Windows process resource monitor:

  1. N+1 PowerShell CIM query to bulk query (ProcessDiagnostics.ts): The Windows process reader was querying Win32_PerfFormattedData_PerfProc_Process individually for each process via an IDProcess filter inside a ForEach-Object loop. Changed to query all perf counter data once into a hashtable, then join with the process list. Reduced from 1+N CIM queries to exactly 2.
  2. Sampling interval 5s to 15s (ProcessResourceMonitor.ts): Tripled the interval between resource samples, reducing overhead 3x while maintaining adequate granularity for multi-second bucket aggregation.

Why

On Windows machines with 200+ processes, ProcessResourceMonitor was spawning powershell.exe every 5 seconds with an N+1 WMI query pattern. Each cycle issued 1+N CIM queries (e.g., 206 queries for 205 processes). The old command consistently timed out after 60 seconds on a typical development machine, pegging CPU indefinitely.

MetricBeforeAfterImprovement
Per-query time>60s (timed out)~2.7s≥22x+
CIM queries per cycle1+N (e.g., 206)2~100x
Sampling interval5s15s3x
Effective overhead100% CPU (never finishes)~18% for 2.7s≥66x

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Low Risk
Diagnostics-only changes on Windows sampling path; behavior is coarser metrics (15s) but lower server CPU load, with no auth or data-path impact.

Overview
Reduces Windows process diagnostics overhead by fixing how PowerShell loads CPU perf data and by sampling less often.

Windows process query:readWindowsProcessRows no longer runs a filtered Win32_PerfFormattedData_PerfProc_Process CIM call inside the per-process loop. It loads all perf rows once into a hashtable keyed by IDProcess, then walks Win32_Process and joins in memory—two CIM queries per cycle instead of 1+N.

Resource monitor:SAMPLE_INTERVAL_MS moves from 5s to 15s, so the background sampler runs three times less often. Approximate CPU-second rollups use the new interval; tests now expect 6 instead of 2 for the same two-sample scenario.

Reviewed by Cursor Bugbot for commit 9d9363e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix N+1 PowerShell process query and increase sampling interval to 15s

  • Rewrites readWindowsProcessRows in ProcessDiagnostics.ts to preload all Win32_PerfFormattedData_PerfProc_Process entries into a hashtable keyed by IDProcess, eliminating a per-process WMI query.
  • Increases SAMPLE_INTERVAL_MS in ProcessResourceMonitor.ts from 5,000 ms to 15,000 ms to reduce polling overhead.
  • Behavioral Change: process CPU metrics are now refreshed every 15s instead of every 5s.

Macroscope summarized 9d9363e.

…agnostics
The readWindowsProcessRows function spawned powershell.exe with an N+1
WMI query pattern: for each process (via Get-CimInstance Win32_Process),
it queried Win32_PerfFormattedData_PerfProc_Process individually using a
-IDProcess filter. On machines with 200+ processes, this created 1+N
CIM queries per sampling cycle.
The old command timed out after 60s on a machine with ~205 processes.
Fix: query all performance counter data once into a hashtable
(IDProcess -> perf object), then join it with the process list in
PowerShell memory. This reduces 1+N queries to exactly 2 queries
regardless of process count.
Measured improvement (~205 processes):
- Old: >60s (timed out)
- New: ~2.7s average per query
- Speedup: ~22x+ per sampling cycle
The ProcessResourceMonitor was sampling process resources every 5
seconds. Combined with the PowerShell CIM query overhead, this caused
excessive CPU usage on Windows.
Increasing to 15s reduces sampling frequency by 3x while still
providing adequate granularity for the resource history visualization
(which aggregates into multi-second buckets).
Test: update cpuSecondsApprox expectation from 2 to 6 to match the new
interval (the calculation is SAMPLE_INTERVAL_MS / 1000 * cpuPercent/100,
so tripling the interval triples the per-sample approximation).
@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 97fb8722-bcb4-4dfc-b5c7-48c11a50685b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Jul 29, 2026
@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved 2db1250

Performance optimization fixing N+1 PowerShell process query and reducing diagnostic sampling frequency from 5s to 15s. Self-contained changes to monitoring code with corresponding test updates.

You can customize Macroscope's approvability policy. Learn more.

@UtkarshUsername
UtkarshUsernameforce-pushed the fix/perf-resource-monitor-n-plus-1 branch from 8713172 to a8e541aCompareJuly 29, 2026 11:23
@UtkarshUsername
UtkarshUsername deleted the fix/perf-resource-monitor-n-plus-1 branch July 29, 2026 14:42
@UtkarshUsername

Copy link
Copy Markdown
ContributorAuthor

Superseded by #2679

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@UtkarshUsername
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(server): fix N+1 PowerShell process query and reduce sampling frequency - #4829

Closed
UtkarshUsername wants to merge 5 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/perf-resource-monitor-n-plus-1
Closed

perf(server): fix N+1 PowerShell process query and reduce sampling frequency#4829
UtkarshUsername wants to merge 5 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/perf-resource-monitor-n-plus-1

Conversation

@UtkarshUsername

@UtkarshUsernameUtkarshUsername commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What Changed

Eliminated two sources of excessive CPU usage in the Windows process resource monitor:

  1. N+1 PowerShell CIM query to bulk query (ProcessDiagnostics.ts): The Windows process reader was querying Win32_PerfFormattedData_PerfProc_Process individually for each process via an IDProcess filter inside a ForEach-Object loop. Changed to query all perf counter data once into a hashtable, then join with the process list. Reduced from 1+N CIM queries to exactly 2.
  2. Sampling interval 5s to 15s (ProcessResourceMonitor.ts): Tripled the interval between resource samples, reducing overhead 3x while maintaining adequate granularity for multi-second bucket aggregation.

Why

On Windows machines with 200+ processes, ProcessResourceMonitor was spawning powershell.exe every 5 seconds with an N+1 WMI query pattern. Each cycle issued 1+N CIM queries (e.g., 206 queries for 205 processes). The old command consistently timed out after 60 seconds on a typical development machine, pegging CPU indefinitely.

MetricBeforeAfterImprovement
Per-query time>60s (timed out)~2.7s≥22x+
CIM queries per cycle1+N (e.g., 206)2~100x
Sampling interval5s15s3x
Effective overhead100% CPU (never finishes)~18% for 2.7s≥66x

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Low Risk
Diagnostics-only changes on Windows sampling path; behavior is coarser metrics (15s) but lower server CPU load, with no auth or data-path impact.

Overview
Reduces Windows process diagnostics overhead by fixing how PowerShell loads CPU perf data and by sampling less often.

Windows process query:readWindowsProcessRows no longer runs a filtered Win32_PerfFormattedData_PerfProc_Process CIM call inside the per-process loop. It loads all perf rows once into a hashtable keyed by IDProcess, then walks Win32_Process and joins in memory—two CIM queries per cycle instead of 1+N.

Resource monitor:SAMPLE_INTERVAL_MS moves from 5s to 15s, so the background sampler runs three times less often. Approximate CPU-second rollups use the new interval; tests now expect 6 instead of 2 for the same two-sample scenario.

Reviewed by Cursor Bugbot for commit 9d9363e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix N+1 PowerShell process query and increase sampling interval to 15s

  • Rewrites readWindowsProcessRows in ProcessDiagnostics.ts to preload all Win32_PerfFormattedData_PerfProc_Process entries into a hashtable keyed by IDProcess, eliminating a per-process WMI query.
  • Increases SAMPLE_INTERVAL_MS in ProcessResourceMonitor.ts from 5,000 ms to 15,000 ms to reduce polling overhead.
  • Behavioral Change: process CPU metrics are now refreshed every 15s instead of every 5s.

Macroscope summarized 9d9363e.

…agnostics
The readWindowsProcessRows function spawned powershell.exe with an N+1
WMI query pattern: for each process (via Get-CimInstance Win32_Process),
it queried Win32_PerfFormattedData_PerfProc_Process individually using a
-IDProcess filter. On machines with 200+ processes, this created 1+N
CIM queries per sampling cycle.
The old command timed out after 60s on a machine with ~205 processes.
Fix: query all performance counter data once into a hashtable
(IDProcess -> perf object), then join it with the process list in
PowerShell memory. This reduces 1+N queries to exactly 2 queries
regardless of process count.
Measured improvement (~205 processes):
- Old: >60s (timed out)
- New: ~2.7s average per query
- Speedup: ~22x+ per sampling cycle
The ProcessResourceMonitor was sampling process resources every 5
seconds. Combined with the PowerShell CIM query overhead, this caused
excessive CPU usage on Windows.
Increasing to 15s reduces sampling frequency by 3x while still
providing adequate granularity for the resource history visualization
(which aggregates into multi-second buckets).
Test: update cpuSecondsApprox expectation from 2 to 6 to match the new
interval (the calculation is SAMPLE_INTERVAL_MS / 1000 * cpuPercent/100,
so tripling the interval triples the per-sample approximation).
@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 97fb8722-bcb4-4dfc-b5c7-48c11a50685b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Jul 29, 2026
@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved 2db1250

Performance optimization fixing N+1 PowerShell process query and reducing diagnostic sampling frequency from 5s to 15s. Self-contained changes to monitoring code with corresponding test updates.

You can customize Macroscope's approvability policy. Learn more.

@UtkarshUsername
UtkarshUsernameforce-pushed the fix/perf-resource-monitor-n-plus-1 branch from 8713172 to a8e541aCompareJuly 29, 2026 11:23
@UtkarshUsername
UtkarshUsername deleted the fix/perf-resource-monitor-n-plus-1 branch July 29, 2026 14:42
@UtkarshUsername

Copy link
Copy Markdown
ContributorAuthor

Superseded by #2679

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@UtkarshUsername
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(server): fix N+1 PowerShell process query and reduce sampling frequency - #4829

Closed
UtkarshUsername wants to merge 5 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/perf-resource-monitor-n-plus-1
Closed

perf(server): fix N+1 PowerShell process query and reduce sampling frequency#4829
UtkarshUsername wants to merge 5 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/perf-resource-monitor-n-plus-1

Conversation

@UtkarshUsername

@UtkarshUsernameUtkarshUsername commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What Changed

Eliminated two sources of excessive CPU usage in the Windows process resource monitor:

  1. N+1 PowerShell CIM query to bulk query (ProcessDiagnostics.ts): The Windows process reader was querying Win32_PerfFormattedData_PerfProc_Process individually for each process via an IDProcess filter inside a ForEach-Object loop. Changed to query all perf counter data once into a hashtable, then join with the process list. Reduced from 1+N CIM queries to exactly 2.
  2. Sampling interval 5s to 15s (ProcessResourceMonitor.ts): Tripled the interval between resource samples, reducing overhead 3x while maintaining adequate granularity for multi-second bucket aggregation.

Why

On Windows machines with 200+ processes, ProcessResourceMonitor was spawning powershell.exe every 5 seconds with an N+1 WMI query pattern. Each cycle issued 1+N CIM queries (e.g., 206 queries for 205 processes). The old command consistently timed out after 60 seconds on a typical development machine, pegging CPU indefinitely.

MetricBeforeAfterImprovement
Per-query time>60s (timed out)~2.7s≥22x+
CIM queries per cycle1+N (e.g., 206)2~100x
Sampling interval5s15s3x
Effective overhead100% CPU (never finishes)~18% for 2.7s≥66x

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Low Risk
Diagnostics-only changes on Windows sampling path; behavior is coarser metrics (15s) but lower server CPU load, with no auth or data-path impact.

Overview
Reduces Windows process diagnostics overhead by fixing how PowerShell loads CPU perf data and by sampling less often.

Windows process query:readWindowsProcessRows no longer runs a filtered Win32_PerfFormattedData_PerfProc_Process CIM call inside the per-process loop. It loads all perf rows once into a hashtable keyed by IDProcess, then walks Win32_Process and joins in memory—two CIM queries per cycle instead of 1+N.

Resource monitor:SAMPLE_INTERVAL_MS moves from 5s to 15s, so the background sampler runs three times less often. Approximate CPU-second rollups use the new interval; tests now expect 6 instead of 2 for the same two-sample scenario.

Reviewed by Cursor Bugbot for commit 9d9363e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix N+1 PowerShell process query and increase sampling interval to 15s

  • Rewrites readWindowsProcessRows in ProcessDiagnostics.ts to preload all Win32_PerfFormattedData_PerfProc_Process entries into a hashtable keyed by IDProcess, eliminating a per-process WMI query.
  • Increases SAMPLE_INTERVAL_MS in ProcessResourceMonitor.ts from 5,000 ms to 15,000 ms to reduce polling overhead.
  • Behavioral Change: process CPU metrics are now refreshed every 15s instead of every 5s.

Macroscope summarized 9d9363e.

…agnostics
The readWindowsProcessRows function spawned powershell.exe with an N+1
WMI query pattern: for each process (via Get-CimInstance Win32_Process),
it queried Win32_PerfFormattedData_PerfProc_Process individually using a
-IDProcess filter. On machines with 200+ processes, this created 1+N
CIM queries per sampling cycle.
The old command timed out after 60s on a machine with ~205 processes.
Fix: query all performance counter data once into a hashtable
(IDProcess -> perf object), then join it with the process list in
PowerShell memory. This reduces 1+N queries to exactly 2 queries
regardless of process count.
Measured improvement (~205 processes):
- Old: >60s (timed out)
- New: ~2.7s average per query
- Speedup: ~22x+ per sampling cycle
The ProcessResourceMonitor was sampling process resources every 5
seconds. Combined with the PowerShell CIM query overhead, this caused
excessive CPU usage on Windows.
Increasing to 15s reduces sampling frequency by 3x while still
providing adequate granularity for the resource history visualization
(which aggregates into multi-second buckets).
Test: update cpuSecondsApprox expectation from 2 to 6 to match the new
interval (the calculation is SAMPLE_INTERVAL_MS / 1000 * cpuPercent/100,
so tripling the interval triples the per-sample approximation).
@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 97fb8722-bcb4-4dfc-b5c7-48c11a50685b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Jul 29, 2026
@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved 2db1250

Performance optimization fixing N+1 PowerShell process query and reducing diagnostic sampling frequency from 5s to 15s. Self-contained changes to monitoring code with corresponding test updates.

You can customize Macroscope's approvability policy. Learn more.

@UtkarshUsername
UtkarshUsernameforce-pushed the fix/perf-resource-monitor-n-plus-1 branch from 8713172 to a8e541aCompareJuly 29, 2026 11:23
@UtkarshUsername
UtkarshUsername deleted the fix/perf-resource-monitor-n-plus-1 branch July 29, 2026 14:42
@UtkarshUsername

Copy link
Copy Markdown
ContributorAuthor

Superseded by #2679

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@UtkarshUsername
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

perf(server): fix N+1 PowerShell process query and reduce sampling frequency - #4829

Closed
UtkarshUsername wants to merge 5 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/perf-resource-monitor-n-plus-1
Closed

perf(server): fix N+1 PowerShell process query and reduce sampling frequency#4829
UtkarshUsername wants to merge 5 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/perf-resource-monitor-n-plus-1

Conversation

@UtkarshUsername

@UtkarshUsernameUtkarshUsername commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What Changed

Eliminated two sources of excessive CPU usage in the Windows process resource monitor:

  1. N+1 PowerShell CIM query to bulk query (ProcessDiagnostics.ts): The Windows process reader was querying Win32_PerfFormattedData_PerfProc_Process individually for each process via an IDProcess filter inside a ForEach-Object loop. Changed to query all perf counter data once into a hashtable, then join with the process list. Reduced from 1+N CIM queries to exactly 2.
  2. Sampling interval 5s to 15s (ProcessResourceMonitor.ts): Tripled the interval between resource samples, reducing overhead 3x while maintaining adequate granularity for multi-second bucket aggregation.

Why

On Windows machines with 200+ processes, ProcessResourceMonitor was spawning powershell.exe every 5 seconds with an N+1 WMI query pattern. Each cycle issued 1+N CIM queries (e.g., 206 queries for 205 processes). The old command consistently timed out after 60 seconds on a typical development machine, pegging CPU indefinitely.

MetricBeforeAfterImprovement
Per-query time>60s (timed out)~2.7s≥22x+
CIM queries per cycle1+N (e.g., 206)2~100x
Sampling interval5s15s3x
Effective overhead100% CPU (never finishes)~18% for 2.7s≥66x

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Low Risk
Diagnostics-only changes on Windows sampling path; behavior is coarser metrics (15s) but lower server CPU load, with no auth or data-path impact.

Overview
Reduces Windows process diagnostics overhead by fixing how PowerShell loads CPU perf data and by sampling less often.

Windows process query:readWindowsProcessRows no longer runs a filtered Win32_PerfFormattedData_PerfProc_Process CIM call inside the per-process loop. It loads all perf rows once into a hashtable keyed by IDProcess, then walks Win32_Process and joins in memory—two CIM queries per cycle instead of 1+N.

Resource monitor:SAMPLE_INTERVAL_MS moves from 5s to 15s, so the background sampler runs three times less often. Approximate CPU-second rollups use the new interval; tests now expect 6 instead of 2 for the same two-sample scenario.

Reviewed by Cursor Bugbot for commit 9d9363e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix N+1 PowerShell process query and increase sampling interval to 15s

  • Rewrites readWindowsProcessRows in ProcessDiagnostics.ts to preload all Win32_PerfFormattedData_PerfProc_Process entries into a hashtable keyed by IDProcess, eliminating a per-process WMI query.
  • Increases SAMPLE_INTERVAL_MS in ProcessResourceMonitor.ts from 5,000 ms to 15,000 ms to reduce polling overhead.
  • Behavioral Change: process CPU metrics are now refreshed every 15s instead of every 5s.

Macroscope summarized 9d9363e.

…agnostics
The readWindowsProcessRows function spawned powershell.exe with an N+1
WMI query pattern: for each process (via Get-CimInstance Win32_Process),
it queried Win32_PerfFormattedData_PerfProc_Process individually using a
-IDProcess filter. On machines with 200+ processes, this created 1+N
CIM queries per sampling cycle.
The old command timed out after 60s on a machine with ~205 processes.
Fix: query all performance counter data once into a hashtable
(IDProcess -> perf object), then join it with the process list in
PowerShell memory. This reduces 1+N queries to exactly 2 queries
regardless of process count.
Measured improvement (~205 processes):
- Old: >60s (timed out)
- New: ~2.7s average per query
- Speedup: ~22x+ per sampling cycle
The ProcessResourceMonitor was sampling process resources every 5
seconds. Combined with the PowerShell CIM query overhead, this caused
excessive CPU usage on Windows.
Increasing to 15s reduces sampling frequency by 3x while still
providing adequate granularity for the resource history visualization
(which aggregates into multi-second buckets).
Test: update cpuSecondsApprox expectation from 2 to 6 to match the new
interval (the calculation is SAMPLE_INTERVAL_MS / 1000 * cpuPercent/100,
so tripling the interval triples the per-sample approximation).
@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 97fb8722-bcb4-4dfc-b5c7-48c11a50685b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Jul 29, 2026
@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved 2db1250

Performance optimization fixing N+1 PowerShell process query and reducing diagnostic sampling frequency from 5s to 15s. Self-contained changes to monitoring code with corresponding test updates.

You can customize Macroscope's approvability policy. Learn more.

@UtkarshUsername
UtkarshUsernameforce-pushed the fix/perf-resource-monitor-n-plus-1 branch from 8713172 to a8e541aCompareJuly 29, 2026 11:23
@UtkarshUsername
UtkarshUsername deleted the fix/perf-resource-monitor-n-plus-1 branch July 29, 2026 14:42
@UtkarshUsername

Copy link
Copy Markdown
ContributorAuthor

Superseded by #2679

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@UtkarshUsername
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(server): fix N+1 PowerShell process query and reduce sampling frequency - #4829

Closed
UtkarshUsername wants to merge 5 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/perf-resource-monitor-n-plus-1
Closed

perf(server): fix N+1 PowerShell process query and reduce sampling frequency#4829
UtkarshUsername wants to merge 5 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/perf-resource-monitor-n-plus-1

Conversation

@UtkarshUsername

@UtkarshUsernameUtkarshUsername commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What Changed

Eliminated two sources of excessive CPU usage in the Windows process resource monitor:

  1. N+1 PowerShell CIM query to bulk query (ProcessDiagnostics.ts): The Windows process reader was querying Win32_PerfFormattedData_PerfProc_Process individually for each process via an IDProcess filter inside a ForEach-Object loop. Changed to query all perf counter data once into a hashtable, then join with the process list. Reduced from 1+N CIM queries to exactly 2.
  2. Sampling interval 5s to 15s (ProcessResourceMonitor.ts): Tripled the interval between resource samples, reducing overhead 3x while maintaining adequate granularity for multi-second bucket aggregation.

Why

On Windows machines with 200+ processes, ProcessResourceMonitor was spawning powershell.exe every 5 seconds with an N+1 WMI query pattern. Each cycle issued 1+N CIM queries (e.g., 206 queries for 205 processes). The old command consistently timed out after 60 seconds on a typical development machine, pegging CPU indefinitely.

MetricBeforeAfterImprovement
Per-query time>60s (timed out)~2.7s≥22x+
CIM queries per cycle1+N (e.g., 206)2~100x
Sampling interval5s15s3x
Effective overhead100% CPU (never finishes)~18% for 2.7s≥66x

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Low Risk
Diagnostics-only changes on Windows sampling path; behavior is coarser metrics (15s) but lower server CPU load, with no auth or data-path impact.

Overview
Reduces Windows process diagnostics overhead by fixing how PowerShell loads CPU perf data and by sampling less often.

Windows process query:readWindowsProcessRows no longer runs a filtered Win32_PerfFormattedData_PerfProc_Process CIM call inside the per-process loop. It loads all perf rows once into a hashtable keyed by IDProcess, then walks Win32_Process and joins in memory—two CIM queries per cycle instead of 1+N.

Resource monitor:SAMPLE_INTERVAL_MS moves from 5s to 15s, so the background sampler runs three times less often. Approximate CPU-second rollups use the new interval; tests now expect 6 instead of 2 for the same two-sample scenario.

Reviewed by Cursor Bugbot for commit 9d9363e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix N+1 PowerShell process query and increase sampling interval to 15s

  • Rewrites readWindowsProcessRows in ProcessDiagnostics.ts to preload all Win32_PerfFormattedData_PerfProc_Process entries into a hashtable keyed by IDProcess, eliminating a per-process WMI query.
  • Increases SAMPLE_INTERVAL_MS in ProcessResourceMonitor.ts from 5,000 ms to 15,000 ms to reduce polling overhead.
  • Behavioral Change: process CPU metrics are now refreshed every 15s instead of every 5s.

Macroscope summarized 9d9363e.

…agnostics
The readWindowsProcessRows function spawned powershell.exe with an N+1
WMI query pattern: for each process (via Get-CimInstance Win32_Process),
it queried Win32_PerfFormattedData_PerfProc_Process individually using a
-IDProcess filter. On machines with 200+ processes, this created 1+N
CIM queries per sampling cycle.
The old command timed out after 60s on a machine with ~205 processes.
Fix: query all performance counter data once into a hashtable
(IDProcess -> perf object), then join it with the process list in
PowerShell memory. This reduces 1+N queries to exactly 2 queries
regardless of process count.
Measured improvement (~205 processes):
- Old: >60s (timed out)
- New: ~2.7s average per query
- Speedup: ~22x+ per sampling cycle
The ProcessResourceMonitor was sampling process resources every 5
seconds. Combined with the PowerShell CIM query overhead, this caused
excessive CPU usage on Windows.
Increasing to 15s reduces sampling frequency by 3x while still
providing adequate granularity for the resource history visualization
(which aggregates into multi-second buckets).
Test: update cpuSecondsApprox expectation from 2 to 6 to match the new
interval (the calculation is SAMPLE_INTERVAL_MS / 1000 * cpuPercent/100,
so tripling the interval triples the per-sample approximation).
@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 97fb8722-bcb4-4dfc-b5c7-48c11a50685b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Jul 29, 2026
@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved 2db1250

Performance optimization fixing N+1 PowerShell process query and reducing diagnostic sampling frequency from 5s to 15s. Self-contained changes to monitoring code with corresponding test updates.

You can customize Macroscope's approvability policy. Learn more.

@UtkarshUsername
UtkarshUsernameforce-pushed the fix/perf-resource-monitor-n-plus-1 branch from 8713172 to a8e541aCompareJuly 29, 2026 11:23
@UtkarshUsername
UtkarshUsername deleted the fix/perf-resource-monitor-n-plus-1 branch July 29, 2026 14:42
@UtkarshUsername

Copy link
Copy Markdown
ContributorAuthor

Superseded by #2679

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@UtkarshUsername
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

perf(server): fix N+1 PowerShell process query and reduce sampling frequency - #4829

Closed
UtkarshUsername wants to merge 5 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/perf-resource-monitor-n-plus-1
Closed

perf(server): fix N+1 PowerShell process query and reduce sampling frequency#4829
UtkarshUsername wants to merge 5 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/perf-resource-monitor-n-plus-1

Conversation

@UtkarshUsername

@UtkarshUsernameUtkarshUsername commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What Changed

Eliminated two sources of excessive CPU usage in the Windows process resource monitor:

  1. N+1 PowerShell CIM query to bulk query (ProcessDiagnostics.ts): The Windows process reader was querying Win32_PerfFormattedData_PerfProc_Process individually for each process via an IDProcess filter inside a ForEach-Object loop. Changed to query all perf counter data once into a hashtable, then join with the process list. Reduced from 1+N CIM queries to exactly 2.
  2. Sampling interval 5s to 15s (ProcessResourceMonitor.ts): Tripled the interval between resource samples, reducing overhead 3x while maintaining adequate granularity for multi-second bucket aggregation.

Why

On Windows machines with 200+ processes, ProcessResourceMonitor was spawning powershell.exe every 5 seconds with an N+1 WMI query pattern. Each cycle issued 1+N CIM queries (e.g., 206 queries for 205 processes). The old command consistently timed out after 60 seconds on a typical development machine, pegging CPU indefinitely.

MetricBeforeAfterImprovement
Per-query time>60s (timed out)~2.7s≥22x+
CIM queries per cycle1+N (e.g., 206)2~100x
Sampling interval5s15s3x
Effective overhead100% CPU (never finishes)~18% for 2.7s≥66x

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Low Risk
Diagnostics-only changes on Windows sampling path; behavior is coarser metrics (15s) but lower server CPU load, with no auth or data-path impact.

Overview
Reduces Windows process diagnostics overhead by fixing how PowerShell loads CPU perf data and by sampling less often.

Windows process query:readWindowsProcessRows no longer runs a filtered Win32_PerfFormattedData_PerfProc_Process CIM call inside the per-process loop. It loads all perf rows once into a hashtable keyed by IDProcess, then walks Win32_Process and joins in memory—two CIM queries per cycle instead of 1+N.

Resource monitor:SAMPLE_INTERVAL_MS moves from 5s to 15s, so the background sampler runs three times less often. Approximate CPU-second rollups use the new interval; tests now expect 6 instead of 2 for the same two-sample scenario.

Reviewed by Cursor Bugbot for commit 9d9363e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix N+1 PowerShell process query and increase sampling interval to 15s

  • Rewrites readWindowsProcessRows in ProcessDiagnostics.ts to preload all Win32_PerfFormattedData_PerfProc_Process entries into a hashtable keyed by IDProcess, eliminating a per-process WMI query.
  • Increases SAMPLE_INTERVAL_MS in ProcessResourceMonitor.ts from 5,000 ms to 15,000 ms to reduce polling overhead.
  • Behavioral Change: process CPU metrics are now refreshed every 15s instead of every 5s.

Macroscope summarized 9d9363e.

…agnostics
The readWindowsProcessRows function spawned powershell.exe with an N+1
WMI query pattern: for each process (via Get-CimInstance Win32_Process),
it queried Win32_PerfFormattedData_PerfProc_Process individually using a
-IDProcess filter. On machines with 200+ processes, this created 1+N
CIM queries per sampling cycle.
The old command timed out after 60s on a machine with ~205 processes.
Fix: query all performance counter data once into a hashtable
(IDProcess -> perf object), then join it with the process list in
PowerShell memory. This reduces 1+N queries to exactly 2 queries
regardless of process count.
Measured improvement (~205 processes):
- Old: >60s (timed out)
- New: ~2.7s average per query
- Speedup: ~22x+ per sampling cycle
The ProcessResourceMonitor was sampling process resources every 5
seconds. Combined with the PowerShell CIM query overhead, this caused
excessive CPU usage on Windows.
Increasing to 15s reduces sampling frequency by 3x while still
providing adequate granularity for the resource history visualization
(which aggregates into multi-second buckets).
Test: update cpuSecondsApprox expectation from 2 to 6 to match the new
interval (the calculation is SAMPLE_INTERVAL_MS / 1000 * cpuPercent/100,
so tripling the interval triples the per-sample approximation).
@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 97fb8722-bcb4-4dfc-b5c7-48c11a50685b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Jul 29, 2026
@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved 2db1250

Performance optimization fixing N+1 PowerShell process query and reducing diagnostic sampling frequency from 5s to 15s. Self-contained changes to monitoring code with corresponding test updates.

You can customize Macroscope's approvability policy. Learn more.

@UtkarshUsername
UtkarshUsernameforce-pushed the fix/perf-resource-monitor-n-plus-1 branch from 8713172 to a8e541aCompareJuly 29, 2026 11:23
@UtkarshUsername
UtkarshUsername deleted the fix/perf-resource-monitor-n-plus-1 branch July 29, 2026 14:42
@UtkarshUsername

Copy link
Copy Markdown
ContributorAuthor

Superseded by #2679

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@UtkarshUsername
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

perf(server): fix N+1 PowerShell process query and reduce sampling frequency - #4829

Closed
UtkarshUsername wants to merge 5 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/perf-resource-monitor-n-plus-1
Closed

perf(server): fix N+1 PowerShell process query and reduce sampling frequency#4829
UtkarshUsername wants to merge 5 commits into
pingdotgg:mainfrom
UtkarshUsername:fix/perf-resource-monitor-n-plus-1

Conversation

@UtkarshUsername

@UtkarshUsernameUtkarshUsername commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

What Changed

Eliminated two sources of excessive CPU usage in the Windows process resource monitor:

  1. N+1 PowerShell CIM query to bulk query (ProcessDiagnostics.ts): The Windows process reader was querying Win32_PerfFormattedData_PerfProc_Process individually for each process via an IDProcess filter inside a ForEach-Object loop. Changed to query all perf counter data once into a hashtable, then join with the process list. Reduced from 1+N CIM queries to exactly 2.
  2. Sampling interval 5s to 15s (ProcessResourceMonitor.ts): Tripled the interval between resource samples, reducing overhead 3x while maintaining adequate granularity for multi-second bucket aggregation.

Why

On Windows machines with 200+ processes, ProcessResourceMonitor was spawning powershell.exe every 5 seconds with an N+1 WMI query pattern. Each cycle issued 1+N CIM queries (e.g., 206 queries for 205 processes). The old command consistently timed out after 60 seconds on a typical development machine, pegging CPU indefinitely.

MetricBeforeAfterImprovement
Per-query time>60s (timed out)~2.7s≥22x+
CIM queries per cycle1+N (e.g., 206)2~100x
Sampling interval5s15s3x
Effective overhead100% CPU (never finishes)~18% for 2.7s≥66x

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Low Risk
Diagnostics-only changes on Windows sampling path; behavior is coarser metrics (15s) but lower server CPU load, with no auth or data-path impact.

Overview
Reduces Windows process diagnostics overhead by fixing how PowerShell loads CPU perf data and by sampling less often.

Windows process query:readWindowsProcessRows no longer runs a filtered Win32_PerfFormattedData_PerfProc_Process CIM call inside the per-process loop. It loads all perf rows once into a hashtable keyed by IDProcess, then walks Win32_Process and joins in memory—two CIM queries per cycle instead of 1+N.

Resource monitor:SAMPLE_INTERVAL_MS moves from 5s to 15s, so the background sampler runs three times less often. Approximate CPU-second rollups use the new interval; tests now expect 6 instead of 2 for the same two-sample scenario.

Reviewed by Cursor Bugbot for commit 9d9363e. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix N+1 PowerShell process query and increase sampling interval to 15s

  • Rewrites readWindowsProcessRows in ProcessDiagnostics.ts to preload all Win32_PerfFormattedData_PerfProc_Process entries into a hashtable keyed by IDProcess, eliminating a per-process WMI query.
  • Increases SAMPLE_INTERVAL_MS in ProcessResourceMonitor.ts from 5,000 ms to 15,000 ms to reduce polling overhead.
  • Behavioral Change: process CPU metrics are now refreshed every 15s instead of every 5s.

Macroscope summarized 9d9363e.

…agnostics
The readWindowsProcessRows function spawned powershell.exe with an N+1
WMI query pattern: for each process (via Get-CimInstance Win32_Process),
it queried Win32_PerfFormattedData_PerfProc_Process individually using a
-IDProcess filter. On machines with 200+ processes, this created 1+N
CIM queries per sampling cycle.
The old command timed out after 60s on a machine with ~205 processes.
Fix: query all performance counter data once into a hashtable
(IDProcess -> perf object), then join it with the process list in
PowerShell memory. This reduces 1+N queries to exactly 2 queries
regardless of process count.
Measured improvement (~205 processes):
- Old: >60s (timed out)
- New: ~2.7s average per query
- Speedup: ~22x+ per sampling cycle
The ProcessResourceMonitor was sampling process resources every 5
seconds. Combined with the PowerShell CIM query overhead, this caused
excessive CPU usage on Windows.
Increasing to 15s reduces sampling frequency by 3x while still
providing adequate granularity for the resource history visualization
(which aggregates into multi-second buckets).
Test: update cpuSecondsApprox expectation from 2 to 6 to match the new
interval (the calculation is SAMPLE_INTERVAL_MS / 1000 * cpuPercent/100,
so tripling the interval triples the per-sample approximation).
@coderabbitai

coderabbitaiBot commented Jul 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 97fb8722-bcb4-4dfc-b5c7-48c11a50685b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot added size:S 10-29 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels Jul 29, 2026
@macroscopeapp

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved 2db1250

Performance optimization fixing N+1 PowerShell process query and reducing diagnostic sampling frequency from 5s to 15s. Self-contained changes to monitoring code with corresponding test updates.

You can customize Macroscope's approvability policy. Learn more.

@UtkarshUsername
UtkarshUsernameforce-pushed the fix/perf-resource-monitor-n-plus-1 branch from 8713172 to a8e541aCompareJuly 29, 2026 11:23
@UtkarshUsername
UtkarshUsername deleted the fix/perf-resource-monitor-n-plus-1 branch July 29, 2026 14:42
@UtkarshUsername

Copy link
Copy Markdown
ContributorAuthor

Superseded by #2679

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:S10-29 changed lines (additions + deletions).vouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@UtkarshUsername