Skip to content

Commit 71adfb0

Browse files
Support multiple processor groups for NativeAOT (#75165)
1 parent ac7309c commit 71adfb0

File tree

8 files changed

+65
-58
lines changed

8 files changed

+65
-58
lines changed

src/coreclr/gc/gc.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44806,8 +44806,9 @@ HRESULT GCHeap::Initialize()
4480644806
uint32_t nhp = 1;
4480744807
uint32_t nhp_from_config = 0;
4480844808

44809-
#ifdef MULTIPLE_HEAPS
44810-
44809+
#ifndef MULTIPLE_HEAPS
44810+
GCConfig::SetServerGC(false);
44811+
#else //!MULTIPLE_HEAPS
4481144812
GCConfig::SetServerGC(true);
4481244813
AffinitySet config_affinity_set;
4481344814
GCConfigStringHolder cpu_index_ranges_holder(GCConfig::GetGCHeapAffinitizeRanges());
@@ -44864,7 +44865,7 @@ HRESULT GCHeap::Initialize()
4486444865
nhp = min(nhp, num_affinitized_processors);
4486544866
}
4486644867
}
44867-
#endif //MULTIPLE_HEAPS
44868+
#endif //!MULTIPLE_HEAPS
4486844869

4486944870
size_t seg_size = 0;
4487044871
size_t large_seg_size = 0;

src/coreclr/gc/gcconfig.cpp

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,18 @@
77

88
#define BOOL_CONFIG(name, unused_private_key, unused_public_key, default, unused_doc) \
99
bool GCConfig::Get##name() { return s_##name; } \
10+
bool GCConfig::Get##name(bool defaultValue) \
11+
{ \
12+
return s_##name##Provided ? s_##name : defaultValue; \
13+
} \
1014
void GCConfig::Set##name(bool value) { s_Updated##name = value; } \
1115
bool GCConfig::s_##name = default; \
16+
bool GCConfig::s_##name##Provided = false; \
1217
bool GCConfig::s_Updated##name = default;
1318

1419
#define INT_CONFIG(name, unused_private_key, unused_public_key, default, unused_doc) \
1520
int64_t GCConfig::Get##name() { return s_##name; } \
16-
void GCConfig::Set##name(int64_t value) { s_Updated##name = value; } \
21+
void GCConfig::Set##name(int64_t value) { s_Updated##name = value; } \
1722
int64_t GCConfig::s_##name = default; \
1823
int64_t GCConfig::s_Updated##name = default;
1924

@@ -36,7 +41,7 @@ GC_CONFIGURATION_KEYS
3641

