From cdc50ac84ee126408a7c797ebc21dcdbfb7eeae9 Mon Sep 17 00:00:00 2001 From: Peter Sollich Date: Mon, 5 Jul 2021 15:19:42 +0200 Subject: [PATCH 1/3] Add a time-based decay to the linear allocation model. Real world scenario that motivated this allocated a huge amount of data once a day, leading to high gen 0 and gen 1 budgets (several GB). After this, there was relatively little activity, cause gen 1 budget to take several hours to normalize. The new logic discounts the previous desired allocation over a period of 5 minutes. --- src/coreclr/gc/gc.cpp | 27 ++++++++++++++------------- src/coreclr/gc/gcpriv.h | 7 +++++++ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index 1d58d35ce866b..c7dacf50d14c0 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -20254,6 +20254,7 @@ void gc_heap::update_collection_counts () } dd_gc_clock (dd) = dd_gc_clock (dd0); + dd_previous_time_clock (dd) = dd_time_clock (dd); dd_time_clock (dd) = now; } } @@ -36701,6 +36702,7 @@ bool gc_heap::init_dynamic_data() dynamic_data* dd = dynamic_data_of (i); dd->gc_clock = 0; dd->time_clock = now; + dd->previous_time_clock = now; dd->current_size = 0; dd->promoted_size = 0; dd->collection_count = 0; @@ -36726,21 +36728,17 @@ float gc_heap::surv_to_growth (float cst, float limit, float max_limit) //not be correct (collection happened too soon). Correct with a linear estimation based on the previous //value of the budget static size_t linear_allocation_model (float allocation_fraction, size_t new_allocation, - size_t previous_desired_allocation, size_t collection_count) + size_t previous_desired_allocation, float time_since_previous_collection_secs) { if ((allocation_fraction < 0.95) && (allocation_fraction > 0.0)) { + const float decay_time = 5*60.0f; // previous desired allocation expires over 5 minutes + float decay_factor = (decay_time <= time_since_previous_collection_secs) ? + 0 : + ((decay_time - time_since_previous_collection_secs) / decay_time); dprintf (2, ("allocation fraction: %d", (int)(allocation_fraction/100.0))); - new_allocation = (size_t)(allocation_fraction*new_allocation + (1.0-allocation_fraction)*previous_desired_allocation); + new_allocation = (size_t)(allocation_fraction*new_allocation + (1.0-allocation_fraction)*decay_factor*previous_desired_allocation); } -#if 0 - size_t smoothing = 3; // exponential smoothing factor - if (smoothing > collection_count) - smoothing = collection_count; - new_allocation = new_allocation / smoothing + ((previous_desired_allocation / smoothing) * (smoothing-1)); -#else - UNREFERENCED_PARAMETER(collection_count); -#endif //0 return new_allocation; } @@ -36767,6 +36765,9 @@ size_t gc_heap::desired_new_allocation (dynamic_data* dd, float f = 0; size_t max_size = dd_max_size (dd); size_t new_allocation = 0; + float time_since_previous_collection_secs = (dd_time_clock (dd) - dd_previous_time_clock (dd))*1e-6f; + + float allocation_fraction = (float) (dd_desired_allocation (dd) - dd_gc_new_allocation (dd)) / (float) (dd_desired_allocation (dd)); if (gen_number >= max_generation) @@ -36793,7 +36794,7 @@ size_t gc_heap::desired_new_allocation (dynamic_data* dd, new_allocation = max((new_size - current_size), min_gc_size); new_allocation = linear_allocation_model (allocation_fraction, new_allocation, - dd_desired_allocation (dd), dd_collection_count (dd)); + dd_desired_allocation (dd), time_since_previous_collection_secs); if ( #ifdef BGC_SERVO_TUNING @@ -36845,7 +36846,7 @@ size_t gc_heap::desired_new_allocation (dynamic_data* dd, max ((current_size/4), min_gc_size)); new_allocation = linear_allocation_model (allocation_fraction, new_allocation, - dd_desired_allocation (dd), dd_collection_count (dd)); + dd_desired_allocation (dd), time_since_previous_collection_secs); } } @@ -36857,7 +36858,7 @@ size_t gc_heap::desired_new_allocation (dynamic_data* dd, new_allocation = (size_t) min (max ((f * (survivors)), min_gc_size), max_size); new_allocation = linear_allocation_model (allocation_fraction, new_allocation, - dd_desired_allocation (dd), dd_collection_count (dd)); + dd_desired_allocation (dd), time_since_previous_collection_secs); if (gen_number == 0) { diff --git a/src/coreclr/gc/gcpriv.h b/src/coreclr/gc/gcpriv.h index 09bd97d189188..7251945ef4b94 100644 --- a/src/coreclr/gc/gcpriv.h +++ b/src/coreclr/gc/gcpriv.h @@ -885,6 +885,7 @@ class dynamic_data size_t fragmentation; //fragmentation when we don't compact size_t gc_clock; //gc# when last GC happened uint64_t time_clock; //time when last gc started + uint64_t previous_time_clock; // time when previous gc started size_t gc_elapsed_time; // Time it took for the gc to complete float gc_speed; // speed in bytes/msec for the gc to complete @@ -5004,6 +5005,12 @@ uint64_t& dd_time_clock (dynamic_data* inst) { return inst->time_clock; } +inline +uint64_t& dd_previous_time_clock (dynamic_data* inst) +{ + return inst->previous_time_clock; +} + inline size_t& dd_gc_clock_interval (dynamic_data* inst) From 24a65c74108ef6c3d93297657e40389614866969 Mon Sep 17 00:00:00 2001 From: Peter Sollich Date: Wed, 7 Jul 2021 15:16:16 +0200 Subject: [PATCH 2/3] Remove extraneous empty lines. --- src/coreclr/gc/gc.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index c7dacf50d14c0..cb7868e4c6262 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -36766,8 +36766,6 @@ size_t gc_heap::desired_new_allocation (dynamic_data* dd, size_t max_size = dd_max_size (dd); size_t new_allocation = 0; float time_since_previous_collection_secs = (dd_time_clock (dd) - dd_previous_time_clock (dd))*1e-6f; - - float allocation_fraction = (float) (dd_desired_allocation (dd) - dd_gc_new_allocation (dd)) / (float) (dd_desired_allocation (dd)); if (gen_number >= max_generation) From 13f87e03c33d329591c2bd96b633de95f56ea171 Mon Sep 17 00:00:00 2001 From: Peter Sollich Date: Wed, 14 Jul 2021 11:16:51 +0200 Subject: [PATCH 3/3] Corrected a problem in the computation of the new allocation pointed out in code review. --- src/coreclr/gc/gc.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp index cb7868e4c6262..4513aa51813e0 100644 --- a/src/coreclr/gc/gc.cpp +++ b/src/coreclr/gc/gc.cpp @@ -36736,8 +36736,10 @@ static size_t linear_allocation_model (float allocation_fraction, size_t new_all float decay_factor = (decay_time <= time_since_previous_collection_secs) ? 0 : ((decay_time - time_since_previous_collection_secs) / decay_time); - dprintf (2, ("allocation fraction: %d", (int)(allocation_fraction/100.0))); - new_allocation = (size_t)(allocation_fraction*new_allocation + (1.0-allocation_fraction)*decay_factor*previous_desired_allocation); + float previous_allocation_factor = (1.0f - allocation_fraction) * decay_factor; + dprintf (2, ("allocation fraction: %d, decay factor: %d, previous allocation factor: %d", + (int)(allocation_fraction*100.0), (int)(decay_factor*100.0), (int)(previous_allocation_factor*100.0))); + new_allocation = (size_t)((1.0 - previous_allocation_factor)*new_allocation + previous_allocation_factor * previous_desired_allocation); } return new_allocation; }