runtime: Windows Server 2022 - Setting affinity in .NET 6 application errors
Hi,
I have a Windows Server 2022 machine with 40 cores and 80 logical processors. Whenever I try and run my application on this machine and attempt to set it’s affinity in code or via Task Manager, I get errors.
The error I get in code is:
Win32Exception (87): The parameter is incorrect
When I try and set it via Task Manager (as an admin with UAC disabled) I get:
Unable to access or set process affinity
Also, when I try and get the affinity mask for the process in code, I get 0 back.
After reading the docs:
https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getprocessaffinitymask
https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setprocessaffinitymask
https://docs.microsoft.com/en-us/windows/win32/procthread/processor-groups
It is clear that on Windows 11 and Server 2022 that threads are not bound to a single processor group any more if there are more than 64 processors and can run across multiple processor groups.
My theory is that I am unable to set the affinity for my application because it is performing actions on threads across multiple processor groups. I have tried setting the affinity mask at startup in my application using:
Process proc = Process.GetCurrentProcess();
long affinityMask = (long)proc.ProcessorAffinity;
affinityMask &= 15; // First 4 processors
proc.ProcessorAffinity = (IntPtr)affinityMask;
But I just get the Win32Exception (87): The parameter is incorrect
And when I try to get the affinity mask at start up it is set to 0 meaning it was unable to get it because there are threads in multiple groups.
So for me, is it possible to set a .NET 6 application to ONLY run in a single processor group on Windows Server 2022 before the application runs, so I can then set its affinity mask?
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 21 (16 by maintainers)
That is correct, once the process becomes multigroup-aware, the
SetProcessAffinityMaskWin32 function (that is whatProcess.ProcessorAffinity’s setter uses underneath) would always fail withERROR_INVALID_PARAMETER(error 87). Even if you successfully set an affinity mask, some components may break away by replacing that mask or callingSetThreadGroupAffinity. In case you need to enforce a limit on CPU usage, a Win32 job object or a Docker container should be used.The initialization of the Quic protocol handler is calling
SetThreadGroupAffinityhere:Nit: It is the exact opposite. This code is multi-group aware and that breaks affinity setting APIs. In other words, the existing Process affinity settings API do not work on multi-group aware processes.
That OS behavior change has been implemented in backward compatible manner. A process must explicitly declare itself multigroup-aware (by calling a relevant API) to break the existing APIs like
SetProcessAffinityMask. Otherwise, the legacy affinity APIs should continue to work even if the process is currently running on multiple processor groups (but not explicitly multigroup-aware).One can use
start /affinity ...for that purpose.