From dd5a82673f341e2f284f336b7bad9385b018e67c Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Mon, 14 Aug 2023 09:56:15 -0300 Subject: [PATCH 1/4] Change the heuristics to use heap size instead of collected memory --- src/gc.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/gc.c b/src/gc.c index 1603213d94efa..6a416b0f713b3 100644 --- a/src/gc.c +++ b/src/gc.c @@ -691,11 +691,11 @@ static const size_t default_collect_interval = 3200 * 1024 * sizeof(void*); static memsize_t max_total_memory = (memsize_t) MAX32HEAP; #endif // heuristic stuff for https://dl.acm.org/doi/10.1145/3563323 -static uint64_t old_pause_time = 0; -static uint64_t old_mut_time = 0; +static uint64_t pause_time_avg = 0; +static uint64_t mut_time_avg = 0; static uint64_t old_heap_size = 0; -static uint64_t old_alloc_diff = 0; -static uint64_t old_freed_diff = 0; +static uint64_t alloc_diff_avg = 0; +static uint64_t heap_size_avg = 0; static uint64_t gc_end_time = 0; static int thrash_counter = 0; static int thrashing = 0; @@ -3326,18 +3326,17 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) double min_interval = default_collect_interval; if (collection == JL_GC_AUTO) { uint64_t alloc_diff = before_free_heap_size - old_heap_size; - uint64_t freed_diff = before_free_heap_size - heap_size; double alloc_smooth_factor = 0.95; double collect_smooth_factor = 0.5; double tuning_factor = 0.03; - double alloc_mem = jl_gc_smooth(old_alloc_diff, alloc_diff, alloc_smooth_factor); - double alloc_time = jl_gc_smooth(old_mut_time, mutator_time + sweep_time, alloc_smooth_factor); // Charge sweeping to the mutator - double gc_mem = jl_gc_smooth(old_freed_diff, freed_diff, collect_smooth_factor); - double gc_time = jl_gc_smooth(old_pause_time, pause - sweep_time, collect_smooth_factor); - old_alloc_diff = alloc_diff; - old_mut_time = mutator_time; - old_freed_diff = freed_diff; - old_pause_time = pause; + double alloc_mem = jl_gc_smooth(alloc_diff_avg, alloc_diff, alloc_smooth_factor); + double alloc_time = jl_gc_smooth(mut_time_avg, mutator_time + sweep_time, alloc_smooth_factor); // Charge sweeping to the mutator + double gc_mem = jl_gc_smooth(heap_size_avg, heap_size, collect_smooth_factor); + double gc_time = jl_gc_smooth(pause_time_avg, pause - sweep_time, collect_smooth_factor); + alloc_diff_avg = alloc_mem; + mut_time_avg = alloc_time; + heap_size_avg = gc_mem; + pause_time_avg = pause; old_heap_size = heap_size; // TODO: Update these values dynamically instead of just during the GC if (gc_time > alloc_time * 95 && !(thrash_counter < 4)) thrash_counter += 1; From 89f3578d85a4ee117cb49e3d31730eeee4d5e50f Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Tue, 12 Sep 2023 16:38:00 -0300 Subject: [PATCH 2/4] Make the pacer more like the V8 implementation --- src/gc.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/gc.c b/src/gc.c index c8c3892643ec0..f33a40888ce7f 100644 --- a/src/gc.c +++ b/src/gc.c @@ -695,7 +695,6 @@ static uint64_t pause_time_avg = 0; static uint64_t mut_time_avg = 0; static uint64_t old_heap_size = 0; static uint64_t alloc_diff_avg = 0; -static uint64_t heap_size_avg = 0; static uint64_t gc_end_time = 0; static int thrash_counter = 0; static int thrashing = 0; @@ -3317,28 +3316,26 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) size_t heap_size = jl_atomic_load_relaxed(&gc_heap_stats.heap_size); double target_allocs = 0.0; double min_interval = default_collect_interval; + double tuning_factor = 3e-10; if (collection == JL_GC_AUTO) { uint64_t alloc_diff = before_free_heap_size - old_heap_size; double alloc_smooth_factor = 0.95; double collect_smooth_factor = 0.5; - double tuning_factor = 0.03; double alloc_mem = jl_gc_smooth(alloc_diff_avg, alloc_diff, alloc_smooth_factor); double alloc_time = jl_gc_smooth(mut_time_avg, mutator_time + sweep_time, alloc_smooth_factor); // Charge sweeping to the mutator - double gc_mem = jl_gc_smooth(heap_size_avg, heap_size, collect_smooth_factor); double gc_time = jl_gc_smooth(pause_time_avg, pause - sweep_time, collect_smooth_factor); alloc_diff_avg = alloc_mem; mut_time_avg = alloc_time; - heap_size_avg = gc_mem; pause_time_avg = pause; old_heap_size = heap_size; // TODO: Update these values dynamically instead of just during the GC if (gc_time > alloc_time * 95 && !(thrash_counter < 4)) thrash_counter += 1; else if (thrash_counter > 0) thrash_counter -= 1; - if (alloc_mem != 0 && alloc_time != 0 && gc_mem != 0 && gc_time != 0 ) { + if (alloc_mem != 0 && alloc_time != 0 && heap_size != 0 && gc_time != 0 ) { double alloc_rate = alloc_mem/alloc_time; - double gc_rate = gc_mem/gc_time; - target_allocs = sqrt(((double)heap_size/min_interval * alloc_rate)/(gc_rate * tuning_factor)); // work on multiples of min interval + double gc_rate = heap_size/gc_time; + target_allocs = sqrt((double)heap_size * alloc_rate/gc_rate / tuning_factor); // work on multiples of min interval } } if (thrashing == 0 && thrash_counter >= 3) @@ -3348,7 +3345,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) int bad_result = (target_allocs*min_interval + heap_size) > 2 * jl_atomic_load_relaxed(&gc_heap_stats.heap_target); // Don't follow through on a bad decision if (target_allocs == 0.0 || thrashing || bad_result) // If we are thrashing go back to default - target_allocs = 2*sqrt((double)heap_size/min_interval); + target_allocs = 2*sqrt((double)heap_size / tuning_factor); uint64_t target_heap = (uint64_t)target_allocs*min_interval + heap_size; if (target_heap > max_total_memory && !thrashing) // Allow it to go over if we are thrashing if we die we die target_heap = max_total_memory; From 6b66a1a153a3088fb666ec252f010e62f171a925 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Mon, 18 Sep 2023 11:37:35 -0300 Subject: [PATCH 3/4] Reduce tuning_factor --- src/gc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gc.c b/src/gc.c index f33a40888ce7f..13f3abc8b7c17 100644 --- a/src/gc.c +++ b/src/gc.c @@ -3316,7 +3316,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) size_t heap_size = jl_atomic_load_relaxed(&gc_heap_stats.heap_size); double target_allocs = 0.0; double min_interval = default_collect_interval; - double tuning_factor = 3e-10; + double tuning_factor = 7e-10; if (collection == JL_GC_AUTO) { uint64_t alloc_diff = before_free_heap_size - old_heap_size; double alloc_smooth_factor = 0.95; From b19f2e644b505bd296aec54bff2f4cd94c05701b Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Wed, 20 Sep 2023 13:41:21 -0300 Subject: [PATCH 4/4] Make the GC less greedy --- src/gc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gc.c b/src/gc.c index 13f3abc8b7c17..ab86898505e81 100644 --- a/src/gc.c +++ b/src/gc.c @@ -3316,7 +3316,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) size_t heap_size = jl_atomic_load_relaxed(&gc_heap_stats.heap_size); double target_allocs = 0.0; double min_interval = default_collect_interval; - double tuning_factor = 7e-10; + double tuning_factor = 3e-9; if (collection == JL_GC_AUTO) { uint64_t alloc_diff = before_free_heap_size - old_heap_size; double alloc_smooth_factor = 0.95; @@ -3345,7 +3345,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) int bad_result = (target_allocs*min_interval + heap_size) > 2 * jl_atomic_load_relaxed(&gc_heap_stats.heap_target); // Don't follow through on a bad decision if (target_allocs == 0.0 || thrashing || bad_result) // If we are thrashing go back to default - target_allocs = 2*sqrt((double)heap_size / tuning_factor); + target_allocs = sqrt((double)heap_size / tuning_factor); uint64_t target_heap = (uint64_t)target_allocs*min_interval + heap_size; if (target_heap > max_total_memory && !thrashing) // Allow it to go over if we are thrashing if we die we die target_heap = max_total_memory;