From 0ae6b957ff535d86f32a315a44641361ea0e778b Mon Sep 17 00:00:00 2001 From: Mukund Raghav Sharma <68247673+mrsharm@users.noreply.github.com> Date: Thu, 21 Apr 2022 21:05:07 -0700 Subject: [PATCH] If the user has < 65 cores and passes in an affinitized range for the 0th CPU group, if valid, honor it. (#68283) * If the user has < 65 cores and passes in a affinitized range for the 0th CPU group, honor that passed in affinitized range if valid. * Added the logic to apply the process afinity set for Windows if No CPU Groups are available * Updated logic to make use of the config affinity mask for cases where there are < 65 cores and the user passed in a config related to the 0th CPU Group * Include an additional case where if the user passes in the affinity mask with CPU groups enabled, we error out since this case isn't valid * Incorporated further feedback --- src/coreclr/gc/gc.cpp | 4 +- src/coreclr/gc/gcconfig.cpp | 83 +++++++++++++++++++++++-------------- src/coreclr/gc/gcconfig.h | 2 +- src/coreclr/vm/gcenv.os.cpp | 17 +++++++- 4 files changed, 71 insertions(+), 35 deletions(-) diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index 64ef8a56d20e5f..964cd85395ac68 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -43876,12 +43876,12 @@ HRESULT GCHeap::Initialize() AffinitySet config_affinity_set; GCConfigStringHolder cpu_index_ranges_holder(GCConfig::GetGCHeapAffinitizeRanges()); - if (!ParseGCHeapAffinitizeRanges(cpu_index_ranges_holder.Get(), &config_affinity_set)) + uintptr_t config_affinity_mask = static_cast(GCConfig::GetGCHeapAffinitizeMask()); + if (!ParseGCHeapAffinitizeRanges(cpu_index_ranges_holder.Get(), &config_affinity_set, config_affinity_mask)) { return CLR_E_GC_BAD_AFFINITY_CONFIG_FORMAT; } - uintptr_t config_affinity_mask = static_cast(GCConfig::GetGCHeapAffinitizeMask()); const AffinitySet* process_affinity_set = GCToOSInterface::SetGCThreadsAffinitySet(config_affinity_mask, &config_affinity_set); if (process_affinity_set->IsEmpty()) diff --git a/src/coreclr/gc/gcconfig.cpp b/src/coreclr/gc/gcconfig.cpp index f33792f8a54a16..188c0220e513e9 100644 --- a/src/coreclr/gc/gcconfig.cpp +++ b/src/coreclr/gc/gcconfig.cpp @@ -81,47 +81,70 @@ bool ParseIndexOrRange(const char** config_string, size_t* start_index, size_t* return true; } -bool ParseGCHeapAffinitizeRanges(const char* cpu_index_ranges, AffinitySet* config_affinity_set) +bool ParseGCHeapAffinitizeRanges(const char* cpu_index_ranges, AffinitySet* config_affinity_set, uintptr_t& config_affinity_mask) { bool success = true; - // Unix: - // The cpu index ranges is a comma separated list of indices or ranges of indices (e.g. 1-5). - // Example 1,3,5,7-9,12 - // Windows: - // The cpu index ranges is a comma separated list of group-annotated indices or ranges of indices. - // The group number always prefixes index or range and is followed by colon. - // Example 0:1,0:3,0:5,1:7-9,1:12 - - if (cpu_index_ranges != NULL) + // Case 1: config_affinity_mask and config_affinity_set are both null. No affinitization. + // Case 2: config_affinity_mask is not null but config_affinity_set is null. Affinitization is based on config_affinity_mask. + if (cpu_index_ranges == nullptr) { - const char* number_end = cpu_index_ranges; - - do + // Case 2.5: If CPU Groups are enabled, however, if the user passes in the config_affinity_mask, it can't apply. + // Therefore, we return a CLR_E_GC_BAD_AFFINITY_CONFIG_FORMAT error. + if (config_affinity_mask != 0 && GCToOSInterface::CanEnableGCCPUGroups()) { - size_t start_index, end_index; - if (!GCToOSInterface::ParseGCHeapAffinitizeRangesEntry(&cpu_index_ranges, &start_index, &end_index)) - { - break; - } + success = false; + } - if ((start_index >= MAX_SUPPORTED_CPUS) || (end_index >= MAX_SUPPORTED_CPUS) || (end_index < start_index)) - { - // Invalid CPU index values or range - break; - } + return success; + } + + // Case 3: config_affinity_mask is null but cpu_index_ranges isn't. + // To facilitate the case where there are less than 65 cores but the user passes in an affinitized range associated + // with the 0th CPU Group, we override the config_affinity_mask with the same contents as the cpu_index_ranges. + else if (config_affinity_mask == 0 && cpu_index_ranges != nullptr) + { + // Unix: + // The cpu index ranges is a comma separated list of indices or ranges of indices (e.g. 1-5). + // Example 1,3,5,7-9,12 + // Windows: + // The cpu index ranges is a comma separated list of group-annotated indices or ranges of indices. + // The group number always prefixes index or range and is followed by colon. + // Example 0:1,0:3,0:5,1:7-9,1:12 + + if (cpu_index_ranges != nullptr) + { + const char* number_end = cpu_index_ranges; - for (size_t i = start_index; i <= end_index; i++) + do { - config_affinity_set->Add(i); + size_t start_index, end_index; + if (!GCToOSInterface::ParseGCHeapAffinitizeRangesEntry(&cpu_index_ranges, &start_index, &end_index)) + { + break; + } + + if ((start_index >= MAX_SUPPORTED_CPUS) || (end_index >= MAX_SUPPORTED_CPUS) || (end_index < start_index)) + { + // Invalid CPU index values or range + break; + } + + static const size_t BitsPerBitsetEntry = 8 * sizeof(uintptr_t); + + for (size_t i = start_index; i <= end_index; i++) + { + config_affinity_set->Add(i); + config_affinity_mask |= (uintptr_t)1 << (i & (BitsPerBitsetEntry - 1)); + } + + number_end = cpu_index_ranges; + cpu_index_ranges++; } + while (*number_end == ','); - number_end = cpu_index_ranges; - cpu_index_ranges++; + success = (*number_end == '\0'); } - while (*number_end == ','); - - success = (*number_end == '\0'); } return success; diff --git a/src/coreclr/gc/gcconfig.h b/src/coreclr/gc/gcconfig.h index 63e2ded8af3b20..28e0581d00c090 100644 --- a/src/coreclr/gc/gcconfig.h +++ b/src/coreclr/gc/gcconfig.h @@ -179,6 +179,6 @@ static void Initialize(); }; -bool ParseGCHeapAffinitizeRanges(const char* cpu_index_ranges, AffinitySet* config_affinity_set); +bool ParseGCHeapAffinitizeRanges(const char* cpu_index_ranges, AffinitySet* config_affinity_set, uintptr_t& config_affinity_mask); #endif // __GCCONFIG_H__ diff --git a/src/coreclr/vm/gcenv.os.cpp b/src/coreclr/vm/gcenv.os.cpp index 716078b87fc704..369d30e538ff27 100644 --- a/src/coreclr/vm/gcenv.os.cpp +++ b/src/coreclr/vm/gcenv.os.cpp @@ -1171,12 +1171,25 @@ bool GCToOSInterface::ParseGCHeapAffinitizeRangesEntry(const char** config_strin return false; } + // If the user passes in 0 as the CPU group and they don't have > 64 cores, + // honor the affinitized range passed in by bypassing the check. + bool bypass_cpu_range_check = !CanEnableGCCPUGroups() && group_number == 0; + WORD group_begin; WORD group_size; if (!CPUGroupInfo::GetCPUGroupRange((WORD)group_number, &group_begin, &group_size)) { - // group number out of range - return false; + if (!bypass_cpu_range_check) + { + // group number out of range + return false; + } + else + { + // the offset in this case where we bypass this check should be from 0 till the # of Processors. + group_begin = 0; + group_size = GetTotalProcessorCount(); + } } index_offset = group_begin;