Skip to content
106 changes: 92 additions & 14 deletions src/coreclr/gc/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12642,6 +12642,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() };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since we are only using this for SOH, it seems like this can just be declared as

size_t min_heap_budget_in_region_units[MAX_SUPPORTED_CPUS];

MAX_SUPPORTED_CPUS is 1024 so this is quite a large data structure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, we are using it for UOH as well, but it's always 0 in this case, so we can use an if-statement or conditional expression.

I'll fix it...

region_free_list surplus_regions[kind_count];
for (int kind = basic_free_region; kind < kind_count; kind++)
Expand All @@ -12659,6 +12660,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++)
Expand All @@ -12669,7 +12671,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);
Expand All @@ -12686,13 +12689,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;
}
Expand Down Expand Up @@ -12742,15 +12775,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
}
Expand Down Expand Up @@ -12802,11 +12874,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]);
}
Expand All @@ -12821,14 +12894,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();
}
Expand Down Expand Up @@ -40561,9 +40636,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",
Expand Down Expand Up @@ -45068,7 +45146,7 @@ HRESULT GCHeap::Initialize()
gc_heap* hp = gc_heap::g_heaps[0];

dynamic_data* gen0_dd = hp->dynamic_data_of (0);
gc_heap::min_gen0_balance_delta = (dd_min_size (gen0_dd) >> 3);
gc_heap::min_gen0_balance_delta = (dd_min_size (gen0_dd) >> 6);

bool can_use_cpu_groups = GCToOSInterface::CanEnableGCCPUGroups();
GCConfig::SetGCCpuGroup(can_use_cpu_groups);
Expand Down