Skip to content

Commit 158b26e

Browse files
authored
Cleaned up version of earlier PR #48601. (#56772)
Port of ConserveMemory setting we implemented on .NET Framework - we already merged this into .NET Core 5.0.
1 parent b726f7b commit 158b26e

File tree

3 files changed

+85
-11
lines changed

3 files changed

+85
-11
lines changed

src/coreclr/gc/gc.cpp

Lines changed: 79 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2250,6 +2250,7 @@ double gc_heap::short_plugs_pad_ratio = 0;
22502250
#endif //SHORT_PLUGS
22512251

22522252
int gc_heap::generation_skip_ratio_threshold = 0;
2253+
int gc_heap::conserve_mem_setting = 0;
22532254

22542255
uint64_t gc_heap::suspended_start_time = 0;
22552256
uint64_t gc_heap::end_gc_time = 0;
@@ -12571,9 +12572,9 @@ void gc_heap::make_generation (int gen_num, heap_segment* seg, uint8_t* start)
1257112572
#endif //DOUBLY_LINKED_FL
1257212573

1257312574
#ifdef FREE_USAGE_STATS
12574-
memset (gen->gen_free_spaces, 0, sizeof (gen.gen_free_spaces));
12575-
memset (gen->gen_current_pinned_free_spaces, 0, sizeof (gen.gen_current_pinned_free_spaces));
12576-
memset (gen->gen_plugs, 0, sizeof (gen.gen_plugs));
12575+
memset (gen->gen_free_spaces, 0, sizeof (gen->gen_free_spaces));
12576+
memset (gen->gen_current_pinned_free_spaces, 0, sizeof (gen->gen_current_pinned_free_spaces));
12577+
memset (gen->gen_plugs, 0, sizeof (gen->gen_plugs));
1257712578
#endif //FREE_USAGE_STATS
1257812579
}
1257912580

@@ -13171,6 +13172,14 @@ gc_heap::init_semi_shared()
1317113172
#endif //FEATURE_LOH_COMPACTION
1317213173
#endif //FEATURE_EVENT_TRACE
1317313174

13175+
conserve_mem_setting = (int)GCConfig::GetGCConserveMem();
13176+
if (conserve_mem_setting < 0)
13177+
conserve_mem_setting = 0;
13178+
if (conserve_mem_setting > 9)
13179+
conserve_mem_setting = 9;
13180+
13181+
dprintf (1, ("conserve_mem_setting = %d", conserve_mem_setting));
13182+
1317413183
ret = 1;
1317513184

1317613185
cleanup:
@@ -17690,7 +17699,6 @@ void gc_heap::init_free_and_plug()
1769017699
#else
1769117700
memset (gen->gen_free_spaces, 0, sizeof (gen->gen_free_spaces));
1769217701
#endif //DOUBLY_LINKED_FL
17693-
memset (gen->gen_plugs_allocated_in_free, 0, sizeof (gen->gen_plugs_allocated_in_free));
1769417702
memset (gen->gen_plugs, 0, sizeof (gen->gen_plugs));
1769517703
memset (gen->gen_current_pinned_free_spaces, 0, sizeof (gen->gen_current_pinned_free_spaces));
1769617704
}
@@ -17708,7 +17716,7 @@ void gc_heap::init_free_and_plug()
1770817716

1770917717
void gc_heap::print_free_and_plug (const char* msg)
1771017718
{
17711-
#if defined(FREE_USAGE_STATS) && defined(SIMPLE_DPRINTF)
17719+
#ifdef FREE_USAGE_STATS
1771217720
int older_gen = ((settings.condemned_generation == max_generation) ? max_generation : (settings.condemned_generation + 1));
1771317721
for (int i = 0; i <= older_gen; i++)
1771417722
{
@@ -17729,7 +17737,7 @@ void gc_heap::print_free_and_plug (const char* msg)
1772917737
}
1773017738
#else
1773117739
UNREFERENCED_PARAMETER(msg);
17732-
#endif //FREE_USAGE_STATS && SIMPLE_DPRINTF
17740+
#endif //FREE_USAGE_STATS
1773317741
}
1773417742

