Skip to content

Commit 166b7f5

Browse files
d-nettoRAI CI (GitHub Action Automation)
authored andcommitted
revert GC heuristics back to 1.9 (#126)
1 parent d9a7d8e commit 166b7f5

File tree

4 files changed

+95
-67
lines changed

4 files changed

+95
-67
lines changed

src/gc-debug.c

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
// This file is a part of Julia. License is MIT: https://julialang.org/license
22

33
#include "gc.h"
4-
#include "julia.h"
54
#include <inttypes.h>
6-
#include <stddef.h>
7-
#include <stdint.h>
85
#include <stdio.h>
96

107
// re-include assert.h without NDEBUG,
@@ -953,6 +950,29 @@ void gc_time_sweep_pause(uint64_t gc_end_t, int64_t actual_allocd,
953950
jl_ns2ms(gc_postmark_end - gc_premark_end),
954951
sweep_full ? "full" : "quick", -gc_num.allocd / 1024);
955952
}
953+
954+
void gc_time_summary(int sweep_full, uint64_t start, uint64_t end,
955+
uint64_t freed, uint64_t live, uint64_t interval,
956+
uint64_t pause, uint64_t ttsp, uint64_t mark,
957+
uint64_t sweep)
958+
{
959+
if (sweep_full > 0)
960+
jl_safe_printf("TS: %" PRIu64 " Major collection: estimate freed = %" PRIu64
961+
" live = %" PRIu64 "m new interval = %" PRIu64
962+
"m time = %" PRIu64 "ms ttsp = %" PRIu64 "us mark time = %"
963+
PRIu64 "ms sweep time = %" PRIu64 "ms \n",
964+
end, freed, live/1024/1024,
965+
interval/1024/1024, pause/1000000, ttsp,
966+
mark/1000000,sweep/1000000);
967+
else
968+
jl_safe_printf("TS: %" PRIu64 " Minor collection: estimate freed = %" PRIu64
969+
" live = %" PRIu64 "m new interval = %" PRIu64 "m pause time = %"
970+
PRIu64 "ms ttsp = %" PRIu64 "us mark time = %" PRIu64
971+
"ms sweep time = %" PRIu64 "ms \n",
972+
end, freed, live/1024/1024,
973+
interval/1024/1024, pause/1000000, ttsp,
974+
mark/1000000,sweep/1000000);
975+
}
956976
#endif
957977

