diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index a7fbe9fd684b12..a6b5d1b41bfc4e 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -12647,6 +12647,7 @@ void gc_heap::distribute_free_regions() size_t num_decommit_regions_by_time = 0; size_t size_decommit_regions_by_time = 0; size_t heap_budget_in_region_units[MAX_SUPPORTED_CPUS][kind_count]; + size_t min_heap_budget_in_region_units[MAX_SUPPORTED_CPUS]; size_t region_size[kind_count] = { global_region_allocator.get_region_alignment(), global_region_allocator.get_large_region_alignment() }; region_free_list surplus_regions[kind_count]; for (int kind = basic_free_region; kind < kind_count; kind++) @@ -12664,6 +12665,7 @@ void gc_heap::distribute_free_regions() gc_heap* hp = pGenGCHeap; // just to reduce the number of #ifdefs in the code below const int i = 0; + const int n_heaps = 1; #endif //MULTIPLE_HEAPS for (int kind = basic_free_region; kind < kind_count; kind++) @@ -12674,7 +12676,8 @@ void gc_heap::distribute_free_regions() for (heap_segment* region = region_list.get_first_free_region(); region != nullptr; region = next_region) { next_region = heap_segment_next (region); - if (heap_segment_age_in_free (region) >= AGE_IN_FREE_TO_DECOMMIT) + int age_in_free_to_decommit = min (max (AGE_IN_FREE_TO_DECOMMIT, n_heaps), MAX_AGE_IN_FREE); + if (heap_segment_age_in_free (region) >= age_in_free_to_decommit) { num_decommit_regions_by_time++; size_decommit_regions_by_time += get_region_committed_size (region); @@ -12691,13 +12694,43 @@ void gc_heap::distribute_free_regions() global_free_huge_regions.transfer_regions (&hp->free_regions[huge_free_region]); heap_budget_in_region_units[i][basic_free_region] = 0; + min_heap_budget_in_region_units[i] = 0; heap_budget_in_region_units[i][large_free_region] = 0; - for (int gen = soh_gen0; gen < total_generation_count; gen++) + } + + for (int gen = soh_gen0; gen < total_generation_count; gen++) + { + if ((gen <= soh_gen2) && + total_budget_in_region_units[basic_free_region] >= (total_num_free_regions[basic_free_region] + + surplus_regions[basic_free_region].get_num_free_regions())) + { + // don't accumulate budget from higher soh generations if we cannot cover lower ones + dprintf (REGIONS_LOG, ("out of free regions - skipping gen %d budget = %Id >= avail %Id", + gen, + total_budget_in_region_units[basic_free_region], + total_num_free_regions[basic_free_region] + surplus_regions[basic_free_region].get_num_free_regions())); + continue; + } +#ifdef MULTIPLE_HEAPS + for (int i = 0; i < n_heaps; i++) { + gc_heap* hp = g_heaps[i]; +#else //MULTIPLE_HEAPS + { + gc_heap* hp = pGenGCHeap; + // just to reduce the number of #ifdefs in the code below + const int i = 0; + const int n_heaps = 1; +#endif //MULTIPLE_HEAPS ptrdiff_t budget_gen = max (hp->estimate_gen_growth (gen), 0); int kind = gen >= loh_generation; size_t budget_gen_in_region_units = (budget_gen + (region_size[kind] - 1)) / region_size[kind]; dprintf (REGIONS_LOG, ("h%2d gen %d has an estimated growth of %Id bytes (%Id regions)", i, gen, budget_gen, budget_gen_in_region_units)); + if (gen <= soh_gen2) + { + // preserve the budget for the previous generation - we should not go below that + min_heap_budget_in_region_units[i] = heap_budget_in_region_units[i][kind]; + } heap_budget_in_region_units[i][kind] += budget_gen_in_region_units; total_budget_in_region_units[kind] += budget_gen_in_region_units; } @@ -12747,15 +12780,54 @@ void gc_heap::distribute_free_regions() { dprintf (REGIONS_LOG, ("distributing the %Id %s regions deficit", -balance, kind_name[kind])); +#ifdef MULTIPLE_HEAPS // we may have a deficit or - if background GC is going on - a surplus. // adjust the budget per heap accordingly - ptrdiff_t adjustment_per_heap = (balance + (n_heaps - 1)) / n_heaps; - -#ifdef MULTIPLE_HEAPS - for (int i = 0; i < n_heaps; i++) + if (balance != 0) { - ptrdiff_t new_budget = (ptrdiff_t)heap_budget_in_region_units[i][kind] + adjustment_per_heap; - heap_budget_in_region_units[i][kind] = max (0, new_budget); + ptrdiff_t curr_balance = 0; + ptrdiff_t rem_balance = 0; + for (int i = 0; i < n_heaps; i++) + { + curr_balance += balance; + ptrdiff_t adjustment_per_heap = curr_balance / n_heaps; + curr_balance -= adjustment_per_heap * n_heaps; + ptrdiff_t new_budget = (ptrdiff_t)heap_budget_in_region_units[i][kind] + adjustment_per_heap; + ptrdiff_t min_budget = (kind == basic_free_region) ? (ptrdiff_t)min_heap_budget_in_region_units[i] : 0; + dprintf (REGIONS_LOG, ("adjusting the budget for heap %d from %Id %s regions by %Id to %Id", + i, + heap_budget_in_region_units[i][kind], + kind_name[kind], + adjustment_per_heap, + max (min_budget, new_budget))); + heap_budget_in_region_units[i][kind] = max (min_budget, new_budget); + rem_balance += new_budget - heap_budget_in_region_units[i][kind]; + } + assert (rem_balance <= 0); + dprintf (REGIONS_LOG, ("remaining balance: %Id %s regions", rem_balance, kind_name[kind])); + + // if we have a left over deficit, distribute that to the heaps that still have more than the minimum + while (rem_balance < 0) + { + for (int i = 0; i < n_heaps; i++) + { + size_t min_budget = (kind == basic_free_region) ? min_heap_budget_in_region_units[i] : 0; + if (heap_budget_in_region_units[i][kind] > min_budget) + { + dprintf (REGIONS_LOG, ("adjusting the budget for heap %d from %Id %s regions by %Id to %Id", + i, + heap_budget_in_region_units[i][kind], + kind_name[kind], + -1, + heap_budget_in_region_units[i][kind] - 1)); + + heap_budget_in_region_units[i][kind] -= 1; + rem_balance += 1; + if (rem_balance == 0) + break; + } + } + } } #endif //MULTIPLE_HEAPS } @@ -12807,11 +12879,12 @@ void gc_heap::distribute_free_regions() if (hp->free_regions[kind].get_num_free_regions() > heap_budget_in_region_units[i][kind]) { - dprintf (REGIONS_LOG, ("removing %Id %s regions from heap %d with %Id regions", + dprintf (REGIONS_LOG, ("removing %Id %s regions from heap %d with %Id regions, budget is %Id", hp->free_regions[kind].get_num_free_regions() - heap_budget_in_region_units[i][kind], kind_name[kind], i, - hp->free_regions[kind].get_num_free_regions())); + hp->free_regions[kind].get_num_free_regions(), + heap_budget_in_region_units[i][kind])); remove_surplus_regions (&hp->free_regions[kind], &surplus_regions[kind], heap_budget_in_region_units[i][kind]); } @@ -12826,14 +12899,16 @@ void gc_heap::distribute_free_regions() const int i = 0; #endif //MULTIPLE_HEAPS + // second pass: fill all the regions having less than budget if (hp->free_regions[kind].get_num_free_regions() < heap_budget_in_region_units[i][kind]) { int64_t num_added_regions = add_regions (&hp->free_regions[kind], &surplus_regions[kind], heap_budget_in_region_units[i][kind]); - dprintf (REGIONS_LOG, ("added %Id %s regions to heap %d - now has %Id", + dprintf (REGIONS_LOG, ("added %Id %s regions to heap %d - now has %Id, budget is %Id", num_added_regions, kind_name[kind], i, - hp->free_regions[kind].get_num_free_regions())); + hp->free_regions[kind].get_num_free_regions(), + heap_budget_in_region_units[i][kind])); } hp->free_regions[kind].sort_by_committed_and_age(); } @@ -40578,9 +40653,12 @@ void gc_heap::decommit_ephemeral_segment_pages() { gradual_decommit_in_progress_p = TRUE; - dprintf (1, ("h%2d gen %d reduce_commit by %IdkB", + dprintf (1, ("h%2d gen %d region %Ix allocated %IdkB committed %IdkB reduce_commit by %IdkB", heap_number, gen_number, + get_region_start (tail_region), + (heap_segment_allocated (tail_region) - get_region_start (tail_region))/1024, + (heap_segment_committed (tail_region) - get_region_start (tail_region))/1024, (heap_segment_committed (tail_region) - decommit_target)/1024)); } dprintf(3, ("h%2d gen %d allocated: %IdkB committed: %IdkB target: %IdkB",