Skip to content

Commit 1408468

Browse files
author
Ryan Daum
committed
Hooks & modifications to GC to allow registration of externally allocated memory.
Goal: allow a mechanism to make the GC aware of non-Julia process memory usage. Background in RAI-7988 * Adds calls to register allocations and frees of process memory unaccounted for by live Julia objects, but relevant for GC collection heuristics. * Adds a separate call to allow the Julia program to adjust the `default_collect_interval`. * Increases the default collection interval (to avoid excessive full sweeps once external memory is reported)
1 parent 8b59441 commit 1408468

File tree

2 files changed

+59
-2
lines changed

2 files changed

+59
-2
lines changed

src/gc.c

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -604,10 +604,10 @@ static void gc_sweep_foreign_objs(void)
604604
static int64_t last_gc_total_bytes = 0;
605605

606606
#ifdef _P64
607-
#define default_collect_interval (5600*1024*sizeof(void*))
607+
static size_t default_collect_interval = (5600*1024*sizeof(void*));
608608
static size_t max_collect_interval = 1250000000UL;
609609
#else
610-
#define default_collect_interval (3200*1024*sizeof(void*))
610+
static size_t default_collect_interval = (3200*1024*sizeof(void*));
611611
static size_t max_collect_interval = 500000000UL;
612612
#endif
613613

@@ -1096,6 +1096,54 @@ void jl_gc_count_allocd(size_t sz) JL_NOTSAFEPOINT
10961096
jl_atomic_load_relaxed(&ptls->gc_num.allocd) + sz);
10971097
}
10981098

1099+
JL_DLLEXPORT void jl_gc_set_default_collect_interval(size_t collect_interval) JL_NOTSAFEPOINT {
1100+
default_collect_interval = collect_interval;
1101+
}
1102+
1103+
JL_DLLEXPORT size_t jl_gc_default_collect_interval() JL_NOTSAFEPOINT {
1104+
return default_collect_interval;
1105+
}
1106+
1107+
JL_DLLEXPORT void jl_gc_allocd_external(size_t sz_delta) JL_NOTSAFEPOINT
1108+
{
1109+
// External memory is divided up for accounting among all threads; this way the
1110+
// per-thread quantity is kept balanced to help avoid full GC thrashing if only one
1111+
// thread goes over max_collect_interval.
1112+
int64_t per_tls_delta = sz_delta / jl_n_threads;
1113+
int64_t remainder = sz_delta % jl_n_threads;
1114+
1115+
for (int i = 0; i < jl_n_threads; i++) {
1116+
jl_ptls_t ptls = jl_all_tls_states[i];
1117+
jl_atomic_store_relaxed(&ptls->gc_num.allocd,
1118+
jl_atomic_load_relaxed(&ptls->gc_num.allocd) +
1119+
per_tls_delta);
1120+
}
1121+
// Stash the remainder in the 1st thread.
1122+
jl_ptls_t ptls = jl_all_tls_states[0];
1123+
jl_atomic_store_relaxed(&ptls->gc_num.allocd,
1124+
jl_atomic_load_relaxed(&ptls->gc_num.allocd) + remainder);
1125+
}
1126+
1127+
JL_DLLEXPORT void jl_gc_freed_external(size_t sz_delta) JL_NOTSAFEPOINT
1128+
{
1129+
// External memory is divided up for accounting among all threads; this way the
1130+
// per-thread quantity is kept balanced to help avoid full GC thrashing if only one
1131+
// thread goes over max_collect_interval.
1132+
int64_t per_tls_delta = sz_delta / jl_n_threads;
1133+
int64_t remainder = sz_delta % jl_n_threads;
1134+
1135+
for (int i = 0; i < jl_n_threads; i++) {
1136+
jl_ptls_t ptls = jl_all_tls_states[i];
1137+
jl_atomic_store_relaxed(&ptls->gc_num.freed,
1138+
jl_atomic_load_relaxed(&ptls->gc_num.freed) +
1139+
per_tls_delta);
1140+
}
1141+
// Subtract the remainder from the 1st thread.
1142+
jl_ptls_t ptls = jl_all_tls_states[0];
1143+
jl_atomic_store_relaxed(&ptls->gc_num.freed,
1144+
jl_atomic_load_relaxed(&ptls->gc_num.freed) + remainder);
1145+
}
1146+
10991147
static void combine_thread_gc_counts(jl_gc_num_t *dest) JL_NOTSAFEPOINT
11001148
{
11011149
for (int i = 0; i < jl_n_threads; i++) {

src/julia.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,15 @@ JL_DLLEXPORT void *jl_gc_managed_realloc(void *d, size_t sz, size_t oldsz,
937937
int isaligned, jl_value_t *owner);
938938
JL_DLLEXPORT void jl_gc_safepoint(void);
939939

940+
JL_DLLEXPORT void jl_gc_set_default_collect_interval(size_t collect_interval) JL_NOTSAFEPOINT;
941+
JL_DLLEXPORT size_t jl_gc_default_collect_interval(void) JL_NOTSAFEPOINT;
942+
943+
// Record accounting for memory that exists outside-of the Julia runtime, but which is
944+
// nevertheless part of the same process RSS and which should be accounted for when
945+
// calculating process memory pressure when triggering garbage collection.
946+
JL_DLLEXPORT void jl_gc_allocd_external(size_t sz_delta) JL_NOTSAFEPOINT;
947+
JL_DLLEXPORT void jl_gc_freed_external(size_t sz_delta) JL_NOTSAFEPOINT;
948+
940949
// object accessors -----------------------------------------------------------
941950

942951
#define jl_svec_len(t) (((jl_svec_t*)(t))->length)

0 commit comments

Comments
 (0)