Skip to content

Commit

Permalink
Implement fixed heap size for Julia
Browse files Browse the repository at this point in the history
  • Loading branch information
qinsoon committed Feb 27, 2024
1 parent 874179e commit b58f9ea
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 7 deletions.
1 change: 1 addition & 0 deletions base/options.jl
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ struct JLOptions
strip_ir::Int8
permalloc_pkgimg::Int8
heap_size_hint::UInt64
fixed_heap_size::UInt64
end

# This runs early in the sysimage != is not defined yet
Expand Down
55 changes: 48 additions & 7 deletions src/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ _Atomic(int) gc_master_tid;
uv_mutex_t gc_threads_lock;
uv_cond_t gc_threads_cond;

// Globally allocated bytes by malloc - used for fixed heap size
_Atomic(uint64_t) malloc_bytes;
// Globally allocated pool pages - used for fixed heap size
extern uint64_t jl_current_pg_count(void);

// Linked list of callback functions

typedef void (*jl_gc_cb_func_t)(void);
Expand Down Expand Up @@ -393,6 +398,7 @@ extern int64_t live_bytes;
static int64_t perm_scanned_bytes; // old bytes scanned while marking
int prev_sweep_full = 1;
int current_sweep_full = 0;
int next_sweep_full = 0; // force next sweep to be a full sweep - used by fixed heap size

// Full collection heuristics
static int64_t promoted_bytes = 0;
Expand Down Expand Up @@ -574,11 +580,22 @@ void gc_setmark_buf(jl_ptls_t ptls, void *o, uint8_t mark_mode, size_t minsz) JL

inline void maybe_collect(jl_ptls_t ptls)
{
if (jl_atomic_load_relaxed(&ptls->gc_num.allocd) >= 0 || jl_gc_debug_check_other()) {
jl_gc_collect(JL_GC_AUTO);
}
else {
jl_gc_safepoint_(ptls);
if (jl_options.fixed_heap_size) {
uint64_t current_heap_size = ((uint64_t)jl_current_pg_count()) << (uint64_t)14;
current_heap_size += jl_atomic_load_relaxed(&malloc_bytes);
if (current_heap_size >= jl_options.fixed_heap_size) {
printf("GC: fixed heap size = %ld, current heap size = %ld\n", jl_options.fixed_heap_size, current_heap_size);
jl_gc_collect(JL_GC_AUTO);
} else {
jl_gc_safepoint_(ptls);
}
} else {
if (jl_atomic_load_relaxed(&ptls->gc_num.allocd) >= 0 || jl_gc_debug_check_other()) {
jl_gc_collect(JL_GC_AUTO);
}
else {
jl_gc_safepoint_(ptls);
}
}
}

Expand Down Expand Up @@ -2698,7 +2715,12 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
sweep_full = 1;
recollect = 1;
}
if (next_sweep_full) {
next_sweep_full = 0;
sweep_full = 1;
}
if (sweep_full) {
printf("Full sweep\n");
// these are the difference between the number of gc-perm bytes scanned
// on the first collection after sweep_full, and the current scan
perm_scanned_bytes = 0;
Expand Down Expand Up @@ -2814,6 +2836,13 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection)
}
}

if (jl_options.fixed_heap_size) {
uint64_t current_heap_size = ((uint64_t)jl_current_pg_count()) << ((uint64_t)14);
if (current_heap_size > (jl_options.fixed_heap_size * 4 / 5)) {
next_sweep_full = 1;
}
}

gc_time_summary(sweep_full, t_start, gc_end_time, gc_num.freed,
live_bytes, gc_num.interval, pause,
gc_num.time_to_safepoint,
Expand Down Expand Up @@ -3019,6 +3048,12 @@ void jl_gc_init(void)
#endif
if (jl_options.heap_size_hint)
jl_gc_set_max_memory(jl_options.heap_size_hint);

if (jl_options.fixed_heap_size) {
// This guarantees that we will not trigger a GC before reaching heap limit
gc_num.interval = jl_options.fixed_heap_size;
}

t_start = jl_hrtime();
}

