Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix high frag in gen2 #48601

Closed
wants to merge 49 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
3d639f2
delete backport.yml so I can push to master
PeterSolMS Aug 21, 2020
c78344e
Merge remote-tracking branch 'upstream/master'
PeterSolMS Aug 27, 2020
0fc9aeb
Undo unintended changes
PeterSolMS Aug 27, 2020
9073278
Merge remote-tracking branch 'upstream/master'
PeterSolMS Aug 31, 2020
eb4f188
Merge remote-tracking branch 'upstream/master'
PeterSolMS Sep 28, 2020
c809f97
Merge remote-tracking branch 'upstream/master'
PeterSolMS Oct 2, 2020
808750e
Merge remote-tracking branch 'upstream/master'
PeterSolMS Oct 20, 2020
8985284
Merge remote-tracking branch 'upstream/master'
PeterSolMS Nov 5, 2020
61be136
Merge remote-tracking branch 'upstream/master'
PeterSolMS Nov 13, 2020
5893c56
Merge remote-tracking branch 'upstream/master'
PeterSolMS Nov 17, 2020
827db97
Merge remote-tracking branch 'upstream/master'
PeterSolMS Nov 26, 2020
a0df529
Merge remote-tracking branch 'upstream/master'
PeterSolMS Nov 30, 2020
15e891c
Merge from upstream/master
PeterSolMS Nov 30, 2020
ddea2eb
Merge remote-tracking branch 'upstream/master'
PeterSolMS Dec 1, 2020
bdeba60
delete backport.yml so I can push to master
PeterSolMS Aug 21, 2020
e5afb51
Undo unintended changes
PeterSolMS Aug 27, 2020
6887c32
Merge from upstream/master
PeterSolMS Nov 30, 2020
4f1f430
Merge branch 'master' of https://github.com/PeterSolMS/runtime-1
PeterSolMS Dec 1, 2020
989a242
Undo unintended Mono changes that somehow crept in.
PeterSolMS Dec 1, 2020
5370012
Merge remote-tracking branch 'upstream/master'
PeterSolMS Dec 7, 2020
9522406
Merge remote-tracking branch 'upstream/master'
PeterSolMS Dec 8, 2020
a31ce60
Merge remote-tracking branch 'upstream/master'
PeterSolMS Dec 16, 2020
0ba8f94
Merge remote-tracking branch 'upstream/master'
PeterSolMS Dec 21, 2020
6bc4d50
Merge remote-tracking branch 'upstream/master'
PeterSolMS Jan 7, 2021
c6f573a
Merge remote-tracking branch 'upstream/master'
PeterSolMS Jan 18, 2021
94e74a4
Merge remote-tracking branch 'upstream/master'
PeterSolMS Jan 25, 2021
871da36
Merge remote-tracking branch 'upstream/master'
PeterSolMS Jan 29, 2021
5e9cdd6
Merge remote-tracking branch 'upstream/master'
PeterSolMS Feb 4, 2021
88fadae
Merge remote-tracking branch 'upstream/master'
PeterSolMS Feb 15, 2021
dcd191d
Introduce a config setting that triggers a compacting gen 2 collectio…
PeterSolMS Feb 22, 2021
d4cd80b
Add more sophistication to the conserve memory logic:
PeterSolMS Feb 24, 2021
33be166
Added dprintf for the setting of GCConserveMemory.
PeterSolMS Feb 25, 2021
3b69fdd
Merge remote-tracking branch 'upstream/master'
PeterSolMS Feb 25, 2021
3a4008d
Merge branch 'master' into Fix_high_frag_in_gen2
PeterSolMS Feb 25, 2021
9d22ff3
Fixed bitrot with FREE_USAGE_STATS, additional debug output.
PeterSolMS Mar 5, 2021
7c8c021
Merge remote-tracking branch 'upstream/main' into main
PeterSolMS Mar 11, 2021
6f0e594
Disable mechanism to reduce budget for gen 2 if conserve_mem_setting …
PeterSolMS Mar 11, 2021
f809435
Merge branch 'main' into Fix_high_frag_in_gen2
PeterSolMS Mar 11, 2021
2623256
Merge remote-tracking branch 'upstream/main' into main
PeterSolMS Mar 15, 2021
240e419
Update logic to look at the combined fragmentation in gen 2 and LOH t…
PeterSolMS Mar 22, 2021
9fcb397
Merge remote-tracking branch 'upstream/main' into main
PeterSolMS Mar 22, 2021
4651147
Merge remote-tracking branch 'upstream/main' into main
PeterSolMS Apr 7, 2021
40bb09a
Merge remote-tracking branch 'upstream/main' into main
PeterSolMS Apr 19, 2021
17d5b8f
Merge remote-tracking branch 'upstream/main' into main
PeterSolMS May 11, 2021
523d66a
Merge branch 'main' into Fix_high_frag_in_gen2
PeterSolMS Jun 1, 2021
e9ce602
Base decision on fully compacting GC in the hard limit case on the co…
PeterSolMS Jun 1, 2021
8916d4e
Merge with main
PeterSolMS Aug 3, 2021
e38e6f0
Fix dprintfs that had bitrotted and were commented out, turned off TR…
PeterSolMS Aug 3, 2021
13a8e47
Remove extra file.
PeterSolMS Aug 3, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 97 additions & 23 deletions src/coreclr/gc/gc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2243,6 +2243,7 @@ double gc_heap::short_plugs_pad_ratio = 0;
#endif //SHORT_PLUGS

