Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add functions to allow "external" memory registration #6

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 50 additions & 2 deletions src/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -604,10 +604,10 @@ static void gc_sweep_foreign_objs(void)
static int64_t last_gc_total_bytes = 0;

#ifdef _P64
#define default_collect_interval (5600*1024*sizeof(void*))
static size_t default_collect_interval = (5600*1024*sizeof(void*));
static size_t max_collect_interval = 1250000000UL;
#else
#define default_collect_interval (3200*1024*sizeof(void*))
static size_t default_collect_interval = (3200*1024*sizeof(void*));
static size_t max_collect_interval = 500000000UL;
#endif

Expand Down Expand Up @@ -1096,6 +1096,54 @@ void jl_gc_count_allocd(size_t sz) JL_NOTSAFEPOINT
jl_atomic_load_relaxed(&ptls->gc_num.allocd) + sz);
}

JL_DLLEXPORT void jl_gc_set_default_collect_interval(size_t collect_interval) JL_NOTSAFEPOINT {
default_collect_interval = collect_interval;
}

JL_DLLEXPORT size_t jl_gc_default_collect_interval() JL_NOTSAFEPOINT {
return default_collect_interval;
}

JL_DLLEXPORT void jl_gc_allocd_external(size_t sz_delta) JL_NOTSAFEPOINT
{
// External memory is divided up for accounting among all threads; this way the
// per-thread quantity is kept balanced to help avoid full GC thrashing if only one
// thread goes over max_collect_interval.
int64_t per_tls_delta = sz_delta / jl_n_threads;
int64_t remainder = sz_delta % jl_n_threads;

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe I get the intent, but not sure it's possible to grab and compare all of jl_all_tls_states like this? jl_atomic_load_relaxed works on a single atomic value, and there'd be no way to atomically load or compare the values from all threads at once, would there? And I suspect combine_thread_gc_counts below is either incorrect or is behind a locking synchronization point?

I'm trying to recall for sure if per-thread allocd being off balance was a concern or not and what led to me writing this. It's possible just sticking it in the current thread and letting combine_thread_gc_counts work it out is good enough.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, my comments are only relevant for Julia 1.9 and up. jl_all_tls_states is not an _Atomic in 1.8.2, so you can ignore all that.

To address your question anyway -- in 1.9, it is possible to add "foreign" threads through the Julia C library interface. When that happens, a new jl_ptls_t * array is created and jl_all_tls_states is atomically switched to point at the new array -- the old array is lazily freed. So my suggestions were basically about checking to see if jl_all_tls_states changed underneath us while we were doing our updates and if it did, to redo them.

@d-netto agreed with the need to partition the allocd across threads, FWIW, maybe he can clarify on that question.

Also, there are plans afoot to make changes to the GC's heuristics -- default_collect_interval may go away altogether. So if we're not immediately using the calls to adjust it, let's drop them from this patch to keep it minimal.

for (int i = 0; i < jl_n_threads; i++) {
jl_ptls_t ptls = jl_all_tls_states[i];
jl_atomic_store_relaxed(&ptls->gc_num.allocd,
jl_atomic_load_relaxed(&ptls->gc_num.allocd) +
per_tls_delta);
}
// Stash the remainder in the 1st thread.
jl_ptls_t ptls = jl_all_tls_states[0];
jl_atomic_store_relaxed(&ptls->gc_num.allocd,
jl_atomic_load_relaxed(&ptls->gc_num.allocd) + remainder);
}

JL_DLLEXPORT void jl_gc_freed_external(size_t sz_delta) JL_NOTSAFEPOINT
{
// External memory is divided up for accounting among all threads; this way the
// per-thread quantity is kept balanced to help avoid full GC thrashing if only one
// thread goes over max_collect_interval.
int64_t per_tls_delta = sz_delta / jl_n_threads;
int64_t remainder = sz_delta % jl_n_threads;

for (int i = 0; i < jl_n_threads; i++) {
jl_ptls_t ptls = jl_all_tls_states[i];
jl_atomic_store_relaxed(&ptls->gc_num.freed,
jl_atomic_load_relaxed(&ptls->gc_num.freed) +
per_tls_delta);
}
// Subtract the remainder from the 1st thread.
jl_ptls_t ptls = jl_all_tls_states[0];
jl_atomic_store_relaxed(&ptls->gc_num.freed,
jl_atomic_load_relaxed(&ptls->gc_num.freed) + remainder);
}

static void combine_thread_gc_counts(jl_gc_num_t *dest) JL_NOTSAFEPOINT
{
for (int i = 0; i < jl_n_threads; i++) {
Expand Down
9 changes: 9 additions & 0 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -937,6 +937,15 @@ JL_DLLEXPORT void *jl_gc_managed_realloc(void *d, size_t sz, size_t oldsz,
int isaligned, jl_value_t *owner);
JL_DLLEXPORT void jl_gc_safepoint(void);

JL_DLLEXPORT void jl_gc_set_default_collect_interval(size_t collect_interval) JL_NOTSAFEPOINT;
JL_DLLEXPORT size_t jl_gc_default_collect_interval(void) JL_NOTSAFEPOINT;

// Record accounting for memory that exists outside-of the Julia runtime, but which is
// nevertheless part of the same process RSS and which should be accounted for when
// calculating process memory pressure when triggering garbage collection.
JL_DLLEXPORT void jl_gc_allocd_external(size_t sz_delta) JL_NOTSAFEPOINT;
JL_DLLEXPORT void jl_gc_freed_external(size_t sz_delta) JL_NOTSAFEPOINT;

// object accessors -----------------------------------------------------------

#define jl_svec_len(t) (((jl_svec_t*)(t))->length)
Expand Down