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__
@@ -696,8 +697,8 @@ static uint64_t old_heap_size = 0;
696
697
static uint64_t old_alloc_diff = 0 ;
697
698
static uint64_t old_freed_diff = 0 ;
698
699
static uint64_t gc_end_time = 0 ;
699
-
700
-
700
+ static int thrash_counter = 0 ;
701
+ static int thrashing = 0 ;
701
702
// global variables for GC stats
702
703
703
704
// Resetting the object to a young object, this is used when marking the
@@ -1170,7 +1171,10 @@ static void combine_thread_gc_counts(jl_gc_num_t *dest) JL_NOTSAFEPOINT
1170
1171
dest -> bigalloc += jl_atomic_load_relaxed (& ptls -> gc_num .bigalloc );
1171
1172
uint64_t alloc_acc = jl_atomic_load_relaxed (& ptls -> gc_num .alloc_acc );
1172
1173
uint64_t free_acc = jl_atomic_load_relaxed (& ptls -> gc_num .free_acc );
1174
+ dest -> freed += jl_atomic_load_relaxed (& ptls -> gc_num .free_acc );
1173
1175
jl_atomic_store_relaxed (& gc_heap_stats .heap_size , alloc_acc - free_acc + jl_atomic_load_relaxed (& gc_heap_stats .heap_size ));
1176
+ jl_atomic_store_relaxed (& ptls -> gc_num .alloc_acc , 0 );
1177
+ jl_atomic_store_relaxed (& ptls -> gc_num .free_acc , 0 );
1174
1178
}
1175
1179
}
1176
1180
}
@@ -3266,9 +3270,6 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
3266
3270
// If the live data outgrows the suggested max_total_memory
3267
3271
// we keep going with minimum intervals and full gcs until
3268
3272
// we either free some space or get an OOM error.
3269
- if (live_bytes > max_total_memory ) {
3270
- sweep_full = 1 ;
3271
- }
3272
3273
if (gc_sweep_always_full ) {
3273
3274
sweep_full = 1 ;
3274
3275
}
@@ -3320,7 +3321,6 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
3320
3321
gc_num .last_incremental_sweep = gc_end_time ;
3321
3322
}
3322
3323
3323
- int thrashing = 0 ; // maybe we should report this to the user or error out?
3324
3324
size_t heap_size = jl_atomic_load_relaxed (& gc_heap_stats .heap_size );
3325
3325
double target_allocs = 0.0 ;
3326
3326
double min_interval = default_collect_interval ;
@@ -3331,24 +3331,32 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
3331
3331
double collect_smooth_factor = 0.5 ;
3332
3332
double tuning_factor = 0.03 ;
3333
3333
double alloc_mem = jl_gc_smooth (old_alloc_diff , alloc_diff , alloc_smooth_factor );
3334
- double alloc_time = jl_gc_smooth (old_mut_time , mutator_time , alloc_smooth_factor );
3334
+ double alloc_time = jl_gc_smooth (old_mut_time , mutator_time + sweep_time , alloc_smooth_factor ); // Charge sweeping to the mutator
3335
3335
double gc_mem = jl_gc_smooth (old_freed_diff , freed_diff , collect_smooth_factor );
3336
- double gc_time = jl_gc_smooth (old_pause_time , pause , collect_smooth_factor );
3336
+ double gc_time = jl_gc_smooth (old_pause_time , pause - sweep_time , collect_smooth_factor );
3337
3337
old_alloc_diff = alloc_diff ;
3338
3338
old_mut_time = mutator_time ;
3339
3339
old_freed_diff = freed_diff ;
3340
3340
old_pause_time = pause ;
3341
- old_heap_size = heap_size ;
3342
- thrashing = gc_time > mutator_time * 98 ? 1 : 0 ;
3341
+ old_heap_size = heap_size ; // TODO: Update these values dynamically instead of just during the GC
3342
+ if (gc_time > alloc_time * 95 && !(thrash_counter < 4 ))
3343
+ thrash_counter += 1 ;
3344
+ else if (thrash_counter > 0 )
3345
+ thrash_counter -= 1 ;
3343
3346
if (alloc_mem != 0 && alloc_time != 0 && gc_mem != 0 && gc_time != 0 ) {
3344
3347
double alloc_rate = alloc_mem /alloc_time ;
3345
3348
double gc_rate = gc_mem /gc_time ;
3346
3349
target_allocs = sqrt (((double )heap_size /min_interval * alloc_rate )/(gc_rate * tuning_factor )); // work on multiples of min interval
3347
3350
}
3348
3351
}
3349
- if (target_allocs == 0.0 || thrashing ) // If we are thrashing go back to default
3350
- target_allocs = 2 * sqrt ((double )heap_size /min_interval );
3352
+ if (thrashing == 0 && thrash_counter >= 3 )
3353
+ thrashing = 1 ;
3354
+ else if (thrashing == 1 && thrash_counter <= 2 )
3355
+ thrashing = 0 ; // maybe we should report this to the user or error out?
3351
3356
3357
+ 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
3358
+ if (target_allocs == 0.0 || thrashing || bad_result ) // If we are thrashing go back to default
3359
+ target_allocs = 2 * sqrt ((double )heap_size /min_interval );
3352
3360
uint64_t target_heap = (uint64_t )target_allocs * min_interval + heap_size ;
3353
3361
if (target_heap > max_total_memory && !thrashing ) // Allow it to go over if we are thrashing if we die we die
3354
3362
target_heap = max_total_memory ;
@@ -3612,10 +3620,10 @@ void jl_gc_init(void)
3612
3620
total_mem = uv_get_total_memory ();
3613
3621
uint64_t constrained_mem = uv_get_constrained_memory ();
3614
3622
if (constrained_mem > 0 && constrained_mem < total_mem )
3615
- total_mem = constrained_mem ;
3623
+ jl_gc_set_max_memory ( constrained_mem - 250 * 1024 * 1024 ); // LLVM + other libraries need some amount of memory
3616
3624
#endif
3617
3625
if (jl_options .heap_size_hint )
3618
- jl_gc_set_max_memory (jl_options .heap_size_hint );
3626
+ jl_gc_set_max_memory (jl_options .heap_size_hint - 250 * 1024 * 1024 );
3619
3627
3620
3628
t_start = jl_hrtime ();
3621
3629
}
@@ -3718,7 +3726,26 @@ JL_DLLEXPORT void *jl_gc_counted_realloc_with_old_size(void *p, size_t old, size
3718
3726
jl_atomic_load_relaxed (& ptls -> gc_num .allocd ) + (sz - old ));
3719
3727
jl_atomic_store_relaxed (& ptls -> gc_num .realloc ,
3720
3728
jl_atomic_load_relaxed (& ptls -> gc_num .realloc ) + 1 );
3721
- jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , sz - old );
3729
+
3730
+ int64_t diff = sz - old ;
3731
+ if (diff < 0 ) {
3732
+ uint64_t free_acc = jl_atomic_load_relaxed (& ptls -> gc_num .free_acc );
3733
+ if (free_acc + diff < 16 * 1024 )
3734
+ jl_atomic_store_relaxed (& ptls -> gc_num .free_acc , free_acc + (- diff ));
3735
+ else {
3736
+ jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , - (free_acc + (- diff )));
3737
+ jl_atomic_store_relaxed (& ptls -> gc_num .free_acc , 0 );
3738
+ }
3739
+ }
3740
+ else {
3741
+ uint64_t alloc_acc = jl_atomic_load_relaxed (& ptls -> gc_num .alloc_acc );
3742
+ if (alloc_acc + diff < 16 * 1024 )
3743
+ jl_atomic_store_relaxed (& ptls -> gc_num .alloc_acc , alloc_acc + diff );
3744
+ else {
3745
+ jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , alloc_acc + diff );
3746
+ jl_atomic_store_relaxed (& ptls -> gc_num .alloc_acc , 0 );
3747
+ }
3748
+ }
3722
3749
}
3723
3750
return realloc (p , sz );
3724
3751
}
@@ -3835,7 +3862,27 @@ static void *gc_managed_realloc_(jl_ptls_t ptls, void *d, size_t sz, size_t olds
3835
3862
jl_atomic_load_relaxed (& ptls -> gc_num .allocd ) + (allocsz - oldsz ));
3836
3863
jl_atomic_store_relaxed (& ptls -> gc_num .realloc ,
3837
3864
jl_atomic_load_relaxed (& ptls -> gc_num .realloc ) + 1 );
3838
- jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , allocsz - oldsz );
3865
+
3866
+ int64_t diff = allocsz - oldsz ;
3867
+ if (diff < 0 ) {
3868
+ uint64_t free_acc = jl_atomic_load_relaxed (& ptls -> gc_num .free_acc );
3869
+ if (free_acc + diff < 16 * 1024 )
3870
+ jl_atomic_store_relaxed (& ptls -> gc_num .free_acc , free_acc + (- diff ));
3871
+ else {
3872
+ jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , - (free_acc + (- diff )));
3873
+ jl_atomic_store_relaxed (& ptls -> gc_num .free_acc , 0 );
3874
+ }
3875
+ }
3876
+ else {
3877
+ uint64_t alloc_acc = jl_atomic_load_relaxed (& ptls -> gc_num .alloc_acc );
3878
+ if (alloc_acc + diff < 16 * 1024 )
3879
+ jl_atomic_store_relaxed (& ptls -> gc_num .alloc_acc , alloc_acc + diff );
3880
+ else {
3881
+ jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , alloc_acc + diff );
3882
+ jl_atomic_store_relaxed (& ptls -> gc_num .alloc_acc , 0 );
3883
+ }
3884
+ }
3885
+
3839
3886
int last_errno = errno ;
3840
3887
#ifdef _OS_WINDOWS_
3841
3888
DWORD last_error = GetLastError ();
0 commit comments