int gc_heap::generation_skip_ratio_threshold = 0;
int gc_heap::conserve_mem_setting = 0;

uint64_t gc_heap::suspended_start_time = 0;
uint64_t gc_heap::end_gc_time = 0;
Expand Down Expand Up @@ -3113,17 +3114,20 @@ gc_heap::dt_high_frag_p (gc_tuning_point tp,
}
else
{
#ifndef MULTIPLE_HEAPS
if (gen_number == max_generation)
{
float frag_ratio = (float)(dd_fragmentation (dynamic_data_of (max_generation))) / (float)generation_size (max_generation);
if (frag_ratio > 0.65)
float frag_limit = 1.0f - conserve_mem_setting / 10.0f;
#ifndef MULTIPLE_HEAPS
if (conserve_mem_setting == 0)
frag_limit = 0.65f;
#endif //!MULTIPLE_HEAPS
if (frag_ratio > frag_limit)
{
dprintf (GTC_LOG, ("g2 FR: %d%%", (int)(frag_ratio*100)));
return TRUE;
}
}
#endif //!MULTIPLE_HEAPS
size_t fr = generation_unusable_fragmentation (generation_of (gen_number));
ret = (fr > dd_fragmentation_limit(dd));
if (ret)
Expand Down Expand Up @@ -11858,9 +11862,9 @@ void gc_heap::make_generation (int gen_num, heap_segment* seg, uint8_t* start)
#endif //DOUBLY_LINKED_FL

#ifdef FREE_USAGE_STATS
memset (gen->gen_free_spaces, 0, sizeof (gen.gen_free_spaces));
memset (gen->gen_current_pinned_free_spaces, 0, sizeof (gen.gen_current_pinned_free_spaces));
memset (gen->gen_plugs, 0, sizeof (gen.gen_plugs));
memset (gen->gen_free_spaces, 0, sizeof (gen->gen_free_spaces));
memset (gen->gen_current_pinned_free_spaces, 0, sizeof (gen->gen_current_pinned_free_spaces));
memset (gen->gen_plugs, 0, sizeof (gen->gen_plugs));
#endif //FREE_USAGE_STATS
}

Expand Down Expand Up @@ -12455,6 +12459,14 @@ gc_heap::init_semi_shared()
#endif //FEATURE_LOH_COMPACTION
#endif //FEATURE_EVENT_TRACE

conserve_mem_setting = (int)GCConfig::GetGCConserveMem();
if (conserve_mem_setting < 0)
conserve_mem_setting = 0;
if (conserve_mem_setting > 9)
conserve_mem_setting = 9;

