#define NUMA_NODE_UNDEFINED UINT16_MAX
+bool ParseIndexOrRange(const char** config_string, size_t* start_index, size_t* end_index);
+
// Critical section used by the GC
class CLRCriticalSection
{
// Return:
// true if it succeeded
static bool GetProcessorForHeap(uint16_t heap_number, uint16_t* proc_no, uint16_t* node_no);
+
+ // Parse the confing string describing affinitization ranges and update the passed in affinitySet accordingly
+ // Parameters:
+ // config_string - string describing the affinitization range, platform specific
+ // start_index - the range start index extracted from the config_string
+ // end_index - the range end index extracted from the config_string, equal to the start_index if only an index and not a range was passed in
+ // Return:
+ // true if the configString was successfully parsed, false if it was not correct
+ static bool ParseGCHeapAffinitizeRangesEntry(const char** config_string, size_t* start_index, size_t* end_index);
+
};
#endif // __GCENV_OS_H__
#ifdef MULTIPLE_HEAPS
AffinitySet config_affinity_set;
- if (!ParseGCHeapAffinitizeRanges(&config_affinity_set))
+ GCConfigStringHolder cpu_index_ranges_holder(GCConfig::GetGCHeapAffinitizeRanges());
+
+ if (!ParseGCHeapAffinitizeRanges(cpu_index_ranges_holder.Get(), &config_affinity_set))
{
return CLR_E_GC_BAD_AFFINITY_CONFIG_FORMAT;
}
#undef INT_CONFIG
}
-bool ParseGCHeapAffinitizeRanges(AffinitySet* config_affinity_set)
+// Parse an integer index or range of two indices separated by '-'.
+// Updates the config_string to point to the first character after the parsed part
+bool ParseIndexOrRange(const char** config_string, size_t* start_index, size_t* end_index)
{
- bool success = true;
+ char* number_end;
+ size_t start = strtoul(*config_string, &number_end, 10);
+
+ if (number_end == *config_string)
+ {
+ // No number found, invalid format
+ return false;
+ }
+
+ size_t end = start;
+
+ if (*number_end == '-')
+ {
+ char* range_end_start = number_end + 1;
+ end = strtoul(range_end_start, &number_end, 10);
+ if (number_end == range_end_start)
+ {
+ // No number found, invalid format
+ return false;
+ }
+ }
- GCConfigStringHolder cpu_index_ranges_holder(GCConfig::GetGCHeapAffinitizeRanges());
- const char* cpu_index_ranges = cpu_index_ranges_holder.Get();
+ *start_index = start;
+ *end_index = end;
- // 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
+ *config_string = number_end;
+
+ return true;
+}
+
+bool ParseGCHeapAffinitizeRanges(const char* cpu_index_ranges, AffinitySet* config_affinity_set)
+{
+ 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)
{
- char* number_end;
+ const char* number_end;
do
{
- size_t start_index = strtoul(cpu_index_ranges, &number_end, 10);
-
- if (number_end == cpu_index_ranges)
+ size_t start_index, end_index;
+ if (!GCToOSInterface::ParseGCHeapAffinitizeRangesEntry(&cpu_index_ranges, &start_index, &end_index))
{
- // No number found, invalid format
break;
}
- size_t end_index = start_index;
-
- if (*number_end == '-')
+ if ((start_index >= MAX_SUPPORTED_CPUS) || (end_index >= MAX_SUPPORTED_CPUS) || (end_index < start_index))
{
- char* range_end_start = number_end + 1;
- end_index = strtoul(range_end_start, &number_end, 10);
- if (number_end == range_end_start)
- {
- // No number found, invalid format
- break;
- }
+ // Invalid CPU index values or range
+ break;
}
- if ((start_index < MAX_SUPPORTED_CPUS) && end_index < (MAX_SUPPORTED_CPUS))
+ for (size_t i = start_index; i <= end_index; i++)
{
- for (size_t i = start_index; i <= end_index; i++)
- {
- config_affinity_set->Add(i);
- }
+ config_affinity_set->Add(i);
}
- cpu_index_ranges = number_end + 1;
+ number_end = cpu_index_ranges;
+ cpu_index_ranges++;
}
while (*number_end == ',');
"Specifies processor mask for Server GC threads") \
STRING_CONFIG(GCHeapAffinitizeRanges, "GCHeapAffinitizeRanges", \
"Specifies list of processors for Server GC threads. The format is a comma separated " \
- "list of processor numbers or ranges of processor numbers. Example: 1,3,5,7-9,12") \
+ "list of processor numbers or ranges of processor numbers. On Windows, each entry is " \
+ "prefixed by the CPU group number. Example: Unix - 1,3,5,7-9,12, Windows - 0:1,1:7-9") \
INT_CONFIG(GCHighMemPercent, "GCHighMemPercent", 0, \
"The percent for GC to consider as high memory") \
INT_CONFIG(GCProvModeStress, "GCProvModeStress", 0, \
};
-bool ParseGCHeapAffinitizeRanges(AffinitySet* config_affinity_set);
+bool ParseGCHeapAffinitizeRanges(const char* cpu_index_ranges, AffinitySet* config_affinity_set);
#endif // __GCCONFIG_H__
return success;
}
+// Parse the confing string describing affinitization ranges and update the passed in affinitySet accordingly
+// Parameters:
+// config_string - string describing the affinitization range, platform specific
+// start_index - the range start index extracted from the config_string
+// end_index - the range end index extracted from the config_string, equal to the start_index if only an index and not a range was passed in
+// Return:
+// true if the configString was successfully parsed, false if it was not correct
+bool GCToOSInterface::ParseGCHeapAffinitizeRangesEntry(const char** config_string, size_t* start_index, size_t* end_index)
+{
+ return ParseIndexOrRange(config_string, start_index, end_index);
+}
+
// Initialize the critical section
void CLRCriticalSection::Initialize()
{
return success;
}
+// Parse the confing string describing affinitization ranges and update the passed in affinitySet accordingly
+// Parameters:
+// config_string - string describing the affinitization range, platform specific
+// start_index - the range start index extracted from the config_string
+// end_index - the range end index extracted from the config_string, equal to the start_index if only an index and not a range was passed in
+// Return:
+// true if the configString was successfully parsed, false if it was not correct
+bool GCToOSInterface::ParseGCHeapAffinitizeRangesEntry(const char** config_string, size_t* start_index, size_t* end_index)
+{
+ assert(g_fEnableGCCPUGroups);
+
+ char* number_end;
+ size_t group_number = strtoul(*config_string, &number_end, 10);
+
+ if ((number_end == *config_string) || (*number_end != ':'))
+ {
+ // No number or no colon after the number found, invalid format
+ return false;
+ }
+
+ if (group_number >= g_nGroups)
+ {
+ // Group number out of range
+ return false;
+ }
+
+ *config_string = number_end + 1;
+
+ size_t start, end;
+ if (!ParseIndexOrRange(config_string, &start, &end))
+ {
+ return false;
+ }
+
+ uint16_t group_processor_count = g_CPUGroupInfoArray[group_number].nr_active;
+ if ((start >= group_processor_count) || (end >= group_processor_count))
+ {
+ // Invalid CPU index values or range
+ return false;
+ }
+
+ uint16_t group_begin = g_CPUGroupInfoArray[group_number].begin;
+
+ *start_index = group_begin + start;
+ *end_index = group_begin + end;
+
+ return true;
+}
+
// Parameters of the GC thread stub
struct GCThreadStubParam
{
static BOOL GetSystemTimes(FILETIME *idleTime, FILETIME *kernelTime, FILETIME *userTime);
static void ChooseCPUGroupAffinity(GROUP_AFFINITY *gf);
static void ClearCPUGroupAffinity(GROUP_AFFINITY *gf);
+ static BOOL GetCPUGroupRange(WORD group_number, WORD* group_begin, WORD* group_size);
#endif
public:
m_CPUGroupInfoArray[group].activeThreadWeight -= m_CPUGroupInfoArray[group].groupWeight;
#endif
}
+
+BOOL CPUGroupInfo::GetCPUGroupRange(WORD group_number, WORD* group_begin, WORD* group_size)
+{
+ if (group_number >= m_nGroups)
+ {
+ return FALSE;
+ }
+
+ *group_begin = m_CPUGroupInfoArray[group_number].begin;
+ *group_size = m_CPUGroupInfoArray[group_number].nr_active;
+
+ return TRUE;
+}
+
#endif
/*static*/ BOOL CPUGroupInfo::CanEnableGCCPUGroups()
return success;
}
+// Parse the confing string describing affinitization ranges and update the passed in affinitySet accordingly
+// Parameters:
+// config_string - string describing the affinitization range, platform specific
+// start_index - the range start index extracted from the config_string
+// end_index - the range end index extracted from the config_string, equal to the start_index if only an index and not a range was passed in
+// Return:
+// true if the configString was successfully parsed, false if it was not correct
+bool GCToOSInterface::ParseGCHeapAffinitizeRangesEntry(const char** config_string, size_t* start_index, size_t* end_index)
+{
+ size_t index_offset = 0;
+
+ char* number_end;
+ size_t group_number = strtoul(*config_string, &number_end, 10);
+
+ if ((number_end == *config_string) || (*number_end != ':'))
+ {
+ // No number or no colon after the number found, invalid format
+ return false;
+ }
+
+ WORD group_begin;
+ WORD group_size;
+ if (!CPUGroupInfo::GetCPUGroupRange((WORD)group_number, &group_begin, &group_size))
+ {
+ // group number out of range
+ return false;
+ }
+
+ index_offset = group_begin;
+ *config_string = number_end + 1;
+
+ size_t start, end;
+ if (!ParseIndexOrRange(config_string, &start, &end))
+ {
+ return false;
+ }
+
+ if ((start >= group_size) || (end >= group_size))
+ {
+ // Invalid CPU index values or range
+ return false;
+ }
+
+ *start_index = index_offset + start;
+ *end_index = index_offset + end;
+
+ return true;
+}
+
// Initialize the critical section
void CLRCriticalSection::Initialize()
{