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__
@@ -804,8 +805,8 @@ static uint64_t old_heap_size = 0;
804
805
static uint64_t old_alloc_diff = 0 ;
805
806
static uint64_t old_freed_diff = 0 ;
806
807
static uint64_t gc_end_time = 0 ;
807
-
808
-
808
+ static int thrash_counter = 0 ;
809
+ static int thrashing = 0 ;
809
810
// global variables for GC stats
810
811
811
812
// Resetting the object to a young object, this is used when marking the
@@ -1337,7 +1338,10 @@ static void combine_thread_gc_counts(jl_gc_num_t *dest) JL_NOTSAFEPOINT
1337
1338
dest -> bigalloc += jl_atomic_load_relaxed (& ptls -> gc_num .bigalloc );
1338
1339
uint64_t alloc_acc = jl_atomic_load_relaxed (& ptls -> gc_num .alloc_acc );
1339
1340
uint64_t free_acc = jl_atomic_load_relaxed (& ptls -> gc_num .free_acc );
1341
+ dest -> freed += jl_atomic_load_relaxed (& ptls -> gc_num .free_acc );
1340
1342
jl_atomic_store_relaxed (& gc_heap_stats .heap_size , alloc_acc - free_acc + jl_atomic_load_relaxed (& gc_heap_stats .heap_size ));
1343
+ jl_atomic_store_relaxed (& ptls -> gc_num .alloc_acc , 0 );
1344
+ jl_atomic_store_relaxed (& ptls -> gc_num .free_acc , 0 );
1341
1345
}
1342
1346
}
1343
1347
}
@@ -3533,9 +3537,6 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
3533
3537
// If the live data outgrows the suggested max_total_memory
3534
3538
// we keep going with minimum intervals and full gcs until
3535
3539
// we either free some space or get an OOM error.
3536
- if (live_bytes > max_total_memory ) {
3537
- sweep_full = 1 ;
3538
- }
3539
3540
if (gc_sweep_always_full ) {
3540
3541
sweep_full = 1 ;
3541
3542
}
@@ -3569,8 +3570,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
3569
3570
uint64_t sweep_time = gc_end_time - start_sweep_time ;
3570
3571
gc_num .total_sweep_time += sweep_time ;
3571
3572
gc_num .sweep_time = sweep_time ;
3572
-
3573
- int thrashing = 0 ; // maybe we should report this to the user or error out?
3573
+
3574
3574
size_t heap_size = jl_atomic_load_relaxed (& gc_heap_stats .heap_size );
3575
3575
double target_allocs = 0.0 ;
3576
3576
double min_interval = default_collect_interval ;
@@ -3581,24 +3581,32 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
3581
3581
double collect_smooth_factor = 0.5 ;
3582
3582
double tuning_factor = 0.03 ;
3583
3583
double alloc_mem = jl_gc_smooth (old_alloc_diff , alloc_diff , alloc_smooth_factor );
3584
- double alloc_time = jl_gc_smooth (old_mut_time , mutator_time , alloc_smooth_factor );
3584
+ double alloc_time = jl_gc_smooth (old_mut_time , mutator_time + sweep_time , alloc_smooth_factor ); // Charge sweeping to the mutator
3585
3585
double gc_mem = jl_gc_smooth (old_freed_diff , freed_diff , collect_smooth_factor );
3586
- double gc_time = jl_gc_smooth (old_pause_time , pause , collect_smooth_factor );
3586
+ double gc_time = jl_gc_smooth (old_pause_time , pause - sweep_time , collect_smooth_factor );
3587
3587
old_alloc_diff = alloc_diff ;
3588
3588
old_mut_time = mutator_time ;
3589
3589
old_freed_diff = freed_diff ;
3590
3590
old_pause_time = pause ;
3591
- old_heap_size = heap_size ;
3592
- thrashing = gc_time > mutator_time * 98 ? 1 : 0 ;
3591
+ old_heap_size = heap_size ; // TODO: Update these values dynamically instead of just during the GC
3592
+ if (gc_time > alloc_time * 95 && !(thrash_counter < 4 ))
3593
+ thrash_counter += 1 ;
3594
+ else if (thrash_counter > 0 )
3595
+ thrash_counter -= 1 ;
3593
3596
if (alloc_mem != 0 && alloc_time != 0 && gc_mem != 0 && gc_time != 0 ) {
3594
3597
double alloc_rate = alloc_mem /alloc_time ;
3595
3598
double gc_rate = gc_mem /gc_time ;
3596
3599
target_allocs = sqrt (((double )heap_size /min_interval * alloc_rate )/(gc_rate * tuning_factor )); // work on multiples of min interval
3597
3600
}
3598
3601
}
3599
- if (target_allocs == 0.0 || thrashing ) // If we are thrashing go back to default
3600
- target_allocs = 2 * sqrt ((double )heap_size /min_interval );
3602
+ if (thrashing == 0 && thrash_counter >= 3 )
3603
+ thrashing = 1 ;
3604
+ else if (thrashing == 1 && thrash_counter <= 2 )
3605
+ thrashing = 0 ; // maybe we should report this to the user or error out?
3601
3606
3607
+ 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
3608
+ if (target_allocs == 0.0 || thrashing || bad_result ) // If we are thrashing go back to default
3609
+ target_allocs = 2 * sqrt ((double )heap_size /min_interval );
3602
3610
uint64_t target_heap = (uint64_t )target_allocs * min_interval + heap_size ;
3603
3611
if (target_heap > max_total_memory && !thrashing ) // Allow it to go over if we are thrashing if we die we die
3604
3612
target_heap = max_total_memory ;
@@ -3852,10 +3860,10 @@ void jl_gc_init(void)
3852
3860
total_mem = uv_get_total_memory ();
3853
3861
uint64_t constrained_mem = uv_get_constrained_memory ();
3854
3862
if (constrained_mem > 0 && constrained_mem < total_mem )
3855
- total_mem = constrained_mem ;
3863
+ jl_gc_set_max_memory ( constrained_mem - 250 * 1024 * 1024 ); // LLVM + other libraries need some amount of memory
3856
3864
#endif
3857
3865
if (jl_options .heap_size_hint )
3858
- jl_gc_set_max_memory (jl_options .heap_size_hint );
3866
+ jl_gc_set_max_memory (jl_options .heap_size_hint - 250 * 1024 * 1024 );
3859
3867
3860
3868
jl_gc_mark_sp_t sp = {NULL , NULL , NULL , NULL };
3861
3869
gc_mark_loop (NULL , sp );
@@ -3959,7 +3967,26 @@ JL_DLLEXPORT void *jl_gc_counted_realloc_with_old_size(void *p, size_t old, size
3959
3967
jl_atomic_load_relaxed (& ptls -> gc_num .allocd ) + (sz - old ));
3960
3968
jl_atomic_store_relaxed (& ptls -> gc_num .realloc ,
3961
3969
jl_atomic_load_relaxed (& ptls -> gc_num .realloc ) + 1 );
3962
- jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , sz - old );
3970
+
3971
+ int64_t diff = sz - old ;
3972
+ if (diff < 0 ) {
3973
+ uint64_t free_acc = jl_atomic_load_relaxed (& ptls -> gc_num .free_acc );
3974
+ if (free_acc + diff < 16 * 1024 )
3975
+ jl_atomic_store_relaxed (& ptls -> gc_num .free_acc , free_acc + (- diff ));
3976
+ else {
3977
+ jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , - (free_acc + (- diff )));
3978
+ jl_atomic_store_relaxed (& ptls -> gc_num .free_acc , 0 );
3979
+ }
3980
+ }
3981
+ else {
3982
+ uint64_t alloc_acc = jl_atomic_load_relaxed (& ptls -> gc_num .alloc_acc );
3983
+ if (alloc_acc + diff < 16 * 1024 )
3984
+ jl_atomic_store_relaxed (& ptls -> gc_num .alloc_acc , alloc_acc + diff );
3985
+ else {
3986
+ jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , alloc_acc + diff );
3987
+ jl_atomic_store_relaxed (& ptls -> gc_num .alloc_acc , 0 );
3988
+ }
3989
+ }
3963
3990
}
3964
3991
return realloc (p , sz );
3965
3992
}
@@ -4076,7 +4103,27 @@ static void *gc_managed_realloc_(jl_ptls_t ptls, void *d, size_t sz, size_t olds
4076
4103
jl_atomic_load_relaxed (& ptls -> gc_num .allocd ) + (allocsz - oldsz ));
4077
4104
jl_atomic_store_relaxed (& ptls -> gc_num .realloc ,
4078
4105
jl_atomic_load_relaxed (& ptls -> gc_num .realloc ) + 1 );
4079
- jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , allocsz - oldsz );
4106
+
4107
+ int64_t diff = allocsz - oldsz ;
4108
+ if (diff < 0 ) {
4109
+ uint64_t free_acc = jl_atomic_load_relaxed (& ptls -> gc_num .free_acc );
4110
+ if (free_acc + diff < 16 * 1024 )
4111
+ jl_atomic_store_relaxed (& ptls -> gc_num .free_acc , free_acc + (- diff ));
4112
+ else {
4113
+ jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , - (free_acc + (- diff )));
4114
+ jl_atomic_store_relaxed (& ptls -> gc_num .free_acc , 0 );
4115
+ }
4116
+ }
4117
+ else {
4118
+ uint64_t alloc_acc = jl_atomic_load_relaxed (& ptls -> gc_num .alloc_acc );
4119
+ if (alloc_acc + diff < 16 * 1024 )
4120
+ jl_atomic_store_relaxed (& ptls -> gc_num .alloc_acc , alloc_acc + diff );
4121
+ else {
4122
+ jl_atomic_fetch_add_relaxed (& gc_heap_stats .heap_size , alloc_acc + diff );
4123
+ jl_atomic_store_relaxed (& ptls -> gc_num .alloc_acc , 0 );
4124
+ }
4125
+ }
4126
+
4080
4127
int last_errno = errno ;
4081
4128
#ifdef _OS_WINDOWS_
4082
4129
DWORD last_error = GetLastError ();
0 commit comments