dprintf (1, ("conserve_mem_setting = %d", conserve_mem_setting));

ret = 1;

cleanup:
Expand Down Expand Up @@ -16961,7 +16973,6 @@ void gc_heap::init_free_and_plug()
#else
memset (gen->gen_free_spaces, 0, sizeof (gen->gen_free_spaces));
#endif //DOUBLY_LINKED_FL
memset (gen->gen_plugs_allocated_in_free, 0, sizeof (gen->gen_plugs_allocated_in_free));
memset (gen->gen_plugs, 0, sizeof (gen->gen_plugs));
memset (gen->gen_current_pinned_free_spaces, 0, sizeof (gen->gen_current_pinned_free_spaces));
}
Expand All @@ -16979,7 +16990,7 @@ void gc_heap::init_free_and_plug()

void gc_heap::print_free_and_plug (const char* msg)
{
#if defined(FREE_USAGE_STATS) && defined(SIMPLE_DPRINTF)
#ifdef FREE_USAGE_STATS
int older_gen = ((settings.condemned_generation == max_generation) ? max_generation : (settings.condemned_generation + 1));
for (int i = 0; i <= older_gen; i++)
{
Expand All @@ -17000,7 +17011,7 @@ void gc_heap::print_free_and_plug (const char* msg)
}
#else
UNREFERENCED_PARAMETER(msg);
#endif //FREE_USAGE_STATS && SIMPLE_DPRINTF
#endif //FREE_USAGE_STATS
}

