How do I configure my multithreaded .NET 5 application to use all Windows CPU groups?

Viewed 268

I'm trying to migrate a project from .NET Framework 4.7.2 to .NET 5, but the performance of my program has dropped significantly. Parts of the program exploit parallelism for bulk operations on a server with 96 Cores and 192 Logical processors split across 4 CPU groups.

I'm running the program on a Windows Server 2016 with the .NET 5 Runtime installed (.NET 5 SDK not installed). The project is written in F# 5.0.

In .NET Framework 4.7.2 we used the following app.config-file which successfully made the program run across all 192 Logical processors, achieving ~98% CPU utilization:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <runtime>
        <Thread_UseAllCpuGroups enabled="true" />
        <GCCpuGroup enabled="true" />
        <gcServer enabled="true" />
        <gcAllowVeryLargeObjects enabled="true" />
    </runtime>
</configuration>

After migrating to .NET 5 (and by extension .NET Core) the CPU utilization dropped, and I am having trouble increasing it again.

According to Microsoft's own documentation app.config is not used to configure .NET Core projects, replaced by [appname].runtimeconfig.json. To accommodate this change i have added a runtimeconfig.template.json to my project:

{
  "configProperties": {
    "System.GC.CpuGroup": true,
    "System.GC.Server": true,
    "COMPlus_gcAllowVeryLargeObjects": 1
  }
}

This produces the following [appname].runtimeconfig.json-file:

{
  "runtimeOptions": {
    "tfm": "net5.0",
    "framework": {
      "name": "Microsoft.NETCore.App",
      "version": "5.0.0"
    },
    "configProperties": {
      "System.GC.CpuGroup": true,
      "System.GC.Server": true,
      "COMPlus_gcAllowVeryLargeObjects": 1
    }
  }
}

The property System.GC.CpuGroup seems to work, giving me a peak of ~28% CPU utilization by distributing threads across a single CPU Group:

Screenshot of Windows Task Manager showing 100% utilization of 48 of 192 logical processors for an overall utilization of 28%

Now I need to distribute threads across different CPU Groups.

Thread_UseAllCpuGroups was omitted due to this documentation saying the variable is N/A in runtimeconfig.json, and must be set as an environment variable.

According to Trying to use Thread_UseAllCpuGroups in a .Net Core app this only works when set at the command line, but i have tried multiple ways of setting it:

  1. CommandLine using set COMPlus_Thread_UseAllCpuGroups=1 before running my program.
  2. Setting the variable though Control Panel -> System and Security -> System -> Environment Variables.
  3. Defining a launchSetting.json-file with the variable and copying it to the output directory.
  4. Manually setting the variable in my program.fs-file using System.Environment.SetEnvironmentVariable("COMPlus_Thread_UseAllCpuGroups", "1").

None of the above methods have worked, and I am unsure what I am doing wrong, especially given how few posts I can find online on this issue.

Finally my question is: How do I make my .NET 5 console application utilize all my logical processors?

Edit: I've tried lifting the project to .NET 6 and F# 6, but the problem still remains.

0 Answers
Related