Expand All @@ -3035,6 +3070,7 @@ JL_DLLEXPORT void *jl_gc_counted_malloc(size_t sz)
jl_atomic_load_relaxed(&ptls->gc_num.allocd) + sz);
jl_atomic_store_relaxed(&ptls->gc_num.malloc,
jl_atomic_load_relaxed(&ptls->gc_num.malloc) + 1);
jl_atomic_fetch_add_relaxed(&malloc_bytes, sz);
}
return malloc(sz);
}
Expand All @@ -3050,6 +3086,7 @@ JL_DLLEXPORT void *jl_gc_counted_calloc(size_t nm, size_t sz)
jl_atomic_load_relaxed(&ptls->gc_num.allocd) + nm*sz);
jl_atomic_store_relaxed(&ptls->gc_num.malloc,
jl_atomic_load_relaxed(&ptls->gc_num.malloc) + 1);
jl_atomic_fetch_add_relaxed(&malloc_bytes, nm * sz);
}
return calloc(nm, sz);
}
Expand All @@ -3065,6 +3102,7 @@ JL_DLLEXPORT void jl_gc_counted_free_with_size(void *p, size_t sz)
jl_atomic_load_relaxed(&ptls->gc_num.freed) + sz);
jl_atomic_store_relaxed(&ptls->gc_num.freecall,
jl_atomic_load_relaxed(&ptls->gc_num.freecall) + 1);
jl_atomic_fetch_add_relaxed(&malloc_bytes, -sz);
}
}

Expand All @@ -3075,12 +3113,15 @@ JL_DLLEXPORT void *jl_gc_counted_realloc_with_old_size(void *p, size_t old, size
if (pgcstack != NULL && ct->world_age) {
jl_ptls_t ptls = ct->ptls;
maybe_collect(ptls);
if (sz < old)
if (sz < old) {
jl_atomic_store_relaxed(&ptls->gc_num.freed,
jl_atomic_load_relaxed(&ptls->gc_num.freed) + (old - sz));
else
jl_atomic_fetch_add_relaxed(&malloc_bytes, old - sz);
} else {
jl_atomic_store_relaxed(&ptls->gc_num.allocd,
jl_atomic_load_relaxed(&ptls->gc_num.allocd) + (sz - old));
jl_atomic_fetch_add_relaxed(&malloc_bytes, sz - old);
}
jl_atomic_store_relaxed(&ptls->gc_num.realloc,
jl_atomic_load_relaxed(&ptls->gc_num.realloc) + 1);
}
Expand Down
35 changes: 35 additions & 0 deletions src/jloptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
opt_strip_metadata,
opt_strip_ir,
opt_heap_size_hint,
opt_fixed_heap_size,
opt_permalloc_pkgimg,
opt_gc_threads,
};
Expand Down Expand Up @@ -318,6 +319,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
{ "strip-ir", no_argument, 0, opt_strip_ir },
{ "permalloc-pkgimg",required_argument, 0, opt_permalloc_pkgimg },
{ "heap-size-hint", required_argument, 0, opt_heap_size_hint },
{ "fixed-heap-size", required_argument, 0, opt_fixed_heap_size },
{ 0, 0, 0, 0 }
};

Expand Down Expand Up @@ -823,6 +825,39 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp)
jl_errorf("julia: invalid argument to --heap-size-hint without memory size specified");

break;
case opt_fixed_heap_size:
if (optarg != NULL) {
size_t endof = strlen(optarg);
long double value = 0.0;
if (sscanf(optarg, "%Lf", &value) == 1 && value > 1e-7) {
char unit = optarg[endof - 1];
uint64_t multiplier = 1ull;
switch (unit) {
case 'k':
case 'K':
multiplier <<= 10;
break;
case 'm':
case 'M':
multiplier <<= 20;
break;
case 'g':
case 'G':
multiplier <<= 30;
break;
case 't':
case 'T':
multiplier <<= 40;
break;
default:
break;
}
jl_options.fixed_heap_size = (uint64_t)(value * multiplier);
}
}
if (jl_options.fixed_heap_size == 0)
jl_errorf("julia: invalid argument to --fixed-heap-size without memory size specified");
break;
case opt_permalloc_pkgimg:
if (!strcmp(optarg,"yes"))
jl_options.permalloc_pkgimg = 1;
Expand Down
1 change: 1 addition & 0 deletions src/jloptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ typedef struct {
int8_t strip_ir;
int8_t permalloc_pkgimg;
uint64_t heap_size_hint;
uint64_t fixed_heap_size;
} jl_options_t;

#endif

0 comments on commit b58f9ea

Please sign in to comment.