// replace with allocator::first_suitable_bucket
Expand Down Expand Up @@ -17072,8 +17083,8 @@ void gc_heap::add_gen_free (int gen_number, size_t free_size)
(gen->gen_free_spaces[i])++;
if (gen_number == max_generation)
{
dprintf (3, ("Mb b%d: f+ %Id (%Id->%Id)",
i, free_size, (gen->gen_free_spaces[i]).num_items, (gen->gen_free_spaces[i]).total_size));
dprintf (3, ("Mb b%d: f+ %Id (%Id)",
i, free_size, gen->gen_free_spaces[i]));
}
#else
UNREFERENCED_PARAMETER(gen_number);
Expand All @@ -17095,8 +17106,8 @@ void gc_heap::remove_gen_free (int gen_number, size_t free_size)
(gen->gen_free_spaces[i])--;
if (gen_number == max_generation)
{
dprintf (3, ("Mb b%d: f- %Id (%Id->%Id)",
i, free_size, (gen->gen_free_spaces[i]).num_items, (gen->gen_free_spaces[i]).total_size));
dprintf (3, ("Mb b%d: f- %Id (%Id)",
i, free_size, gen->gen_free_spaces[i]));
}
#else
UNREFERENCED_PARAMETER(gen_number);
Expand Down Expand Up @@ -17206,6 +17217,8 @@ uint8_t* gc_heap::allocate_in_older_generation (generation* gen, size_t size,
for (unsigned int a_l_idx = gen_allocator->first_suitable_bucket(real_size * 2);
a_l_idx < gen_allocator->number_of_buckets(); a_l_idx++)
{
dprintf (3, ("trying free list bucket %u for size %Id", a_l_idx, real_size));

uint8_t* free_list = 0;
uint8_t* prev_free_item = 0;

Expand Down Expand Up @@ -18257,26 +18270,28 @@ int gc_heap::joined_generation_to_condemn (BOOL should_evaluate_elevation,
}
else if ((current_total_committed * 10) >= (heap_hard_limit * 9))
{
size_t loh_frag = get_total_gen_fragmentation (loh_generation);
size_t combined_frag = get_total_gen_fragmentation(max_generation) +
get_total_gen_fragmentation(loh_generation);

// If the LOH frag is >= 1/8 it's worth compacting it
if ((loh_frag * 8) >= heap_hard_limit)
// If the combined frag is >= 1/8 it's worth compacting
if ((combined_frag * 8) >= heap_hard_limit)
{
dprintf (GTC_LOG, ("loh frag: %Id > 1/8 of limit %Id", loh_frag, (heap_hard_limit / 8)));
dprintf (GTC_LOG, ("gen2+loh frag: %Id > 1/8 of limit %Id", combined_frag, (heap_hard_limit / 8)));
gc_data_global.gen_to_condemn_reasons.set_condition(gen_joined_limit_loh_frag);
full_compact_gc_p = true;
}
else
{
// If there's not much fragmentation but it looks like it'll be productive to
// collect LOH, do that.
size_t est_loh_reclaim = get_total_gen_estimated_reclaim (loh_generation);
if ((est_loh_reclaim * 8) >= heap_hard_limit)
// collect, do that.
size_t est_combined_reclaim = get_total_gen_estimated_reclaim (max_generation) +
get_total_gen_estimated_reclaim(loh_generation);
if ((est_combined_reclaim * 8) >= heap_hard_limit)
{
gc_data_global.gen_to_condemn_reasons.set_condition(gen_joined_limit_loh_reclaim);
full_compact_gc_p = true;
}
dprintf (GTC_LOG, ("loh est reclaim: %Id, 1/8 of limit %Id", est_loh_reclaim, (heap_hard_limit / 8)));
dprintf (GTC_LOG, ("gen2+loh est reclaim: %Id, 1/8 of limit %Id", est_combined_reclaim, (heap_hard_limit / 8)));
}
}

Expand All @@ -18285,7 +18300,38 @@ int gc_heap::joined_generation_to_condemn (BOOL should_evaluate_elevation,
n = max_generation;
*blocking_collection_p = TRUE;
settings.loh_compaction = TRUE;
dprintf (GTC_LOG, ("compacting LOH due to hard limit"));
dprintf (GTC_LOG, ("compacting gen2+loh due to hard limit"));
}
}

if ((conserve_mem_setting != 0) && (n >= max_generation))
{
float frag_limit = 1.0f - conserve_mem_setting / 10.0f;

size_t loh_size = get_total_gen_size (loh_generation);
size_t gen2_size = get_total_gen_size (max_generation);
float loh_frag_ratio = 0.0f;
float combined_frag_ratio = 0.0f;
if (loh_size != 0)
{
size_t loh_frag = get_total_gen_fragmentation (loh_generation);
size_t gen2_frag = get_total_gen_fragmentation (max_generation);
loh_frag_ratio = (float)loh_frag / (float)loh_size;
combined_frag_ratio = (float)(gen2_frag + loh_frag) / (float)(gen2_size + loh_size);
}
if (combined_frag_ratio > frag_limit)
{
dprintf (GTC_LOG, ("combined frag: %f > limit %f, loh frag: %f", combined_frag_ratio, frag_limit, loh_frag_ratio));
gc_data_global.gen_to_condemn_reasons.set_condition (gen_max_high_frag_p);

n = max_generation;
*blocking_collection_p = TRUE;
if (loh_frag_ratio > frag_limit)
{
settings.loh_compaction = TRUE;

dprintf (GTC_LOG, ("compacting LOH due to GCConserveMem setting"));
}
}
}

Expand Down Expand Up @@ -23360,6 +23406,21 @@ size_t gc_heap::get_total_gen_estimated_reclaim (int gen_number)
return total_estimated_reclaim;
}

size_t gc_heap::get_total_gen_size (int gen_number)
{
#ifdef MULTIPLE_HEAPS
size_t size = 0;
for (int hn = 0; hn < gc_heap::n_heaps; hn++)
{
gc_heap* hp = gc_heap::g_heaps[hn];
size += hp->generation_sizes (hp->generation_of (gen_number));
}
#else
size_t size = generation_sizes (generation_of (gen_number));
#endif //MULTIPLE_HEAPS
return size;
}

