Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/coreclr/gc/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43845,12 +43845,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<uintptr_t>(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<uintptr_t>(GCConfig::GetGCHeapAffinitizeMask());
const AffinitySet* process_affinity_set = GCToOSInterface::SetGCThreadsAffinitySet(config_affinity_mask, &config_affinity_set);

if (process_affinity_set->IsEmpty())
Expand Down
83 changes: 53 additions & 30 deletions src/coreclr/gc/gcconfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/gc/gcconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__
17 changes: 15 additions & 2 deletions src/coreclr/vm/gcenv.os.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down