Fix the accounting for gen 1 allocations by taking into account what has been already...
authorPeter Sollich <petersol@microsoft.com>
Thu, 10 Mar 2022 10:26:41 +0000 (11:26 +0100)
committerGitHub <noreply@github.com>
Thu, 10 Mar 2022 10:26:41 +0000 (11:26 +0100)
Details:

In gen 1 GCs, we recompute the budget at the end of the GC. However, the amount consumed in the current GC is nowhere taken into account. That causes us to do at most alternate gen 0 and gen 1 GCs, we cannot do back-to-back gen 1 GCs.

If we take the gen 1 budget as the amount of memory we are aiming to be used for gen 1, then it seems illogical to just drop the amount used in this GC on the floor.

The fix is to actually subtract the amount of gen 1 budget used in this GC from dd_new_allocation for gen 1. This is a bit awkward for server GC, because we even out the budget and the amount to subtract from dd_new_allocation across heaps after having computed it for each heap individually.

src/coreclr/gc/gc.cpp

index f20d24c..4b3c07d 100644 (file)
@@ -20912,6 +20912,7 @@ void gc_heap::gc1()
             for (int gen = 0; gen <= limit; gen++)
             {
                 size_t total_desired = 0;
+                size_t total_already_consumed = 0;
 
                 for (int i = 0; i < gc_heap::n_heaps; i++)
                 {
@@ -20925,11 +20926,22 @@ void gc_heap::gc1()
                         break;
                     }
                     total_desired = temp_total_desired;
+                    // for gen 1 and gen 2, there may have been some incoming size
+                    // already accounted for
+                    assert ((ptrdiff_t)dd_desired_allocation (dd) >= dd_new_allocation (dd));
+                    size_t already_consumed = dd_desired_allocation (dd) - dd_new_allocation (dd);
+                    size_t temp_total_already_consumed = total_already_consumed + already_consumed;
+
+                    // we should never have an overflow here as the consumed size should always fit in a size_t
+                    assert (temp_total_already_consumed >= total_already_consumed);
+                    total_already_consumed = temp_total_already_consumed;
                 }
 
                 size_t desired_per_heap = Align (total_desired/gc_heap::n_heaps,
                                                     get_alignment_constant (gen <= max_generation));
 
+                size_t already_consumed_per_heap = total_already_consumed / gc_heap::n_heaps;
+
                 if (gen == 0)
                 {
 #if 1 //subsumed by the linear allocation model
@@ -20973,7 +20985,7 @@ void gc_heap::gc1()
                     dynamic_data* dd = hp->dynamic_data_of (gen);
                     dd_desired_allocation (dd) = desired_per_heap;
                     dd_gc_new_allocation (dd) = desired_per_heap;
-                    dd_new_allocation (dd) = desired_per_heap;
+                    dd_new_allocation (dd) = desired_per_heap - already_consumed_per_heap;
 
                     if (gen == 0)
                     {
@@ -39412,6 +39424,8 @@ void gc_heap::compute_new_dynamic_data (int gen_number)
         // When we are in the low latency mode, we can still be
         // condemning more than gen1's 'cause of induced GCs.
         dd_desired_allocation (dd) = low_latency_alloc;
+        dd_gc_new_allocation (dd) = dd_desired_allocation (dd);
+        dd_new_allocation (dd) = dd_gc_new_allocation (dd);
     }
     else
     {
@@ -39461,14 +39475,16 @@ void gc_heap::compute_new_dynamic_data (int gen_number)
         {
             dd_desired_allocation (dd) = desired_new_allocation (dd, out, gen_number, 0);
         }
+        dd_gc_new_allocation (dd) = dd_desired_allocation (dd);
+
+        // we may have had some incoming objects during this GC -
+        // adjust the consumed budget for these
+        dd_new_allocation (dd) = dd_gc_new_allocation (dd) - in;
     }
 
     gen_data->pinned_surv = dd_pinned_survived_size (dd);
     gen_data->npinned_surv = dd_survived_size (dd) - dd_pinned_survived_size (dd);
 
-    dd_gc_new_allocation (dd) = dd_desired_allocation (dd);
-    dd_new_allocation (dd) = dd_gc_new_allocation (dd);
-
     dd_promoted_size (dd) = out;
     if (gen_number == max_generation)
     {