size_t gc_heap::committed_size()
{
size_t total_committed = 0;
Expand Down Expand Up @@ -25521,7 +25582,7 @@ BOOL gc_heap::plan_loh()

void gc_heap::compact_loh()
{
assert (loh_compaction_requested() || heap_hard_limit);
assert (loh_compaction_requested() || heap_hard_limit || conserve_mem_setting);

#ifdef FEATURE_EVENT_TRACE
uint64_t start_time, end_time;
Expand Down Expand Up @@ -37294,6 +37355,16 @@ size_t gc_heap::desired_new_allocation (dynamic_data* dd,
cst = min (1.0f, float (out) / float (dd_begin_data_size (dd)));

f = surv_to_growth (cst, limit, max_limit);
if (conserve_mem_setting != 0)
{
// if this is set, compute a growth factor based on it.
// formula below means use 50% of the allowable fragmentation
float f_conserve = (10.0f / conserve_mem_setting - 1) * 0.5f + 1.0f;

// use the smaller one
f = min (f, f_conserve);
}

size_t max_growth_size = (size_t)(max_size / f);
if (current_size >= max_growth_size)
{
Expand All @@ -37317,6 +37388,7 @@ size_t gc_heap::desired_new_allocation (dynamic_data* dd,
#ifdef BGC_SERVO_TUNING
!bgc_tuning::fl_tuning_triggered &&
#endif //BGC_SERVO_TUNING
(conserve_mem_setting == 0) &&
(dd_fragmentation (dd) > ((size_t)((f-1)*current_size))))
{
//reducing allocation in case of fragmentation
Expand Down Expand Up @@ -37415,6 +37487,8 @@ size_t gc_heap::desired_new_allocation (dynamic_data* dd,
heap_number, gen_number, out, current_size, (dd_desired_allocation (dd) - dd_gc_new_allocation (dd)),
(int)(cst*100), (int)(f*100), current_size + new_allocation, new_allocation));

dprintf (2, ("heap%d gen%d size: %Id MB fragmentation: %Id MB", heap_number, gen_number, generation_size (gen_number)/(1924*1024), dd_fragmentation (dd)/(1924*1024)));

return new_allocation_ret;
}
}
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/gc/gcconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ class GCConfigStringHolder
INT_CONFIG (GCHeapHardLimitLOHPercent, "GCHeapHardLimitLOHPercent", "System.GC.HeapHardLimitLOHPercent", 0, "Specifies the GC heap LOH usage as a percentage of the total memory") \
INT_CONFIG (GCHeapHardLimitPOHPercent, "GCHeapHardLimitPOHPercent", "System.GC.HeapHardLimitPOHPercent", 0, "Specifies the GC heap POH usage as a percentage of the total memory") \
INT_CONFIG (GCEnabledInstructionSets, "GCEnabledInstructionSets", NULL, -1, "Specifies whether GC can use AVX2 or AVX512F - 0 for neither, 1 for AVX2, 3 for AVX512F")\
INT_CONFIG (GCConserveMem, "GCConserveMemory", NULL, 0, "Specifies how hard GC should try to conserve memory - values 0-9") \

// This class is responsible for retreiving configuration information
// for how the GC should operate.
Expand Down
7 changes: 7 additions & 0 deletions src/coreclr/gc/gcpriv.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ inline void FATAL_GC_ERROR()
//#define SYNCHRONIZATION_STATS
//#define SEG_REUSE_STATS

//#define FREE_USAGE_STATS

#ifdef SYNCHRONIZATION_STATS
#define BEGIN_TIMING(x) \
int64_t x##_start; \
Expand Down Expand Up @@ -3142,6 +3144,8 @@ class gc_heap
PER_HEAP_ISOLATED
size_t get_total_gen_estimated_reclaim (int gen_number);
PER_HEAP_ISOLATED
size_t get_total_gen_size (int gen_number);
PER_HEAP_ISOLATED
void get_memory_info (uint32_t* memory_load,
uint64_t* available_physical=NULL,
uint64_t* available_page_file=NULL);
Expand Down Expand Up @@ -4639,6 +4643,9 @@ class gc_heap
PER_HEAP_ISOLATED
int generation_skip_ratio_threshold;

PER_HEAP_ISOLATED
int conserve_mem_setting;

PER_HEAP
BOOL gen0_bricks_cleared;
PER_HEAP
Expand Down