Skip to content

Revert "Improve cross-platform node discovery for reuse with NodeMode filtering"#13313

Closed
JanProvaznik wants to merge 1 commit intomainfrom
revert-13256-copilot/improve-node-discovery-for-msbuild
Closed

Revert "Improve cross-platform node discovery for reuse with NodeMode filtering"#13313
JanProvaznik wants to merge 1 commit intomainfrom
revert-13256-copilot/improve-node-discovery-for-msbuild

Conversation

@JanProvaznik
Copy link
Copy Markdown
Member

@JanProvaznik JanProvaznik commented Mar 2, 2026

Reverts #13256

Causes VS perf regression in loaded DLL count scenarios.

Copilot analysis:

Root Cause: WMI COM Interop for Process Command Line Retrieval

Commit c48fb46ac1 ("Improve cross-platform node discovery for reuse with NodeMode filtering") introduces direct WMI
COM interop in ProcessExtensions.Windows.GetCommandLine() to retrieve process command lines on Windows. This is the
chain:

Call Path

 1. NodeProviderOutOfProcBase → when nodeReuseRequested is true and ChangeWaves.Wave18_5 is enabled,
GetPossibleRunningNodes() now iterates candidate processes and calls:
 2. process.TryGetCommandLine() → on Windows, delegates to Windows.GetCommandLine(process.Id) which:
 3. Creates WMI COM objects via raw P/Invoke:
  - CoCreateInstance(CLSID_WbemLocator, ...) — instantiates the WMI locator
  - IWbemLocator.ConnectServer("ROOT\CIMV2", ...) — connects to WMI namespace
  - IWbemServices.ExecQuery("WQL", "SELECT CommandLine FROM Win32_Process WHERE ProcessId='...'") — queries process
info

Why Each DLL Gets Loaded

┌──────────────┬────────────────────────────────────────────────────────────────────────────────────────────────────
──────────────────────────────────────────────────────────────────────────┐
│ DLL          │ Reason
                                                                          │
├──────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────
──────────────────────────────────────────────────────────────────────────┤
│ wbemcomn.dll │ WMI common infrastructure library — loaded when CoCreateInstance creates WbemLocator
                                                                          │
├──────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────
──────────────────────────────────────────────────────────────────────────┤
│ wbemprox.dll │ WMI proxy — routes the ConnectServer("ROOT\CIMV2") call
                                                                          │
├──────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────
──────────────────────────────────────────────────────────────────────────┤
│ wbemsvc.dll  │ WMI service support — backs the IWbemServices interface
                                                                          │
├──────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────
──────────────────────────────────────────────────────────────────────────┤
│ fastprox.dll │ WMI fast proxy — provides the COM proxy stubs for IEnumWbemClassObject/IWbemClassObject enumeration
                                                                          │
├──────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────
──────────────────────────────────────────────────────────────────────────┤
│ amsi.dll     │ Antimalware Scan Interface — Windows automatically loads this to scan WQL query strings executed
through WMI COM for malicious content (a Windows Defender security feature) │
└──────────────┴────────────────────────────────────────────────────────────────────────────────────────────────────
──────────────────────────────────────────────────────────────────────────┘
Summary

Before this commit, node discovery only called Process.GetProcessesByName(). After it, every candidate process
triggers a full WMI COM round-trip to read its command line for NodeMode filtering. This pulls the entire WMI stack
+ AMSI into the process address space. During VS tests where node reuse is enabled, this happens for every MSBuild
node provider initialization.

Copilot AI review requested due to automatic review settings March 2, 2026 11:38
@JanProvaznik
Copy link
Copy Markdown
Member Author

JanProvaznik commented Mar 2, 2026

confirmed also by RPS trace analyzer

combase.dll!CoCreateInstanceEx
wbemprox.dll!
wbemprox.dll!
wbemprox.dll!
wbemprox.dll!
microsoft.build.dll!DomainBoundILStubClass.IL_STUB_CLRtoCOM
microsoft.build.dll!Microsoft.Build.Shared.ProcessExtensions+Windows.GetCommandLine
microsoft.build.dll!Microsoft.Build.Shared.ProcessExtensions.TryGetCommandLine
microsoft.build.dll!Microsoft.Build.BackEnd.NodeProviderOutOfProcBase.GetPossibleRunningNodes
microsoft.build.dll!Microsoft.Build.BackEnd.NodeProviderOutOfProcBase.GetNodes

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

This PR reverts PR #13256 ("Improve cross-platform node discovery for reuse with NodeMode filtering") because it caused a Visual Studio performance regression by loading WMI-related DLLs (wbemcomn.dll, wbemprox.dll, wbemsvc.dll, fastprox.dll, amsi.dll) on every MSBuild node provider initialization when node reuse was enabled.

Changes:

  • Removes the WMI COM interop–based TryGetCommandLine / Windows.GetCommandLine implementation and related platform-specific (Linux /proc, macOS/BSD sysctl) command line retrieval code from ProcessExtensions.cs
  • Removes NodeMode-based process filtering from GetPossibleRunningNodes in NodeProviderOutOfProcBase.cs and the ExtractFromCommandLine helper from NodeModeHelper, replacing it with a simpler inline regex in DebugUtils.cs
  • Removes associated tests and cleans up AllowUnsafeBlocks, partial class modifiers, and [SupportedOSPlatformGuard] attributes that were no longer necessary

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/Shared/ProcessExtensions.cs Removes all WMI/Linux/macOS command-line retrieval logic; restores to KillTree-only class
src/Build/BackEnd/Components/Communications/NodeProviderOutOfProcBase.cs Removes NodeMode-based process filtering from GetPossibleRunningNodes; reverts to plain process-name lookup
src/Framework/NodeMode.cs Removes ExtractFromCommandLine, ReadOnlySpan<char> overload, and partial keyword from NodeModeHelper
src/Shared/Debugging/DebugUtils.cs Inlines a new ScanNodeMode local function to replace the removed NodeModeHelper.ExtractFromCommandLine
src/Framework/NativeMethods.cs Removes [SupportedOSPlatformGuard] attributes from IsBSD and IsOSX (no longer needed without platform-specific dispatch)
src/Utilities.UnitTests/ProcessExtensions_Tests.cs Removes TryGetCommandLine-related tests; keeps KillTree test
src/MSBuild.UnitTests/Microsoft.Build.CommandLine.UnitTests.csproj Removes AllowUnsafeBlocks (no longer needed)
src/Tasks.UnitTests/Microsoft.Build.Tasks.UnitTests.csproj Adds ProcessExtensions.cs compile include (re-adding shared file reference)
src/Framework.UnitTests/Microsoft.Build.Framework.UnitTests.csproj Adds ProcessExtensions.cs compile include
src/Build.OM.UnitTests/Microsoft.Build.Engine.OM.UnitTests.csproj Adds ProcessExtensions.cs compile include

Comment thread src/Shared/ProcessExtensions.cs
@JanProvaznik JanProvaznik enabled auto-merge (squash) March 2, 2026 11:46
@JanProvaznik JanProvaznik disabled auto-merge March 2, 2026 12:43
@baronfel
Copy link
Copy Markdown
Member

baronfel commented Mar 2, 2026

@JanProvaznik per internal chat we'd like to instead of reverting simply ifdef the change so that it only appears in core msbuild for now.

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.

3 participants