1773517743
// replace with allocator::first_suitable_bucket
@@ -17801,8 +17809,8 @@ void gc_heap::add_gen_free (int gen_number, size_t free_size)
1780117809
(gen->gen_free_spaces[i])++;
1780217810
if (gen_number == max_generation)
1780317811
{
17804-
dprintf (3, ("Mb b%d: f+ %Id (%Id->%Id)",
17805-
i, free_size, (gen->gen_free_spaces[i]).num_items, (gen->gen_free_spaces[i]).total_size));
17812+
dprintf (3, ("Mb b%d: f+ %Id (%Id)",
17813+
i, free_size, gen->gen_free_spaces[i]));
1780617814
}
1780717815
#else
1780817816
UNREFERENCED_PARAMETER(gen_number);
@@ -17824,8 +17832,8 @@ void gc_heap::remove_gen_free (int gen_number, size_t free_size)
1782417832
(gen->gen_free_spaces[i])--;
1782517833
if (gen_number == max_generation)
1782617834
{
17827-
dprintf (3, ("Mb b%d: f- %Id (%Id->%Id)",
17828-
i, free_size, (gen->gen_free_spaces[i]).num_items, (gen->gen_free_spaces[i]).total_size));
17835+
dprintf (3, ("Mb b%d: f- %Id (%Id)",
17836+
i, free_size, gen->gen_free_spaces[i]));
1782917837
}
1783017838
#else
1783117839
UNREFERENCED_PARAMETER(gen_number);
@@ -19022,6 +19030,37 @@ int gc_heap::joined_generation_to_condemn (BOOL should_evaluate_elevation,
1902219030
}
1902319031
}
1902419032

19033+
if ((conserve_mem_setting != 0) && (n == max_generation))
19034+
{
19035+
float frag_limit = 1.0f - conserve_mem_setting / 10.0f;
19036+
19037+
size_t loh_size = get_total_gen_size (loh_generation);
19038+
size_t gen2_size = get_total_gen_size (max_generation);
19039+
float loh_frag_ratio = 0.0f;
19040+
float combined_frag_ratio = 0.0f;
19041+
if (loh_size != 0)
19042+
{
19043+
size_t loh_frag = get_total_gen_fragmentation (loh_generation);
19044+
size_t gen2_frag = get_total_gen_fragmentation (max_generation);
19045+
loh_frag_ratio = (float)loh_frag / (float)loh_size;
19046+
combined_frag_ratio = (float)(gen2_frag + loh_frag) / (float)(gen2_size + loh_size);
19047+
}
19048+
if (combined_frag_ratio > frag_limit)
19049+
{
19050+
dprintf (GTC_LOG, ("combined frag: %f > limit %f, loh frag: %f", combined_frag_ratio, frag_limit, loh_frag_ratio));
19051+
gc_data_global.gen_to_condemn_reasons.set_condition (gen_max_high_frag_p);
19052+
19053+
n = max_generation;
19054+
*blocking_collection_p = TRUE;
19055+
if (loh_frag_ratio > frag_limit)
19056+
{
19057+
settings.loh_compaction = TRUE;
19058+
19059+
dprintf (GTC_LOG, ("compacting LOH due to GCConserveMem setting"));
19060+
}
19061+
}
19062+
}
19063+
1902519064
#ifdef BGC_SERVO_TUNING
1902619065
if (bgc_tuning::should_trigger_ngc2())
1902719066
{
@@ -24180,6 +24219,21 @@ size_t gc_heap::get_total_gen_estimated_reclaim (int gen_number)
2418024219
return total_estimated_reclaim;
2418124220
}
2418224221