958978
void jl_gc_debug_init(void)
@@ -1200,8 +1220,8 @@ void _report_gc_finished(uint64_t pause, uint64_t freed, int full, int recollect
12001220
if (!gc_logging_enabled) {
12011221
return;
12021222
}
1203-
jl_safe_printf("\nGC: pause %.2fms. collected %fMB. %s %s\n",
1204-
pause/1e6, freed/(double)(1<<20),
1223+
jl_safe_printf("GC: pause %.2fms. collected %fMB. %s %s\n",
1224+
pause/1e6, freed/1e6,
12051225
full ? "full" : "incr",
12061226
recollect ? "recollect" : ""
12071227
);

src/gc.c

Lines changed: 70 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,6 @@ jl_gc_num_t gc_num = {0};
195195
static size_t last_long_collect_interval;
196196
int gc_n_threads;
197197
jl_ptls_t* gc_all_tls_states;
198-
int next_sweep_full = 0;
199198
const uint64_t _jl_buff_tag[3] = {0x4eadc0004eadc000ull, 0x4eadc0004eadc000ull, 0x4eadc0004eadc000ull}; // aka 0xHEADER00
200199
JL_DLLEXPORT uintptr_t jl_get_buff_tag(void)
201200
{
@@ -695,10 +694,8 @@ static const size_t max_collect_interval = 500000000UL;
695694
// Work really hard to stay within 2GB
696695
// Alternative is to risk running out of address space
697696
// on 32 bit architectures.
698-
#define MAX32HEAP 1536 * 1024 * 1024
699-
static memsize_t max_total_memory = (memsize_t) MAX32HEAP;
697+
static memsize_t max_total_memory = (memsize_t) 2 * 1024 * 1024 * 1024;
700698
#endif
701-
static uint64_t gc_end_time = 0;
702699
// global variables for GC stats
703700

704701
// Resetting the object to a young object, this is used when marking the
@@ -751,14 +748,12 @@ static int64_t scanned_bytes; // young bytes scanned while marking
751748
static int64_t perm_scanned_bytes; // old bytes scanned while marking
752749
int prev_sweep_full = 1;
753750
int current_sweep_full = 0;
754-
int under_pressure = 0;
755751

756752
// Full collection heuristics
757753
static int64_t live_bytes = 0;
758754
static int64_t promoted_bytes = 0;
759-
static int64_t last_full_live = 0; // live_bytes after last full collection
760755
static int64_t last_live_bytes = 0; // live_bytes at last collection
761-
static int64_t grown_heap_age = 0; // # of collects since live_bytes grew and remained
756+
static int64_t t_start = 0; // Time GC starts;
762757
#ifdef __GLIBC__
763758
// maxrss at last malloc_trim
764759
static int64_t last_trim_maxrss = 0;
@@ -3332,11 +3327,6 @@ JL_DLLEXPORT int64_t jl_gc_live_bytes(void)
33323327
return live_bytes;
33333328
}
33343329

3335-
double jl_gc_smooth(uint64_t old_val, uint64_t new_val, double factor)
3336-
{
3337-
return factor * old_val + (1.0-factor) * new_val;
3338-
}
3339-
33403330
size_t jl_maxrss(void);
33413331

33423332
// Only one thread should be running in this function
@@ -3453,6 +3443,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
34533443
int64_t estimate_freed = live_sz_ub - live_sz_est;
34543444

34553445
gc_verify(ptls);
3446+
34563447
gc_stats_all_pool();
34573448
gc_stats_big_obj();
34583449
objprofile_printall();
@@ -3469,46 +3460,34 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
34693460
if (ptls2 != NULL)
34703461
nptr += ptls2->heap.remset_nptr;
34713462
}
3472-
int large_frontier = nptr*sizeof(void*) >= default_collect_interval; // many pointers in the intergen frontier => "quick" mark is not quick
3473-
// trigger a full collection if the number of live bytes doubles since the last full
3474-
// collection and then remains at least that high for a while.
3475-
if (grown_heap_age == 0) {
3476-
if (live_bytes > 2 * last_full_live)
3477-
grown_heap_age = 1;
3478-
}
3479-
else if (live_bytes >= last_live_bytes) {
3480-
grown_heap_age++;
3481-
}
3463+
3464+
// many pointers in the intergen frontier => "quick" mark is not quick
3465+
int large_frontier = nptr*sizeof(void*) >= default_collect_interval;
34823466
int sweep_full = 0;
34833467
int recollect = 0;
3484-
if ((large_frontier ||
3485-
((not_freed_enough || promoted_bytes >= gc_num.interval) &&
3486-
(promoted_bytes >= default_collect_interval || prev_sweep_full)) ||
3487-
grown_heap_age > 1) && gc_num.pause > 1) {
3488-
sweep_full = 1;
3489-
}
3468+
34903469
// update heuristics only if this GC was automatically triggered
34913470
if (collection == JL_GC_AUTO) {
3492-
if (sweep_full) {
3493-
if (large_frontier)
3494-
gc_num.interval = last_long_collect_interval;
3495-
if (not_freed_enough || large_frontier) {
3496-
if (gc_num.interval <= 2*(max_collect_interval/5)) {
3497-
gc_num.interval = 5 * (gc_num.interval / 2);
3498-
}
3499-
}
3500-
last_long_collect_interval = gc_num.interval;
3471+
if (large_frontier) {
3472+
sweep_full = 1;
3473+
gc_num.interval = last_long_collect_interval;
35013474
}
3502-
else {
3503-
// reset interval to default, or at least half of live_bytes
3504-
int64_t half = live_bytes/2;
3505-
if (default_collect_interval < half && half <= max_collect_interval)
3506-
gc_num.interval = half;
3507-
else
3508-
gc_num.interval = default_collect_interval;
3475+
if (not_freed_enough || large_frontier) {
3476+
gc_num.interval = gc_num.interval * 2;
35093477
}
3510-
}
35113478

3479+
size_t maxmem = 0;
3480+
#ifdef _P64
3481+
// on a big memory machine, increase max_collect_interval to totalmem / nthreads / 2
3482+
maxmem = total_mem / (gc_n_threads - jl_n_gcthreads) / 2;
3483+
#endif
3484+
if (maxmem < max_collect_interval)
3485+
maxmem = max_collect_interval;
3486+
if (gc_num.interval > maxmem) {
3487+
sweep_full = 1;
3488+
gc_num.interval = maxmem;
3489+
}
3490+
}
35123491

35133492
// If the live data outgrows the suggested max_total_memory
35143493
// we keep going with full gcs until we either free some space or get an OOM error.
@@ -3528,6 +3507,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
35283507
// on the first collection after sweep_full, and the current scan
35293508
perm_scanned_bytes = 0;
35303509
promoted_bytes = 0;
3510+
last_long_collect_interval = gc_num.interval;
35313511
}
35323512
scanned_bytes = 0;
35333513
// 6. start sweeping
@@ -3556,7 +3536,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
35563536

35573537
JL_PROBE_GC_SWEEP_END();
35583538

3559-
gc_end_time = jl_hrtime();
3539+
uint64_t gc_end_time = jl_hrtime();
35603540
uint64_t pause = gc_end_time - gc_start_time;
35613541
uint64_t sweep_time = gc_end_time - start_sweep_time;
35623542
gc_num.total_sweep_time += sweep_time;
@@ -3613,18 +3593,48 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
36133593
gc_num.allocd = 0;
36143594
last_live_bytes = live_bytes;
36153595
live_bytes += -gc_num.freed + actual_allocd;
3616-
jl_timing_counter_dec(JL_TIMING_COUNTER_HeapSize, gc_num.freed);
3596+
3597+
if (collection == JL_GC_AUTO) {
3598+
//If we aren't freeing enough or are seeing lots and lots of pointers let it increase faster
3599+
if (!not_freed_enough || large_frontier) {
3600+
int64_t tot = 2 * (live_bytes + actual_allocd) / 3;
3601+
if (gc_num.interval > tot) {
3602+
gc_num.interval = tot;
3603+
last_long_collect_interval = tot;
3604+
}
3605+
}
3606+
// If the current interval is larger than half the live data decrease the interval
3607+
else {
3608+
int64_t half = (live_bytes / 2);
3609+
if (gc_num.interval > half)
3610+
gc_num.interval = half;
3611+
}
3612+
// But never go below default
3613+
if (gc_num.interval < default_collect_interval) gc_num.interval = default_collect_interval;
3614+
}
3615+
3616+
if (gc_num.interval + live_bytes > max_total_memory) {
3617+
if (live_bytes < max_total_memory) {
3618+
gc_num.interval = max_total_memory - live_bytes;
3619+
last_long_collect_interval = max_total_memory - live_bytes;
3620+
}
3621+
else {
3622+
// We can't stay under our goal so let's go back to
3623+
// the minimum interval and hope things get better
3624+
under_memory_pressure = 1;
3625+
gc_num.interval = default_collect_interval;
3626+
}
3627+
}
3628+
36173629
gc_time_summary(sweep_full, t_start, gc_end_time, gc_num.freed,
36183630
live_bytes, gc_num.interval, pause,
36193631
gc_num.time_to_safepoint,
36203632
gc_num.mark_time, gc_num.sweep_time);
3621-
if (prev_sweep_full) {
3622-
last_full_live = live_bytes;
3623-
grown_heap_age = 0;
3624-
}
3633+
36253634
prev_sweep_full = sweep_full;
36263635
gc_num.pause += !recollect;
36273636
gc_num.total_time += pause;
3637+
gc_num.allocd = 0;
36283638
gc_num.freed = 0;
36293639
if (pause > gc_num.max_pause) {
36303640
gc_num.max_pause = pause;
@@ -3826,21 +3836,25 @@ void jl_gc_init(void)
38263836
total_mem = uv_get_total_memory();
38273837
uint64_t constrained_mem = uv_get_constrained_memory();
38283838
if (constrained_mem > 0 && constrained_mem < total_mem)
3829-
jl_gc_set_max_memory(constrained_mem - 250*1024*1024); // LLVM + other libraries need some amount of memory
3839+
total_mem = constrained_mem;
3840+
double percent;
3841+
if (total_mem < 128e9)
3842+
percent = total_mem * 2.34375e-12 + 0.6; // 60% at 0 gigs and 90% at 128 to not
3843+
else // overcommit too much on memory contrained devices
3844+
percent = 0.9;
3845+
max_total_memory = total_mem * percent;
38303846
#endif
38313847
if (jl_options.heap_size_hint)
38323848
jl_gc_set_max_memory(jl_options.heap_size_hint - 250*1024*1024);
3849+
3850+
t_start = jl_hrtime();
38333851
}
38343852

38353853
JL_DLLEXPORT void jl_gc_set_max_memory(uint64_t max_mem)
38363854
{
38373855
if (max_mem > 0
38383856
&& max_mem < (uint64_t)1 << (sizeof(memsize_t) * 8 - 1)) {
3839-
#ifdef _P64
38403857
max_total_memory = max_mem;
3841-
#else
3842-
max_total_memory = max_mem < MAX32HEAP ? max_mem : MAX32HEAP;
3843-
#endif
38443858
}
38453859
}
38463860

src/gc.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
#ifndef JL_GC_H
1010
#define JL_GC_H
1111

12-
#include <stddef.h>
13-
#include <stdint.h>
1412
#include <stdlib.h>
1513
#include <string.h>
1614
#include <strings.h>

test/testenv.jl

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,6 @@ if !@isdefined(testenv_defined)
3737

3838
function addprocs_with_testenv(X; rr_allowed=true, kwargs...)
3939
exename = rr_allowed ? `$rr_exename $test_exename` : test_exename
40-
if X isa Integer
41-
heap_size=round(Int,(Sys.total_memory()/(1024^2)/(X+1)))
42-
push!(test_exeflags.exec, "--heap-size-hint=$(heap_size)M")
43-
end
4440
addprocs(X; exename=exename, exeflags=test_exeflags, kwargs...)
4541
end
4642

0 commit comments

Comments
 (0)