11// This file is a part of Julia. License is MIT: https://julialang.org/license
22
33#include "gc.h"
4+ #include "julia.h"
45#include "julia_gcext.h"
56#include "julia_assert.h"
67#ifdef __GLIBC__
@@ -805,8 +806,8 @@ static uint64_t old_heap_size = 0;
805806static uint64_t old_alloc_diff = 0 ;
806807static uint64_t old_freed_diff = 0 ;
807808static uint64_t gc_end_time = 0 ;
808-
809-
809+ static int thrash_counter = 0 ;
810+ static int thrashing = 0 ;
810811// global variables for GC stats
811812
812813// Resetting the object to a young object, this is used when marking the
@@ -1277,7 +1278,10 @@ static void combine_thread_gc_counts(jl_gc_num_t *dest) JL_NOTSAFEPOINT
12771278 dest -> bigalloc += jl_atomic_load_relaxed (& ptls -> gc_num .bigalloc );
12781279 uint64_t alloc_acc = jl_atomic_load_relaxed (& ptls -> gc_num .alloc_acc );
12791280 uint64_t free_acc = jl_atomic_load_relaxed (& ptls -> gc_num .free_acc );
1281+ dest -> freed += jl_atomic_load_relaxed (& ptls -> gc_num .free_acc );
12801282 jl_atomic_store_relaxed (& gc_heap_stats .heap_size , alloc_acc - free_acc + jl_atomic_load_relaxed (& gc_heap_stats .heap_size ));
1283+ jl_atomic_store_relaxed (& ptls -> gc_num .alloc_acc , 0 );
1284+ jl_atomic_store_relaxed (& ptls -> gc_num .free_acc , 0 );
12811285 }
12821286 }
12831287}
@@ -3363,9 +3367,6 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
33633367 // If the live data outgrows the suggested max_total_memory
33643368 // we keep going with minimum intervals and full gcs until
33653369 // we either free some space or get an OOM error.
3366- if (live_bytes > max_total_memory ) {
3367- sweep_full = 1 ;
3368- }
33693370 if (gc_sweep_always_full ) {
33703371 sweep_full = 1 ;
33713372 }
@@ -3408,7 +3409,6 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
34083409 gc_num .last_incremental_sweep = gc_end_time ;
34093410 }
34103411
3411- int thrashing = 0 ; // maybe we should report this to the user or error out?
34123412 size_t heap_size = jl_atomic_load_relaxed (& gc_heap_stats .heap_size );
34133413 double target_allocs = 0.0 ;
34143414 double min_interval = default_collect_interval ;
@@ -3419,24 +3419,32 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
34193419 double collect_smooth_factor = 0.5 ;
34203420 double tuning_factor = 0.03 ;
34213421 double alloc_mem = jl_gc_smooth (old_alloc_diff , alloc_diff , alloc_smooth_factor );
3422- double alloc_time = jl_gc_smooth (old_mut_time , mutator_time , alloc_smooth_factor );
3422+ double alloc_time = jl_gc_smooth (old_mut_time , mutator_time + sweep_time , alloc_smooth_factor ); // Charge sweeping to the mutator
34233423 double gc_mem = jl_gc_smooth (old_freed_diff , freed_diff , collect_smooth_factor );
3424- double gc_time = jl_gc_smooth (old_pause_time , pause , collect_smooth_factor );
3424+ double gc_time = jl_gc_smooth (old_pause_time , pause - sweep_time , collect_smooth_factor );
34253425 old_alloc_diff = alloc_diff ;
34263426 old_mut_time = mutator_time ;
34273427 old_freed_diff = freed_diff ;
34283428 old_pause_time = pause ;
3429- old_heap_size = heap_size ;
3430- thrashing = gc_time > mutator_time * 98 ? 1 : 0 ;
3429+ old_heap_size = heap_size ; // TODO: Update these values dynamically instead of just during the GC
3430+ if (gc_time > alloc_time * 95 && !(thrash_counter < 4 ))
3431+ thrash_counter += 1 ;
3432+ else if (thrash_counter > 0 )
3433+ thrash_counter -= 1 ;
34313434 if (alloc_mem != 0 && alloc_time != 0 && gc_mem != 0 && gc_time != 0 ) {
34323435 double alloc_rate = alloc_mem /alloc_time ;
34333436 double gc_rate = gc_mem /gc_time ;
34343437 target_allocs = sqrt (((double )heap_size /min_interval * alloc_rate )/(gc_rate * tuning_factor )); // work on multiples of min interval
34353438 }
34363439 }
3437- if (target_allocs == 0.0 || thrashing ) // If we are thrashing go back to default
3438- target_allocs = 2 * sqrt ((double )heap_size /min_interval );
3440+ if (thrashing == 0 && thrash_counter >= 3 )
3441+ thrashing = 1 ;
3442+ else if (thrashing == 1 && thrash_counter <= 2 )
3443+ thrashing = 0 ; // maybe we should report this to the user or error out?
34393444
3445+ 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
3446+ if (target_allocs == 0.0 || thrashing || bad_result ) // If we are thrashing go back to default
3447+ target_allocs = 2 * sqrt ((double )heap_size /min_interval );
34403448 uint64_t target_heap = (uint64_t )target_allocs * min_interval + heap_size ;
34413449 if (target_heap > max_total_memory && !thrashing ) // Allow it to go over if we are thrashing if we die we die
34423450 target_heap = max_total_memory ;
@@ -3704,10 +3712,11 @@ void jl_gc_init(void)
37043712 total_mem = uv_get_total_memory ();
37053713 uint64_t constrained_mem = uv_get_constrained_memory ();
37063714 if (constrained_mem > 0 && constrained_mem < total_mem )
3707- total_mem = constrained_mem ;
3715+ jl_gc_set_max_memory ( constrained_mem - 250 * 1024 * 1024 ); // LLVM + other libraries need some amount of memory
37083716#endif
37093717 if (jl_options .heap_size_hint )
3710- jl_gc_set_max_memory (jl_options .heap_size_hint );
3718+ jl_gc_set_max_memory (jl_options .heap_size_hint - 250 * 1024 * 1024 );
3719+
37113720 t_start = jl_hrtime ();
37123721}
37133722
@@ -3808,7 +3817,26 @@ JL_DLLEXPORT void *jl_gc_counted_realloc_with_old_size(void *p, size_t old, size
38083817 jl_atomic_load_relaxed (& ptls -> gc_num .allocd ) + (sz - old ));
38093818 jl_atomic_store_relaxed (& ptls -> gc_num .realloc ,
38103819 jl_atomic_load_relaxed (& ptls -> gc_num .realloc ) + 1 );
3811- jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , sz - old );
3820+
3821+ int64_t diff = sz - old ;
3822+ if (diff < 0 ) {
3823+ uint64_t free_acc = jl_atomic_load_relaxed (& ptls -> gc_num .free_acc );
3824+ if (free_acc + diff < 16 * 1024 )
3825+ jl_atomic_store_relaxed (& ptls -> gc_num .free_acc , free_acc + (- diff ));
3826+ else {
3827+ jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , - (free_acc + (- diff )));
3828+ jl_atomic_store_relaxed (& ptls -> gc_num .free_acc , 0 );
3829+ }
3830+ }
3831+ else {
3832+ uint64_t alloc_acc = jl_atomic_load_relaxed (& ptls -> gc_num .alloc_acc );
3833+ if (alloc_acc + diff < 16 * 1024 )
3834+ jl_atomic_store_relaxed (& ptls -> gc_num .alloc_acc , alloc_acc + diff );
3835+ else {
3836+ jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , alloc_acc + diff );
3837+ jl_atomic_store_relaxed (& ptls -> gc_num .alloc_acc , 0 );
3838+ }
3839+ }
38123840 }
38133841 return realloc (p , sz );
38143842}
@@ -3925,7 +3953,27 @@ static void *gc_managed_realloc_(jl_ptls_t ptls, void *d, size_t sz, size_t olds
39253953 jl_atomic_load_relaxed (& ptls -> gc_num .allocd ) + (allocsz - oldsz ));
39263954 jl_atomic_store_relaxed (& ptls -> gc_num .realloc ,
39273955 jl_atomic_load_relaxed (& ptls -> gc_num .realloc ) + 1 );
3928- jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , allocsz - oldsz );
3956+
3957+ int64_t diff = allocsz - oldsz ;
3958+ if (diff < 0 ) {
3959+ uint64_t free_acc = jl_atomic_load_relaxed (& ptls -> gc_num .free_acc );
3960+ if (free_acc + diff < 16 * 1024 )
3961+ jl_atomic_store_relaxed (& ptls -> gc_num .free_acc , free_acc + (- diff ));
3962+ else {
3963+ jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , - (free_acc + (- diff )));
3964+ jl_atomic_store_relaxed (& ptls -> gc_num .free_acc , 0 );
3965+ }
3966+ }
3967+ else {
3968+ uint64_t alloc_acc = jl_atomic_load_relaxed (& ptls -> gc_num .alloc_acc );
3969+ if (alloc_acc + diff < 16 * 1024 )
3970+ jl_atomic_store_relaxed (& ptls -> gc_num .alloc_acc , alloc_acc + diff );
3971+ else {
3972+ jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , alloc_acc + diff );
3973+ jl_atomic_store_relaxed (& ptls -> gc_num .alloc_acc , 0 );
3974+ }
3975+ }
3976+
39293977 int last_errno = errno ;
39303978#ifdef _OS_WINDOWS_
39313979 DWORD last_error = GetLastError ();
0 commit comments