Skip to content

Commit 80346c1

Browse files
author
Christine Flood
authored
Put off major collections to improve GC times. (#44215)
* Updated GC Heuristics to avoid a full GC unless absolutely necessary. This helps with #40644 and other programs which suffer from non-productive full collections.
1 parent 4d04294 commit 80346c1

File tree

3 files changed

+45
-37
lines changed

3 files changed

+45
-37
lines changed

Diff for: src/gc-debug.c

+16
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,22 @@ void gc_time_sweep_pause(uint64_t gc_end_t, int64_t actual_allocd,
977977
jl_ns2ms(gc_postmark_end - gc_premark_end),
978978
sweep_full ? "full" : "quick", -gc_num.allocd / 1024);
979979
}
980+
981+
void gc_time_summary(int sweep_full, uint64_t start, uint64_t end,
982+
uint64_t freed, uint64_t live, uint64_t interval,
983+
uint64_t pause)
984+
{
985+
if (sweep_full > 0)
986+
jl_safe_printf("%ld Major collection: estimate freed = %ld
987+
live = %ldm new interval = %ldm time = %ldms\n",
988+
end - start, freed, live/1024/1024,
989+
interval/1024/1024, pause/1000000 );
990+
else
991+
jl_safe_printf("%ld Minor collection: estimate freed = %ld live = %ldm
992+
new interval = %ldm time = %ldms\n",
993+
end - start, freed, live/1024/1024,
994+
interval/1024/1024, pause/1000000 );
995+
}
980996
#endif
981997

982998
void jl_gc_debug_init(void)

Diff for: src/gc.c

+24-37
Original file line numberDiff line numberDiff line change
@@ -653,9 +653,8 @@ static int prev_sweep_full = 1;
653653
// Full collection heuristics
654654
static int64_t live_bytes = 0;
655655
static int64_t promoted_bytes = 0;
656-
static int64_t last_full_live = 0; // live_bytes after last full collection
657656
static int64_t last_live_bytes = 0; // live_bytes at last collection
658-
static int64_t grown_heap_age = 0; // # of collects since live_bytes grew and remained
657+
static int64_t t_start = 0; // Time GC starts;
659658
#ifdef __GLIBC__
660659
// maxrss at last malloc_trim
661660
static int64_t last_trim_maxrss = 0;
@@ -3140,43 +3139,23 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
31403139
int nptr = 0;
31413140
for (int i = 0;i < jl_n_threads;i++)
31423141
nptr += jl_all_tls_states[i]->heap.remset_nptr;
3143-
int large_frontier = nptr*sizeof(void*) >= default_collect_interval; // many pointers in the intergen frontier => "quick" mark is not quick
3144-
// trigger a full collection if the number of live bytes doubles since the last full
3145-
// collection and then remains at least that high for a while.
3146-
if (grown_heap_age == 0) {
3147-
if (live_bytes > 2 * last_full_live)
3148-
grown_heap_age = 1;
3149-
}
3150-
else if (live_bytes >= last_live_bytes) {
3151-
grown_heap_age++;
3152-
}
3142+
3143+
// many pointers in the intergen frontier => "quick" mark is not quick
3144+
int large_frontier = nptr*sizeof(void*) >= default_collect_interval;
31533145
int sweep_full = 0;
31543146
int recollect = 0;
3155-
if ((large_frontier ||
3156-
((not_freed_enough || promoted_bytes >= gc_num.interval) &&
3157-
(promoted_bytes >= default_collect_interval || prev_sweep_full)) ||
3158-
grown_heap_age > 1) && gc_num.pause > 1) {
3159-
sweep_full = 1;
3160-
}
3147+
31613148
// update heuristics only if this GC was automatically triggered
31623149
if (collection == JL_GC_AUTO) {
3163-
if (sweep_full) {
3164-
if (large_frontier)
3165-
gc_num.interval = last_long_collect_interval;
3166-
if (not_freed_enough || large_frontier) {
3167-
if (gc_num.interval <= 2*(max_collect_interval/5)) {
3168-
gc_num.interval = 5 * (gc_num.interval / 2);
3169-
}
3170-
}
3171-
last_long_collect_interval = gc_num.interval;
3150+
if (not_freed_enough) {
3151+
gc_num.interval = gc_num.interval * 2;
31723152
}
3173-
else {
3174-
// reset interval to default, or at least half of live_bytes
3175-
int64_t half = live_bytes/2;
3176-
if (default_collect_interval < half && half <= max_collect_interval)
3177-
gc_num.interval = half;
3178-
else
3179-
gc_num.interval = default_collect_interval;
3153+
if (large_frontier) {
3154+
sweep_full = 1;
3155+
}
3156+
if (gc_num.interval > max_collect_interval) {
3157+
sweep_full = 1;
3158+
gc_num.interval = max_collect_interval;
31803159
}
31813160
}
31823161
if (gc_sweep_always_full) {
@@ -3249,10 +3228,17 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
32493228
gc_num.allocd = 0;
32503229
last_live_bytes = live_bytes;
32513230
live_bytes += -gc_num.freed + gc_num.since_sweep;
3252-
if (prev_sweep_full) {
3253-
last_full_live = live_bytes;
3254-
grown_heap_age = 0;
3231+
3232+
if (collection == JL_GC_AUTO) {
3233+
// If the current interval is larger than half the live data decrease the interval
3234+
int64_t half = live_bytes/2;
3235+
if (gc_num.interval > half) gc_num.interval = half;
3236+
// But never go below default
3237+
if (gc_num.interval < default_collect_interval) gc_num.interval = default_collect_interval;
32553238
}
3239+
3240+
gc_time_summary(sweep_full, t_start, gc_end_t, gc_num.freed, live_bytes, gc_num.interval, pause);
3241+
32563242
prev_sweep_full = sweep_full;
32573243
gc_num.pause += !recollect;
32583244
gc_num.total_time += pause;
@@ -3420,6 +3406,7 @@ void jl_gc_init(void)
34203406
#endif
34213407
jl_gc_mark_sp_t sp = {NULL, NULL, NULL, NULL};
34223408
gc_mark_loop(NULL, sp);
3409+
t_start = jl_hrtime();
34233410
}
34243411

34253412
// callback for passing OOM errors from gmp

Diff for: src/gc.h

+5
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,9 @@ void gc_time_mark_pause(int64_t t0, int64_t scanned_bytes,
557557
void gc_time_sweep_pause(uint64_t gc_end_t, int64_t actual_allocd,
558558
int64_t live_bytes, int64_t estimate_freed,
559559
int sweep_full);
560+
void gc_time_summary(int sweep_full, uint64_t start, uint64_t end,
561+
uint64_t freed, uint64_t live, uint64_t interval,
562+
uint64_t pause);
560563
#else
561564
#define gc_time_pool_start()
562565
STATIC_INLINE void gc_time_count_page(int freedall, int pg_skpd) JL_NOTSAFEPOINT
@@ -582,6 +585,8 @@ STATIC_INLINE void gc_time_count_mallocd_array(int bits) JL_NOTSAFEPOINT
582585
#define gc_time_mark_pause(t0, scanned_bytes, perm_scanned_bytes)
583586
#define gc_time_sweep_pause(gc_end_t, actual_allocd, live_bytes, \
584587
estimate_freed, sweep_full)
588+
#define gc_time_summary(sweep_full, start, end, freed, live, \
589+
interval, pause)
585590
#endif
586591

587592
#ifdef MEMFENCE

0 commit comments

Comments
 (0)