24222+
size_t gc_heap::get_total_gen_size (int gen_number)
24223+
{
24224+
#ifdef MULTIPLE_HEAPS
24225+
size_t size = 0;
24226+
for (int hn = 0; hn < gc_heap::n_heaps; hn++)
24227+
{
24228+
gc_heap* hp = gc_heap::g_heaps[hn];
24229+
size += hp->generation_size (gen_number);
24230+
}
24231+
#else
24232+
size_t size = generation_size (gen_number);
24233+
#endif //MULTIPLE_HEAPS
24234+
return size;
24235+
}
24236+
2418324237
size_t gc_heap::committed_size()
2418424238
{
2418524239
size_t total_committed = 0;
@@ -26341,7 +26395,7 @@ BOOL gc_heap::plan_loh()
2634126395

2634226396
void gc_heap::compact_loh()
2634326397
{
26344-
assert (loh_compaction_requested() || heap_hard_limit);
26398+
assert (loh_compaction_requested() || heap_hard_limit || conserve_mem_setting);
2634526399

2634626400
#ifdef FEATURE_EVENT_TRACE
2634726401
uint64_t start_time, end_time;
@@ -38122,6 +38176,19 @@ size_t gc_heap::desired_new_allocation (dynamic_data* dd,
3812238176
cst = min (1.0f, float (out) / float (dd_begin_data_size (dd)));
3812338177

3812438178
f = surv_to_growth (cst, limit, max_limit);
38179+
if (conserve_mem_setting != 0)
38180+
{
38181+
// if this is set, compute a growth factor based on it.
38182+
// example: a setting of 6 means we have a goal of 60% live data
38183+
// this means we allow 40% fragmentation
38184+
// to keep heap size stable, we only use half of that (20%) for new allocation
38185+
// f is (live data + new allocation)/(live data), so would be (60% + 20%) / 60% or 1.33
38186+
float f_conserve = ((10.0f / conserve_mem_setting) - 1) * 0.5f + 1.0f;
38187+
38188+
// use the smaller one
38189+
f = min (f, f_conserve);
38190+
}
38191+
3812538192
size_t max_growth_size = (size_t)(max_size / f);
3812638193
if (current_size >= max_growth_size)
3812738194
{
@@ -38145,6 +38212,7 @@ size_t gc_heap::desired_new_allocation (dynamic_data* dd,
3814538212
#ifdef BGC_SERVO_TUNING
3814638213
!bgc_tuning::fl_tuning_triggered &&
3814738214
#endif //BGC_SERVO_TUNING
38215+
(conserve_mem_setting == 0) &&
3814838216
(dd_fragmentation (dd) > ((size_t)((f-1)*current_size))))
3814938217
{
3815038218
//reducing allocation in case of fragmentation

src/coreclr/gc/gcconfig.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ class GCConfigStringHolder
133133
INT_CONFIG (GCHeapHardLimitLOHPercent, "GCHeapHardLimitLOHPercent", "System.GC.HeapHardLimitLOHPercent", 0, "Specifies the GC heap LOH usage as a percentage of the total memory") \
134134
INT_CONFIG (GCHeapHardLimitPOHPercent, "GCHeapHardLimitPOHPercent", "System.GC.HeapHardLimitPOHPercent", 0, "Specifies the GC heap POH usage as a percentage of the total memory") \
135135
INT_CONFIG (GCEnabledInstructionSets, "GCEnabledInstructionSets", NULL, -1, "Specifies whether GC can use AVX2 or AVX512F - 0 for neither, 1 for AVX2, 3 for AVX512F")\
136+
INT_CONFIG (GCConserveMem, "GCConserveMemory", NULL, 0, "Specifies how hard GC should try to conserve memory - values 0-9") \
136137

137138
// This class is responsible for retreiving configuration information
138139
// for how the GC should operate.

src/coreclr/gc/gcpriv.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3218,6 +3218,8 @@ class gc_heap
32183218
PER_HEAP_ISOLATED
32193219
size_t get_total_gen_estimated_reclaim (int gen_number);
32203220
PER_HEAP_ISOLATED
3221+
size_t get_total_gen_size (int gen_number);
3222+
PER_HEAP_ISOLATED
32213223
void get_memory_info (uint32_t* memory_load,
32223224
uint64_t* available_physical=NULL,
32233225
uint64_t* available_page_file=NULL);
@@ -4694,6 +4696,9 @@ class gc_heap
46944696
PER_HEAP_ISOLATED
46954697
int generation_skip_ratio_threshold;
46964698

4699+
PER_HEAP_ISOLATED
4700+
int conserve_mem_setting;
4701+
46974702
PER_HEAP
46984703
BOOL gen0_bricks_cleared;
46994704
PER_HEAP

0 commit comments

Comments
 (0)