Fix creation of the NUMA node to heap number map
authorJan Vorlicek <janvorli@microsoft.com>
Fri, 26 Apr 2019 09:53:41 +0000 (11:53 +0200)
committerJan Vorlicek <janvorli@microsoft.com>
Fri, 26 Apr 2019 11:55:11 +0000 (13:55 +0200)
The current implementation assumes that the NUMA nodes of CPUs
used for GC threads form a zero based continous range. However that
doesn't have to be true for cases when user selects only a subset of the
available CPUs for the GC heap threads using the
COMPlus_GCHeapAffinitizeMask or COMPlus_GCHeapAffinitizeRanges. The
selected CPUs may belong only to a subset of NUMA nodes that don't
necessarily start at node 0 or form a continuous range.

This change fixes the algorithm that initializes the
numa_node_to_heap_map lookup array so that it works correctly even in
such cases.

Commit migrated from https://github.com/dotnet/coreclr/commit/9733c30b27ca90d3eeb07928df6e6e5861c203bb

src/coreclr/src/gc/gc.cpp

index bcffca0..b3bb610 100644 (file)
@@ -5195,23 +5195,31 @@ public:
     }
 
     static void init_numa_node_to_heap_map(int nheaps)
-    {   // called right after GCHeap::Init() for each heap is finished
-        // when numa is not enabled, heap_no_to_numa_node[] are all filled
-        // with 0s during initialization, and will be treated as one node
-        numa_node_to_heap_map[0] = 0;
-        int node_index = 1;
+    {   // Called right after GCHeap::Init() for each heap
+        // For each NUMA node used by the heaps, the
+        // numa_node_to_heap_map[numa_node] is set to the first heap number on that node and
+        // numa_node_to_heap_map[numa_node + 1] is set to the first heap number not on that node 
+
+        // Set the start of the heap number range for the first NUMA node
+        numa_node_to_heap_map[heap_no_to_numa_node[0]] = 0;
 
         for (int i=1; i < nheaps; i++)
         {
             if (heap_no_to_numa_node[i] != heap_no_to_numa_node[i-1])
-                numa_node_to_heap_map[node_index++] = (uint16_t)i;
+            {
+                // Set the end of the heap number range for the previous NUMA node
+                numa_node_to_heap_map[heap_no_to_numa_node[i-1] + 1] =
+                // Set the start of the heap number range for the current NUMA node
+                numa_node_to_heap_map[heap_no_to_numa_node[i]] = (uint16_t)i;
+            }
         }
-        numa_node_to_heap_map[node_index] = (uint16_t)nheaps; //mark the end with nheaps
+
+        // Set the end of the heap range for the last NUMA node
+        numa_node_to_heap_map[heap_no_to_numa_node[nheaps-1] + 1] = (uint16_t)nheaps; //mark the end with nheaps
     }
 
     static void get_heap_range_for_heap(int hn, int* start, int* end)
-    {   // 1-tier/no numa case: heap_no_to_numa_node[] all zeros, 
-        // and treated as in one node. thus: start=0, end=n_heaps
+    {
         uint16_t numa_node = heap_no_to_numa_node[hn];
         *start = (int)numa_node_to_heap_map[numa_node];
         *end   = (int)(numa_node_to_heap_map[numa_node+1]);