-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Description
Issue Description
MSBuild detects the wrong processor count on Windows when debugging processor groups and the bug was introduced with PR: #5625
Analysis
The comments in PR 5625 mentioned various ongoing issues testing processor group support on Windows due to the lack of hardware:
I don't have a machine with > 32 cores to actually test this.
I'm trying to pull some strings internally to borrow a machine big enough to test it on
The lack of hardware should never have been an issue. Windows has special boot parameters to enable virtual processor groups specially designed for developers to write and debug processor group support on Windows without requiring physical hardware with >64 processors. 😋
The MSDN documentation is aimed at driver developers however the same steps are required for testing and debugging usermode applications: https://docs.microsoft.com/en-us/windows-hardware/drivers/devtest/boot-parameters-to-test-drivers-for-multiple-processor-group-support
For example:
bcdedit.exe /set groupsize 2
If you have 16 processors this will create 8 processor groups with 2 processors in each group and simulate a machine with > 64 processors. Usermode functions such as GetSystemInfo (and the .NET framework which is not group aware) will now only report 2 processors and this includes MSBuild because of two issues:
-
This check for
>= 32is incompatible with the groupsize boot paramater and must be removed:
msbuild/src/Framework/NativeMethods.cs
Line 516 in 65c50fb
&& (numberOfCpus >= 32) -
MSBuild is using a custom enumerator with GetLogicalProcessorInformationEx which is incorrect:
msbuild/src/Framework/NativeMethods.cs
Lines 538 to 575 in 65c50fb
private unsafe static int GetLogicalCoreCountOnWindows() { uint len = 0; const int ERROR_INSUFFICIENT_BUFFER = 122; if (!GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore, IntPtr.Zero, ref len) && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER) { // Allocate that much space var buffer = new byte[len]; fixed (byte* bufferPtr = buffer) { // Call GetLogicalProcessorInformationEx with the allocated buffer if (GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore, (IntPtr)bufferPtr, ref len)) { // Walk each SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX in the buffer, where the Size of each dictates how // much space it's consuming. For each group relation, count the number of active processors in each of its group infos. int processorCount = 0; byte* ptr = bufferPtr; byte* endPtr = bufferPtr + len; while (ptr < endPtr) { var current = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)ptr; if (current->Relationship == LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore) { // Flags is 0 if the core has a single logical proc, LTP_PC_SMT if more than one // for now, assume "more than 1" == 2, as it has historically been for hyperthreading processorCount += (current->Processor.Flags == 0) ? 1 : 2; } ptr += current->Size; } return processorCount; } } } return -1; }
Starting Windows 7 usermode applications are supposed to call GetActiveProcessorCount and kernel drivers KeQueryActiveProcessorCountEx
The GetLogicalCoreCountOnWindows function MSBuild is using should be removed and all the code be replaced with a single line:
int numberOfProcessors = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);Typedefs:
const ushort ALL_PROCESSOR_GROUPS = 0xFFFF;
[DllImport("kernel32.dll")]
public static extern int GetActiveProcessorCount(ushort GroupNumber);Steps to Reproduce
- Open command prompt as Administrator
- Execute
bcdedit.exe /set groupsize 2 - Reboot
- MsBuild is now limited to 2 processors (on a 16 processor machine).
Expected Behavior
MSBuild support for multiple processor groups.
Actual Behavior
MSBuild is limited to 2 processors making testing/debugging applications significantly slower.