This may be entirely attributable to #13691 but I'm not sure, so I'm filing it.
On a Standard_F72s_v2 VM, which has 72 logical processors, Environment.ProcessorCount returns 36.
```c#
using System;
namespace proccount
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(System.Environment.ProcessorCount);
}
}
}
```sh-session
$ dotnet run
36
$ dotnet --info
.NET SDK (reflecting any global.json):
Version: 5.0.100-rc.1.20452.6
Commit: 31c7208879
Runtime Environment:
OS Name: Windows
OS Version: 10.0.19041
OS Platform: Windows
RID: win10-x64
Base Path: C:\Users\raines.NTDEV\Downloads\dotnet-sdk-5.0.100-rc.1.20452.6-win-x64\sdk\5.0.100-rc.1.20452.6\
Host (useful for support):
Version: 5.0.0-rc.1.20451.14
Commit: 38017c3935
.NET SDKs installed:
5.0.100-rc.1.20452.6 [C:\Users\raines.NTDEV\Downloads\dotnet-sdk-5.0.100-rc.1.20452.6-win-x64\sdk]
.NET runtimes installed:
Microsoft.AspNetCore.App 5.0.0-rc.1.20451.17 [C:\Users\raines.NTDEV\Downloads\dotnet-sdk-5.0.100-rc.1.20452.6-win-x64\shared\Microsoft.AspNetCore.App]
Microsoft.NETCore.App 5.0.0-rc.1.20451.14 [C:\Users\raines.NTDEV\Downloads\dotnet-sdk-5.0.100-rc.1.20452.6-win-x64\shared\Microsoft.NETCore.App]
Microsoft.WindowsDesktop.App 5.0.0-rc.1.20452.2 [C:\Users\raines.NTDEV\Downloads\dotnet-sdk-5.0.100-rc.1.20452.6-win-x64\shared\Microsoft.WindowsDesktop.App]
Not from 3.1.
I think what's being returned is the number of available cores _in the current NUMA node_:
That condition looks backward to me: if you can use use all CPU groups, shouldn't you do so rather than only the current group? But maybe I'm misunderstanding the intention.
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label.
That contion means - if we can enable using of all CPU groups, then all CPUs will be available for the process. Otherwise only the processors in the current group will be available. Windows never runs a process on processors from multiple groups unless application explicitly uses the SetThreadGroupAffinity API to do that. When a process starts, windows pick a group in which it will run. So when using CPU groups is not enabled, you are stuck to just one group, which is those 36 CPUs. Managed thread will never run on threads from the other group, hence we report that number.
To enable .NET to use all CPU groups, you need to set the COMPlus_Thread_UseAllCpuGroup env var to nonzero. Then you should see your test to report 72.
@janvorli, i have always thought COMPlus_ solution as expecting the user to do a local build of runtime. :) is it so that some of the COMPlus_ knobs are applicable to Checked/Debug build of runtime only and some can be used with Release? If that鈥檚 the case maybe they can be prefixed in a self-descriptive way (e.g. COMPlus_RELEASE_ and COMPlus_ continue to mean debug/checked -only).
Some of them are debug only and some of them are for all configs. I believe all the GC ones are for all configs.
For the non-gc ones, you can look it up in the clrconfig.h file, the macros to define them start with RETAIL_CONFIG or CONFIG. The RETAIL ones are the ones that work even in release.
I don't think it would be reasonable to rename them by adding the RELEASE into the name now, most of them have been named as they are for many years.
Is there a recommendation for a use-case like ours, where we don't want to schedule _this process_ across CPU groups but instead want to know _how many processes to launch_? Using the win32 API directly (as we must do in .NET Framework 4.8 on Windows) avoids asking users to set an environment variable, so I guess we'll go with that.
Is there a recommendation for a use-case like ours, where we don't want to schedule this process across CPU groups but instead want to know how many processes to launch?
This is tracked as API proposal https://github.com/dotnet/runtime/issues/29686 . Resolving as duplicate.
Using the win32 API directly
I think this is fine.
Note that there is another factor to consider unrelated to NUMA: Process affinity. Process affinity is inherited by child processes by default. If somebody sets process affinity for the build process and you just take total number of processors into account, you may be launching a lot more processes than what the build can utilize.
Duplicate of #29686 .
Most helpful comment
Some of them are debug only and some of them are for all configs. I believe all the GC ones are for all configs.
For the non-gc ones, you can look it up in the clrconfig.h file, the macros to define them start with RETAIL_CONFIG or CONFIG. The RETAIL ones are the ones that work even in release.
I don't think it would be reasonable to rename them by adding the RELEASE into the name now, most of them have been named as they are for many years.