Skip to content

Commit

Permalink
Possible fix for NUMA nodes issue on Windows Home (#76)
Browse files Browse the repository at this point in the history
  • Loading branch information
lowleveldesign committed Dec 14, 2024
1 parent aa0effe commit 95277c4
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 58 deletions.
10 changes: 5 additions & 5 deletions procgov/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,11 @@ internal static IExecutionMode ParseArgs(SystemInfo systemInfo, string[] rawArgs
"terminate-job-on-exit", "background", "service", "q", "quiet", "nowait", "v", "verbose",
"nomonitor", "monitor", "uninstall-all" , "h", "?", "help"], rawArgs);

if (parsedArgs.Remove("v") || parsedArgs.Remove("verbose"))
{
Logger.Switch.Level = SourceLevels.Verbose;
}

if (parsedArgs.Count == 0)
{
return new ShowSystemInfoAndExit();
Expand Down Expand Up @@ -247,11 +252,6 @@ internal static IExecutionMode ParseArgs(SystemInfo systemInfo, string[] rawArgs
_ => ExitBehavior.WaitForJobCompletion
};

if (parsedArgs.Remove("v") || parsedArgs.Remove("verbose"))
{
Logger.Switch.Level = SourceLevels.Verbose;
}

var environment = parsedArgs.Remove("env", out v) ? GetCustomEnvironmentVariables(v[^1]) : [];

var privileges = parsedArgs.Remove("enable-privilege", out v) ? v : [];
Expand Down
118 changes: 65 additions & 53 deletions procgov/SystemInfoModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,19 @@ static class SystemInfoModule
{
public static SystemInfo GetSystemInfo()
{
return new(GetNumaNodes(), GetProcessorGroups(), GetProcessorCores());
var processorGroups = GetProcessorGroups();
NumaNode[] numaNodes = [];
try
{
numaNodes = GetNumaNodes();
}
catch (Win32Exception ex)
{
Program.Logger.TraceInformation($"NUMA information not available (Is it Windows Home?). Error: {ex}");
numaNodes = [new(0, processorGroups)];
}

return new(numaNodes, processorGroups, GetProcessorCores());

static NumaNode[] GetNumaNodes()
{
Expand Down Expand Up @@ -69,79 +81,79 @@ static NumaNode[] GetNumaNodes()
}
}

static ProcessorGroup[] GetProcessorGroups()
{
unsafe
static ProcessorGroup[] GetProcessorGroups()
{
uint length = 0;
PInvoke.GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationGroup, null, &length);
if (Marshal.GetLastWin32Error() is var lastError && lastError != (int)WIN32_ERROR.ERROR_INSUFFICIENT_BUFFER)
unsafe
{
throw new Win32Exception(lastError);
}
uint length = 0;
PInvoke.GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationGroup, null, &length);
if (Marshal.GetLastWin32Error() is var lastError && lastError != (int)WIN32_ERROR.ERROR_INSUFFICIENT_BUFFER)
{
throw new Win32Exception(lastError);
}

byte* infoBytes = stackalloc byte[(int)length];
if (!PInvoke.GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationGroup,
(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)infoBytes, &length))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
var info = ((SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)infoBytes);
byte* infoBytes = stackalloc byte[(int)length];
if (!PInvoke.GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationGroup,
(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)infoBytes, &length))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
var info = ((SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)infoBytes);

ref var relationGroup = ref info->Anonymous.Group;
ref var relationGroup = ref info->Anonymous.Group;

var processorGroups = new ProcessorGroup[relationGroup.ActiveGroupCount];
var processorGroups = new ProcessorGroup[relationGroup.ActiveGroupCount];

var groupInfos = relationGroup.GroupInfo.AsSpan(relationGroup.ActiveGroupCount);
var groupInfos = relationGroup.GroupInfo.AsSpan(relationGroup.ActiveGroupCount);

for (ushort groupNumber = 0; groupNumber < relationGroup.ActiveGroupCount; groupNumber++)
{
ref var groupInfo = ref groupInfos[groupNumber];
processorGroups[groupNumber] = new ProcessorGroup(groupNumber, groupInfo.ActiveProcessorMask);
}
for (ushort groupNumber = 0; groupNumber < relationGroup.ActiveGroupCount; groupNumber++)
{
ref var groupInfo = ref groupInfos[groupNumber];
processorGroups[groupNumber] = new ProcessorGroup(groupNumber, groupInfo.ActiveProcessorMask);
}

return processorGroups;
return processorGroups;
}
}
}

static ProcessorCore[] GetProcessorCores()
{
unsafe
static ProcessorCore[] GetProcessorCores()
{
uint length = 0;
PInvoke.GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore, null, &length);
if (Marshal.GetLastWin32Error() is var lastError && lastError != (int)WIN32_ERROR.ERROR_INSUFFICIENT_BUFFER)
unsafe
{
throw new Win32Exception(lastError);
}
uint length = 0;
PInvoke.GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore, null, &length);
if (Marshal.GetLastWin32Error() is var lastError && lastError != (int)WIN32_ERROR.ERROR_INSUFFICIENT_BUFFER)
{
throw new Win32Exception(lastError);
}

byte* infoBytes = stackalloc byte[(int)length];
if (!PInvoke.GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore,
(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)infoBytes, &length))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
byte* infoBytes = stackalloc byte[(int)length];
if (!PInvoke.GetLogicalProcessorInformationEx(LOGICAL_PROCESSOR_RELATIONSHIP.RelationProcessorCore,
(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)infoBytes, &length))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}

var cores = new List<ProcessorCore>();
var infoBytesEndAddress = infoBytes + length;
var cores = new List<ProcessorCore>();
var infoBytesEndAddress = infoBytes + length;

while (infoBytes < infoBytesEndAddress)
{
var info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)infoBytes;
while (infoBytes < infoBytesEndAddress)
{
var info = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)infoBytes;

ref var processor = ref info->Anonymous.Processor;
ref var processor = ref info->Anonymous.Processor;

var group = processor.GroupMask[0];
cores.Add(new(processor.Flags == PInvoke.LTP_PC_SMT, new(group.Group, group.Mask)));
var group = processor.GroupMask[0];
cores.Add(new(processor.Flags == PInvoke.LTP_PC_SMT, new(group.Group, group.Mask)));

infoBytes += info->Size;
}
Debug.Assert(infoBytes == infoBytesEndAddress, $"{(nint)infoBytes} == {(nint)infoBytesEndAddress}");
infoBytes += info->Size;
}
Debug.Assert(infoBytes == infoBytesEndAddress, $"{(nint)infoBytes} == {(nint)infoBytesEndAddress}");

return [.. cores];
return [.. cores];
}
}
}
}

public static PerformanceInformation GetSystemPerformanceInformation()
{
Expand Down

0 comments on commit 95277c4

Please sign in to comment.