3742
void GCConfig::EnumerateConfigurationValues(void* context, ConfigurationValueFunc configurationValueFunc)
3843
{
39-
#define INT_CONFIG(name, unused_private_key, public_key, default, unused_doc) \
44+
#define INT_CONFIG(name, unused_private_key, public_key, unused_default, unused_doc) \
4045
configurationValueFunc(context, (void*)(#name), (void*)(public_key), GCConfigurationType::Int64, static_cast<int64_t>(s_Updated##name));
4146

4247
#define STRING_CONFIG(name, private_key, public_key, unused_doc) \
@@ -47,7 +52,7 @@ void GCConfig::EnumerateConfigurationValues(void* context, ConfigurationValueFun
4752
configurationValueFunc(context, (void*)(#name), (void*)(public_key), GCConfigurationType::StringUtf8, reinterpret_cast<int64_t>(resultStr)); \
4853
}
4954

50-
#define BOOL_CONFIG(name, unused_private_key, public_key, default, unused_doc) \
55+
#define BOOL_CONFIG(name, unused_private_key, public_key, unused_default, unused_doc) \
5156
configurationValueFunc(context, (void*)(#name), (void*)(public_key), GCConfigurationType::Boolean, static_cast<int64_t>(s_Updated##name));
5257

5358
GC_CONFIGURATION_KEYS
@@ -59,10 +64,10 @@ GC_CONFIGURATION_KEYS
5964

6065
void GCConfig::Initialize()
6166
{
62-
#define BOOL_CONFIG(name, private_key, public_key, default, unused_doc) \
63-
GCToEEInterface::GetBooleanConfigValue(private_key, public_key, &s_##name);
67+
#define BOOL_CONFIG(name, private_key, public_key, unused_default, unused_doc) \
68+
s_##name##Provided = GCToEEInterface::GetBooleanConfigValue(private_key, public_key, &s_##name);
6469

65-
#define INT_CONFIG(name, private_key, public_key, default, unused_doc) \
70+
#define INT_CONFIG(name, private_key, public_key, unused_default, unused_doc) \
6671
GCToEEInterface::GetIntConfigValue(private_key, public_key, &s_##name);
6772

6873
#define STRING_CONFIG(unused_name, unused_private_key, unused_public_key, unused_doc)

src/coreclr/gc/gcconfig.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,10 @@ class GCConfig
143143
{
144144
#define BOOL_CONFIG(name, unused_private_key, unused_public_key, unused_default, unused_doc) \
145145
public: static bool Get##name(); \
146+
public: static bool Get##name(bool defaultValue); \
146147
public: static void Set##name(bool value); \
147148
private: static bool s_##name; \
149+
private: static bool s_##name##Provided; \
148150
private: static bool s_Updated##name;
149151

150152
#define INT_CONFIG(name, unused_private_key, unused_public_key, unused_default, unused_doc) \

src/coreclr/gc/gcload.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,11 @@ GC_Initialize(
7474
assert(clrToGC == nullptr);
7575
#endif
7676

77+
#ifndef FEATURE_NATIVEAOT // GCConfig and GCToOSInterface are initialized in PalInit
7778
// Initialize GCConfig before anything else - initialization of our
7879
// various components may want to query the current configuration.
7980
GCConfig::Initialize();
8081

81-
#ifndef FEATURE_NATIVEAOT // GCToOSInterface is initialized directly
8282
if (!GCToOSInterface::Initialize())
8383
{
8484
return E_FAIL;
@@ -92,7 +92,7 @@ GC_Initialize(
9292
}
9393

9494
#ifdef FEATURE_SVR_GC
95-
if (GCConfig::GetServerGC())
95+
if (GCConfig::GetServerGC() && GCToEEInterface::GetCurrentProcessCpuCount() > 1)
9696
{
9797
#ifdef WRITE_BARRIER_CHECK
9898
g_GCShadow = 0;

src/coreclr/gc/windows/gcenv.windows.cpp

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ struct CPU_Group_Info
6161
};
6262

6363
static bool g_fEnableGCCPUGroups;
64-
static bool g_fHadSingleProcessorAtStartup;
6564
static DWORD g_nGroups;
6665
static DWORD g_nProcessors;
6766
static CPU_Group_Info *g_CPUGroupInfoArray;
@@ -220,26 +219,26 @@ void InitCPUGroupInfo()
220219
g_fEnableGCCPUGroups = false;
221220

222221
#if (defined(TARGET_AMD64) || defined(TARGET_ARM64))
223-
if (!GCConfig::GetGCCpuGroup())
222+
USHORT groupCount = 0;
223+
224+
// On Windows 11+ and Windows Server 2022+, a process is no longer restricted to a single processor group by default.
225+
// If more than one processor group is available to the process (a non-affinitized process on Windows 11+),
226+
// default to using multiple processor groups; otherwise, default to using a single processor group. This default
227+
// behavior may be overridden by the configuration value below.
228+
if (GetProcessGroupAffinity(GetCurrentProcess(), &groupCount, NULL) || GetLastError() != ERROR_INSUFFICIENT_BUFFER)
229+
groupCount = 1;
230+
231+
bool enableGCCPUGroups = GCConfig::GetGCCpuGroup(/* defaultValue */ groupCount > 1);
232+
233+
if (!enableGCCPUGroups)
224234
return;
225235

226236
if (!InitCPUGroupInfoArray())
227237
return;
228238

229-
// only enable CPU groups if more than one group exists
239+
// Enable processor groups only if more than one group exists
230240
g_fEnableGCCPUGroups = g_nGroups > 1;
231241
#endif // TARGET_AMD64 || TARGET_ARM64
232-
233-
// Determine if the process is affinitized to a single processor (or if the system has a single processor)
234-
DWORD_PTR processAffinityMask, systemAffinityMask;
235-
if (::GetProcessAffinityMask(::GetCurrentProcess(), &processAffinityMask, &systemAffinityMask))
236-
{
237-
if (processAffinityMask != 0 && // only one CPU group is involved
238-
(processAffinityMask & (processAffinityMask - 1)) == 0) // only one bit is set
239-
{
240-
g_fHadSingleProcessorAtStartup = true;
241-
}
242-
}
243242
}
244243

245244
void GetProcessMemoryLoad(LPMEMORYSTATUSEX pMSEX)
@@ -475,17 +474,12 @@ size_t GetLogicalProcessorCacheSizeFromOS()
475474
return cache_size;
476475
}
477476

478-
bool CanEnableGCCPUGroups()
479-
{
480-
return g_fEnableGCCPUGroups;
481-
}
482-
483477
// Get the CPU group for the specified processor
484478
void GetGroupForProcessor(uint16_t processor_number, uint16_t* group_number, uint16_t* group_processor_number)
485479
{
486480
assert(g_fEnableGCCPUGroups);
487481

488-
#if !defined(FEATURE_NATIVEAOT) && (defined(TARGET_AMD64) || defined(TARGET_ARM64))
482+
#if defined(TARGET_AMD64) || defined(TARGET_ARM64)
489483
WORD bTemp = 0;
490484
WORD bDiff = processor_number - bTemp;
491485

src/coreclr/nativeaot/Runtime/gcrhenv.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,13 +1313,6 @@ MethodTable* GCToEEInterface::GetFreeObjectMethodTable()
13131313

13141314
bool GCToEEInterface::GetBooleanConfigValue(const char* privateKey, const char* publicKey, bool* value)
13151315
{
1316-
// these configuration values are given to us via startup flags.
1317-
if (strcmp(privateKey, "gcServer") == 0)
1318-
{
1319-
*value = g_heap_type == GC_HEAP_SVR;
1320-
return true;
1321-
}
1322-
13231316
if (strcmp(privateKey, "gcConservative") == 0)
13241317
{
13251318
*value = true;

src/coreclr/nativeaot/Runtime/unix/PalRedhawkUnix.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#include "UnixHandle.h"
1414
#include <pthread.h>
1515
#include "gcenv.h"
16+
#include "gcenv.ee.h"
17+
#include "gcconfig.h"
1618
#include "holder.h"
1719
#include "UnixSignals.h"
1820
#include "UnixContext.h"
@@ -417,6 +419,8 @@ REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalInit()
417419

418420
ConfigureSignals();
419421

422+
GCConfig::Initialize();
423+
420424
if (!GCToOSInterface::Initialize())
421425
{
422426
return false;

src/coreclr/nativeaot/Runtime/windows/PalRedhawkMinWin.cpp

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ uint32_t PalEventWrite(REGHANDLE arg1, const EVENT_DESCRIPTOR * arg2, uint32_t a
3030
}
3131

3232
#include "gcenv.h"
33+
#include "gcenv.ee.h"
34+
#include "gcconfig.h"
3335

3436

3537
#define REDHAWK_PALEXPORT extern "C"
@@ -71,29 +73,36 @@ void InitializeCurrentProcessCpuCount()
7173
}
7274
else
7375
{
74-
DWORD_PTR pmask, smask;
75-
76-
if (!GetProcessAffinityMask(GetCurrentProcess(), &pmask, &smask))
76+
if (GCToOSInterface::CanEnableGCCPUGroups())
7777
{
78-
count = 1;
78+
count = GCToOSInterface::GetTotalProcessorCount();
7979
}
8080
else
8181
{
82-
count = 0;
82+
DWORD_PTR pmask, smask;
8383

84-
while (pmask)
84+
if (!GetProcessAffinityMask(GetCurrentProcess(), &pmask, &smask))
8585
{
86-
pmask &= (pmask - 1);
87-
count++;
86+
count = 1;
87+
}
88+
else
89+
{
90+
count = 0;
91+
92+
while (pmask)
93+
{
94+
pmask &= (pmask - 1);
95+
count++;
96+
}
97+
98+
// GetProcessAffinityMask can return pmask=0 and smask=0 on systems with more
99+
// than 64 processors, which would leave us with a count of 0. Since the GC
100+
// expects there to be at least one processor to run on (and thus at least one
101+
// heap), we'll return 64 here if count is 0, since there are likely a ton of
102+
// processors available in that case.
103+
if (count == 0)
104+
count = 64;
88105
}
89-
90-
// GetProcessAffinityMask can return pmask=0 and smask=0 on systems with more
91-
// than 64 processors, which would leave us with a count of 0. Since the GC
92-
// expects there to be at least one processor to run on (and thus at least one
93-
// heap), we'll return 64 here if count is 0, since there are likely a ton of
94-
// processors available in that case.
95-
if (count == 0)
96-
count = 64;
97106
}
98107

99108
JOBOBJECT_CPU_RATE_CONTROL_INFORMATION cpuRateControl;
@@ -119,10 +128,7 @@ void InitializeCurrentProcessCpuCount()
119128

120129
if (0 < maxRate && maxRate < MAXIMUM_CPU_RATE)
121130
{
122-
SYSTEM_INFO systemInfo;
123-
GetSystemInfo(&systemInfo);
124-
125-
DWORD cpuLimit = (maxRate * systemInfo.dwNumberOfProcessors + MAXIMUM_CPU_RATE - 1) / MAXIMUM_CPU_RATE;
131+
DWORD cpuLimit = (maxRate * GCToOSInterface::GetTotalProcessorCount() + MAXIMUM_CPU_RATE - 1) / MAXIMUM_CPU_RATE;
126132
if (cpuLimit < count)
127133
count = cpuLimit;
128134
}
@@ -145,6 +151,8 @@ REDHAWK_PALEXPORT bool REDHAWK_PALAPI PalInit()
145151
return false;
146152
}
147153

154+
GCConfig::Initialize();
155+
148156
if (!GCToOSInterface::Initialize())
149157
{
150158
return false;

0 commit comments

Comments
 (0)