Modify affinity range config format for Windows
authorJan Vorlicek <janvorli@microsoft.com>
Thu, 4 Apr 2019 10:46:33 +0000 (12:46 +0200)
committerJan Vorlicek <janvorli@microsoft.com>
Thu, 4 Apr 2019 10:46:33 +0000 (12:46 +0200)
Each entry has to be prefixed by group number followed by comma. There
is nothing like global CPU index on Windows, all the APIs that support
more than 64 processors use group, in-group index pair. So specifying
the affinity this way matches what users are used to.

src/gc/env/gcenv.os.h
src/gc/gc.cpp
src/gc/gcconfig.cpp
src/gc/gcconfig.h
src/gc/unix/gcenv.unix.cpp
src/gc/windows/gcenv.windows.cpp
src/inc/utilcode.h
src/utilcode/util.cpp
src/vm/gcenv.os.cpp

index b98037b..4f86cd7 100644 (file)
@@ -26,6 +26,8 @@
 
 #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
 {
@@ -479,6 +481,16 @@ public:
     // 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__
index 952ad92..0dc7e36 100644 (file)
@@ -34086,7 +34086,9 @@ HRESULT GCHeap::Initialize()
 
 #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;
     }
index b151511..fa31814 100644 (file)
@@ -47,52 +47,77 @@ GC_CONFIGURATION_KEYS
 #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 == ',');
 
index b2fea16..95252ad 100644 (file)
@@ -97,7 +97,8 @@ public:
       "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,                                          \
@@ -156,6 +157,6 @@ static void Initialize();
 
 };
 
-bool ParseGCHeapAffinitizeRanges(AffinitySet* config_affinity_set);
+bool ParseGCHeapAffinitizeRanges(const char* cpu_index_ranges, AffinitySet* config_affinity_set);
 
 #endif // __GCCONFIG_H__
index 4719dc9..4e3c4e4 100644 (file)
@@ -725,6 +725,18 @@ bool GCToOSInterface::GetProcessorForHeap(uint16_t heap_number, uint16_t* proc_n
     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()
 {
index 5d323dd..fa13e54 100644 (file)
@@ -1300,6 +1300,55 @@ bool GCToOSInterface::GetProcessorForHeap(uint16_t heap_number, uint16_t* proc_n
     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
 {
index 6f103c4..5b222b1 100644 (file)
@@ -1402,6 +1402,7 @@ public:
     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:
index cabb19b..61f41d7 100644 (file)
@@ -1160,6 +1160,20 @@ found:
     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()
index 243b897..9093198 100644 (file)
@@ -912,6 +912,55 @@ bool GCToOSInterface::GetProcessorForHeap(uint16_t heap_number, uint16_t* proc_n
     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()
 {