1
1
// This file is a part of Julia. License is MIT: https://julialang.org/license
2
2
3
3
#include "gc.h"
4
+ #include "julia.h"
4
5
#include "julia_gcext.h"
5
6
#include "julia_assert.h"
6
7
#ifdef __GLIBC__
@@ -805,8 +806,8 @@ static uint64_t old_heap_size = 0;
805
806
static uint64_t old_alloc_diff = 0 ;
806
807
static uint64_t old_freed_diff = 0 ;
807
808
static uint64_t gc_end_time = 0 ;
808
-
809
-
809
+ static int thrash_counter = 0 ;
810
+ static int thrashing = 0 ;
810
811
// global variables for GC stats
811
812
812
813
// 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
1277
1278
dest -> bigalloc += jl_atomic_load_relaxed (& ptls -> gc_num .bigalloc );
1278
1279
uint64_t alloc_acc = jl_atomic_load_relaxed (& ptls -> gc_num .alloc_acc );
1279
1280
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 );
1280
1282
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 );
1281
1285
}
1282
1286
}
1283
1287
}
@@ -3363,9 +3367,6 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
3363
3367
// If the live data outgrows the suggested max_total_memory
3364
3368
// we keep going with minimum intervals and full gcs until
3365
3369
// we either free some space or get an OOM error.
3366
- if (live_bytes > max_total_memory ) {
3367
- sweep_full = 1 ;
3368
- }
3369
3370
if (gc_sweep_always_full ) {
3370
3371
sweep_full = 1 ;
3371
3372
}
@@ -3408,7 +3409,6 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
3408
3409
gc_num .last_incremental_sweep = gc_end_time ;
3409
3410
}
3410
3411
3411
- int thrashing = 0 ; // maybe we should report this to the user or error out?
3412
3412
size_t heap_size = jl_atomic_load_relaxed (& gc_heap_stats .heap_size );
3413
3413
double target_allocs = 0.0 ;
3414
3414
double min_interval = default_collect_interval ;
@@ -3419,24 +3419,32 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
3419
3419
double collect_smooth_factor = 0.5 ;
3420
3420
double tuning_factor = 0.03 ;
3421
3421
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
3423
3423
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 );
3425
3425
old_alloc_diff = alloc_diff ;
3426
3426
old_mut_time = mutator_time ;
3427
3427
old_freed_diff = freed_diff ;
3428
3428
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 ;
3431
3434
if (alloc_mem != 0 && alloc_time != 0 && gc_mem != 0 && gc_time != 0 ) {
3432
3435
double alloc_rate = alloc_mem /alloc_time ;
3433
3436
double gc_rate = gc_mem /gc_time ;
3434
3437
target_allocs = sqrt (((double )heap_size /min_interval * alloc_rate )/(gc_rate * tuning_factor )); // work on multiples of min interval
3435
3438
}
3436
3439
}
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?
3439
3444
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 );
3440
3448
uint64_t target_heap = (uint64_t )target_allocs * min_interval + heap_size ;
3441
3449
if (target_heap > max_total_memory && !thrashing ) // Allow it to go over if we are thrashing if we die we die
3442
3450
target_heap = max_total_memory ;
@@ -3704,10 +3712,11 @@ void jl_gc_init(void)
3704
3712
total_mem = uv_get_total_memory ();
3705
3713
uint64_t constrained_mem = uv_get_constrained_memory ();
3706
3714
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
3708
3716
#endif
3709
3717
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
+
3711
3720
t_start = jl_hrtime ();
3712
3721
}
3713
3722
@@ -3808,7 +3817,26 @@ JL_DLLEXPORT void *jl_gc_counted_realloc_with_old_size(void *p, size_t old, size
3808
3817
jl_atomic_load_relaxed (& ptls -> gc_num .allocd ) + (sz - old ));
3809
3818
jl_atomic_store_relaxed (& ptls -> gc_num .realloc ,
3810
3819
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
+ }
3812
3840
}
3813
3841
return realloc (p , sz );
3814
3842
}
@@ -3925,7 +3953,27 @@ static void *gc_managed_realloc_(jl_ptls_t ptls, void *d, size_t sz, size_t olds
3925
3953
jl_atomic_load_relaxed (& ptls -> gc_num .allocd ) + (allocsz - oldsz ));
3926
3954
jl_atomic_store_relaxed (& ptls -> gc_num .realloc ,
3927
3955
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
+
3929
3977
int last_errno = errno ;
3930
3978
#ifdef _OS_WINDOWS_
3931
3979
DWORD last_error = GetLastError ();
0 commit comments