From 5aa21c050b70334503108b86002ba705f3d3a298 Mon Sep 17 00:00:00 2001 From: Kristoffer Carlsson Date: Mon, 29 Jan 2024 12:51:55 +0100 Subject: [PATCH 001/109] Extensions: make loading of extensions independent of what packages are in the sysimage (#52841) When triggers of extension are in the sysimage it is easy to end up with cycles in package loading. Say we have a package A with exts BExt and CExt and say that B and C is in the sysimage. - Upon loading A, we will immidiately start to precompile BExt (because the trigger B is "loaded" by virtue of being in the sysimage). - BExt will load A which will cause CExt to start precompiling (again because C is in the sysimage). - CExt will load A which will now cause BExt to start loading and we get a cycle. This is fixed in this PR by instead of looking at what modules are loaded, we look at what modules are actually `require`d and only use that to drive the loading of extensions. Fixes https://github.com/JuliaLang/julia/issues/52132. (cherry picked from commit 08d229f4a7cb0c3ef5becddd1b3bc4f8f178b8e4) --- base/Base.jl | 1 + base/loading.jl | 10 +++++++++- test/loading.jl | 18 ++++++++++++++++++ .../HasDepWithExtensions.jl/Manifest.toml | 9 +++++++-- .../Extensions/HasExtensions.jl/Project.toml | 2 ++ .../HasExtensions.jl/ext/LinearAlgebraExt.jl | 3 +++ 6 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 test/project/Extensions/HasExtensions.jl/ext/LinearAlgebraExt.jl diff --git a/base/Base.jl b/base/Base.jl index 6ed423a799e4e..5e5588465bdf7 100644 --- a/base/Base.jl +++ b/base/Base.jl @@ -595,6 +595,7 @@ function __init__() init_load_path() init_active_project() append!(empty!(_sysimage_modules), keys(loaded_modules)) + empty!(explicit_loaded_modules) if haskey(ENV, "JULIA_MAX_NUM_PRECOMPILE_FILES") MAX_NUM_PRECOMPILE_FILES[] = parse(Int, ENV["JULIA_MAX_NUM_PRECOMPILE_FILES"]) end diff --git a/base/loading.jl b/base/loading.jl index b652e56c922e0..c1972907b02bb 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -1275,7 +1275,7 @@ function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any} # TODO: Better error message if this lookup fails? uuid_trigger = UUID(weakdeps[trigger]::String) trigger_id = PkgId(uuid_trigger, trigger) - if !haskey(Base.loaded_modules, trigger_id) || haskey(package_locks, trigger_id) + if !haskey(explicit_loaded_modules, trigger_id) || haskey(package_locks, trigger_id) trigger1 = get!(Vector{ExtensionId}, EXT_DORMITORY, trigger_id) push!(trigger1, gid) else @@ -1821,6 +1821,11 @@ function __require_prelocked(uuidkey::PkgId, env=nothing) REPL_MODULE_REF[] = newm end else + m = get(loaded_modules, uuidkey, nothing) + if m !== nothing + explicit_loaded_modules[uuidkey] = m + run_package_callbacks(uuidkey) + end newm = root_module(uuidkey) end return newm @@ -1835,6 +1840,8 @@ PkgOrigin() = PkgOrigin(nothing, nothing, nothing) const pkgorigins = Dict{PkgId,PkgOrigin}() const loaded_modules = Dict{PkgId,Module}() +# Emptied on Julia start +const explicit_loaded_modules = Dict{PkgId,Module}() const loaded_modules_order = Vector{Module}() const module_keys = IdDict{Module,PkgId}() # the reverse @@ -1858,6 +1865,7 @@ root_module_key(m::Module) = @lock require_lock module_keys[m] end push!(loaded_modules_order, m) loaded_modules[key] = m + explicit_loaded_modules[key] = m module_keys[m] = key end nothing diff --git a/test/loading.jl b/test/loading.jl index 394c13c5f2962..e5f508b9bb55f 100644 --- a/test/loading.jl +++ b/test/loading.jl @@ -1083,6 +1083,24 @@ end cmd_proj_ext = addenv(cmd_proj_ext, "JULIA_LOAD_PATH" => join([joinpath(proj, "HasExtensions.jl"), joinpath(proj, "EnvWithDeps")], sep)) run(cmd_proj_ext) end + + # Sysimage extensions + # The test below requires that LinearAlgebra is in the sysimage and that it has not been loaded yet. + # if it gets moved out, this test will need to be updated. + # We run this test in a new process so we are not vulnerable to a previous test having loaded LinearAlgebra + sysimg_ext_test_code = """ + uuid_key = Base.PkgId(Base.UUID("37e2e46d-f89d-539d-b4ee-838fcccc9c8e"), "LinearAlgebra") + Base.in_sysimage(uuid_key) || error("LinearAlgebra not in sysimage") + haskey(Base.explicit_loaded_modules, uuid_key) && error("LinearAlgebra already loaded") + using HasExtensions + Base.get_extension(HasExtensions, :LinearAlgebraExt) === nothing || error("unexpectedly got an extension") + using LinearAlgebra + haskey(Base.explicit_loaded_modules, uuid_key) || error("LinearAlgebra not loaded") + Base.get_extension(HasExtensions, :LinearAlgebraExt) isa Module || error("expected extension to load") + """ + cmd = `$(Base.julia_cmd()) --startup-file=no -e $sysimg_ext_test_code` + cmd = addenv(cmd, "JULIA_LOAD_PATH" => join([proj, "@stdlib"], sep)) + run(cmd) finally try rm(depot_path, force=true, recursive=true) diff --git a/test/project/Extensions/HasDepWithExtensions.jl/Manifest.toml b/test/project/Extensions/HasDepWithExtensions.jl/Manifest.toml index 52542fc822094..15f068f250ce3 100644 --- a/test/project/Extensions/HasDepWithExtensions.jl/Manifest.toml +++ b/test/project/Extensions/HasDepWithExtensions.jl/Manifest.toml @@ -1,6 +1,6 @@ # This file is machine-generated - editing it directly is not advised -julia_version = "1.10.0-DEV" +julia_version = "1.10.0" manifest_format = "2.0" project_hash = "d523b3401f72a1ed34b7b43749fd2655c6b78542" @@ -19,11 +19,16 @@ version = "0.1.0" path = "../HasExtensions.jl" uuid = "4d3288b3-3afc-4bb6-85f3-489fffe514c8" version = "0.1.0" -weakdeps = ["ExtDep", "ExtDep2"] [deps.HasExtensions.extensions] Extension = "ExtDep" ExtensionFolder = ["ExtDep", "ExtDep2"] + LinearAlgebraExt = "LinearAlgebra" + + [deps.HasExtensions.weakdeps] + ExtDep = "fa069be4-f60b-4d4c-8b95-f8008775090c" + ExtDep2 = "55982ee5-2ad5-4c40-8cfe-5e9e1b01500d" + LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" [[deps.SomePackage]] path = "../SomePackage" diff --git a/test/project/Extensions/HasExtensions.jl/Project.toml b/test/project/Extensions/HasExtensions.jl/Project.toml index 72577de36d65d..a5f9bb1e42d29 100644 --- a/test/project/Extensions/HasExtensions.jl/Project.toml +++ b/test/project/Extensions/HasExtensions.jl/Project.toml @@ -5,7 +5,9 @@ version = "0.1.0" [weakdeps] ExtDep = "fa069be4-f60b-4d4c-8b95-f8008775090c" ExtDep2 = "55982ee5-2ad5-4c40-8cfe-5e9e1b01500d" +LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" [extensions] Extension = "ExtDep" ExtensionFolder = ["ExtDep", "ExtDep2"] +LinearAlgebraExt = "LinearAlgebra" diff --git a/test/project/Extensions/HasExtensions.jl/ext/LinearAlgebraExt.jl b/test/project/Extensions/HasExtensions.jl/ext/LinearAlgebraExt.jl new file mode 100644 index 0000000000000..19f87cb849417 --- /dev/null +++ b/test/project/Extensions/HasExtensions.jl/ext/LinearAlgebraExt.jl @@ -0,0 +1,3 @@ +module LinearAlgebraExt + +end From e7c563a08801613d0e9f1335ea8bffc97e72d11f Mon Sep 17 00:00:00 2001 From: "RAI CI (GitHub Action Automation)" Date: Fri, 1 Mar 2024 10:30:37 +0000 Subject: [PATCH 002/109] RAI: Add 'RAI' as the build part of the semantic version # Conflicts: # VERSION # Conflicts: # VERSION # Conflicts: # VERSION # Conflicts: # VERSION # Conflicts: # VERSION # Conflicts: # VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 5ad2491cf8808..d54cfb129dea4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.10.2 +1.10.2+RAI From 9314aa64f4c6c4953f73858aea899a0ea5bc2581 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Sun, 29 Oct 2023 21:21:03 -0300 Subject: [PATCH 003/109] RAI: Track blocks and bytes allocated for GC pools This needed updating for 1.10 (#102). * port pool stats to 1.10 * increment/decrement current_pg_count --------- Co-authored-by: K Pamnany --- src/gc-pages.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/gc-pages.c b/src/gc-pages.c index 682e76611f5d9..2d20e756234e9 100644 --- a/src/gc-pages.c +++ b/src/gc-pages.c @@ -19,6 +19,31 @@ extern "C" { #define MIN_BLOCK_PG_ALLOC (1) // 16 KB static int block_pg_cnt = DEFAULT_BLOCK_PG_ALLOC; +static _Atomic(size_t) current_pg_count = 0; + +// Julia allocates large blocks (64M) with mmap. These are never +// released back but the underlying physical memory may be released +// with calls to madvise(MADV_DONTNEED). +// These large blocks are used to allocated jl_page_size sized +// pages, that are tracked by current_pg_count. +static uint64_t poolmem_bytes_allocated = 0; +static uint64_t poolmem_blocks_allocated_total = 0; + + +JL_DLLEXPORT uint64_t jl_poolmem_blocks_allocated_total(void) +{ + return poolmem_blocks_allocated_total; +} + +JL_DLLEXPORT uint64_t jl_poolmem_bytes_allocated(void) +{ + return poolmem_bytes_allocated; +} + +JL_DLLEXPORT uint64_t jl_current_pg_count(void) +{ + return (uint64_t)jl_atomic_load(¤t_pg_count); +} void jl_gc_init_page(void) { @@ -47,6 +72,8 @@ char *jl_gc_try_alloc_pages_(int pg_cnt) JL_NOTSAFEPOINT MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (mem == MAP_FAILED) return NULL; + poolmem_bytes_allocated += pages_sz; + poolmem_blocks_allocated_total++; #endif if (GC_PAGE_SZ > jl_page_size) // round data pointer up to the nearest gc_page_data-aligned @@ -148,6 +175,7 @@ NOINLINE jl_gc_pagemeta_t *jl_gc_alloc_page(void) JL_NOTSAFEPOINT SetLastError(last_error); #endif errno = last_errno; + jl_atomic_fetch_add(¤t_pg_count, 1); return meta; } @@ -188,6 +216,7 @@ void jl_gc_free_page(jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT madvise(p, decommit_size, MADV_DONTNEED); #endif msan_unpoison(p, decommit_size); + jl_atomic_fetch_add(¤t_pg_count, -1); } #ifdef __cplusplus From 3c79c50a0a99eca6e0419b7bfa826c8e8768b413 Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Wed, 9 Aug 2023 12:57:35 -0400 Subject: [PATCH 004/109] RAI: Change task ordering behavior to prioritize older tasks --- base/partr.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/partr.jl b/base/partr.jl index c77a24bdcc003..f84d7bd1a37b7 100644 --- a/base/partr.jl +++ b/base/partr.jl @@ -50,7 +50,7 @@ function multiq_sift_down(heap::taskheap, idx::Int32) child = Int(child) child > length(heap.tasks) && break if isassigned(heap.tasks, child) && - heap.tasks[child].priority < heap.tasks[idx].priority + heap.tasks[child].priority <= heap.tasks[idx].priority t = heap.tasks[idx] heap.tasks[idx] = heap.tasks[child] heap.tasks[child] = t From 71435e3a3fd16e91b06734de177103c88c0b63f6 Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Mon, 21 Aug 2023 12:10:18 -0400 Subject: [PATCH 005/109] RAI: Prepend signal number and thread ID on backtraces Prepend `[signal (X) ]thread (Y) ` to each backtrace line that is displayed. Co-authored-by: Diogo Netto <61364108+d-netto@users.noreply.github.com> --- src/julia_internal.h | 4 ++-- src/signal-handling.c | 2 +- src/signals-unix.c | 2 +- src/signals-win.c | 2 +- src/stackwalk.c | 37 +++++++++++++++++++++++++------------ 5 files changed, 30 insertions(+), 17 deletions(-) diff --git a/src/julia_internal.h b/src/julia_internal.h index 4fa3154b765d1..67f771e398578 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -1159,8 +1159,8 @@ JL_DLLEXPORT jl_value_t *jl_get_backtrace(void); void jl_critical_error(int sig, int si_code, bt_context_t *context, jl_task_t *ct); JL_DLLEXPORT void jl_raise_debugger(void) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_gdblookup(void* ip) JL_NOTSAFEPOINT; -void jl_print_native_codeloc(uintptr_t ip) JL_NOTSAFEPOINT; -void jl_print_bt_entry_codeloc(jl_bt_element_t *bt_data) JL_NOTSAFEPOINT; +void jl_print_native_codeloc(char *pre_str, uintptr_t ip) JL_NOTSAFEPOINT; +void jl_print_bt_entry_codeloc(int sig, jl_bt_element_t *bt_data) JL_NOTSAFEPOINT; #ifdef _OS_WINDOWS_ JL_DLLEXPORT void jl_refresh_dbg_module_list(void); #endif diff --git a/src/signal-handling.c b/src/signal-handling.c index e241fd22ecb18..b280fc1e0aeef 100644 --- a/src/signal-handling.c +++ b/src/signal-handling.c @@ -475,7 +475,7 @@ void jl_critical_error(int sig, int si_code, bt_context_t *context, jl_task_t *c *bt_size = n = rec_backtrace_ctx(bt_data, JL_MAX_BT_SIZE, context, NULL); } for (i = 0; i < n; i += jl_bt_entry_size(bt_data + i)) { - jl_print_bt_entry_codeloc(bt_data + i); + jl_print_bt_entry_codeloc(sig, bt_data + i); } jl_gc_debug_print_status(); jl_gc_debug_critical_error(); diff --git a/src/signals-unix.c b/src/signals-unix.c index 0d5ad9b1be7c5..a79043d78e682 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -956,7 +956,7 @@ static void *signal_listener(void *arg) jl_safe_printf("\nsignal (%d): %s\n", sig, strsignal(sig)); size_t i; for (i = 0; i < bt_size; i += jl_bt_entry_size(bt_data + i)) { - jl_print_bt_entry_codeloc(bt_data + i); + jl_print_bt_entry_codeloc(-1, bt_data + i); } } } diff --git a/src/signals-win.c b/src/signals-win.c index 10bd0dec7f480..cbf3c7436c8ff 100644 --- a/src/signals-win.c +++ b/src/signals-win.c @@ -327,7 +327,7 @@ LONG WINAPI jl_exception_handler(struct _EXCEPTION_POINTERS *ExceptionInfo) jl_safe_printf("UNKNOWN"); break; } jl_safe_printf(" at 0x%Ix -- ", (size_t)ExceptionInfo->ExceptionRecord->ExceptionAddress); - jl_print_native_codeloc((uintptr_t)ExceptionInfo->ExceptionRecord->ExceptionAddress); + jl_print_native_codeloc("", (uintptr_t)ExceptionInfo->ExceptionRecord->ExceptionAddress); jl_critical_error(0, 0, ExceptionInfo->ContextRecord, ct); static int recursion = 0; diff --git a/src/stackwalk.c b/src/stackwalk.c index dcac2c4501682..bb15ebe754533 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -614,22 +614,25 @@ JL_DLLEXPORT jl_value_t *jl_lookup_code_address(void *ip, int skipC) return rs; } -static void jl_safe_print_codeloc(const char* func_name, const char* file_name, +static void jl_safe_print_codeloc(const char *pre_str, + const char* func_name, const char* file_name, int line, int inlined) JL_NOTSAFEPOINT { const char *inlined_str = inlined ? " [inlined]" : ""; if (line != -1) { - jl_safe_printf("%s at %s:%d%s\n", func_name, file_name, line, inlined_str); + jl_safe_printf("%s%s at %s:%d%s\n", + pre_str, func_name, file_name, line, inlined_str); } else { - jl_safe_printf("%s at %s (unknown line)%s\n", func_name, file_name, inlined_str); + jl_safe_printf("%s%s at %s (unknown line)%s\n", + pre_str, func_name, file_name, inlined_str); } } // Print function, file and line containing native instruction pointer `ip` by // looking up debug info. Prints multiple such frames when `ip` points to // inlined code. -void jl_print_native_codeloc(uintptr_t ip) JL_NOTSAFEPOINT +void jl_print_native_codeloc(char *pre_str, uintptr_t ip) JL_NOTSAFEPOINT { // This function is not allowed to reference any TLS variables since // it can be called from an unmanaged thread on OSX. @@ -641,10 +644,11 @@ void jl_print_native_codeloc(uintptr_t ip) JL_NOTSAFEPOINT for (i = 0; i < n; i++) { jl_frame_t frame = frames[i]; if (!frame.func_name) { - jl_safe_printf("unknown function (ip: %p)\n", (void*)ip); + jl_safe_printf("%sunknown function (ip: %p)\n", pre_str, (void*)ip); } else { - jl_safe_print_codeloc(frame.func_name, frame.file_name, frame.line, frame.inlined); + jl_safe_print_codeloc(pre_str, frame.func_name, + frame.file_name, frame.line, frame.inlined); free(frame.func_name); free(frame.file_name); } @@ -653,10 +657,17 @@ void jl_print_native_codeloc(uintptr_t ip) JL_NOTSAFEPOINT } // Print code location for backtrace buffer entry at *bt_entry -void jl_print_bt_entry_codeloc(jl_bt_element_t *bt_entry) JL_NOTSAFEPOINT +void jl_print_bt_entry_codeloc(int sig, jl_bt_element_t *bt_entry) JL_NOTSAFEPOINT { + char sig_str[32], pre_str[64]; + sig_str[0] = '\0'; + if (sig != -1) { + snprintf(sig_str, 32, "signal (%d) ", sig); + } + snprintf(pre_str, 64, "%sthread (%d) ", sig_str, jl_threadid() + 1); + if (jl_bt_is_native(bt_entry)) { - jl_print_native_codeloc(bt_entry[0].uintptr); + jl_print_native_codeloc(pre_str, bt_entry[0].uintptr); } else if (jl_bt_entry_tag(bt_entry) == JL_BT_INTERP_FRAME_TAG) { size_t ip = jl_bt_entry_header(bt_entry); @@ -682,7 +693,7 @@ void jl_print_bt_entry_codeloc(jl_bt_element_t *bt_entry) JL_NOTSAFEPOINT method = (jl_value_t*)((jl_method_t*)method)->name; if (jl_is_symbol(method)) func_name = jl_symbol_name((jl_sym_t*)method); - jl_safe_print_codeloc(func_name, jl_symbol_name(locinfo->file), + jl_safe_print_codeloc(pre_str, func_name, jl_symbol_name(locinfo->file), locinfo->line, locinfo->inlined_at); debuginfoloc = locinfo->inlined_at; } @@ -1108,7 +1119,9 @@ static void jl_rec_backtrace(jl_task_t *t) JL_NOTSAFEPOINT JL_DLLEXPORT void jl_gdblookup(void* ip) { - jl_print_native_codeloc((uintptr_t)ip); + char pre_str[64]; + snprintf(pre_str, 64, "thread (%d) ", jl_threadid() + 1); + jl_print_native_codeloc(pre_str, (uintptr_t)ip); } // Print backtrace for current exception in catch block @@ -1123,7 +1136,7 @@ JL_DLLEXPORT void jlbacktrace(void) JL_NOTSAFEPOINT size_t i, bt_size = jl_excstack_bt_size(s, s->top); jl_bt_element_t *bt_data = jl_excstack_bt_data(s, s->top); for (i = 0; i < bt_size; i += jl_bt_entry_size(bt_data + i)) { - jl_print_bt_entry_codeloc(bt_data + i); + jl_print_bt_entry_codeloc(-1, bt_data + i); } } @@ -1136,7 +1149,7 @@ JL_DLLEXPORT void jlbacktracet(jl_task_t *t) JL_NOTSAFEPOINT size_t i, bt_size = ptls->bt_size; jl_bt_element_t *bt_data = ptls->bt_data; for (i = 0; i < bt_size; i += jl_bt_entry_size(bt_data + i)) { - jl_print_bt_entry_codeloc(bt_data + i); + jl_print_bt_entry_codeloc(-1, bt_data + i); } } From c70be9e1f80d58dd207253821ea76e3c546de81d Mon Sep 17 00:00:00 2001 From: Malte Sandstede Date: Thu, 6 Jul 2023 20:45:02 +0200 Subject: [PATCH 006/109] Add GC metric `last_incremental_sweep` (#50190) * Add GC metric `last_incremental_sweep` * Update gc.c * Update gc.c --- base/timing.jl | 1 + src/gc.c | 3 +++ src/gc.h | 1 + 3 files changed, 5 insertions(+) diff --git a/base/timing.jl b/base/timing.jl index d089a43071e78..aeca790bce7e9 100644 --- a/base/timing.jl +++ b/base/timing.jl @@ -25,6 +25,7 @@ struct GC_Num total_sweep_time ::Int64 total_mark_time ::Int64 last_full_sweep ::Int64 + last_incremental_sweep ::Int64 end gc_num() = ccall(:jl_gc_num, GC_Num, ()) diff --git a/src/gc.c b/src/gc.c index 272fe42a43958..5ab41424bf570 100644 --- a/src/gc.c +++ b/src/gc.c @@ -3408,6 +3408,9 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) if (sweep_full) { gc_num.last_full_sweep = gc_end_time; } + else { + gc_num.last_incremental_sweep = gc_end_time; + } // sweeping is over // 7. if it is a quick sweep, put back the remembered objects in queued state diff --git a/src/gc.h b/src/gc.h index 23e73eced6eb8..749cfbbf9227a 100644 --- a/src/gc.h +++ b/src/gc.h @@ -83,6 +83,7 @@ typedef struct { uint64_t total_sweep_time; uint64_t total_mark_time; uint64_t last_full_sweep; + uint64_t last_incremental_sweep; } jl_gc_num_t; // Array chunks (work items representing suffixes of From 2fbcf5ad301f04b1489ac3f62fa1c7447d184cf0 Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Mon, 21 Aug 2023 12:19:17 -0400 Subject: [PATCH 007/109] RAI: Disable huge pages for all mmap'ed memory Prevent transparent huge pages (THP) overallocating pysical memory. Co-authored-by: Adnan Alhomssi --- src/gc-pages.c | 4 ++++ src/gc-stacks.c | 3 +++ src/gc.c | 3 +++ 3 files changed, 10 insertions(+) diff --git a/src/gc-pages.c b/src/gc-pages.c index 2d20e756234e9..7f0e1da42f795 100644 --- a/src/gc-pages.c +++ b/src/gc-pages.c @@ -74,6 +74,10 @@ char *jl_gc_try_alloc_pages_(int pg_cnt) JL_NOTSAFEPOINT return NULL; poolmem_bytes_allocated += pages_sz; poolmem_blocks_allocated_total++; + +#ifdef MADV_NOHUGEPAGE + madvise(mem, pages_sz, MADV_NOHUGEPAGE); +#endif #endif if (GC_PAGE_SZ > jl_page_size) // round data pointer up to the nearest gc_page_data-aligned diff --git a/src/gc-stacks.c b/src/gc-stacks.c index b89ae8cb08e0d..c04e48821e46f 100644 --- a/src/gc-stacks.c +++ b/src/gc-stacks.c @@ -61,6 +61,9 @@ static void *malloc_stack(size_t bufsz) JL_NOTSAFEPOINT munmap(stk, bufsz); return MAP_FAILED; } +#ifdef MADV_NOHUGEPAGE + madvise(stk, bufsz, MADV_NOHUGEPAGE); +#endif #endif jl_atomic_fetch_add(&num_stack_mappings, 1); return stk; diff --git a/src/gc.c b/src/gc.c index 5ab41424bf570..58b59bb1d1d33 100644 --- a/src/gc.c +++ b/src/gc.c @@ -4007,6 +4007,9 @@ void *jl_gc_perm_alloc_nolock(size_t sz, int zero, unsigned align, unsigned offs errno = last_errno; if (__unlikely(pool == MAP_FAILED)) return NULL; +#ifdef MADV_NOHUGEPAGE + madvise(pool, GC_PERM_POOL_SIZE, MADV_NOHUGEPAGE); +#endif #endif gc_perm_pool = (uintptr_t)pool; gc_perm_end = gc_perm_pool + GC_PERM_POOL_SIZE; From 6468d9e203a408de6ef09b62aa7a602f405a9006 Mon Sep 17 00:00:00 2001 From: "Bradley C. Kuszmaul" Date: Tue, 22 Aug 2023 14:27:07 -0400 Subject: [PATCH 008/109] RAI: Never use MADV_FREE --- src/gc-pages.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gc-pages.c b/src/gc-pages.c index 7f0e1da42f795..7a32a7f4bf975 100644 --- a/src/gc-pages.c +++ b/src/gc-pages.c @@ -205,7 +205,7 @@ void jl_gc_free_page(jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT } #ifdef _OS_WINDOWS_ VirtualFree(p, decommit_size, MEM_DECOMMIT); -#elif defined(MADV_FREE) +#elif 0 static int supports_madv_free = 1; if (supports_madv_free) { if (madvise(p, decommit_size, MADV_FREE) == -1) { From c053c42d5289fd1a97317d37a7f7a8bf2b9dc699 Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Sun, 30 Jul 2023 22:27:11 -0400 Subject: [PATCH 009/109] Allocation Profiler: Types for all allocations (#50337) Pass the types to the allocator functions. ------- Before this PR, we were missing the types for allocations in two cases: 1. allocations from codegen 2. allocations in `gc_managed_realloc_` The second one is easy: those are always used for buffers, right? For the first one: we extend the allocation functions called from codegen, to take the type as a parameter, and set the tag there. I kept the old interfaces around, since I think that they cannot be removed due to supporting legacy code? ------ An example of the generated code: ```julia %ptls_field6 = getelementptr inbounds {}**, {}*** %4, i64 2 %13 = bitcast {}*** %ptls_field6 to i8** %ptls_load78 = load i8*, i8** %13, align 8 %box = call noalias nonnull dereferenceable(32) {}* @ijl_gc_pool_alloc_typed(i8* %ptls_load78, i32 1184, i32 32, i64 4366152144) #7 ``` Fixes #43688. Fixes #45268. Co-authored-by: Valentin Churavy --- doc/src/manual/profile.md | 90 +++++++++++++++++++-- src/gc-alloc-profiler.h | 1 + src/gc.c | 19 ++++- src/jl_exported_funcs.inc | 2 + src/llvm-final-gc-lowering.cpp | 9 ++- src/llvm-late-gc-lowering.cpp | 46 +++++++---- src/llvm-pass-helpers.cpp | 14 ++-- stdlib/Profile/test/allocs.jl | 31 +++++++ test/llvmpasses/alloc-opt-gcframe.ll | 16 ++-- test/llvmpasses/final-lower-gc.ll | 14 ++-- test/llvmpasses/late-lower-gc-addrspaces.ll | 8 +- test/llvmpasses/late-lower-gc.ll | 8 +- 12 files changed, 199 insertions(+), 59 deletions(-) diff --git a/doc/src/manual/profile.md b/doc/src/manual/profile.md index e5f1d6c417fa6..6e9f98d3f1780 100644 --- a/doc/src/manual/profile.md +++ b/doc/src/manual/profile.md @@ -338,15 +338,91 @@ argument can be passed to speed it up by making it skip some allocations. Passing `sample_rate=1.0` will make it record everything (which is slow); `sample_rate=0.1` will record only 10% of the allocations (faster), etc. -!!! note +!!! compat "Julia 1.11" + + Older versions of Julia could not capture types in all cases. In older versions of + Julia, if you see an allocation of type `Profile.Allocs.UnknownType`, it means that + the profiler doesn't know what type of object was allocated. This mainly happened when + the allocation was coming from generated code produced by the compiler. See + [issue #43688](https://github.com/JuliaLang/julia/issues/43688) for more info. + + Since Julia 1.11, all allocations should have a type reported. + +For more details on how to use this tool, please see the following talk from JuliaCon 2022: +https://www.youtube.com/watch?v=BFvpwC8hEWQ + +##### Allocation Profiler Example - The current implementation of the Allocations Profiler _does not - capture types for all allocations._ Allocations for which the profiler - could not capture the type are represented as having type - `Profile.Allocs.UnknownType`. +In this simple example, we use PProf to visualize the alloc profile. You could use another +visualization tool instead. We collect the profile (specifying a sample rate), then we visualize it. +```julia +using Profile, PProf +Profile.Allocs.clear() +Profile.Allocs.@profile sample_rate=0.0001 my_function() +PProf.Allocs.pprof() +``` + +Here is a more in-depth example, showing how we can tune the sample rate. A +good number of samples to aim for is around 1 - 10 thousand. Too many, and the +profile visualizer can get overwhelmed, and profiling will be slow. Too few, +and you don't have a representative sample. - You can read more about the missing types and the plan to improve this, here: - [issue #43688](https://github.com/JuliaLang/julia/issues/43688). + +```julia-repl +julia> import Profile + +julia> @time my_function() # Estimate allocations from a (second-run) of the function + 0.110018 seconds (1.50 M allocations: 58.725 MiB, 17.17% gc time) +500000 + +julia> Profile.Allocs.clear() + +julia> Profile.Allocs.@profile sample_rate=0.001 begin # 1.5 M * 0.001 = ~1.5K allocs. + my_function() + end +500000 + +julia> prof = Profile.Allocs.fetch(); # If you want, you can also manually inspect the results. + +julia> length(prof.allocs) # Confirm we have expected number of allocations. +1515 + +julia> using PProf # Now, visualize with an external tool, like PProf or ProfileCanvas. + +julia> PProf.Allocs.pprof(prof; from_c=false) # You can optionally pass in a previously fetched profile result. +Analyzing 1515 allocation samples... 100%|████████████████████████████████| Time: 0:00:00 +Main binary filename not available. +Serving web UI on http://localhost:62261 +"alloc-profile.pb.gz" +``` +Then you can view the profile by navigating to http://localhost:62261, and the profile is saved to disk. +See PProf package for more options. + +##### Allocation Profiling Tips + +As stated above, aim for around 1-10 thousand samples in your profile. + +Note that we are uniformly sampling in the space of _all allocations_, and are not weighting +our samples by the size of the allocation. So a given allocation profile may not give a +representative profile of where most bytes are allocated in your program, unless you had set +`sample_rate=1`. + +Allocations can come from users directly constructing objects, but can also come from inside +the runtime or be inserted into compiled code to handle type instability. Looking at the +"source code" view can be helpful to isolate them, and then other external tools such as +[`Cthulhu.jl`](https://github.com/JuliaDebug/Cthulhu.jl) can be useful for identifying the +cause of the allocation. + +##### Allocation Profile Visualization Tools + +There are several profiling visualization tools now that can all display Allocation +Profiles. Here is a small list of some of the main ones we know about: +- [PProf.jl](https://github.com/JuliaPerf/PProf.jl) +- [ProfileCanvas.jl](https://github.com/pfitzseb/ProfileCanvas.jl) +- VSCode's built-in profile visualizer (`@profview_allocs`) [docs needed] +- Viewing the results directly in the REPL + - You can inspect the results in the REPL via [`Profile.Allocs.fetch()`](@ref), to view + the stacktrace and type of each allocation. #### Line-by-Line Allocation Tracking diff --git a/src/gc-alloc-profiler.h b/src/gc-alloc-profiler.h index 3fd8bf4388a0a..fcd8e45caa2d8 100644 --- a/src/gc-alloc-profiler.h +++ b/src/gc-alloc-profiler.h @@ -35,6 +35,7 @@ void _maybe_record_alloc_to_profile(jl_value_t *val, size_t size, jl_datatype_t extern int g_alloc_profile_enabled; +// This should only be used from _deprecated_ code paths. We shouldn't see UNKNOWN anymore. #define jl_gc_unknown_type_tag ((jl_datatype_t*)0xdeadaa03) static inline void maybe_record_alloc_to_profile(jl_value_t *val, size_t size, jl_datatype_t *typ) JL_NOTSAFEPOINT { diff --git a/src/gc.c b/src/gc.c index 58b59bb1d1d33..a5b4998a370a4 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1030,13 +1030,20 @@ STATIC_INLINE jl_value_t *jl_gc_big_alloc_inner(jl_ptls_t ptls, size_t sz) return jl_valueof(&v->header); } -// Instrumented version of jl_gc_big_alloc_inner, called into by LLVM-generated code. +// Deprecated version, supported for legacy code. JL_DLLEXPORT jl_value_t *jl_gc_big_alloc(jl_ptls_t ptls, size_t sz) { jl_value_t *val = jl_gc_big_alloc_inner(ptls, sz); maybe_record_alloc_to_profile(val, sz, jl_gc_unknown_type_tag); return val; } +// Instrumented version of jl_gc_big_alloc_inner, called into by LLVM-generated code. +JL_DLLEXPORT jl_value_t *jl_gc_big_alloc_instrumented(jl_ptls_t ptls, size_t sz, jl_value_t *type) +{ + jl_value_t *val = jl_gc_big_alloc_inner(ptls, sz); + maybe_record_alloc_to_profile(val, sz, (jl_datatype_t*)type); + return val; +} // This wrapper exists only to prevent `jl_gc_big_alloc_inner` from being inlined into // its callers. We provide an external-facing interface for callers, and inline `jl_gc_big_alloc_inner` @@ -1334,7 +1341,7 @@ STATIC_INLINE jl_value_t *jl_gc_pool_alloc_inner(jl_ptls_t ptls, int pool_offset return jl_valueof(v); } -// Instrumented version of jl_gc_pool_alloc_inner, called into by LLVM-generated code. +// Deprecated version, supported for legacy code. JL_DLLEXPORT jl_value_t *jl_gc_pool_alloc(jl_ptls_t ptls, int pool_offset, int osize) { @@ -1342,6 +1349,14 @@ JL_DLLEXPORT jl_value_t *jl_gc_pool_alloc(jl_ptls_t ptls, int pool_offset, maybe_record_alloc_to_profile(val, osize, jl_gc_unknown_type_tag); return val; } +// Instrumented version of jl_gc_pool_alloc_inner, called into by LLVM-generated code. +JL_DLLEXPORT jl_value_t *jl_gc_pool_alloc_instrumented(jl_ptls_t ptls, int pool_offset, + int osize, jl_value_t* type) +{ + jl_value_t *val = jl_gc_pool_alloc_inner(ptls, pool_offset, osize); + maybe_record_alloc_to_profile(val, osize, (jl_datatype_t*)type); + return val; +} // This wrapper exists only to prevent `jl_gc_pool_alloc_inner` from being inlined into // its callers. We provide an external-facing interface for callers, and inline `jl_gc_pool_alloc_inner` diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index ee255a0e1a876..40ad295b30e58 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -158,6 +158,7 @@ XX(jl_gc_alloc_3w) \ XX(jl_gc_alloc_typed) \ XX(jl_gc_big_alloc) \ + XX(jl_gc_big_alloc_instrumented) \ XX(jl_gc_collect) \ XX(jl_gc_conservative_gc_support_enabled) \ XX(jl_gc_counted_calloc) \ @@ -185,6 +186,7 @@ XX(jl_gc_new_weakref_th) \ XX(jl_gc_num) \ XX(jl_gc_pool_alloc) \ + XX(jl_gc_pool_alloc_instrumented) \ XX(jl_gc_queue_multiroot) \ XX(jl_gc_queue_root) \ XX(jl_gc_safepoint) \ diff --git a/src/llvm-final-gc-lowering.cpp b/src/llvm-final-gc-lowering.cpp index e31bcb21199f5..5defee9bd80be 100644 --- a/src/llvm-final-gc-lowering.cpp +++ b/src/llvm-final-gc-lowering.cpp @@ -187,12 +187,13 @@ Value *FinalLowerGC::lowerSafepoint(CallInst *target, Function &F) Value *FinalLowerGC::lowerGCAllocBytes(CallInst *target, Function &F) { ++GCAllocBytesCount; - assert(target->arg_size() == 2); + assert(target->arg_size() == 3); CallInst *newI; IRBuilder<> builder(target); builder.SetCurrentDebugLocation(target->getDebugLoc()); auto ptls = target->getArgOperand(0); + auto type = target->getArgOperand(2); Attribute derefAttr; if (auto CI = dyn_cast(target->getArgOperand(1))) { @@ -203,19 +204,19 @@ Value *FinalLowerGC::lowerGCAllocBytes(CallInst *target, Function &F) if (offset < 0) { newI = builder.CreateCall( bigAllocFunc, - { ptls, ConstantInt::get(T_size, sz + sizeof(void*)) }); + { ptls, ConstantInt::get(T_size, sz + sizeof(void*)), type }); derefAttr = Attribute::getWithDereferenceableBytes(F.getContext(), sz + sizeof(void*)); } else { auto pool_offs = ConstantInt::get(Type::getInt32Ty(F.getContext()), offset); auto pool_osize = ConstantInt::get(Type::getInt32Ty(F.getContext()), osize); - newI = builder.CreateCall(poolAllocFunc, { ptls, pool_offs, pool_osize }); + newI = builder.CreateCall(poolAllocFunc, { ptls, pool_offs, pool_osize, type }); derefAttr = Attribute::getWithDereferenceableBytes(F.getContext(), osize); } } else { auto size = builder.CreateZExtOrTrunc(target->getArgOperand(1), T_size); size = builder.CreateAdd(size, ConstantInt::get(T_size, sizeof(void*))); - newI = builder.CreateCall(allocTypedFunc, { ptls, size, ConstantPointerNull::get(Type::getInt8PtrTy(F.getContext())) }); + newI = builder.CreateCall(allocTypedFunc, { ptls, size, type }); derefAttr = Attribute::getWithDereferenceableBytes(F.getContext(), sizeof(void*)); } newI->setAttributes(newI->getCalledFunction()->getAttributes()); diff --git a/src/llvm-late-gc-lowering.cpp b/src/llvm-late-gc-lowering.cpp index 63a71a9e180ac..19dfb7c5a5be1 100644 --- a/src/llvm-late-gc-lowering.cpp +++ b/src/llvm-late-gc-lowering.cpp @@ -2348,22 +2348,6 @@ bool LateLowerGCFrame::CleanupIR(Function &F, State *S, bool *CFGModified) { IRBuilder<> builder(CI); builder.SetCurrentDebugLocation(CI->getDebugLoc()); - // Create a call to the `julia.gc_alloc_bytes` intrinsic, which is like - // `julia.gc_alloc_obj` except it doesn't set the tag. - auto allocBytesIntrinsic = getOrDeclare(jl_intrinsics::GCAllocBytes); - auto ptlsLoad = get_current_ptls_from_task(builder, T_size, CI->getArgOperand(0), tbaa_gcframe); - auto ptls = builder.CreateBitCast(ptlsLoad, Type::getInt8PtrTy(builder.getContext())); - auto newI = builder.CreateCall( - allocBytesIntrinsic, - { - ptls, - builder.CreateIntCast( - CI->getArgOperand(1), - allocBytesIntrinsic->getFunctionType()->getParamType(1), - false) - }); - newI->takeName(CI); - // LLVM alignment/bit check is not happy about addrspacecast and refuse // to remove write barrier because of it. // We pretty much only load using `T_size` so try our best to strip @@ -2401,7 +2385,35 @@ bool LateLowerGCFrame::CleanupIR(Function &F, State *S, bool *CFGModified) { builder.CreateAlignmentAssumption(DL, tag, 16); } } - // Set the tag. + + // Create a call to the `julia.gc_alloc_bytes` intrinsic, which is like + // `julia.gc_alloc_obj` except it specializes the call based on the constant + // size of the object to allocate, to save one indirection, and doesn't set + // the type tag. (Note that if the size is not a constant, it will call + // gc_alloc_obj, and will redundantly set the tag.) + auto allocBytesIntrinsic = getOrDeclare(jl_intrinsics::GCAllocBytes); + auto ptlsLoad = get_current_ptls_from_task(builder, T_size, CI->getArgOperand(0), tbaa_gcframe); + auto ptls = builder.CreateBitCast(ptlsLoad, Type::getInt8PtrTy(builder.getContext())); + auto newI = builder.CreateCall( + allocBytesIntrinsic, + { + ptls, + builder.CreateIntCast( + CI->getArgOperand(1), + allocBytesIntrinsic->getFunctionType()->getParamType(1), + false), + builder.CreatePtrToInt(tag, T_size), + }); + newI->takeName(CI); + + // Now, finally, set the tag. We do this in IR instead of in the C alloc + // function, to provide possible optimization opportunities. (I think? TBH + // the most recent editor of this code is not entirely clear on why we + // prefer to set the tag in the generated code. Providing optimziation + // opportunities is the most likely reason; the tradeoff is slightly + // larger code size and increased compilation time, compiling this + // instruction at every allocation site, rather than once in the C alloc + // function.) auto &M = *builder.GetInsertBlock()->getModule(); StoreInst *store = builder.CreateAlignedStore( tag, EmitTagPtr(builder, tag_type, T_size, newI), M.getDataLayout().getPointerABIAlignment(0)); diff --git a/src/llvm-pass-helpers.cpp b/src/llvm-pass-helpers.cpp index b006f191937f5..39d37cee3928b 100644 --- a/src/llvm-pass-helpers.cpp +++ b/src/llvm-pass-helpers.cpp @@ -151,7 +151,9 @@ namespace jl_intrinsics { auto intrinsic = Function::Create( FunctionType::get( T_prjlvalue, - { Type::getInt8PtrTy(ctx), T_size }, + { Type::getInt8PtrTy(ctx), + T_size, + T_size }, // type false), Function::ExternalLinkage, GC_ALLOC_BYTES_NAME); @@ -236,8 +238,8 @@ namespace jl_intrinsics { } namespace jl_well_known { - static const char *GC_BIG_ALLOC_NAME = XSTR(jl_gc_big_alloc); - static const char *GC_POOL_ALLOC_NAME = XSTR(jl_gc_pool_alloc); + static const char *GC_BIG_ALLOC_NAME = XSTR(jl_gc_big_alloc_instrumented); + static const char *GC_POOL_ALLOC_NAME = XSTR(jl_gc_pool_alloc_instrumented); static const char *GC_QUEUE_ROOT_NAME = XSTR(jl_gc_queue_root); static const char *GC_ALLOC_TYPED_NAME = XSTR(jl_gc_alloc_typed); @@ -251,7 +253,7 @@ namespace jl_well_known { auto bigAllocFunc = Function::Create( FunctionType::get( T_prjlvalue, - { Type::getInt8PtrTy(ctx), T_size }, + { Type::getInt8PtrTy(ctx), T_size , T_size}, false), Function::ExternalLinkage, GC_BIG_ALLOC_NAME); @@ -267,7 +269,7 @@ namespace jl_well_known { auto poolAllocFunc = Function::Create( FunctionType::get( T_prjlvalue, - { Type::getInt8PtrTy(ctx), Type::getInt32Ty(ctx), Type::getInt32Ty(ctx) }, + { Type::getInt8PtrTy(ctx), Type::getInt32Ty(ctx), Type::getInt32Ty(ctx), T_size }, false), Function::ExternalLinkage, GC_POOL_ALLOC_NAME); @@ -301,7 +303,7 @@ namespace jl_well_known { T_prjlvalue, { Type::getInt8PtrTy(ctx), T_size, - Type::getInt8PtrTy(ctx) }, + T_size }, // type false), Function::ExternalLinkage, GC_ALLOC_TYPED_NAME); diff --git a/stdlib/Profile/test/allocs.jl b/stdlib/Profile/test/allocs.jl index c2ec7d2f6cb54..ae0cbab945f01 100644 --- a/stdlib/Profile/test/allocs.jl +++ b/stdlib/Profile/test/allocs.jl @@ -121,3 +121,34 @@ end @test length(prof.allocs) >= 1 @test length([a for a in prof.allocs if a.type == String]) >= 1 end + +@testset "alloc profiler catches allocs from codegen" begin + @eval begin + struct MyType x::Int; y::Int end + Base.:(+)(n::Number, x::MyType) = n + x.x + x.y + foo(a, x) = a[1] + x + wrapper(a) = foo(a, MyType(0,1)) + end + a = Any[1,2,3] + # warmup + wrapper(a) + + @eval Allocs.@profile sample_rate=1 wrapper($a) + + prof = Allocs.fetch() + Allocs.clear() + + @test length(prof.allocs) >= 1 + @test length([a for a in prof.allocs if a.type == MyType]) >= 1 +end + +@testset "alloc profiler catches allocs from buffer resize" begin + a = Int[] + Allocs.@profile sample_rate=1 for _ in 1:100; push!(a, 1); end + + prof = Allocs.fetch() + Allocs.clear() + + @test length(prof.allocs) >= 1 + @test length([a for a in prof.allocs if a.type == Profile.Allocs.BufferType]) >= 1 +end diff --git a/test/llvmpasses/alloc-opt-gcframe.ll b/test/llvmpasses/alloc-opt-gcframe.ll index a04d6566cec0a..f600399ac2a7a 100644 --- a/test/llvmpasses/alloc-opt-gcframe.ll +++ b/test/llvmpasses/alloc-opt-gcframe.ll @@ -14,17 +14,17 @@ target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" ; CHECK-NOT: @julia.gc_alloc_obj ; TYPED: %current_task = getelementptr inbounds {}*, {}** %gcstack, i64 -12 -; TYPED-NEXT: [[ptls_field:%.*]] = getelementptr inbounds {}*, {}** %current_task, i64 16 +; TYPED: [[ptls_field:%.*]] = getelementptr inbounds {}*, {}** %current_task, i64 16 ; TYPED-NEXT: [[ptls_load:%.*]] = load {}*, {}** [[ptls_field]], align 8, !tbaa !0 ; TYPED-NEXT: [[ppjl_ptls:%.*]] = bitcast {}* [[ptls_load]] to {}** ; TYPED-NEXT: [[ptls_i8:%.*]] = bitcast {}** [[ppjl_ptls]] to i8* -; TYPED-NEXT: %v = call noalias nonnull dereferenceable({{[0-9]+}}) {} addrspace(10)* @ijl_gc_pool_alloc(i8* [[ptls_i8]], i32 [[SIZE_T:[0-9]+]], i32 16) +; TYPED-NEXT: %v = call noalias nonnull dereferenceable({{[0-9]+}}) {} addrspace(10)* @ijl_gc_pool_alloc_instrumented(i8* [[ptls_i8]], i32 [[SIZE_T:[0-9]+]], i32 16, i64 {{.*}} @tag {{.*}}) ; TYPED: store atomic {} addrspace(10)* @tag, {} addrspace(10)* addrspace(10)* {{.*}} unordered, align 8, !tbaa !4 ; OPAQUE: %current_task = getelementptr inbounds ptr, ptr %gcstack, i64 -12 -; OPAQUE-NEXT: [[ptls_field:%.*]] = getelementptr inbounds ptr, ptr %current_task, i64 16 +; OPAQUE: [[ptls_field:%.*]] = getelementptr inbounds ptr, ptr %current_task, i64 16 ; OPAQUE-NEXT: [[ptls_load:%.*]] = load ptr, ptr [[ptls_field]], align 8, !tbaa !0 -; OPAQUE-NEXT: %v = call noalias nonnull dereferenceable({{[0-9]+}}) ptr addrspace(10) @ijl_gc_pool_alloc(ptr [[ptls_load]], i32 [[SIZE_T:[0-9]+]], i32 16) +; OPAQUE-NEXT: %v = call noalias nonnull dereferenceable({{[0-9]+}}) ptr addrspace(10) @ijl_gc_pool_alloc_instrumented(ptr [[ptls_load]], i32 [[SIZE_T:[0-9]+]], i32 16, i64 {{.*}} @tag {{.*}}) ; OPAQUE: store atomic ptr addrspace(10) @tag, ptr addrspace(10) {{.*}} unordered, align 8, !tbaa !4 define {} addrspace(10)* @return_obj() { @@ -270,11 +270,11 @@ L3: } ; CHECK-LABEL: }{{$}} -; TYPED: declare noalias nonnull {} addrspace(10)* @ijl_gc_pool_alloc(i8*, -; TYPED: declare noalias nonnull {} addrspace(10)* @ijl_gc_big_alloc(i8*, +; TYPED: declare noalias nonnull {} addrspace(10)* @ijl_gc_pool_alloc_instrumented(i8*, +; TYPED: declare noalias nonnull {} addrspace(10)* @ijl_gc_big_alloc_instrumented(i8*, -; OPAQUE: declare noalias nonnull ptr addrspace(10) @ijl_gc_pool_alloc(ptr, -; OPAQUE: declare noalias nonnull ptr addrspace(10) @ijl_gc_big_alloc(ptr, +; OPAQUE: declare noalias nonnull ptr addrspace(10) @ijl_gc_pool_alloc_instrumented(ptr, +; OPAQUE: declare noalias nonnull ptr addrspace(10) @ijl_gc_big_alloc_instrumented(ptr, declare void @external_function() declare {}*** @julia.get_pgcstack() declare noalias nonnull {} addrspace(10)* @julia.gc_alloc_obj({}**, i64, {} addrspace(10)*) diff --git a/test/llvmpasses/final-lower-gc.ll b/test/llvmpasses/final-lower-gc.ll index 5bbaa2f4d81ea..64d2c06e534b2 100644 --- a/test/llvmpasses/final-lower-gc.ll +++ b/test/llvmpasses/final-lower-gc.ll @@ -18,7 +18,7 @@ declare noalias nonnull {} addrspace(10)** @julia.new_gc_frame(i32) declare void @julia.push_gc_frame({} addrspace(10)**, i32) declare {} addrspace(10)** @julia.get_gc_frame_slot({} addrspace(10)**, i32) declare void @julia.pop_gc_frame({} addrspace(10)**) -declare noalias nonnull {} addrspace(10)* @julia.gc_alloc_bytes(i8*, i64) #0 +declare noalias nonnull {} addrspace(10)* @julia.gc_alloc_bytes(i8*, i64, i64) #0 attributes #0 = { allocsize(1) } @@ -80,9 +80,9 @@ top: %pgcstack = call {}*** @julia.get_pgcstack() %ptls = call {}*** @julia.ptls_states() %ptls_i8 = bitcast {}*** %ptls to i8* -; TYPED: %v = call noalias nonnull dereferenceable({{[0-9]+}}) {} addrspace(10)* @ijl_gc_pool_alloc -; OPAQUE: %v = call noalias nonnull dereferenceable({{[0-9]+}}) ptr addrspace(10) @ijl_gc_pool_alloc - %v = call {} addrspace(10)* @julia.gc_alloc_bytes(i8* %ptls_i8, i64 8) +; TYPED: %v = call noalias nonnull dereferenceable({{[0-9]+}}) {} addrspace(10)* @ijl_gc_pool_alloc_instrumented +; OPAQUE: %v = call noalias nonnull dereferenceable({{[0-9]+}}) ptr addrspace(10) @ijl_gc_pool_alloc_instrumented + %v = call {} addrspace(10)* @julia.gc_alloc_bytes(i8* %ptls_i8, i64 8, i64 12341234) %0 = bitcast {} addrspace(10)* %v to {} addrspace(10)* addrspace(10)* %1 = getelementptr {} addrspace(10)*, {} addrspace(10)* addrspace(10)* %0, i64 -1 store {} addrspace(10)* @tag, {} addrspace(10)* addrspace(10)* %1, align 8, !tbaa !0 @@ -96,9 +96,9 @@ top: %ptls = call {}*** @julia.ptls_states() %ptls_i8 = bitcast {}*** %ptls to i8* ; CHECK: %0 = add i64 %size, 8 -; TYPED: %v = call noalias nonnull dereferenceable(8) {} addrspace(10)* @ijl_gc_alloc_typed(i8* %ptls_i8, i64 %0, i8* null) -; OPAQUE: %v = call noalias nonnull dereferenceable(8) ptr addrspace(10) @ijl_gc_alloc_typed(ptr %ptls_i8, i64 %0, ptr null) - %v = call {} addrspace(10)* @julia.gc_alloc_bytes(i8* %ptls_i8, i64 %size) +; TYPED: %v = call noalias nonnull dereferenceable(8) {} addrspace(10)* @ijl_gc_alloc_typed(i8* %ptls_i8, i64 %0, i64 12341234) +; OPAQUE: %v = call noalias nonnull dereferenceable(8) ptr addrspace(10) @ijl_gc_alloc_typed(ptr %ptls_i8, i64 %0, i64 12341234) + %v = call {} addrspace(10)* @julia.gc_alloc_bytes(i8* %ptls_i8, i64 %size, i64 12341234) %0 = bitcast {} addrspace(10)* %v to {} addrspace(10)* addrspace(10)* %1 = getelementptr {} addrspace(10)*, {} addrspace(10)* addrspace(10)* %0, i64 -1 store {} addrspace(10)* @tag, {} addrspace(10)* addrspace(10)* %1, align 8, !tbaa !0 diff --git a/test/llvmpasses/late-lower-gc-addrspaces.ll b/test/llvmpasses/late-lower-gc-addrspaces.ll index 9849f432fb9a7..8021aab6c99a3 100644 --- a/test/llvmpasses/late-lower-gc-addrspaces.ll +++ b/test/llvmpasses/late-lower-gc-addrspaces.ll @@ -69,7 +69,7 @@ top: ; TYPED-NEXT: [[ptls_load:%.*]] = load {}*, {}** [[ptls_field]], align 8, !tbaa !0 ; TYPED-NEXT: [[ppjl_ptls:%.*]] = bitcast {}* [[ptls_load]] to {}** ; TYPED-NEXT: [[ptls_i8:%.*]] = bitcast {}** [[ppjl_ptls]] to i8* -; TYPED-NEXT: %v = call {} addrspace(10)* @julia.gc_alloc_bytes(i8* [[ptls_i8]], [[SIZE_T:i.[0-9]+]] 8) +; TYPED-NEXT: %v = call {} addrspace(10)* @julia.gc_alloc_bytes(i8* [[ptls_i8]], [[SIZE_T:i.[0-9]+]] 8, i64 {{.*}} @tag {{.*}}) ; TYPED-NEXT: [[V2:%.*]] = bitcast {} addrspace(10)* %v to {} addrspace(10)* addrspace(10)* ; TYPED-NEXT: [[V_HEADROOM:%.*]] = getelementptr inbounds {} addrspace(10)*, {} addrspace(10)* addrspace(10)* [[V2]], i64 -1 ; TYPED-NEXT: store atomic {} addrspace(10)* @tag, {} addrspace(10)* addrspace(10)* [[V_HEADROOM]] unordered, align 8, !tbaa !4 @@ -77,7 +77,7 @@ top: ; OPAQUE: %current_task = getelementptr inbounds ptr, ptr %0, i64 -12 ; OPAQUE-NEXT: [[ptls_field:%.*]] = getelementptr inbounds ptr, ptr %current_task, i64 16 ; OPAQUE-NEXT: [[ptls_load:%.*]] = load ptr, ptr [[ptls_field]], align 8, !tbaa !0 -; OPAQUE-NEXT: %v = call ptr addrspace(10) @julia.gc_alloc_bytes(ptr [[ptls_load]], [[SIZE_T:i.[0-9]+]] 8) +; OPAQUE-NEXT: %v = call ptr addrspace(10) @julia.gc_alloc_bytes(ptr [[ptls_load]], [[SIZE_T:i.[0-9]+]] 8, i64 {{.*}} @tag {{.*}}) ; OPAQUE-NEXT: [[V_HEADROOM:%.*]] = getelementptr inbounds ptr addrspace(10), ptr addrspace(10) %v, i64 -1 ; OPAQUE-NEXT: store atomic ptr addrspace(10) @tag, ptr addrspace(10) [[V_HEADROOM]] unordered, align 8, !tbaa !4 %v = call noalias {} addrspace(10)* @julia.gc_alloc_obj({}** %current_task, i64 8, {} addrspace(10)* @tag) @@ -102,7 +102,7 @@ top: ; TYPED-NEXT: [[ptls_load:%.*]] = load {}*, {}** [[ptls_field]], align 8, !tbaa !0 ; TYPED-NEXT: [[ppjl_ptls:%.*]] = bitcast {}* [[ptls_load]] to {}** ; TYPED-NEXT: [[ptls_i8:%.*]] = bitcast {}** [[ppjl_ptls]] to i8* -; TYPED-NEXT: %v = call {} addrspace(10)* @julia.gc_alloc_bytes(i8* [[ptls_i8]], [[SIZE_T:i.[0-9]+]] 8) +; TYPED-NEXT: %v = call {} addrspace(10)* @julia.gc_alloc_bytes(i8* [[ptls_i8]], [[SIZE_T:i.[0-9]+]] 8, i64 {{.*}} @tag {{.*}}) ; TYPED-NEXT: [[V2:%.*]] = bitcast {} addrspace(10)* %v to {} addrspace(10)* addrspace(10)* ; TYPED-NEXT: [[V_HEADROOM:%.*]] = getelementptr inbounds {} addrspace(10)*, {} addrspace(10)* addrspace(10)* [[V2]], i64 -1 ; TYPED-NEXT: store atomic {} addrspace(10)* @tag, {} addrspace(10)* addrspace(10)* [[V_HEADROOM]] unordered, align 8, !tbaa !4 @@ -110,7 +110,7 @@ top: ; OPAQUE: %current_task = getelementptr inbounds ptr, ptr %0, i64 -12 ; OPAQUE-NEXT: [[ptls_field:%.*]] = getelementptr inbounds ptr, ptr %current_task, i64 16 ; OPAQUE-NEXT: [[ptls_load:%.*]] = load ptr, ptr [[ptls_field]], align 8, !tbaa !0 -; OPAQUE-NEXT: %v = call ptr addrspace(10) @julia.gc_alloc_bytes(ptr [[ptls_load]], [[SIZE_T:i.[0-9]+]] 8) +; OPAQUE-NEXT: %v = call ptr addrspace(10) @julia.gc_alloc_bytes(ptr [[ptls_load]], [[SIZE_T:i.[0-9]+]] 8, i64 {{.*}} @tag {{.*}}) ; OPAQUE-NEXT: [[V_HEADROOM:%.*]] = getelementptr inbounds ptr addrspace(10), ptr addrspace(10) %v, i64 -1 ; OPAQUE-NEXT: store atomic ptr addrspace(10) @tag, ptr addrspace(10) [[V_HEADROOM]] unordered, align 8, !tbaa !4 %v = call noalias {} addrspace(10)* @julia.gc_alloc_obj({}** %current_task, i64 8, {} addrspace(10)* @tag) diff --git a/test/llvmpasses/late-lower-gc.ll b/test/llvmpasses/late-lower-gc.ll index 36e581993c176..26eec245c2de9 100644 --- a/test/llvmpasses/late-lower-gc.ll +++ b/test/llvmpasses/late-lower-gc.ll @@ -66,7 +66,7 @@ top: ; TYPED-NEXT: [[ptls_load:%.*]] = load {}*, {}** [[ptls_field]], align 8, !tbaa !0 ; TYPED-NEXT: [[ppjl_ptls:%.*]] = bitcast {}* [[ptls_load]] to {}** ; TYPED-NEXT: [[ptls_i8:%.*]] = bitcast {}** [[ppjl_ptls]] to i8* -; TYPED-NEXT: %v = call {} addrspace(10)* @julia.gc_alloc_bytes(i8* [[ptls_i8]], [[SIZE_T:i.[0-9]+]] 8) +; TYPED-NEXT: %v = call {} addrspace(10)* @julia.gc_alloc_bytes(i8* [[ptls_i8]], [[SIZE_T:i.[0-9]+]] 8, i64 {{.*}} @tag {{.*}}) ; TYPED-NEXT: [[V2:%.*]] = bitcast {} addrspace(10)* %v to {} addrspace(10)* addrspace(10)* ; TYPED-NEXT: [[V_HEADROOM:%.*]] = getelementptr inbounds {} addrspace(10)*, {} addrspace(10)* addrspace(10)* [[V2]], i64 -1 ; TYPED-NEXT: store atomic {} addrspace(10)* @tag, {} addrspace(10)* addrspace(10)* [[V_HEADROOM]] unordered, align 8, !tbaa !4 @@ -74,7 +74,7 @@ top: ; OPAQUE: %current_task = getelementptr inbounds ptr, ptr %0, i64 -12 ; OPAQUE-NEXT: [[ptls_field:%.*]] = getelementptr inbounds ptr, ptr %current_task, i64 16 ; OPAQUE-NEXT: [[ptls_load:%.*]] = load ptr, ptr [[ptls_field]], align 8, !tbaa !0 -; OPAQUE-NEXT: %v = call ptr addrspace(10) @julia.gc_alloc_bytes(ptr [[ptls_load]], [[SIZE_T:i.[0-9]+]] 8) +; OPAQUE-NEXT: %v = call ptr addrspace(10) @julia.gc_alloc_bytes(ptr [[ptls_load]], [[SIZE_T:i.[0-9]+]] 8, i64 {{.*}} @tag {{.*}}) ; OPAQUE-NEXT: [[V_HEADROOM:%.*]] = getelementptr inbounds ptr addrspace(10), ptr addrspace(10) %v, i64 -1 ; OPAQUE-NEXT: store atomic ptr addrspace(10) @tag, ptr addrspace(10) [[V_HEADROOM]] unordered, align 8, !tbaa !4 %v = call noalias {} addrspace(10)* @julia.gc_alloc_obj({}** %current_task, i64 8, {} addrspace(10)* @tag) @@ -99,7 +99,7 @@ top: ; TYPED-NEXT: [[ptls_load:%.*]] = load {}*, {}** [[ptls_field]], align 8, !tbaa !0 ; TYPED-NEXT: [[ppjl_ptls:%.*]] = bitcast {}* [[ptls_load]] to {}** ; TYPED-NEXT: [[ptls_i8:%.*]] = bitcast {}** [[ppjl_ptls]] to i8* -; TYPED-NEXT: %v = call {} addrspace(10)* @julia.gc_alloc_bytes(i8* [[ptls_i8]], [[SIZE_T:i.[0-9]+]] 8) +; TYPED-NEXT: %v = call {} addrspace(10)* @julia.gc_alloc_bytes(i8* [[ptls_i8]], [[SIZE_T:i.[0-9]+]] 8, i64 {{.*}} @tag {{.*}}) ; TYPED-NEXT: [[V2:%.*]] = bitcast {} addrspace(10)* %v to {} addrspace(10)* addrspace(10)* ; TYPED-NEXT: [[V_HEADROOM:%.*]] = getelementptr inbounds {} addrspace(10)*, {} addrspace(10)* addrspace(10)* [[V2]], i64 -1 ; TYPED-NEXT: store atomic {} addrspace(10)* @tag, {} addrspace(10)* addrspace(10)* [[V_HEADROOM]] unordered, align 8, !tbaa !4 @@ -107,7 +107,7 @@ top: ; OPAQUE: %current_task = getelementptr inbounds ptr, ptr %0, i64 -12 ; OPAQUE-NEXT: [[ptls_field:%.*]] = getelementptr inbounds ptr, ptr %current_task, i64 16 ; OPAQUE-NEXT: [[ptls_load:%.*]] = load ptr, ptr [[ptls_field]], align 8, !tbaa !0 -; OPAQUE-NEXT: %v = call ptr addrspace(10) @julia.gc_alloc_bytes(ptr [[ptls_load]], [[SIZE_T:i.[0-9]+]] 8) +; OPAQUE-NEXT: %v = call ptr addrspace(10) @julia.gc_alloc_bytes(ptr [[ptls_load]], [[SIZE_T:i.[0-9]+]] 8, i64 {{.*}} @tag {{.*}}) ; OPAQUE-NEXT: [[V_HEADROOM:%.*]] = getelementptr inbounds ptr addrspace(10), ptr addrspace(10) %v, i64 -1 ; OPAQUE-NEXT: store atomic ptr addrspace(10) @tag, ptr addrspace(10) [[V_HEADROOM]] unordered, align 8, !tbaa !4 %v = call noalias {} addrspace(10)* @julia.gc_alloc_obj({}** %current_task, i64 8, {} addrspace(10)* @tag) From 5931671fd3f2347691fdfa40c4430e526811ad95 Mon Sep 17 00:00:00 2001 From: d-netto Date: Mon, 21 Aug 2023 12:41:56 -0300 Subject: [PATCH 010/109] Metric for number of live bytes in the pool allocator (#51151) --- src/gc.c | 8 ++++++++ src/jl_exported_funcs.inc | 1 + 2 files changed, 9 insertions(+) diff --git a/src/gc.c b/src/gc.c index a5b4998a370a4..79c41d334ebe3 100644 --- a/src/gc.c +++ b/src/gc.c @@ -748,6 +748,7 @@ int prev_sweep_full = 1; int under_pressure = 0; // Full collection heuristics +static int64_t pool_live_bytes = 0; static int64_t live_bytes = 0; static int64_t promoted_bytes = 0; static int64_t last_full_live = 0; // live_bytes after last full collection @@ -1501,6 +1502,7 @@ static jl_taggedvalue_t **gc_sweep_page(jl_gc_pool_t *p, jl_gc_pagemeta_t **allo } gc_time_count_page(freedall, pg_skpd); gc_num.freed += (nfree - old_nfree) * osize; + pool_live_bytes += GC_PAGE_SZ - GC_PAGE_OFFSET - nfree * osize; return pfl; } @@ -3188,6 +3190,11 @@ JL_DLLEXPORT int64_t jl_gc_sync_total_bytes(int64_t offset) JL_NOTSAFEPOINT return newtb - oldtb; } +JL_DLLEXPORT int64_t jl_gc_pool_live_bytes(void) +{ + return pool_live_bytes; +} + JL_DLLEXPORT int64_t jl_gc_live_bytes(void) { return live_bytes; @@ -3390,6 +3397,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) promoted_bytes = 0; } scanned_bytes = 0; + pool_live_bytes = 0; // 6. start sweeping uint64_t start_sweep_time = jl_hrtime(); JL_PROBE_GC_SWEEP_BEGIN(sweep_full); diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index 40ad295b30e58..f52ef7f794442 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -176,6 +176,7 @@ XX(jl_gc_internal_obj_base_ptr) \ XX(jl_gc_is_enabled) \ XX(jl_gc_is_in_finalizer) \ + XX(jl_gc_pool_live_bytes) \ XX(jl_gc_live_bytes) \ XX(jl_gc_managed_malloc) \ XX(jl_gc_managed_realloc) \ From 0f706c4c180302854ef67b7ec037c721173de45a Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Wed, 20 Sep 2023 01:13:44 -0600 Subject: [PATCH 011/109] Export num_stack_mappings to track the number of in-flight stack mappings and tasks in application (#51301) --- src/gc-stacks.c | 4 ++++ test/threads.jl | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/src/gc-stacks.c b/src/gc-stacks.c index c04e48821e46f..693cb8d0eadf0 100644 --- a/src/gc-stacks.c +++ b/src/gc-stacks.c @@ -76,6 +76,10 @@ static void free_stack(void *stkbuf, size_t bufsz) } #endif +JL_DLLEXPORT uint32_t jl_get_num_stack_mappings(void) +{ + return jl_atomic_load_relaxed(&num_stack_mappings); +} const unsigned pool_sizes[] = { 128 * 1024, diff --git a/test/threads.jl b/test/threads.jl index 8189311739e31..14fe94408a050 100644 --- a/test/threads.jl +++ b/test/threads.jl @@ -327,3 +327,9 @@ end @test_throws ArgumentError @macroexpand(@threads 1) # arg isn't an Expr @test_throws ArgumentError @macroexpand(@threads if true 1 end) # arg doesn't start with for end + +@testset "num_stack_mappings metric" begin + @test @ccall(jl_get_num_stack_mappings()::Cint) >= 1 + # There must be at least two: one for the root test task and one for the async task: + @test fetch(@async(@ccall(jl_get_num_stack_mappings()::Cint))) >= 2 +end From ecf48c36922ccfba622641ca20a8f75072b74c2a Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Fri, 22 Sep 2023 15:48:34 -0300 Subject: [PATCH 012/109] parallelize sweeping of object pools (#51282) Sweeping of object pools will either construct a free list through dead objects (if there is at least one live object in a given page) or return the page to the OS (if there are no live objects whatsoever). With this PR, we're basically constructing the free-lists for each GC page in parallel. --- src/gc-debug.c | 4 +- src/gc-pages.c | 12 +-- src/gc.c | 188 ++++++++++++++++++++++++++++++-------------- src/gc.h | 33 ++++---- src/julia_threads.h | 9 ++- src/partr.c | 33 ++++---- src/threading.c | 4 +- src/threading.h | 4 +- 8 files changed, 187 insertions(+), 100 deletions(-) diff --git a/src/gc-debug.c b/src/gc-debug.c index 3f0f3368533a4..12acb1cfbe7cb 100644 --- a/src/gc-debug.c +++ b/src/gc-debug.c @@ -115,7 +115,7 @@ static void gc_clear_mark_outer(int bits) { for (int i = 0; i < gc_n_threads; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; - jl_gc_pagemeta_t *pg = ptls2->page_metadata_allocd; + jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->page_metadata_allocd.bottom); while (pg != NULL) { gc_clear_mark_page(pg, bits); pg = pg->next; @@ -1129,7 +1129,7 @@ static void gc_count_pool_pagetable(void) { for (int i = 0; i < gc_n_threads; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; - jl_gc_pagemeta_t *pg = ptls2->page_metadata_allocd; + jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->page_metadata_allocd.bottom); while (pg != NULL) { if (gc_alloc_map_is_set(pg->data)) { gc_count_pool_page(pg); diff --git a/src/gc-pages.c b/src/gc-pages.c index 7a32a7f4bf975..40e5454136148 100644 --- a/src/gc-pages.c +++ b/src/gc-pages.c @@ -129,7 +129,7 @@ NOINLINE jl_gc_pagemeta_t *jl_gc_alloc_page(void) JL_NOTSAFEPOINT jl_gc_pagemeta_t *meta = NULL; // try to get page from `pool_lazily_freed` - meta = pop_lf_page_metadata_back(&global_page_pool_lazily_freed); + meta = pop_lf_back(&global_page_pool_lazily_freed); if (meta != NULL) { gc_alloc_map_set(meta->data, GC_PAGE_ALLOCATED); // page is already mapped @@ -137,14 +137,14 @@ NOINLINE jl_gc_pagemeta_t *jl_gc_alloc_page(void) JL_NOTSAFEPOINT } // try to get page from `pool_clean` - meta = pop_lf_page_metadata_back(&global_page_pool_clean); + meta = pop_lf_back(&global_page_pool_clean); if (meta != NULL) { gc_alloc_map_set(meta->data, GC_PAGE_ALLOCATED); goto exit; } // try to get page from `pool_freed` - meta = pop_lf_page_metadata_back(&global_page_pool_freed); + meta = pop_lf_back(&global_page_pool_freed); if (meta != NULL) { gc_alloc_map_set(meta->data, GC_PAGE_ALLOCATED); goto exit; @@ -152,7 +152,7 @@ NOINLINE jl_gc_pagemeta_t *jl_gc_alloc_page(void) JL_NOTSAFEPOINT uv_mutex_lock(&gc_perm_lock); // another thread may have allocated a large block while we were waiting... - meta = pop_lf_page_metadata_back(&global_page_pool_clean); + meta = pop_lf_back(&global_page_pool_clean); if (meta != NULL) { uv_mutex_unlock(&gc_perm_lock); gc_alloc_map_set(meta->data, 1); @@ -166,10 +166,10 @@ NOINLINE jl_gc_pagemeta_t *jl_gc_alloc_page(void) JL_NOTSAFEPOINT pg->data = data + GC_PAGE_SZ * i; gc_alloc_map_maybe_create(pg->data); if (i == 0) { - gc_alloc_map_set(pg->data, 1); + gc_alloc_map_set(pg->data, GC_PAGE_ALLOCATED); } else { - push_lf_page_metadata_back(&global_page_pool_clean, pg); + push_lf_back(&global_page_pool_clean, pg); } } uv_mutex_unlock(&gc_perm_lock); diff --git a/src/gc.c b/src/gc.c index 79c41d334ebe3..982c2e3e73633 100644 --- a/src/gc.c +++ b/src/gc.c @@ -18,6 +18,10 @@ int jl_n_markthreads; int jl_n_sweepthreads; // Number of threads currently running the GC mark-loop _Atomic(int) gc_n_threads_marking; +// Number of threads sweeping +_Atomic(int) gc_n_threads_sweeping; +// Temporary for the `ptls->page_metadata_allocd` used during parallel sweeping +_Atomic(jl_gc_page_stack_t *) gc_allocd_scratch; // `tid` of mutator thread that triggered GC _Atomic(int) gc_master_tid; // `tid` of first GC thread @@ -745,6 +749,7 @@ static int mark_reset_age = 0; static int64_t scanned_bytes; // young bytes scanned while marking static int64_t perm_scanned_bytes; // old bytes scanned while marking int prev_sweep_full = 1; +int current_sweep_full = 0; int under_pressure = 0; // Full collection heuristics @@ -1259,9 +1264,9 @@ STATIC_INLINE jl_taggedvalue_t *gc_reset_page(jl_ptls_t ptls2, const jl_gc_pool_ return beg; } -jl_gc_global_page_pool_t global_page_pool_lazily_freed; -jl_gc_global_page_pool_t global_page_pool_clean; -jl_gc_global_page_pool_t global_page_pool_freed; +jl_gc_page_stack_t global_page_pool_lazily_freed; +jl_gc_page_stack_t global_page_pool_clean; +jl_gc_page_stack_t global_page_pool_freed; pagetable_t alloc_map; // Add a new page to the pool. Discards any pages in `p->newpages` before. @@ -1270,7 +1275,7 @@ static NOINLINE jl_taggedvalue_t *gc_add_page(jl_gc_pool_t *p) JL_NOTSAFEPOINT // Do not pass in `ptls` as argument. This slows down the fast path // in pool_alloc significantly jl_ptls_t ptls = jl_current_task->ptls; - jl_gc_pagemeta_t *pg = pop_page_metadata_back(&ptls->page_metadata_lazily_freed); + jl_gc_pagemeta_t *pg = pop_lf_back(&ptls->page_metadata_buffered); if (pg != NULL) { gc_alloc_map_set(pg->data, GC_PAGE_ALLOCATED); } @@ -1280,7 +1285,7 @@ static NOINLINE jl_taggedvalue_t *gc_add_page(jl_gc_pool_t *p) JL_NOTSAFEPOINT pg->osize = p->osize; pg->thread_n = ptls->tid; set_page_metadata(pg); - push_page_metadata_back(&ptls->page_metadata_allocd, pg); + push_lf_back(&ptls->page_metadata_allocd, pg); jl_taggedvalue_t *fl = gc_reset_page(ptls, p, pg); p->newpages = fl; return fl; @@ -1378,11 +1383,11 @@ int jl_gc_classify_pools(size_t sz, int *osize) // sweep phase -int64_t lazy_freed_pages = 0; +int64_t buffered_pages = 0; // Returns pointer to terminal pointer of list rooted at *pfl. -static jl_taggedvalue_t **gc_sweep_page(jl_gc_pool_t *p, jl_gc_pagemeta_t **allocd, - jl_gc_pagemeta_t **lazily_freed, jl_gc_pagemeta_t *pg, jl_taggedvalue_t **pfl, int sweep_full, int osize) JL_NOTSAFEPOINT +static void gc_sweep_page(jl_gc_pool_t *p, jl_gc_page_stack_t *allocd, jl_gc_page_stack_t *buffered, + jl_gc_pagemeta_t *pg, int osize) JL_NOTSAFEPOINT { char *data = pg->data; jl_taggedvalue_t *v = (jl_taggedvalue_t*)(data + GC_PAGE_OFFSET); @@ -1395,7 +1400,7 @@ static jl_taggedvalue_t **gc_sweep_page(jl_gc_pool_t *p, jl_gc_pagemeta_t **allo size_t nfree; int re_use_page = 1; - int freed_lazily = 0; + int keep_as_local_buffer = 0; int freedall = 1; int pg_skpd = 1; if (!pg->has_marked) { @@ -1406,9 +1411,9 @@ static jl_taggedvalue_t **gc_sweep_page(jl_gc_pool_t *p, jl_gc_pagemeta_t **allo // the eager one uses less memory. // FIXME - need to do accounting on a per-thread basis // on quick sweeps, keep a few pages empty but allocated for performance - if (!sweep_full && lazy_freed_pages <= default_collect_interval / GC_PAGE_SZ) { - lazy_freed_pages++; - freed_lazily = 1; + if (!current_sweep_full && buffered_pages <= default_collect_interval / GC_PAGE_SZ) { + buffered_pages++; + keep_as_local_buffer = 1; } #endif nfree = (GC_PAGE_SZ - GC_PAGE_OFFSET) / osize; @@ -1416,15 +1421,9 @@ static jl_taggedvalue_t **gc_sweep_page(jl_gc_pool_t *p, jl_gc_pagemeta_t **allo } // For quick sweep, we might be able to skip the page if the page doesn't // have any young live cell before marking. - if (!sweep_full && !pg->has_young) { + if (!current_sweep_full && !pg->has_young) { assert(!prev_sweep_full || pg->prev_nold >= pg->nold); if (!prev_sweep_full || pg->prev_nold == pg->nold) { - // the position of the freelist begin/end in this page - // is stored in its metadata - if (pg->fl_begin_offset != (uint16_t)-1) { - *pfl = page_pfl_beg(pg); - pfl = (jl_taggedvalue_t**)page_pfl_end(pg); - } freedall = 0; nfree = pg->nfree; goto done; @@ -1437,6 +1436,8 @@ static jl_taggedvalue_t **gc_sweep_page(jl_gc_pool_t *p, jl_gc_pagemeta_t **allo int has_young = 0; int16_t prev_nold = 0; int pg_nfree = 0; + jl_taggedvalue_t *fl = NULL; + jl_taggedvalue_t **pfl = &fl; jl_taggedvalue_t **pfl_begin = NULL; while ((char*)v <= lim) { int bits = v->bits.gc; @@ -1448,7 +1449,7 @@ static jl_taggedvalue_t **gc_sweep_page(jl_gc_pool_t *p, jl_gc_pagemeta_t **allo pg_nfree++; } else { // marked young or old - if (sweep_full || bits == GC_MARKED) { // old enough + if (current_sweep_full || bits == GC_MARKED) { // old enough bits = v->bits.gc = GC_OLD; // promote } prev_nold++; @@ -1470,7 +1471,7 @@ static jl_taggedvalue_t **gc_sweep_page(jl_gc_pool_t *p, jl_gc_pagemeta_t **allo } pg->nfree = pg_nfree; - if (sweep_full) { + if (current_sweep_full) { pg->nold = 0; pg->prev_nold = prev_nold; } @@ -1479,43 +1480,32 @@ static jl_taggedvalue_t **gc_sweep_page(jl_gc_pool_t *p, jl_gc_pagemeta_t **allo done: if (re_use_page) { - push_page_metadata_back(allocd, pg); - } - else if (freed_lazily) { - gc_alloc_map_set(pg->data, GC_PAGE_LAZILY_FREED); - push_page_metadata_back(lazily_freed, pg); + push_lf_back(allocd, pg); } else { - #ifdef _P64 // only enable concurrent sweeping on 64bit - if (jl_n_sweepthreads == 0) { - jl_gc_free_page(pg); - push_lf_page_metadata_back(&global_page_pool_freed, pg); + gc_alloc_map_set(pg->data, GC_PAGE_LAZILY_FREED); + if (keep_as_local_buffer) { + push_lf_back(buffered, pg); } else { - gc_alloc_map_set(pg->data, GC_PAGE_LAZILY_FREED); - push_lf_page_metadata_back(&global_page_pool_lazily_freed, pg); + push_lf_back(&global_page_pool_lazily_freed, pg); } - #else - jl_gc_free_page(pg); - push_lf_page_metadata_back(&global_page_pool_freed, pg); - #endif } gc_time_count_page(freedall, pg_skpd); - gc_num.freed += (nfree - old_nfree) * osize; - pool_live_bytes += GC_PAGE_SZ - GC_PAGE_OFFSET - nfree * osize; - return pfl; + jl_atomic_fetch_add((_Atomic(int64_t) *)&pool_live_bytes, GC_PAGE_SZ - GC_PAGE_OFFSET - nfree * osize); + jl_atomic_fetch_add((_Atomic(int64_t) *)&gc_num.freed, (nfree - old_nfree) * osize); } // the actual sweeping over all allocated pages in a memory pool -STATIC_INLINE void gc_sweep_pool_page(jl_taggedvalue_t ***pfl, jl_gc_pagemeta_t **allocd, - jl_gc_pagemeta_t **lazily_freed, jl_gc_pagemeta_t *pg, int sweep_full) JL_NOTSAFEPOINT +STATIC_INLINE void gc_sweep_pool_page(jl_gc_page_stack_t *allocd, jl_gc_page_stack_t *lazily_freed, + jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT { int p_n = pg->pool_n; int t_n = pg->thread_n; jl_ptls_t ptls2 = gc_all_tls_states[t_n]; jl_gc_pool_t *p = &ptls2->heap.norm_pools[p_n]; int osize = pg->osize; - pfl[t_n * JL_GC_N_POOLS + p_n] = gc_sweep_page(p, allocd, lazily_freed, pg, pfl[t_n * JL_GC_N_POOLS + p_n], sweep_full, osize); + gc_sweep_page(p, allocd, lazily_freed, pg, osize); } // sweep over all memory that is being used and not in a pool @@ -1541,11 +1531,70 @@ static void gc_pool_sync_nfree(jl_gc_pagemeta_t *pg, jl_taggedvalue_t *last) JL_ pg->nfree = nfree; } +void gc_sweep_wake_all(void) +{ + uv_mutex_lock(&gc_threads_lock); + for (int i = gc_first_tid; i < gc_first_tid + jl_n_markthreads; i++) { + jl_ptls_t ptls2 = gc_all_tls_states[i]; + jl_atomic_fetch_add(&ptls2->gc_sweeps_requested, 1); + } + uv_cond_broadcast(&gc_threads_cond); + uv_mutex_unlock(&gc_threads_lock); +} + +void gc_sweep_pool_parallel(void) +{ + jl_atomic_fetch_add(&gc_n_threads_sweeping, 1); + jl_gc_page_stack_t *allocd_scratch = jl_atomic_load(&gc_allocd_scratch); + if (allocd_scratch != NULL) { + while (1) { + int found_pg = 0; + for (int t_i = 0; t_i < gc_n_threads; t_i++) { + jl_ptls_t ptls2 = gc_all_tls_states[t_i]; + if (ptls2 == NULL) { + continue; + } + jl_gc_page_stack_t *allocd = &allocd_scratch[t_i]; + jl_gc_pagemeta_t *pg = pop_lf_back(&ptls2->page_metadata_allocd); + if (pg == NULL) { + continue; + } + gc_sweep_pool_page(allocd, &ptls2->page_metadata_buffered, pg); + found_pg = 1; + } + if (!found_pg) { + break; + } + } + } + jl_atomic_fetch_add(&gc_n_threads_sweeping, -1); +} + +void gc_sweep_wait_for_all(void) +{ + jl_atomic_store(&gc_allocd_scratch, NULL); + while (jl_atomic_load_relaxed(&gc_n_threads_sweeping) != 0) { + jl_cpu_pause(); + } +} + +void gc_free_pages(void) +{ + while (1) { + jl_gc_pagemeta_t *pg = pop_lf_back(&global_page_pool_lazily_freed); + if (pg == NULL) { + break; + } + jl_gc_free_page(pg); + push_lf_back(&global_page_pool_freed, pg); + } +} + // setup the data-structures for a sweep over all memory pools -static void gc_sweep_pool(int sweep_full) +static void gc_sweep_pool(void) { gc_time_pool_start(); - lazy_freed_pages = 0; + buffered_pages = 0; // For the benefit of the analyzer, which doesn't know that gc_n_threads // doesn't change over the course of this function @@ -1585,26 +1634,26 @@ static void gc_sweep_pool(int sweep_full) pg->has_young = 1; } } - jl_gc_pagemeta_t *pg = ptls2->page_metadata_lazily_freed; + jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->page_metadata_buffered.bottom); while (pg != NULL) { jl_gc_pagemeta_t *pg2 = pg->next; - lazy_freed_pages++; + buffered_pages++; pg = pg2; } } // the actual sweeping + jl_gc_page_stack_t *tmp = (jl_gc_page_stack_t *)alloca(n_threads * sizeof(jl_gc_page_stack_t)); + memset(tmp, 0, n_threads * sizeof(jl_gc_page_stack_t)); + jl_atomic_store(&gc_allocd_scratch, tmp); + gc_sweep_wake_all(); + gc_sweep_pool_parallel(); + gc_sweep_wait_for_all(); + for (int t_i = 0; t_i < n_threads; t_i++) { jl_ptls_t ptls2 = gc_all_tls_states[t_i]; if (ptls2 != NULL) { - jl_gc_pagemeta_t *allocd = NULL; - jl_gc_pagemeta_t *pg = ptls2->page_metadata_allocd; - while (pg != NULL) { - jl_gc_pagemeta_t *pg2 = pg->next; - gc_sweep_pool_page(pfl, &allocd, &ptls2->page_metadata_lazily_freed, pg, sweep_full); - pg = pg2; - } - ptls2->page_metadata_allocd = allocd; + ptls2->page_metadata_allocd = tmp[t_i]; for (int i = 0; i < JL_GC_N_POOLS; i++) { jl_gc_pool_t *p = &ptls2->heap.norm_pools[i]; p->newpages = NULL; @@ -1612,6 +1661,26 @@ static void gc_sweep_pool(int sweep_full) } } + // merge free lists + for (int t_i = 0; t_i < n_threads; t_i++) { + jl_ptls_t ptls2 = gc_all_tls_states[t_i]; + if (ptls2 == NULL) { + continue; + } + jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->page_metadata_allocd.bottom); + while (pg != NULL) { + jl_gc_pagemeta_t *pg2 = pg->next; + if (pg->fl_begin_offset != UINT16_MAX) { + char *cur_pg = pg->data; + jl_taggedvalue_t *fl_beg = (jl_taggedvalue_t*)(cur_pg + pg->fl_begin_offset); + jl_taggedvalue_t *fl_end = (jl_taggedvalue_t*)(cur_pg + pg->fl_end_offset); + *pfl[t_i * JL_GC_N_POOLS + pg->pool_n] = fl_beg; + pfl[t_i * JL_GC_N_POOLS + pg->pool_n] = &fl_end->next; + } + pg = pg2; + } + } + // null out terminal pointers of free lists for (int t_i = 0; t_i < n_threads; t_i++) { jl_ptls_t ptls2 = gc_all_tls_states[t_i]; @@ -1627,9 +1696,13 @@ static void gc_sweep_pool(int sweep_full) if (jl_n_sweepthreads > 0) { uv_sem_post(&gc_sweep_assists_needed); } + else { + gc_free_pages(); + } +#else + gc_free_pages(); #endif - - gc_time_pool_end(sweep_full); + gc_time_pool_end(current_sweep_full); } static void gc_sweep_perm_alloc(void) @@ -3410,13 +3483,14 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) #ifdef USE_TRACY TracyCZoneColor(full_timing_block.tracy_ctx, 0xFFA500); #endif + current_sweep_full = sweep_full; sweep_weak_refs(); sweep_stack_pools(); gc_sweep_foreign_objs(); gc_sweep_other(ptls, sweep_full); gc_scrub(); gc_verify_tags(); - gc_sweep_pool(sweep_full); + gc_sweep_pool(); if (sweep_full) gc_sweep_perm_alloc(); } diff --git a/src/gc.h b/src/gc.h index 749cfbbf9227a..ddb695b37dc8d 100644 --- a/src/gc.h +++ b/src/gc.h @@ -180,37 +180,39 @@ typedef struct _jl_gc_pagemeta_t { char *data; } jl_gc_pagemeta_t; -typedef struct { - _Atomic(jl_gc_pagemeta_t *) page_metadata_back; -} jl_gc_global_page_pool_t; - -extern jl_gc_global_page_pool_t global_page_pool_lazily_freed; -extern jl_gc_global_page_pool_t global_page_pool_clean; -extern jl_gc_global_page_pool_t global_page_pool_freed; +extern jl_gc_page_stack_t global_page_pool_lazily_freed; +extern jl_gc_page_stack_t global_page_pool_clean; +extern jl_gc_page_stack_t global_page_pool_freed; // Lock-free stack implementation taken // from Herlihy's "The Art of Multiprocessor Programming" +// XXX: this is not a general-purpose lock-free stack. We can +// get away with just using a CAS and not implementing some ABA +// prevention mechanism since once a node is popped from the +// `jl_gc_global_page_pool_t`, it may only be pushed back to them +// in the sweeping phase, which also doesn't push a node into the +// same stack after it's popped -STATIC_INLINE void push_lf_page_metadata_back(jl_gc_global_page_pool_t *pool, jl_gc_pagemeta_t *elt) JL_NOTSAFEPOINT +STATIC_INLINE void push_lf_back(jl_gc_page_stack_t *pool, jl_gc_pagemeta_t *elt) JL_NOTSAFEPOINT { while (1) { - jl_gc_pagemeta_t *old_back = jl_atomic_load_relaxed(&pool->page_metadata_back); + jl_gc_pagemeta_t *old_back = jl_atomic_load_relaxed(&pool->bottom); elt->next = old_back; - if (jl_atomic_cmpswap(&pool->page_metadata_back, &old_back, elt)) { + if (jl_atomic_cmpswap(&pool->bottom, &old_back, elt)) { break; } jl_cpu_pause(); } } -STATIC_INLINE jl_gc_pagemeta_t *pop_lf_page_metadata_back(jl_gc_global_page_pool_t *pool) JL_NOTSAFEPOINT +STATIC_INLINE jl_gc_pagemeta_t *pop_lf_back(jl_gc_page_stack_t *pool) JL_NOTSAFEPOINT { while (1) { - jl_gc_pagemeta_t *old_back = jl_atomic_load_relaxed(&pool->page_metadata_back); + jl_gc_pagemeta_t *old_back = jl_atomic_load_relaxed(&pool->bottom); if (old_back == NULL) { return NULL; } - if (jl_atomic_cmpswap(&pool->page_metadata_back, &old_back, old_back->next)) { + if (jl_atomic_cmpswap(&pool->bottom, &old_back, old_back->next)) { return old_back; } jl_cpu_pause(); @@ -359,7 +361,7 @@ extern jl_gc_num_t gc_num; extern bigval_t *big_objects_marked; extern arraylist_t finalizer_list_marked; extern arraylist_t to_finalize; -extern int64_t lazy_freed_pages; +extern int64_t buffered_pages; extern int gc_first_tid; extern int gc_n_threads; extern jl_ptls_t* gc_all_tls_states; @@ -427,12 +429,15 @@ extern uv_mutex_t gc_threads_lock; extern uv_cond_t gc_threads_cond; extern uv_sem_t gc_sweep_assists_needed; extern _Atomic(int) gc_n_threads_marking; +extern _Atomic(int) gc_n_threads_sweeping; void gc_mark_queue_all_roots(jl_ptls_t ptls, jl_gc_markqueue_t *mq); void gc_mark_finlist_(jl_gc_markqueue_t *mq, jl_value_t *fl_parent, jl_value_t **fl_begin, jl_value_t **fl_end) JL_NOTSAFEPOINT; void gc_mark_finlist(jl_gc_markqueue_t *mq, arraylist_t *list, size_t start) JL_NOTSAFEPOINT; void gc_mark_loop_serial_(jl_ptls_t ptls, jl_gc_markqueue_t *mq); void gc_mark_loop_serial(jl_ptls_t ptls); void gc_mark_loop_parallel(jl_ptls_t ptls, int master); +void gc_sweep_pool_parallel(void); +void gc_free_pages(void); void sweep_stack_pools(void); void jl_gc_debug_init(void); diff --git a/src/julia_threads.h b/src/julia_threads.h index 8acbf9b53d90c..025c5707e5507 100644 --- a/src/julia_threads.h +++ b/src/julia_threads.h @@ -200,6 +200,10 @@ typedef struct { struct _jl_bt_element_t; struct _jl_gc_pagemeta_t; +typedef struct { + _Atomic(struct _jl_gc_pagemeta_t *) bottom; +} jl_gc_page_stack_t; + // This includes all the thread local states we care about for a thread. // Changes to TLS field types must be reflected in codegen. #define JL_MAX_BT_SIZE 80000 @@ -261,11 +265,12 @@ typedef struct _jl_tls_states_t { #endif jl_thread_t system_id; arraylist_t finalizers; - struct _jl_gc_pagemeta_t *page_metadata_allocd; - struct _jl_gc_pagemeta_t *page_metadata_lazily_freed; + jl_gc_page_stack_t page_metadata_allocd; + jl_gc_page_stack_t page_metadata_buffered; jl_gc_markqueue_t mark_queue; jl_gc_mark_cache_t gc_cache; arraylist_t sweep_objs; + _Atomic(int64_t) gc_sweeps_requested; // Saved exception for previous *external* API call or NULL if cleared. // Access via jl_exception_occurred(). struct _jl_value_t *previous_exception; diff --git a/src/partr.c b/src/partr.c index 0f3b581f5122f..23a252b537f99 100644 --- a/src/partr.c +++ b/src/partr.c @@ -108,14 +108,18 @@ void jl_init_threadinginfra(void) void JL_NORETURN jl_finish_task(jl_task_t *t); - static inline int may_mark(void) JL_NOTSAFEPOINT { return (jl_atomic_load(&gc_n_threads_marking) > 0); } -// gc thread mark function -void jl_gc_mark_threadfun(void *arg) +static inline int may_sweep(jl_ptls_t ptls) JL_NOTSAFEPOINT +{ + return (jl_atomic_load(&ptls->gc_sweeps_requested) > 0); +} + +// parallel gc thread function +void jl_parallel_gc_threadfun(void *arg) { jl_threadarg_t *targ = (jl_threadarg_t*)arg; @@ -131,16 +135,22 @@ void jl_gc_mark_threadfun(void *arg) while (1) { uv_mutex_lock(&gc_threads_lock); - while (!may_mark()) { + while (!may_mark() && !may_sweep(ptls)) { uv_cond_wait(&gc_threads_cond, &gc_threads_lock); } uv_mutex_unlock(&gc_threads_lock); - gc_mark_loop_parallel(ptls, 0); + if (may_mark()) { + gc_mark_loop_parallel(ptls, 0); + } + if (may_sweep(ptls)) { // not an else! + gc_sweep_pool_parallel(); + jl_atomic_fetch_add(&ptls->gc_sweeps_requested, -1); + } } } -// gc thread sweep function -void jl_gc_sweep_threadfun(void *arg) +// concurrent gc thread function +void jl_concurrent_gc_threadfun(void *arg) { jl_threadarg_t *targ = (jl_threadarg_t*)arg; @@ -156,14 +166,7 @@ void jl_gc_sweep_threadfun(void *arg) while (1) { uv_sem_wait(&gc_sweep_assists_needed); - while (1) { - jl_gc_pagemeta_t *pg = pop_lf_page_metadata_back(&global_page_pool_lazily_freed); - if (pg == NULL) { - break; - } - jl_gc_free_page(pg); - push_lf_page_metadata_back(&global_page_pool_freed, pg); - } + gc_free_pages(); } } diff --git a/src/threading.c b/src/threading.c index b82e36f66d994..5a0b16e17c782 100644 --- a/src/threading.c +++ b/src/threading.c @@ -767,10 +767,10 @@ void jl_start_threads(void) } } else if (i == nthreads - 1 && jl_n_sweepthreads == 1) { - uv_thread_create(&uvtid, jl_gc_sweep_threadfun, t); + uv_thread_create(&uvtid, jl_concurrent_gc_threadfun, t); } else { - uv_thread_create(&uvtid, jl_gc_mark_threadfun, t); + uv_thread_create(&uvtid, jl_parallel_gc_threadfun, t); } uv_thread_detach(&uvtid); } diff --git a/src/threading.h b/src/threading.h index 73d2cd73fb70d..260ecffa30dd5 100644 --- a/src/threading.h +++ b/src/threading.h @@ -25,8 +25,8 @@ jl_ptls_t jl_init_threadtls(int16_t tid) JL_NOTSAFEPOINT; // provided by a threading infrastructure void jl_init_threadinginfra(void); -void jl_gc_mark_threadfun(void *arg); -void jl_gc_sweep_threadfun(void *arg); +void jl_parallel_gc_threadfun(void *arg); +void jl_concurrent_gc_threadfun(void *arg); void jl_threadfun(void *arg); #ifdef __cplusplus From 165a150a5b17ca6a49d36a0ac74e0708b98b1a10 Mon Sep 17 00:00:00 2001 From: Kiran Date: Tue, 26 Sep 2023 16:03:40 -0400 Subject: [PATCH 013/109] don't print task backtrace for GC threads (#51413) (#78) GC threads don't have tasks associated with them. --- src/stackwalk.c | 6 ++++++ uv_constants.jl | 5 +++++ 2 files changed, 11 insertions(+) create mode 100644 uv_constants.jl diff --git a/src/stackwalk.c b/src/stackwalk.c index bb15ebe754533..d4f6aeecad51e 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -1158,12 +1158,18 @@ JL_DLLEXPORT void jl_print_backtrace(void) JL_NOTSAFEPOINT jlbacktrace(); } +extern int gc_first_tid; + // Print backtraces for all live tasks, for all threads, to jl_safe_printf stderr JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT { size_t nthreads = jl_atomic_load_acquire(&jl_n_threads); jl_ptls_t *allstates = jl_atomic_load_relaxed(&jl_all_tls_states); for (size_t i = 0; i < nthreads; i++) { + // skip GC threads since they don't have tasks + if (gc_first_tid <= i && i < gc_first_tid + jl_n_gcthreads) { + continue; + } jl_ptls_t ptls2 = allstates[i]; if (ptls2 == NULL) { continue; diff --git a/uv_constants.jl b/uv_constants.jl new file mode 100644 index 0000000000000..1db24e45bc2fc --- /dev/null +++ b/uv_constants.jl @@ -0,0 +1,5 @@ +-mmacosx-version-min=11.0 + +-P +-I/Users/dnetto/RAI/julia-RAI/usr/include +16 From 04d0aefbe06c8ec4f6be258b66d4408906f6d6ee Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Mon, 9 Oct 2023 16:32:13 -0400 Subject: [PATCH 014/109] RAI: Prepend "thread (%d) " to output from `jl_print_task_backtraces()` --- src/stackwalk.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/stackwalk.c b/src/stackwalk.c index d4f6aeecad51e..5ceea5a8e30e9 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -1165,6 +1165,8 @@ JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT { size_t nthreads = jl_atomic_load_acquire(&jl_n_threads); jl_ptls_t *allstates = jl_atomic_load_relaxed(&jl_all_tls_states); + int ctid = jl_threadid() + 1; + jl_safe_printf("thread (%d) ++++ Task backtraces\n", ctid); for (size_t i = 0; i < nthreads; i++) { // skip GC threads since they don't have tasks if (gc_first_tid <= i && i < gc_first_tid + jl_n_gcthreads) { @@ -1180,22 +1182,22 @@ JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT jl_task_t *t = ptls2->root_task; if (t != NULL) t_state = jl_atomic_load_relaxed(&t->_state); - jl_safe_printf("==== Thread %d created %zu live tasks\n", - ptls2->tid + 1, n + (t_state != JL_TASK_STATE_DONE)); + jl_safe_printf("thread (%d) ==== Thread %d created %zu live tasks\n", + ctid, ptls2->tid + 1, n + (t_state != JL_TASK_STATE_DONE)); if (show_done || t_state != JL_TASK_STATE_DONE) { - jl_safe_printf(" ---- Root task (%p)\n", ptls2->root_task); + jl_safe_printf("thread (%d) ---- Root task (%p)\n", ctid, ptls2->root_task); if (t != NULL) { - jl_safe_printf(" (sticky: %d, started: %d, state: %d, tid: %d)\n", - t->sticky, t->started, t_state, + jl_safe_printf("thread (%d) (sticky: %d, started: %d, state: %d, tid: %d)\n", + ctid, t->sticky, t->started, t_state, jl_atomic_load_relaxed(&t->tid) + 1); if (t->stkbuf != NULL) { jlbacktracet(t); } else { - jl_safe_printf(" no stack\n"); + jl_safe_printf("thread (%d) no stack\n", ctid); } } - jl_safe_printf(" ---- End root task\n"); + jl_safe_printf("thread (%d) ---- End root task\n", ctid); } for (size_t j = 0; j < n; j++) { @@ -1205,20 +1207,20 @@ JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT int t_state = jl_atomic_load_relaxed(&t->_state); if (!show_done && t_state == JL_TASK_STATE_DONE) continue; - jl_safe_printf(" ---- Task %zu (%p)\n", j + 1, t); + jl_safe_printf("thread (%d) ---- Task %zu (%p)\n", ctid, j + 1, t); // n.b. this information might not be consistent with the stack printing after it, since it could start running or change tid, etc. - jl_safe_printf(" (sticky: %d, started: %d, state: %d, tid: %d)\n", - t->sticky, t->started, t_state, + jl_safe_printf("thread (%d) (sticky: %d, started: %d, state: %d, tid: %d)\n", + ctid, t->sticky, t->started, t_state, jl_atomic_load_relaxed(&t->tid) + 1); if (t->stkbuf != NULL) jlbacktracet(t); else - jl_safe_printf(" no stack\n"); - jl_safe_printf(" ---- End task %zu\n", j + 1); + jl_safe_printf("thread (%d) no stack\n", ctid); + jl_safe_printf("thread (%d) ---- End task %zu\n", ctid, j + 1); } - jl_safe_printf("==== End thread %d\n", ptls2->tid + 1); + jl_safe_printf("thread (%d) ==== End thread %d\n", ctid, ptls2->tid + 1); } - jl_safe_printf("==== Done\n"); + jl_safe_printf("thread (%d) ++++ Done\n", ctid); } #ifdef __cplusplus From 315f49e22e59db116f14dd9f544031254de2869a Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Sat, 7 Oct 2023 18:30:01 -0400 Subject: [PATCH 015/109] Add heartbeat capability Presence is controlled by a build-time option. Start a separate thread which simply sleeps. When heartbeats are enabled, this thread wakes up at specified intervals to verify that user code is heartbeating as requested and if not, prints task backtraces. Also fixes the call to `maxthreadid` in `generate_precompile.jl`. --- contrib/generate_precompile.jl | 2 +- src/init.c | 4 + src/options.h | 3 + src/threading.c | 221 +++++++++++++++++++++++++++++++++ 4 files changed, 229 insertions(+), 1 deletion(-) diff --git a/contrib/generate_precompile.jl b/contrib/generate_precompile.jl index 7ad976e1e0106..4741f99e81126 100644 --- a/contrib/generate_precompile.jl +++ b/contrib/generate_precompile.jl @@ -4,7 +4,7 @@ @eval Module() begin if Threads.maxthreadid() != 1 - @warn "Running this file with multiple Julia threads may lead to a build error" Threads.maxthreadid() + @warn "Running this file with multiple Julia threads may lead to a build error" Base.Threads.maxthreadid() end if Base.isempty(Base.ARGS) || Base.ARGS[1] !== "0" diff --git a/src/init.c b/src/init.c index c49ec2ac80be2..f7a35e95daa1b 100644 --- a/src/init.c +++ b/src/init.c @@ -844,6 +844,8 @@ JL_DLLEXPORT void julia_init(JL_IMAGE_SEARCH rel) _finish_julia_init(rel, ptls, ct); } +void jl_init_heartbeat(void); + static NOINLINE void _finish_julia_init(JL_IMAGE_SEARCH rel, jl_ptls_t ptls, jl_task_t *ct) { JL_TIMING(JULIA_INIT, JULIA_INIT); @@ -889,6 +891,8 @@ static NOINLINE void _finish_julia_init(JL_IMAGE_SEARCH rel, jl_ptls_t ptls, jl_ } jl_start_threads(); + jl_init_heartbeat(); + jl_gc_enable(1); if (jl_options.image_file && (!jl_generating_output() || jl_options.incremental) && jl_module_init_order) { diff --git a/src/options.h b/src/options.h index b535d5ad4566f..de20097a0b986 100644 --- a/src/options.h +++ b/src/options.h @@ -138,6 +138,9 @@ #define MACHINE_EXCLUSIVE_NAME "JULIA_EXCLUSIVE" #define DEFAULT_MACHINE_EXCLUSIVE 0 +// heartbeats +#define JL_HEARTBEAT_THREAD + // partr -- parallel tasks runtime options ------------------------------------ // multiq diff --git a/src/threading.c b/src/threading.c index 5a0b16e17c782..37138ba0795f1 100644 --- a/src/threading.c +++ b/src/threading.c @@ -938,6 +938,227 @@ JL_DLLEXPORT int jl_alignment(size_t sz) return jl_gc_alignment(sz); } +// Heartbeat mechanism for Julia's task scheduler +// --- +// Start a thread that does not participate in running Julia's tasks. This +// thread simply sleeps until the heartbeat mechanism is enabled. When +// enabled, the heartbeat thread enters a loop in which it blocks waiting +// for the specified heartbeat interval. If, within that interval, +// `jl_heartbeat()` is *not* called at least once, then the thread calls +// `jl_print_task_backtraces(0)`. + +#ifdef JL_HEARTBEAT_THREAD + +#include + +volatile int heartbeat_enabled; +uv_sem_t heartbeat_on_sem, // jl_heartbeat_enable -> thread + heartbeat_off_sem; // thread -> jl_heartbeat_enable +int heartbeat_interval_s, + n_loss_reports, + reset_reporting_s; +int last_report_s, report_interval_s, n_reported; +_Atomic(int) heartbeats; + +JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT; +void jl_heartbeat_threadfun(void *arg); + +// start the heartbeat thread with heartbeats disabled +void jl_init_heartbeat(void) +{ + uv_thread_t uvtid; + heartbeat_enabled = 0; + uv_sem_init(&heartbeat_on_sem, 0); + uv_sem_init(&heartbeat_off_sem, 0); + uv_thread_create(&uvtid, jl_heartbeat_threadfun, NULL); + uv_thread_detach(&uvtid); +} + +// enable/disable heartbeats +// heartbeat_s: interval within which jl_heartbeat() must be called +// n_reports: for one heartbeat loss interval, how many times to report +// reset_reporting_after_s: how long to wait after a heartbeat loss +// interval and a return to steady heartbeats, before resetting +// reporting behavior +// +// When disabling heartbeats, the heartbeat thread must wake up, +// find out that heartbeats are now diabled, and reset. For now, we +// handle this by preventing re-enabling of heartbeats until this +// completes. +JL_DLLEXPORT int jl_heartbeat_enable(int heartbeat_s, int n_reports, + int reset_reporting_after_s) +{ + if (heartbeat_s <= 0) { + heartbeat_enabled = 0; + heartbeat_interval_s = n_loss_reports = reset_reporting_s = 0; + } + else { + // must disable before enabling + if (heartbeat_enabled) { + return -1; + } + // heartbeat thread must be ready + if (uv_sem_trywait(&heartbeat_off_sem) != 0) { + return -1; + } + + jl_atomic_store_relaxed(&heartbeats, 0); + heartbeat_interval_s = heartbeat_s; + n_loss_reports = n_reports; + reset_reporting_s = reset_reporting_after_s; + last_report_s = 0; + report_interval_s = heartbeat_interval_s; + heartbeat_enabled = 1; + uv_sem_post(&heartbeat_on_sem); // wake the heartbeat thread + } + return 0; +} + +// heartbeat +JL_DLLEXPORT void jl_heartbeat(void) +{ + jl_atomic_fetch_add(&heartbeats, 1); +} + +// sleep the thread for the specified interval +void sleep_for(int secs, int nsecs) +{ + struct timespec rqtp, rmtp; + rqtp.tv_sec = secs; + rqtp.tv_nsec = nsecs; + rmtp.tv_sec = 0; + rmtp.tv_nsec = 0; + for (; ;) { + // this suspends the thread so we aren't using CPU + if (nanosleep(&rqtp, &rmtp) == 0) { + return; + } + // TODO: else if (errno == EINTR) + // this could be SIGTERM and we should shutdown but how to find out? + rqtp = rmtp; + } +} + +// check for heartbeats and maybe report loss +uint8_t check_heartbeats(uint8_t gc_state) +{ + int hb = jl_atomic_exchange(&heartbeats, 0); + uint64_t curr_s = jl_hrtime() / 1e9; + + if (hb <= 0) { + // we didn't get a heartbeat in the last interval; should we report? + if (n_reported < n_loss_reports && + curr_s - last_report_s >= report_interval_s) { + jl_task_t *ct = jl_current_task; + jl_ptls_t ptls = ct->ptls; + + // exit GC-safe region to report then re-enter + jl_gc_safe_leave(ptls, gc_state); + jl_safe_printf("==== heartbeat loss ====\n"); + jl_print_task_backtraces(0); + gc_state = jl_gc_safe_enter(ptls); + + // we've reported + n_reported++; + + // record the reporting time _after_ the report + last_report_s = jl_hrtime() / 1e9; + + // double the reporting interval up to a maximum + if (report_interval_s < 60 * heartbeat_interval_s) { + report_interval_s *= 2; + } + } + // no heartbeats, don't change reporting state + return gc_state; + } + else { + // we got a heartbeat; reset the report count + n_reported = 0; + } + + // reset the reporting interval only once we're steadily getting + // heartbeats for the requested reset interval + if (curr_s - reset_reporting_s > last_report_s) { + report_interval_s = heartbeat_interval_s; + } + + return gc_state; +} + +// heartbeat thread function +void jl_heartbeat_threadfun(void *arg) +{ + int s, ns = 1e9 - 1, rs; + uint64_t t0, tchb; + + // We need a TLS because backtraces are accumulated into ptls->bt_size + // and ptls->bt_data, so we need to call jl_adopt_thread(). + jl_adopt_thread(); + jl_task_t *ct = jl_current_task; + jl_ptls_t ptls = ct->ptls; + + // Don't hold up GC, this thread doesn't participate. + uint8_t gc_state = jl_gc_safe_enter(ptls); + + for (;;) { + if (!heartbeat_enabled) { + // post the off semaphore to indicate we're ready to enable + uv_sem_post(&heartbeat_off_sem); + + // sleep the thread here; this semaphore is posted in + // jl_heartbeat_enable() + uv_sem_wait(&heartbeat_on_sem); + + // Set the sleep duration. + s = heartbeat_interval_s - 1; + ns = 1e9 - 1; + continue; + } + + // heartbeat is enabled; sleep, waiting for the desired interval + sleep_for(s, ns); + + // if heartbeats were turned off while we were sleeping, reset + if (!heartbeat_enabled) { + continue; + } + + // check if any heartbeats have happened, report as appropriate + t0 = jl_hrtime(); + gc_state = check_heartbeats(gc_state); + tchb = jl_hrtime() - t0; + + // adjust the next sleep duration based on how long the heartbeat + // check took + rs = 1; + while (tchb > 1e9) { + rs++; + tchb -= 1e9; + } + s = heartbeat_interval_s - rs; + ns = 1e9 - tchb; + } +} + +#else // !JL_HEARTBEAT_THREAD + +void jl_init_heartbeat(void) +{ +} + +JL_DLLEXPORT int jl_heartbeat_enable(int heartbeat_s, int n_reports, + int reset_reporting_after_s) +{ + return -1; +} + +JL_DLLEXPORT void jl_heartbeat(void) +{ +} + +#endif // JL_HEARTBEAT_THREAD + #ifdef __cplusplus } #endif From 08424f3e06633a442198c225de53805f318a855a Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Sun, 12 Nov 2023 17:12:54 -0500 Subject: [PATCH 016/109] Change heartbeat thread controls When enabling heartbeats, the user must specify: - heartbeat_s: jl_heartbeat() must be called at least once every heartbeat_s; if it isn't, a one-line heartbeat loss report is printed - show_tasks_after_n: after these many heartbeat_s have passed without jl_heartbeat() being called, print task backtraces and stop all reporting - reset_after_n: after these many heartbeat_s have passed with jl_heartbeat() being called, print a heartbeats recovered message and reset reporting --- src/threading.c | 95 ++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 49 deletions(-) diff --git a/src/threading.c b/src/threading.c index 37138ba0795f1..5d0c0c614840f 100644 --- a/src/threading.c +++ b/src/threading.c @@ -955,9 +955,9 @@ volatile int heartbeat_enabled; uv_sem_t heartbeat_on_sem, // jl_heartbeat_enable -> thread heartbeat_off_sem; // thread -> jl_heartbeat_enable int heartbeat_interval_s, - n_loss_reports, - reset_reporting_s; -int last_report_s, report_interval_s, n_reported; + tasks_after_n, + reset_tasks_after_n; +int tasks_showed, n_hbs_missed, n_hbs_recvd; _Atomic(int) heartbeats; JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT; @@ -976,21 +976,19 @@ void jl_init_heartbeat(void) // enable/disable heartbeats // heartbeat_s: interval within which jl_heartbeat() must be called -// n_reports: for one heartbeat loss interval, how many times to report -// reset_reporting_after_s: how long to wait after a heartbeat loss -// interval and a return to steady heartbeats, before resetting -// reporting behavior +// show_tasks_after_n: number of heartbeats missed before printing task backtraces +// reset_after_n: number of heartbeats after which to reset // // When disabling heartbeats, the heartbeat thread must wake up, // find out that heartbeats are now diabled, and reset. For now, we // handle this by preventing re-enabling of heartbeats until this // completes. -JL_DLLEXPORT int jl_heartbeat_enable(int heartbeat_s, int n_reports, - int reset_reporting_after_s) +JL_DLLEXPORT int jl_heartbeat_enable(int heartbeat_s, int show_tasks_after_n, + int reset_after_n) { if (heartbeat_s <= 0) { heartbeat_enabled = 0; - heartbeat_interval_s = n_loss_reports = reset_reporting_s = 0; + heartbeat_interval_s = tasks_after_n = reset_tasks_after_n = 0; } else { // must disable before enabling @@ -1004,10 +1002,11 @@ JL_DLLEXPORT int jl_heartbeat_enable(int heartbeat_s, int n_reports, jl_atomic_store_relaxed(&heartbeats, 0); heartbeat_interval_s = heartbeat_s; - n_loss_reports = n_reports; - reset_reporting_s = reset_reporting_after_s; - last_report_s = 0; - report_interval_s = heartbeat_interval_s; + tasks_after_n = show_tasks_after_n; + reset_tasks_after_n = reset_after_n; + tasks_showed = 0; + n_hbs_missed = 0; + n_hbs_recvd = 0; heartbeat_enabled = 1; uv_sem_post(&heartbeat_on_sem); // wake the heartbeat thread } @@ -1043,44 +1042,42 @@ void sleep_for(int secs, int nsecs) uint8_t check_heartbeats(uint8_t gc_state) { int hb = jl_atomic_exchange(&heartbeats, 0); - uint64_t curr_s = jl_hrtime() / 1e9; if (hb <= 0) { - // we didn't get a heartbeat in the last interval; should we report? - if (n_reported < n_loss_reports && - curr_s - last_report_s >= report_interval_s) { - jl_task_t *ct = jl_current_task; - jl_ptls_t ptls = ct->ptls; - - // exit GC-safe region to report then re-enter - jl_gc_safe_leave(ptls, gc_state); - jl_safe_printf("==== heartbeat loss ====\n"); - jl_print_task_backtraces(0); - gc_state = jl_gc_safe_enter(ptls); - - // we've reported - n_reported++; - - // record the reporting time _after_ the report - last_report_s = jl_hrtime() / 1e9; - - // double the reporting interval up to a maximum - if (report_interval_s < 60 * heartbeat_interval_s) { - report_interval_s *= 2; + // we didn't get a heartbeat + n_hbs_recvd = 0; + n_hbs_missed++; + + // if we've printed task backtraces already, do nothing + if (!tasks_showed) { + // otherwise, at least show this message + jl_safe_printf("==== heartbeat loss (%ds) ====\n", + n_hbs_missed * heartbeat_interval_s); + // if we've missed enough heartbeats, print task backtraces + if (n_hbs_missed >= tasks_after_n) { + jl_task_t *ct = jl_current_task; + jl_ptls_t ptls = ct->ptls; + + // exit GC-safe region to report then re-enter + jl_gc_safe_leave(ptls, gc_state); + jl_print_task_backtraces(0); + gc_state = jl_gc_safe_enter(ptls); + + // we printed task backtraces + tasks_showed = 1; } } - // no heartbeats, don't change reporting state - return gc_state; } else { - // we got a heartbeat; reset the report count - n_reported = 0; - } - - // reset the reporting interval only once we're steadily getting - // heartbeats for the requested reset interval - if (curr_s - reset_reporting_s > last_report_s) { - report_interval_s = heartbeat_interval_s; + // got a heartbeat + n_hbs_recvd++; + // if we'd printed task backtraces, check for reset + if (tasks_showed && n_hbs_recvd >= reset_tasks_after_n) { + tasks_showed = 0; + jl_safe_printf("==== heartbeats recovered (lost for %ds) ====\n", + n_hbs_missed * heartbeat_interval_s); + } + n_hbs_missed = 0; } return gc_state; @@ -1089,7 +1086,7 @@ uint8_t check_heartbeats(uint8_t gc_state) // heartbeat thread function void jl_heartbeat_threadfun(void *arg) { - int s, ns = 1e9 - 1, rs; + int s = 59, ns = 1e9 - 1, rs; uint64_t t0, tchb; // We need a TLS because backtraces are accumulated into ptls->bt_size @@ -1147,8 +1144,8 @@ void jl_init_heartbeat(void) { } -JL_DLLEXPORT int jl_heartbeat_enable(int heartbeat_s, int n_reports, - int reset_reporting_after_s) +JL_DLLEXPORT int jl_heartbeat_enable(int heartbeat_s, int show_tasks_after_n, + int reset_after_n) { return -1; } From 48723bbf23df4f05935c063cec6bdbaa368956cc Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Sat, 4 Nov 2023 10:23:15 -0300 Subject: [PATCH 017/109] make pool_live_bytes metric more accurate (#52015) `pool_live_bytes` was previously lazily updated during the GC, meaning it was only accurate right after a GC. Make this metric accurate if gathered after a GC has happened. --- src/gc.c | 15 ++++++++++++--- src/julia_threads.h | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/gc.c b/src/gc.c index 982c2e3e73633..5b833d911d21d 100644 --- a/src/gc.c +++ b/src/gc.c @@ -753,7 +753,6 @@ int current_sweep_full = 0; int under_pressure = 0; // Full collection heuristics -static int64_t pool_live_bytes = 0; static int64_t live_bytes = 0; static int64_t promoted_bytes = 0; static int64_t last_full_live = 0; // live_bytes after last full collection @@ -1306,6 +1305,8 @@ STATIC_INLINE jl_value_t *jl_gc_pool_alloc_inner(jl_ptls_t ptls, int pool_offset maybe_collect(ptls); jl_atomic_store_relaxed(&ptls->gc_num.allocd, jl_atomic_load_relaxed(&ptls->gc_num.allocd) + osize); + jl_atomic_store_relaxed(&ptls->gc_num.pool_live_bytes, + jl_atomic_load_relaxed(&ptls->gc_num.pool_live_bytes) + osize); jl_atomic_store_relaxed(&ptls->gc_num.poolalloc, jl_atomic_load_relaxed(&ptls->gc_num.poolalloc) + 1); // first try to use the freelist @@ -1492,7 +1493,8 @@ static void gc_sweep_page(jl_gc_pool_t *p, jl_gc_page_stack_t *allocd, jl_gc_pag } } gc_time_count_page(freedall, pg_skpd); - jl_atomic_fetch_add((_Atomic(int64_t) *)&pool_live_bytes, GC_PAGE_SZ - GC_PAGE_OFFSET - nfree * osize); + jl_ptls_t ptls = gc_all_tls_states[pg->thread_n]; + jl_atomic_fetch_add(&ptls->gc_num.pool_live_bytes, GC_PAGE_SZ - GC_PAGE_OFFSET - nfree * osize); jl_atomic_fetch_add((_Atomic(int64_t) *)&gc_num.freed, (nfree - old_nfree) * osize); } @@ -1614,6 +1616,7 @@ static void gc_sweep_pool(void) } continue; } + jl_atomic_store_relaxed(&ptls2->gc_num.pool_live_bytes, 0); for (int i = 0; i < JL_GC_N_POOLS; i++) { jl_gc_pool_t *p = &ptls2->heap.norm_pools[i]; jl_taggedvalue_t *last = p->freelist; @@ -3265,6 +3268,13 @@ JL_DLLEXPORT int64_t jl_gc_sync_total_bytes(int64_t offset) JL_NOTSAFEPOINT JL_DLLEXPORT int64_t jl_gc_pool_live_bytes(void) { + int64_t pool_live_bytes = 0; + for (int i = 0; i < gc_n_threads; i++) { + jl_ptls_t ptls2 = gc_all_tls_states[i]; + if (ptls2 != NULL) { + pool_live_bytes += jl_atomic_load_relaxed(&ptls2->gc_num.pool_live_bytes); + } + } return pool_live_bytes; } @@ -3470,7 +3480,6 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) promoted_bytes = 0; } scanned_bytes = 0; - pool_live_bytes = 0; // 6. start sweeping uint64_t start_sweep_time = jl_hrtime(); JL_PROBE_GC_SWEEP_BEGIN(sweep_full); diff --git a/src/julia_threads.h b/src/julia_threads.h index 025c5707e5507..98aa4497abfd2 100644 --- a/src/julia_threads.h +++ b/src/julia_threads.h @@ -130,6 +130,7 @@ typedef struct { typedef struct { _Atomic(int64_t) allocd; + _Atomic(int64_t) pool_live_bytes; _Atomic(int64_t) freed; _Atomic(uint64_t) malloc; _Atomic(uint64_t) realloc; From 66d02fe5984a3029a6d61305c80cf7cfe85237d2 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Mon, 6 Nov 2023 07:56:20 -0300 Subject: [PATCH 018/109] bugfix: load jl_n_threads in jl_gc_pool_live_bytes (#52034) Otherwise we may just observe `gc_n_threads = 0` (`jl_gc_collect` sets it to 0 in the very end of its body) and this function becomes a no-op. --- src/gc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gc.c b/src/gc.c index 5b833d911d21d..39de0c68070b0 100644 --- a/src/gc.c +++ b/src/gc.c @@ -3268,9 +3268,11 @@ JL_DLLEXPORT int64_t jl_gc_sync_total_bytes(int64_t offset) JL_NOTSAFEPOINT JL_DLLEXPORT int64_t jl_gc_pool_live_bytes(void) { + int n_threads = jl_atomic_load_acquire(&jl_n_threads); + jl_ptls_t *all_tls_states = jl_atomic_load_relaxed(&jl_all_tls_states); int64_t pool_live_bytes = 0; - for (int i = 0; i < gc_n_threads; i++) { - jl_ptls_t ptls2 = gc_all_tls_states[i]; + for (int i = 0; i < n_threads; i++) { + jl_ptls_t ptls2 = all_tls_states[i]; if (ptls2 != NULL) { pool_live_bytes += jl_atomic_load_relaxed(&ptls2->gc_num.pool_live_bytes); } From b3519733da4672a8e665760b8b582c8a87857a57 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Tue, 7 Nov 2023 14:01:59 -0300 Subject: [PATCH 019/109] bugfix: don't set pool_live_bytes to zero at the end of GC (#107) --- src/gc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/gc.c b/src/gc.c index 39de0c68070b0..5f1bf96e481b2 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1169,8 +1169,14 @@ static void reset_thread_gc_counts(void) JL_NOTSAFEPOINT for (int i = 0; i < gc_n_threads; i++) { jl_ptls_t ptls = gc_all_tls_states[i]; if (ptls != NULL) { - memset(&ptls->gc_num, 0, sizeof(ptls->gc_num)); + // don't reset `pool_live_bytes` here jl_atomic_store_relaxed(&ptls->gc_num.allocd, -(int64_t)gc_num.interval); + jl_atomic_store_relaxed(&ptls->gc_num.freed, 0); + jl_atomic_store_relaxed(&ptls->gc_num.malloc, 0); + jl_atomic_store_relaxed(&ptls->gc_num.realloc, 0); + jl_atomic_store_relaxed(&ptls->gc_num.poolalloc, 0); + jl_atomic_store_relaxed(&ptls->gc_num.bigalloc, 0); + jl_atomic_store_relaxed(&ptls->gc_num.freecall, 0); } } } From 18b3b079b2d6d6f2ecc7b5ed4d88482b97ee71be Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Thu, 16 Nov 2023 16:15:03 -0300 Subject: [PATCH 020/109] add some instrumentation to measure page utilization per size class (#52164) One of the limitations is that it's only accurate right after the GC. Still might be helpful for observability purposes. --- src/gc.c | 34 ++++++++++++++++++++++++++++++++++ src/gc.h | 8 ++++++++ 2 files changed, 42 insertions(+) diff --git a/src/gc.c b/src/gc.c index 5f1bf96e481b2..3bafd00bc43f9 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1390,6 +1390,38 @@ int jl_gc_classify_pools(size_t sz, int *osize) // sweep phase +gc_fragmentation_stat_t gc_page_fragmentation_stats[JL_GC_N_POOLS]; + +extern gc_fragmentation_stat_t gc_page_fragmentation_stats[JL_GC_N_POOLS]; + +STATIC_INLINE void gc_update_page_fragmentation_data(jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT +{ +#ifdef GC_MEASURE_PAGE_FRAGMENTATION + gc_fragmentation_stat_t *stats = &gc_page_fragmentation_stats[pg->pool_n]; + jl_atomic_fetch_add(&stats->n_freed_objs, pg->nfree); + jl_atomic_fetch_add(&stats->n_pages_allocd, 1); +#endif +} + +STATIC_INLINE void gc_dump_page_utilization_data(void) JL_NOTSAFEPOINT +{ +#ifdef GC_MEASURE_PAGE_FRAGMENTATION + for (int i = 0; i < JL_GC_N_POOLS; i++) { + gc_fragmentation_stat_t *stats = &gc_page_fragmentation_stats[i]; + double utilization = 1.0; + size_t n_freed_objs = jl_atomic_load_relaxed(&stats->n_freed_objs); + size_t n_pages_allocd = jl_atomic_load_relaxed(&stats->n_pages_allocd); + if (n_pages_allocd != 0) { + utilization -= ((double)n_freed_objs * (double)jl_gc_sizeclasses[i]) / (double)n_pages_allocd / (double)GC_PAGE_SZ; + } + jl_safe_printf("Size class %d: %.2f%% utilization\n", jl_gc_sizeclasses[i], utilization * 100.0); + jl_atomic_store_relaxed(&stats->n_freed_objs, 0); + jl_atomic_store_relaxed(&stats->n_pages_allocd, 0); + } + jl_safe_printf("-----------------------------------------\n"); +#endif +} + int64_t buffered_pages = 0; // Returns pointer to terminal pointer of list rooted at *pfl. @@ -1498,6 +1530,7 @@ static void gc_sweep_page(jl_gc_pool_t *p, jl_gc_page_stack_t *allocd, jl_gc_pag push_lf_back(&global_page_pool_lazily_freed, pg); } } + gc_update_page_fragmentation_data(pg); gc_time_count_page(freedall, pg_skpd); jl_ptls_t ptls = gc_all_tls_states[pg->thread_n]; jl_atomic_fetch_add(&ptls->gc_num.pool_live_bytes, GC_PAGE_SZ - GC_PAGE_OFFSET - nfree * osize); @@ -1711,6 +1744,7 @@ static void gc_sweep_pool(void) #else gc_free_pages(); #endif + gc_dump_page_utilization_data(); gc_time_pool_end(current_sweep_full); } diff --git a/src/gc.h b/src/gc.h index ddb695b37dc8d..c49aa63db73d4 100644 --- a/src/gc.h +++ b/src/gc.h @@ -219,6 +219,14 @@ STATIC_INLINE jl_gc_pagemeta_t *pop_lf_back(jl_gc_page_stack_t *pool) JL_NOTSAFE } } +// data structures for tracking fragmentation in the pool allocator +// #define GC_MEASURE_PAGE_FRAGMENTATION + +typedef struct { + _Atomic(size_t) n_freed_objs; + _Atomic(size_t) n_pages_allocd; +} gc_fragmentation_stat_t; + #ifdef _P64 #define REGION0_PG_COUNT (1 << 16) #define REGION1_PG_COUNT (1 << 16) From 6051f41c07c84e1b7b6f82ebeba43577a389f632 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Wed, 22 Nov 2023 11:26:21 -0300 Subject: [PATCH 021/109] add a compile-time option to enable 4k page sizes (#52229) We're suffering from heavy fragmentation in some of our workloads. Add a build-time option to enable 4k pages (instead of 16k) in the GC, since that improves memory utilization considerably for us. Drawback is that this may increase the number of `madvise` system calls in the sweeping phase by a factor of 4, but concurrent page sweeping should help with some of that. --- src/gc.h | 24 ++++++++++++++++++++++- src/julia_internal.h | 45 ++++++++++++++++++++++++++++++++++++-------- src/julia_threads.h | 12 +++--------- src/options.h | 5 +++++ 4 files changed, 68 insertions(+), 18 deletions(-) diff --git a/src/gc.h b/src/gc.h index c49aa63db73d4..e22cfe4c13e90 100644 --- a/src/gc.h +++ b/src/gc.h @@ -33,8 +33,12 @@ extern "C" { #endif +#ifdef GC_SMALL_PAGE +#define GC_PAGE_LG2 12 // log2(size of a page) +#else #define GC_PAGE_LG2 14 // log2(size of a page) -#define GC_PAGE_SZ (1 << GC_PAGE_LG2) // 16k +#endif +#define GC_PAGE_SZ (1 << GC_PAGE_LG2) #define GC_PAGE_OFFSET (JL_HEAP_ALIGNMENT - (sizeof(jl_taggedvalue_t) % JL_HEAP_ALIGNMENT)) #define jl_malloc_tag ((void*)0xdeadaa01) @@ -227,6 +231,23 @@ typedef struct { _Atomic(size_t) n_pages_allocd; } gc_fragmentation_stat_t; +#ifdef GC_SMALL_PAGE +#ifdef _P64 +#define REGION0_PG_COUNT (1 << 16) +#define REGION1_PG_COUNT (1 << 18) +#define REGION2_PG_COUNT (1 << 18) +#define REGION0_INDEX(p) (((uintptr_t)(p) >> 12) & 0xFFFF) // shift by GC_PAGE_LG2 +#define REGION1_INDEX(p) (((uintptr_t)(p) >> 28) & 0x3FFFF) +#define REGION_INDEX(p) (((uintptr_t)(p) >> 46) & 0x3FFFF) +#else +#define REGION0_PG_COUNT (1 << 10) +#define REGION1_PG_COUNT (1 << 10) +#define REGION2_PG_COUNT (1 << 0) +#define REGION0_INDEX(p) (((uintptr_t)(p) >> 12) & 0x3FF) // shift by GC_PAGE_LG2 +#define REGION1_INDEX(p) (((uintptr_t)(p) >> 22) & 0x3FF) +#define REGION_INDEX(p) (0) +#endif +#else #ifdef _P64 #define REGION0_PG_COUNT (1 << 16) #define REGION1_PG_COUNT (1 << 16) @@ -242,6 +263,7 @@ typedef struct { #define REGION1_INDEX(p) (((uintptr_t)(p) >> 22) & 0x3FF) #define REGION_INDEX(p) (0) #endif +#endif // define the representation of the levels of the page-table (0 to 2) typedef struct { diff --git a/src/julia_internal.h b/src/julia_internal.h index 67f771e398578..b7da156b340a7 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -375,24 +375,48 @@ static const int jl_gc_sizeclasses[] = { 144, 160, 176, 192, 208, 224, 240, 256, // the following tables are computed for maximum packing efficiency via the formula: - // pg = 2^14 + // pg = GC_SMALL_PAGE ? 2^12 : 2^14 // sz = (div.(pg-8, rng).÷16)*16; hcat(sz, (pg-8).÷sz, pg .- (pg-8).÷sz.*sz)' +#ifdef GC_SMALL_PAGE + // rng = 15:-1:2 (14 pools) + 272, 288, 304, 336, 368, 400, 448, 496, 576, 672, 816, 1008, 1360, 2032 +// 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, /pool +// 16, 64, 144, 64, 48, 96, 64, 128, 64, 64, 16, 64, 16, 32, bytes lost +#else // rng = 60:-4:32 (8 pools) 272, 288, 304, 336, 368, 400, 448, 496, -// 60, 56, 53, 48, 44, 40, 36, 33, /pool -// 64, 256, 272, 256, 192, 384, 256, 16, bytes lost +// 60, 56, 53, 48, 44, 40, 36, 33, /pool +// 64, 256, 272, 256, 192, 384, 256, 16, bytes lost // rng = 30:-2:16 (8 pools) 544, 576, 624, 672, 736, 816, 896, 1008, -// 30, 28, 26, 24, 22, 20, 18, 16, /pool -// 64, 256, 160, 256, 192, 64, 256, 256, bytes lost +// 30, 28, 26, 24, 22, 20, 18, 16, /pool +// 64, 256, 160, 256, 192, 64, 256, 256, bytes lost // rng = 15:-1:8 (8 pools) 1088, 1168, 1248, 1360, 1488, 1632, 1808, 2032 -// 15, 14, 13, 12, 11, 10, 9, 8, /pool -// 64, 32, 160, 64, 16, 64, 112, 128, bytes lost +// 15, 14, 13, 12, 11, 10, 9, 8, /pool +// 64, 32, 160, 64, 16, 64, 112, 128, bytes lost +#endif }; +#ifdef GC_SMALL_PAGE +#ifdef _P64 +# define JL_GC_N_POOLS 39 +#elif MAX_ALIGN == 8 +# define JL_GC_N_POOLS 40 +#else +# define JL_GC_N_POOLS 41 +#endif +#else +#ifdef _P64 +# define JL_GC_N_POOLS 49 +#elif MAX_ALIGN == 8 +# define JL_GC_N_POOLS 50 +#else +# define JL_GC_N_POOLS 51 +#endif +#endif static_assert(sizeof(jl_gc_sizeclasses) / sizeof(jl_gc_sizeclasses[0]) == JL_GC_N_POOLS, ""); STATIC_INLINE int jl_gc_alignment(size_t sz) JL_NOTSAFEPOINT @@ -419,7 +443,12 @@ JL_DLLEXPORT int jl_alignment(size_t sz) JL_NOTSAFEPOINT; // the following table is computed as: // [searchsortedfirst(jl_gc_sizeclasses, i) - 1 for i = 0:16:jl_gc_sizeclasses[end]] -static const uint8_t szclass_table[] = {0, 1, 3, 5, 7, 9, 11, 13, 15, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 28, 29, 29, 30, 30, 31, 31, 31, 32, 32, 32, 33, 33, 33, 34, 34, 35, 35, 35, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 38, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 42, 42, 42, 42, 42, 43, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 46, 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48}; +static const uint8_t szclass_table[] = +#ifdef GC_SMALL_PAGE + {0,1,3,5,7,9,11,13,15,17,18,19,20,21,22,23,24,25,26,27,28,28,29,29,30,30,31,31,31,32,32,32,33,33,33,33,33,34,34,34,34,34,34,35,35,35,35,35,35,35,35,35,36,36,36,36,36,36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38}; +#else + {0,1,3,5,7,9,11,13,15,17,18,19,20,21,22,23,24,25,26,27,28,28,29,29,30,30,31,31,31,32,32,32,33,33,33,34,34,35,35,35,36,36,36,37,37,37,37,38,38,38,38,38,39,39,39,39,39,40,40,40,40,40,40,40,41,41,41,41,41,42,42,42,42,42,43,43,43,43,43,44,44,44,44,44,44,44,45,45,45,45,45,45,45,45,46,46,46,46,46,46,46,46,46,47,47,47,47,47,47,47,47,47,47,47,48,48,48,48,48,48,48,48,48,48,48,48,48,48}; +#endif static_assert(sizeof(szclass_table) == 128, ""); STATIC_INLINE uint8_t JL_CONST_FUNC jl_gc_szclass(unsigned sz) JL_NOTSAFEPOINT diff --git a/src/julia_threads.h b/src/julia_threads.h index 98aa4497abfd2..56c74c2cff698 100644 --- a/src/julia_threads.h +++ b/src/julia_threads.h @@ -4,8 +4,8 @@ #ifndef JL_THREADS_H #define JL_THREADS_H -#include "work-stealing-queue.h" #include "julia_atomics.h" +#include "work-stealing-queue.h" #ifndef _OS_WINDOWS_ #include "pthread.h" #endif @@ -161,14 +161,8 @@ typedef struct { arraylist_t *last_remset; // variables for allocating objects from pools -#ifdef _P64 -# define JL_GC_N_POOLS 49 -#elif MAX_ALIGN == 8 -# define JL_GC_N_POOLS 50 -#else -# define JL_GC_N_POOLS 51 -#endif - jl_gc_pool_t norm_pools[JL_GC_N_POOLS]; +#define JL_GC_N_MAX_POOLS 51 // conservative. must be kept in sync with `src/julia_internal.h` + jl_gc_pool_t norm_pools[JL_GC_N_MAX_POOLS]; #define JL_N_STACK_POOLS 16 small_arraylist_t free_stacks[JL_N_STACK_POOLS]; diff --git a/src/options.h b/src/options.h index de20097a0b986..f4a052ddc1cb4 100644 --- a/src/options.h +++ b/src/options.h @@ -78,6 +78,11 @@ // OBJPROFILE counts objects by type // #define OBJPROFILE +// pool allocator configuration options + +// GC_SMALL_PAGE allocates objects in 4k pages +// #define GC_SMALL_PAGE + // method dispatch profiling -------------------------------------------------- From 361f3ce9d6cb9e71a698ccf5cef751923bea8f0b Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Wed, 6 Dec 2023 09:57:44 -0300 Subject: [PATCH 022/109] functionality to expose page utilization at the julia level (#113) --- base/timing.jl | 7 +++++++ src/gc.c | 8 ++------ src/gc.h | 3 --- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/base/timing.jl b/base/timing.jl index aeca790bce7e9..4b14161aa89d2 100644 --- a/base/timing.jl +++ b/base/timing.jl @@ -98,6 +98,13 @@ function gc_live_bytes() Int(ccall(:jl_gc_live_bytes, Int64, ())) + num.allocd + num.deferred_alloc end +# must be kept in sync with the value from `src/julia_threads.h`` +const JL_GC_N_MAX_POOLS = 51 +function gc_page_utilization_data() + page_utilization_raw = cglobal(:jl_gc_page_utilization_stats, Float64) + return Base.unsafe_wrap(Array, page_utilization_raw, JL_GC_N_MAX_POOLS, own=false) +end + """ Base.jit_total_bytes() diff --git a/src/gc.c b/src/gc.c index 3bafd00bc43f9..3a7246383bf2f 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1391,21 +1391,19 @@ int jl_gc_classify_pools(size_t sz, int *osize) // sweep phase gc_fragmentation_stat_t gc_page_fragmentation_stats[JL_GC_N_POOLS]; +JL_DLLEXPORT double jl_gc_page_utilization_stats[JL_GC_N_MAX_POOLS]; extern gc_fragmentation_stat_t gc_page_fragmentation_stats[JL_GC_N_POOLS]; STATIC_INLINE void gc_update_page_fragmentation_data(jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT { -#ifdef GC_MEASURE_PAGE_FRAGMENTATION gc_fragmentation_stat_t *stats = &gc_page_fragmentation_stats[pg->pool_n]; jl_atomic_fetch_add(&stats->n_freed_objs, pg->nfree); jl_atomic_fetch_add(&stats->n_pages_allocd, 1); -#endif } STATIC_INLINE void gc_dump_page_utilization_data(void) JL_NOTSAFEPOINT { -#ifdef GC_MEASURE_PAGE_FRAGMENTATION for (int i = 0; i < JL_GC_N_POOLS; i++) { gc_fragmentation_stat_t *stats = &gc_page_fragmentation_stats[i]; double utilization = 1.0; @@ -1414,12 +1412,10 @@ STATIC_INLINE void gc_dump_page_utilization_data(void) JL_NOTSAFEPOINT if (n_pages_allocd != 0) { utilization -= ((double)n_freed_objs * (double)jl_gc_sizeclasses[i]) / (double)n_pages_allocd / (double)GC_PAGE_SZ; } - jl_safe_printf("Size class %d: %.2f%% utilization\n", jl_gc_sizeclasses[i], utilization * 100.0); + jl_gc_page_utilization_stats[i] = utilization; jl_atomic_store_relaxed(&stats->n_freed_objs, 0); jl_atomic_store_relaxed(&stats->n_pages_allocd, 0); } - jl_safe_printf("-----------------------------------------\n"); -#endif } int64_t buffered_pages = 0; diff --git a/src/gc.h b/src/gc.h index e22cfe4c13e90..a6ad9f41dabf0 100644 --- a/src/gc.h +++ b/src/gc.h @@ -223,9 +223,6 @@ STATIC_INLINE jl_gc_pagemeta_t *pop_lf_back(jl_gc_page_stack_t *pool) JL_NOTSAFE } } -// data structures for tracking fragmentation in the pool allocator -// #define GC_MEASURE_PAGE_FRAGMENTATION - typedef struct { _Atomic(size_t) n_freed_objs; _Atomic(size_t) n_pages_allocd; From cc1f3e2d6da8ae5e1986f6128153d251d8e16b03 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Wed, 13 Dec 2023 13:38:41 -0300 Subject: [PATCH 023/109] backport memory pressure callback to 1.9 (#114) --- src/gc.c | 23 +++++++++++++---------- src/julia_gcext.h | 4 ++++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/gc.c b/src/gc.c index 3a7246383bf2f..1776c6beacade 100644 --- a/src/gc.c +++ b/src/gc.c @@ -50,7 +50,6 @@ static jl_gc_callback_list_t *gc_cblist_post_gc; static jl_gc_callback_list_t *gc_cblist_notify_external_alloc; static jl_gc_callback_list_t *gc_cblist_notify_external_free; static jl_gc_callback_list_t *gc_cblist_notify_gc_pressure; -typedef void (*jl_gc_cb_notify_gc_pressure_t)(void); #define gc_invoke_callbacks(ty, list, args) \ do { \ @@ -138,12 +137,12 @@ JL_DLLEXPORT void jl_gc_set_cb_notify_external_free(jl_gc_cb_notify_external_fre } JL_DLLEXPORT void jl_gc_set_cb_notify_gc_pressure(jl_gc_cb_notify_gc_pressure_t cb, int enable) -{ - if (enable) - jl_gc_register_callback(&gc_cblist_notify_gc_pressure, (jl_gc_cb_func_t)cb); - else - jl_gc_deregister_callback(&gc_cblist_notify_gc_pressure, (jl_gc_cb_func_t)cb); -} + { + if (enable) + jl_gc_register_callback(&gc_cblist_notify_gc_pressure, (jl_gc_cb_func_t)cb); + else + jl_gc_deregister_callback(&gc_cblist_notify_gc_pressure, (jl_gc_cb_func_t)cb); + } // Protect all access to `finalizer_list_marked` and `to_finalize`. // For accessing `ptls->finalizers`, the lock is needed if a thread @@ -676,6 +675,7 @@ static void gc_sweep_foreign_objs(void) } // GC knobs and self-measurement variables +static int under_memory_pressure; static int64_t last_gc_total_bytes = 0; // max_total_memory is a suggestion. We try very hard to stay @@ -2958,7 +2958,7 @@ size_t gc_count_work_in_queue(jl_ptls_t ptls) JL_NOTSAFEPOINT * have tried to steal from the queue which still has a work item left, but failed to do so, * which violates the semantics of Chase-Lev's work-stealing queue. * - * - Let E1 be the event "master thread writes -1 to gc_master_tid" and E2 be the even + * - Let E1 be the event "master thread writes -1 to gc_master_tid" and E2 be the event * "master thread observes that `gc_n_threads_marking` is zero". Since we're using * sequentially consistent atomics, E1 => E2. Now suppose one thread which is spinning in * `gc_should_mark` tries to enter the mark-loop after E2. In order to do so, it must @@ -3502,6 +3502,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) // If the live data outgrows the suggested max_total_memory // we keep going with full gcs until we either free some space or get an OOM error. if (live_bytes > max_total_memory) { + under_memory_pressure = 1; sweep_full = 1; } if (gc_sweep_always_full) { @@ -3709,10 +3710,12 @@ JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection) gc_invoke_callbacks(jl_gc_cb_post_gc_t, gc_cblist_post_gc, (collection)); - if (under_pressure) + + if (under_memory_pressure) { gc_invoke_callbacks(jl_gc_cb_notify_gc_pressure_t, gc_cblist_notify_gc_pressure, ()); - under_pressure = 0; + } + under_memory_pressure = 0; #ifdef _OS_WINDOWS_ SetLastError(last_error); #endif diff --git a/src/julia_gcext.h b/src/julia_gcext.h index 27f0a6b5ec11c..e7cb57d622a78 100644 --- a/src/julia_gcext.h +++ b/src/julia_gcext.h @@ -34,6 +34,10 @@ JL_DLLEXPORT void jl_gc_set_cb_notify_external_alloc(jl_gc_cb_notify_external_al JL_DLLEXPORT void jl_gc_set_cb_notify_external_free(jl_gc_cb_notify_external_free_t cb, int enable); +// Memory pressure callback +typedef void (*jl_gc_cb_notify_gc_pressure_t)(void); +JL_DLLEXPORT void jl_gc_set_cb_notify_gc_pressure(jl_gc_cb_notify_gc_pressure_t cb, int enable); + // Types for custom mark and sweep functions. typedef uintptr_t (*jl_markfunc_t)(jl_ptls_t, jl_value_t *obj); typedef void (*jl_sweepfunc_t)(jl_value_t *obj); From a0af597f3ec68178f86e47df122266e9438829ac Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Fri, 29 Dec 2023 13:01:14 -0300 Subject: [PATCH 024/109] page profile (#123) --- src/Makefile | 2 +- src/gc-page-profiler.c | 167 ++++++++++++++++++++++++++++++++ src/gc-page-profiler.h | 63 ++++++++++++ src/gc.c | 54 ++++++++--- stdlib/Profile/src/Profile.jl | 15 +++ stdlib/Profile/test/runtests.jl | 10 ++ 6 files changed, 296 insertions(+), 15 deletions(-) create mode 100644 src/gc-page-profiler.c create mode 100644 src/gc-page-profiler.h diff --git a/src/Makefile b/src/Makefile index 08fb816d302a0..334a9baa6ade8 100644 --- a/src/Makefile +++ b/src/Makefile @@ -44,7 +44,7 @@ SRCS := \ jltypes gf typemap smallintset ast builtins module interpreter symbol \ dlload sys init task array staticdata toplevel jl_uv datatype \ simplevector runtime_intrinsics precompile jloptions mtarraylist \ - threading partr stackwalk gc gc-debug gc-pages gc-stacks gc-alloc-profiler method \ + threading partr stackwalk gc gc-debug gc-pages gc-stacks gc-alloc-profiler gc-page-profiler method \ jlapi signal-handling safepoint timing subtype rtutils gc-heap-snapshot \ crc32c APInt-C processor ircode opaque_closure codegen-stubs coverage runtime_ccall diff --git a/src/gc-page-profiler.c b/src/gc-page-profiler.c new file mode 100644 index 0000000000000..5af1c3d014770 --- /dev/null +++ b/src/gc-page-profiler.c @@ -0,0 +1,167 @@ +// This file is a part of Julia. License is MIT: https://julialang.org/license + +#include "gc-page-profiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// whether page profiling is enabled +int page_profile_enabled; +// number of pages written +size_t page_profile_pages_written; +// stream to write page profile to +ios_t *page_profile_stream; +// mutex for page profile +uv_mutex_t page_profile_lock; + +gc_page_profiler_serializer_t gc_page_serializer_create(void) JL_NOTSAFEPOINT +{ + gc_page_profiler_serializer_t serializer; + if (__unlikely(page_profile_enabled)) { + arraylist_new(&serializer.typestrs, GC_PAGE_SZ); + } + else { + serializer.typestrs.len = 0; + } + return serializer; +} + +void gc_page_serializer_init(gc_page_profiler_serializer_t *serializer, + jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT +{ + if (__unlikely(page_profile_enabled)) { + serializer->typestrs.len = 0; + serializer->data = (char *)pg->data; + serializer->osize = pg->osize; + } +} + +void gc_page_serializer_destroy(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT +{ + if (__unlikely(page_profile_enabled)) { + arraylist_free(&serializer->typestrs); + } +} + +void gc_page_serializer_write(gc_page_profiler_serializer_t *serializer, + const char *str) JL_NOTSAFEPOINT +{ + if (__unlikely(page_profile_enabled)) { + arraylist_push(&serializer->typestrs, (void *)str); + } +} + +void gc_enable_page_profile(void) JL_NOTSAFEPOINT +{ + page_profile_enabled = 1; +} + +void gc_disable_page_profile(void) JL_NOTSAFEPOINT +{ + page_profile_enabled = 0; +} + +int gc_page_profile_is_enabled(void) JL_NOTSAFEPOINT +{ + return page_profile_enabled; +} + +void gc_page_profile_write_preamble(gc_page_profiler_serializer_t *serializer) + JL_NOTSAFEPOINT +{ + if (__unlikely(page_profile_enabled)) { + char str[GC_TYPE_STR_MAXLEN]; + snprintf(str, GC_TYPE_STR_MAXLEN, + "{\"address\": \"%p\",\"object_size\": %d,\"objects\": [", + serializer->data, serializer->osize); + ios_write(page_profile_stream, str, strlen(str)); + } +} + +void gc_page_profile_write_epilogue(gc_page_profiler_serializer_t *serializer) + JL_NOTSAFEPOINT +{ + if (__unlikely(page_profile_enabled)) { + const char *str = "]}"; + ios_write(page_profile_stream, str, strlen(str)); + } +} + +void gc_page_profile_write_comma(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT +{ + if (__unlikely(page_profile_enabled)) { + // write comma if not first page + if (page_profile_pages_written > 0) { + const char *str = ","; + ios_write(page_profile_stream, str, strlen(str)); + } + } +} + +void gc_page_profile_write_to_file(gc_page_profiler_serializer_t *serializer) + JL_NOTSAFEPOINT +{ + if (__unlikely(page_profile_enabled)) { + // write to file + uv_mutex_lock(&page_profile_lock); + gc_page_profile_write_comma(serializer); + gc_page_profile_write_preamble(serializer); + char str[GC_TYPE_STR_MAXLEN]; + for (size_t i = 0; i < serializer->typestrs.len; i++) { + const char *name = (const char *)serializer->typestrs.items[i]; + if (name == GC_SERIALIZER_EMPTY) { + snprintf(str, GC_TYPE_STR_MAXLEN, "\"empty\","); + } + else if (name == GC_SERIALIZER_GARBAGE) { + snprintf(str, GC_TYPE_STR_MAXLEN, "\"garbage\","); + } + else { + snprintf(str, GC_TYPE_STR_MAXLEN, "\"%s\",", name); + } + // remove trailing comma for last element + if (i == serializer->typestrs.len - 1) { + str[strlen(str) - 1] = '\0'; + } + ios_write(page_profile_stream, str, strlen(str)); + } + gc_page_profile_write_epilogue(serializer); + page_profile_pages_written++; + uv_mutex_unlock(&page_profile_lock); + } +} + +void gc_page_profile_write_json_preamble(ios_t *stream) JL_NOTSAFEPOINT +{ + if (__unlikely(page_profile_enabled)) { + uv_mutex_lock(&page_profile_lock); + const char *str = "{\"pages\": ["; + ios_write(stream, str, strlen(str)); + uv_mutex_unlock(&page_profile_lock); + } +} + +void gc_page_profile_write_json_epilogue(ios_t *stream) JL_NOTSAFEPOINT +{ + if (__unlikely(page_profile_enabled)) { + uv_mutex_lock(&page_profile_lock); + const char *str = "]}"; + ios_write(stream, str, strlen(str)); + uv_mutex_unlock(&page_profile_lock); + } +} + +JL_DLLEXPORT void jl_gc_take_page_profile(ios_t *stream) +{ + gc_enable_page_profile(); + page_profile_pages_written = 0; + page_profile_stream = stream; + gc_page_profile_write_json_preamble(stream); + jl_gc_collect(JL_GC_FULL); + gc_page_profile_write_json_epilogue(stream); + gc_disable_page_profile(); +} + +#ifdef __cplusplus +} +#endif diff --git a/src/gc-page-profiler.h b/src/gc-page-profiler.h new file mode 100644 index 0000000000000..b103e23905ba5 --- /dev/null +++ b/src/gc-page-profiler.h @@ -0,0 +1,63 @@ +// This file is a part of Julia. License is MIT: https://julialang.org/license + +#ifndef GC_PAGE_PROFILER_H +#define GC_PAGE_PROFILER_H + +#include "gc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define GC_TYPE_STR_MAXLEN (512) + +typedef struct { + arraylist_t typestrs; + char *data; + int osize; +} gc_page_profiler_serializer_t; + +// mutex for page profile +extern uv_mutex_t page_profile_lock; + +// Serializer functions +gc_page_profiler_serializer_t gc_page_serializer_create(void) JL_NOTSAFEPOINT; +void gc_page_serializer_init(gc_page_profiler_serializer_t *serializer, jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT; +void gc_page_serializer_destroy(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT; +void gc_page_serializer_write(gc_page_profiler_serializer_t *serializer, const char *str) JL_NOTSAFEPOINT; +// Page profile functions +#define GC_SERIALIZER_EMPTY ((const char *)0x1) +#define GC_SERIALIZER_GARBAGE ((const char *)0x2) +STATIC_INLINE void gc_page_profile_write_empty_page(gc_page_profiler_serializer_t *serializer, + int enabled) JL_NOTSAFEPOINT +{ + if (__unlikely(enabled)) { + gc_page_serializer_write(serializer, GC_SERIALIZER_EMPTY); + } +} +STATIC_INLINE void gc_page_profile_write_garbage(gc_page_profiler_serializer_t *serializer, + int enabled) JL_NOTSAFEPOINT +{ + if (__unlikely(enabled)) { + gc_page_serializer_write(serializer, GC_SERIALIZER_GARBAGE); + } +} +STATIC_INLINE void gc_page_profile_write_live_obj(gc_page_profiler_serializer_t *serializer, + jl_taggedvalue_t *v, + int enabled) JL_NOTSAFEPOINT +{ + if (__unlikely(enabled)) { + const char *name = jl_typeof_str(jl_valueof(v)); + gc_page_serializer_write(serializer, name); + } +} +void gc_enable_page_profile(void) JL_NOTSAFEPOINT; +void gc_disable_page_profile(void) JL_NOTSAFEPOINT; +int gc_page_profile_is_enabled(void) JL_NOTSAFEPOINT; +void gc_page_profile_write_to_file(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT; + +#ifdef __cplusplus +} +#endif + +#endif // GC_PAGE_PROFILER_H diff --git a/src/gc.c b/src/gc.c index 1776c6beacade..e72c748922c14 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1,6 +1,7 @@ // This file is a part of Julia. License is MIT: https://julialang.org/license #include "gc.h" +#include "gc-page-profiler.h" #include "julia.h" #include "julia_gcext.h" #include "julia_assert.h" @@ -1421,11 +1422,11 @@ STATIC_INLINE void gc_dump_page_utilization_data(void) JL_NOTSAFEPOINT int64_t buffered_pages = 0; // Returns pointer to terminal pointer of list rooted at *pfl. -static void gc_sweep_page(jl_gc_pool_t *p, jl_gc_page_stack_t *allocd, jl_gc_page_stack_t *buffered, +static void gc_sweep_page(gc_page_profiler_serializer_t *s, jl_gc_pool_t *p, jl_gc_page_stack_t *allocd, jl_gc_page_stack_t *buffered, jl_gc_pagemeta_t *pg, int osize) JL_NOTSAFEPOINT { char *data = pg->data; - jl_taggedvalue_t *v = (jl_taggedvalue_t*)(data + GC_PAGE_OFFSET); + jl_taggedvalue_t *v0 = (jl_taggedvalue_t*)(data + GC_PAGE_OFFSET); char *lim = data + GC_PAGE_SZ - osize; char *lim_newpages = data + GC_PAGE_SZ; if (gc_page_data((char*)p->newpages - 1) == data) { @@ -1433,6 +1434,9 @@ static void gc_sweep_page(jl_gc_pool_t *p, jl_gc_page_stack_t *allocd, jl_gc_pag } size_t old_nfree = pg->nfree; size_t nfree; + // avoid loading a global variable in the hot path + int page_profile_enabled = gc_page_profile_is_enabled(); + gc_page_serializer_init(s, pg); int re_use_page = 1; int keep_as_local_buffer = 0; @@ -1452,6 +1456,7 @@ static void gc_sweep_page(jl_gc_pool_t *p, jl_gc_page_stack_t *allocd, jl_gc_pag } #endif nfree = (GC_PAGE_SZ - GC_PAGE_OFFSET) / osize; + gc_page_profile_write_empty_page(s, page_profile_enabled); goto done; } // For quick sweep, we might be able to skip the page if the page doesn't @@ -1461,12 +1466,13 @@ static void gc_sweep_page(jl_gc_pool_t *p, jl_gc_page_stack_t *allocd, jl_gc_pag if (!prev_sweep_full || pg->prev_nold == pg->nold) { freedall = 0; nfree = pg->nfree; + gc_page_profile_write_empty_page(s, page_profile_enabled); goto done; } } pg_skpd = 0; - { // scope to avoid clang goto errors + { // scope to avoid clang goto errors int has_marked = 0; int has_young = 0; int16_t prev_nold = 0; @@ -1474,6 +1480,22 @@ static void gc_sweep_page(jl_gc_pool_t *p, jl_gc_page_stack_t *allocd, jl_gc_pag jl_taggedvalue_t *fl = NULL; jl_taggedvalue_t **pfl = &fl; jl_taggedvalue_t **pfl_begin = NULL; + // collect page profile + jl_taggedvalue_t *v = v0; + if (page_profile_enabled) { + while ((char*)v <= lim) { + int bits = v->bits.gc; + if (!gc_marked(bits) || (char*)v >= lim_newpages) { + gc_page_profile_write_garbage(s, page_profile_enabled); + } + else { + gc_page_profile_write_live_obj(s, v, page_profile_enabled); + } + v = (jl_taggedvalue_t*)((char*)v + osize); + } + v = v0; + } + // sweep the page while ((char*)v <= lim) { int bits = v->bits.gc; // if an object is past `lim_newpages` then we can guarantee it's garbage @@ -1526,6 +1548,7 @@ static void gc_sweep_page(jl_gc_pool_t *p, jl_gc_page_stack_t *allocd, jl_gc_pag push_lf_back(&global_page_pool_lazily_freed, pg); } } + gc_page_profile_write_to_file(s); gc_update_page_fragmentation_data(pg); gc_time_count_page(freedall, pg_skpd); jl_ptls_t ptls = gc_all_tls_states[pg->thread_n]; @@ -1534,7 +1557,7 @@ static void gc_sweep_page(jl_gc_pool_t *p, jl_gc_page_stack_t *allocd, jl_gc_pag } // the actual sweeping over all allocated pages in a memory pool -STATIC_INLINE void gc_sweep_pool_page(jl_gc_page_stack_t *allocd, jl_gc_page_stack_t *lazily_freed, +STATIC_INLINE void gc_sweep_pool_page(gc_page_profiler_serializer_t *s, jl_gc_page_stack_t *allocd, jl_gc_page_stack_t *lazily_freed, jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT { int p_n = pg->pool_n; @@ -1542,7 +1565,7 @@ STATIC_INLINE void gc_sweep_pool_page(jl_gc_page_stack_t *allocd, jl_gc_page_sta jl_ptls_t ptls2 = gc_all_tls_states[t_n]; jl_gc_pool_t *p = &ptls2->heap.norm_pools[p_n]; int osize = pg->osize; - gc_sweep_page(p, allocd, lazily_freed, pg, osize); + gc_sweep_page(s, p, allocd, lazily_freed, pg, osize); } // sweep over all memory that is being used and not in a pool @@ -1579,11 +1602,20 @@ void gc_sweep_wake_all(void) uv_mutex_unlock(&gc_threads_lock); } +void gc_sweep_wait_for_all(void) +{ + jl_atomic_store(&gc_allocd_scratch, NULL); + while (jl_atomic_load_relaxed(&gc_n_threads_sweeping) != 0) { + jl_cpu_pause(); + } +} + void gc_sweep_pool_parallel(void) { jl_atomic_fetch_add(&gc_n_threads_sweeping, 1); jl_gc_page_stack_t *allocd_scratch = jl_atomic_load(&gc_allocd_scratch); if (allocd_scratch != NULL) { + gc_page_profiler_serializer_t serializer = gc_page_serializer_create(); while (1) { int found_pg = 0; for (int t_i = 0; t_i < gc_n_threads; t_i++) { @@ -1596,25 +1628,18 @@ void gc_sweep_pool_parallel(void) if (pg == NULL) { continue; } - gc_sweep_pool_page(allocd, &ptls2->page_metadata_buffered, pg); + gc_sweep_pool_page(&serializer, allocd, &ptls2->page_metadata_buffered, pg); found_pg = 1; } if (!found_pg) { break; } } + gc_page_serializer_destroy(&serializer); } jl_atomic_fetch_add(&gc_n_threads_sweeping, -1); } -void gc_sweep_wait_for_all(void) -{ - jl_atomic_store(&gc_allocd_scratch, NULL); - while (jl_atomic_load_relaxed(&gc_n_threads_sweeping) != 0) { - jl_cpu_pause(); - } -} - void gc_free_pages(void) { while (1) { @@ -3792,6 +3817,7 @@ void jl_gc_init(void) { JL_MUTEX_INIT(&heapsnapshot_lock, "heapsnapshot_lock"); JL_MUTEX_INIT(&finalizers_lock, "finalizers_lock"); + uv_mutex_init(&page_profile_lock); uv_mutex_init(&gc_cache_lock); uv_mutex_init(&gc_perm_lock); uv_mutex_init(&gc_threads_lock); diff --git a/stdlib/Profile/src/Profile.jl b/stdlib/Profile/src/Profile.jl index 690d0465b3ec0..24d2512dcbedf 100644 --- a/stdlib/Profile/src/Profile.jl +++ b/stdlib/Profile/src/Profile.jl @@ -1260,6 +1260,21 @@ function take_heap_snapshot(all_one::Bool=false; dir::Union{Nothing,S}=nothing) return take_heap_snapshot(fpath, all_one) end +""" + Profile.take_page_profile(io::IOStream) + Profile.take_page_profile(filepath::String) + +Write a JSON snapshot of the pages from Julia's pool allocator, printing for every pool allocated object, whether it's garbage, or its type. +""" +function take_page_profile(io::IOStream) + Base.@_lock_ios(io, ccall(:jl_gc_take_page_profile, Cvoid, (Ptr{Cvoid},), io.handle)) +end +function take_page_profile(filepath::String) + open(filepath, "w") do io + take_page_profile(io) + end + return filepath +end include("Allocs.jl") include("precompile.jl") diff --git a/stdlib/Profile/test/runtests.jl b/stdlib/Profile/test/runtests.jl index 2d6df81b1015d..f4d64c791956f 100644 --- a/stdlib/Profile/test/runtests.jl +++ b/stdlib/Profile/test/runtests.jl @@ -294,4 +294,14 @@ end rm(tmpdir, force = true, recursive = true) end +@testset "PageProfile" begin + fname = "$(getpid())_$(time_ns())" + fpath = joinpath(tempdir(), fname) + Profile.take_page_profile(fpath) + open(fpath) do fs + @test readline(fs) != "" + end + rm(fpath) +end + include("allocs.jl") From 4a3d5bdf98d5a077d268c06049415ceb3f3a3eb7 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Thu, 4 Jan 2024 14:48:12 -0300 Subject: [PATCH 025/109] revert GC heuristics back to 1.9 (#126) --- src/gc-debug.c | 30 ++++++++++-- src/gc.c | 126 +++++++++++++++++++++++++++--------------------- src/gc.h | 2 - test/testenv.jl | 4 -- 4 files changed, 95 insertions(+), 67 deletions(-) diff --git a/src/gc-debug.c b/src/gc-debug.c index 12acb1cfbe7cb..1f1aca1a467f5 100644 --- a/src/gc-debug.c +++ b/src/gc-debug.c @@ -1,10 +1,7 @@ // This file is a part of Julia. License is MIT: https://julialang.org/license #include "gc.h" -#include "julia.h" #include -#include -#include #include // re-include assert.h without NDEBUG, @@ -953,6 +950,29 @@ void gc_time_sweep_pause(uint64_t gc_end_t, int64_t actual_allocd, jl_ns2ms(gc_postmark_end - gc_premark_end), sweep_full ? "full" : "quick", -gc_num.allocd / 1024); } + +void gc_time_summary(int sweep_full, uint64_t start, uint64_t end, + uint64_t freed, uint64_t live, uint64_t interval, + uint64_t pause, uint64_t ttsp, uint64_t mark, + uint64_t sweep) +{ + if (sweep_full > 0) + jl_safe_printf("TS: %" PRIu64 " Major collection: estimate freed = %" PRIu64 + " live = %" PRIu64 "m new interval = %" PRIu64 + "m time = %" PRIu64 "ms ttsp = %" PRIu64 "us mark time = %" + PRIu64 "ms sweep time = %" PRIu64 "ms \n", + end, freed, live/1024/1024, + interval/1024/1024, pause/1000000, ttsp, + mark/1000000,sweep/1000000); + else + jl_safe_printf("TS: %" PRIu64 " Minor collection: estimate freed = %" PRIu64 + " live = %" PRIu64 "m new interval = %" PRIu64 "m pause time = %" + PRIu64 "ms ttsp = %" PRIu64 "us mark time = %" PRIu64 + "ms sweep time = %" PRIu64 "ms \n", + end, freed, live/1024/1024, + interval/1024/1024, pause/1000000, ttsp, + mark/1000000,sweep/1000000); +} #endif void jl_gc_debug_init(void) @@ -1200,8 +1220,8 @@ void _report_gc_finished(uint64_t pause, uint64_t freed, int full, int recollect if (!gc_logging_enabled) { return; } - jl_safe_printf("\nGC: pause %.2fms. collected %fMB. %s %s\n", - pause/1e6, freed/(double)(1<<20), + jl_safe_printf("GC: pause %.2fms. collected %fMB. %s %s\n", + pause/1e6, freed/1e6, full ? "full" : "incr", recollect ? "recollect" : "" ); diff --git a/src/gc.c b/src/gc.c index e72c748922c14..693243a415756 100644 --- a/src/gc.c +++ b/src/gc.c @@ -195,7 +195,6 @@ jl_gc_num_t gc_num = {0}; static size_t last_long_collect_interval; int gc_n_threads; jl_ptls_t* gc_all_tls_states; -int next_sweep_full = 0; const uint64_t _jl_buff_tag[3] = {0x4eadc0004eadc000ull, 0x4eadc0004eadc000ull, 0x4eadc0004eadc000ull}; // aka 0xHEADER00 JL_DLLEXPORT uintptr_t jl_get_buff_tag(void) { @@ -695,10 +694,8 @@ static const size_t max_collect_interval = 500000000UL; // Work really hard to stay within 2GB // Alternative is to risk running out of address space // on 32 bit architectures. -#define MAX32HEAP 1536 * 1024 * 1024 -static memsize_t max_total_memory = (memsize_t) MAX32HEAP; +static memsize_t max_total_memory = (memsize_t) 2 * 1024 * 1024 * 1024; #endif -static uint64_t gc_end_time = 0; // global variables for GC stats // 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 static int64_t perm_scanned_bytes; // old bytes scanned while marking int prev_sweep_full = 1; int current_sweep_full = 0; -int under_pressure = 0; // Full collection heuristics static int64_t live_bytes = 0; static int64_t promoted_bytes = 0; -static int64_t last_full_live = 0; // live_bytes after last full collection static int64_t last_live_bytes = 0; // live_bytes at last collection -static int64_t grown_heap_age = 0; // # of collects since live_bytes grew and remained +static int64_t t_start = 0; // Time GC starts; #ifdef __GLIBC__ // maxrss at last malloc_trim static int64_t last_trim_maxrss = 0; @@ -3346,11 +3341,6 @@ JL_DLLEXPORT int64_t jl_gc_live_bytes(void) return live_bytes; } -double jl_gc_smooth(uint64_t old_val, uint64_t new_val, double factor) -{ - return factor * old_val + (1.0-factor) * new_val; -} - size_t jl_maxrss(void); // Only one thread should be running in this function @@ -3467,6 +3457,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) int64_t estimate_freed = live_sz_ub - live_sz_est; gc_verify(ptls); + gc_stats_all_pool(); gc_stats_big_obj(); objprofile_printall(); @@ -3483,46 +3474,34 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) if (ptls2 != NULL) nptr += ptls2->heap.remset_nptr; } - int large_frontier = nptr*sizeof(void*) >= default_collect_interval; // many pointers in the intergen frontier => "quick" mark is not quick - // trigger a full collection if the number of live bytes doubles since the last full - // collection and then remains at least that high for a while. - if (grown_heap_age == 0) { - if (live_bytes > 2 * last_full_live) - grown_heap_age = 1; - } - else if (live_bytes >= last_live_bytes) { - grown_heap_age++; - } + + // many pointers in the intergen frontier => "quick" mark is not quick + int large_frontier = nptr*sizeof(void*) >= default_collect_interval; int sweep_full = 0; int recollect = 0; - if ((large_frontier || - ((not_freed_enough || promoted_bytes >= gc_num.interval) && - (promoted_bytes >= default_collect_interval || prev_sweep_full)) || - grown_heap_age > 1) && gc_num.pause > 1) { - sweep_full = 1; - } + // update heuristics only if this GC was automatically triggered if (collection == JL_GC_AUTO) { - if (sweep_full) { - if (large_frontier) - gc_num.interval = last_long_collect_interval; - if (not_freed_enough || large_frontier) { - if (gc_num.interval <= 2*(max_collect_interval/5)) { - gc_num.interval = 5 * (gc_num.interval / 2); - } - } - last_long_collect_interval = gc_num.interval; + if (large_frontier) { + sweep_full = 1; + gc_num.interval = last_long_collect_interval; } - else { - // reset interval to default, or at least half of live_bytes - int64_t half = live_bytes/2; - if (default_collect_interval < half && half <= max_collect_interval) - gc_num.interval = half; - else - gc_num.interval = default_collect_interval; + if (not_freed_enough || large_frontier) { + gc_num.interval = gc_num.interval * 2; } - } + size_t maxmem = 0; +#ifdef _P64 + // on a big memory machine, increase max_collect_interval to totalmem / nthreads / 2 + maxmem = total_mem / (gc_n_threads - jl_n_gcthreads) / 2; +#endif + if (maxmem < max_collect_interval) + maxmem = max_collect_interval; + if (gc_num.interval > maxmem) { + sweep_full = 1; + gc_num.interval = maxmem; + } + } // If the live data outgrows the suggested max_total_memory // we keep going with full gcs until we either free some space or get an OOM error. @@ -3542,6 +3521,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) // on the first collection after sweep_full, and the current scan perm_scanned_bytes = 0; promoted_bytes = 0; + last_long_collect_interval = gc_num.interval; } scanned_bytes = 0; // 6. start sweeping @@ -3570,7 +3550,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) JL_PROBE_GC_SWEEP_END(); - gc_end_time = jl_hrtime(); + uint64_t gc_end_time = jl_hrtime(); uint64_t pause = gc_end_time - gc_start_time; uint64_t sweep_time = gc_end_time - start_sweep_time; gc_num.total_sweep_time += sweep_time; @@ -3627,18 +3607,48 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) gc_num.allocd = 0; last_live_bytes = live_bytes; live_bytes += -gc_num.freed + actual_allocd; - jl_timing_counter_dec(JL_TIMING_COUNTER_HeapSize, gc_num.freed); + + if (collection == JL_GC_AUTO) { + //If we aren't freeing enough or are seeing lots and lots of pointers let it increase faster + if (!not_freed_enough || large_frontier) { + int64_t tot = 2 * (live_bytes + actual_allocd) / 3; + if (gc_num.interval > tot) { + gc_num.interval = tot; + last_long_collect_interval = tot; + } + } + // If the current interval is larger than half the live data decrease the interval + else { + int64_t half = (live_bytes / 2); + if (gc_num.interval > half) + gc_num.interval = half; + } + // But never go below default + if (gc_num.interval < default_collect_interval) gc_num.interval = default_collect_interval; + } + + if (gc_num.interval + live_bytes > max_total_memory) { + if (live_bytes < max_total_memory) { + gc_num.interval = max_total_memory - live_bytes; + last_long_collect_interval = max_total_memory - live_bytes; + } + else { + // We can't stay under our goal so let's go back to + // the minimum interval and hope things get better + under_memory_pressure = 1; + gc_num.interval = default_collect_interval; + } + } + gc_time_summary(sweep_full, t_start, gc_end_time, gc_num.freed, live_bytes, gc_num.interval, pause, gc_num.time_to_safepoint, gc_num.mark_time, gc_num.sweep_time); - if (prev_sweep_full) { - last_full_live = live_bytes; - grown_heap_age = 0; - } + prev_sweep_full = sweep_full; gc_num.pause += !recollect; gc_num.total_time += pause; + gc_num.allocd = 0; gc_num.freed = 0; if (pause > gc_num.max_pause) { gc_num.max_pause = pause; @@ -3840,21 +3850,25 @@ void jl_gc_init(void) total_mem = uv_get_total_memory(); uint64_t constrained_mem = uv_get_constrained_memory(); if (constrained_mem > 0 && constrained_mem < total_mem) - jl_gc_set_max_memory(constrained_mem - 250*1024*1024); // LLVM + other libraries need some amount of memory + total_mem = constrained_mem; + double percent; + if (total_mem < 128e9) + percent = total_mem * 2.34375e-12 + 0.6; // 60% at 0 gigs and 90% at 128 to not + else // overcommit too much on memory contrained devices + percent = 0.9; + max_total_memory = total_mem * percent; #endif if (jl_options.heap_size_hint) jl_gc_set_max_memory(jl_options.heap_size_hint - 250*1024*1024); + + t_start = jl_hrtime(); } JL_DLLEXPORT void jl_gc_set_max_memory(uint64_t max_mem) { if (max_mem > 0 && max_mem < (uint64_t)1 << (sizeof(memsize_t) * 8 - 1)) { - #ifdef _P64 max_total_memory = max_mem; - #else - max_total_memory = max_mem < MAX32HEAP ? max_mem : MAX32HEAP; - #endif } } diff --git a/src/gc.h b/src/gc.h index a6ad9f41dabf0..1d63c1d96e397 100644 --- a/src/gc.h +++ b/src/gc.h @@ -9,8 +9,6 @@ #ifndef JL_GC_H #define JL_GC_H -#include -#include #include #include #include diff --git a/test/testenv.jl b/test/testenv.jl index 6f99291e01138..41706dd24e75e 100644 --- a/test/testenv.jl +++ b/test/testenv.jl @@ -37,10 +37,6 @@ if !@isdefined(testenv_defined) function addprocs_with_testenv(X; rr_allowed=true, kwargs...) exename = rr_allowed ? `$rr_exename $test_exename` : test_exename - if X isa Integer - heap_size=round(Int,(Sys.total_memory()/(1024^2)/(X+1))) - push!(test_exeflags.exec, "--heap-size-hint=$(heap_size)M") - end addprocs(X; exename=exename, exeflags=test_exeflags, kwargs...) end From 61c1b962f4076bb2a60003d126286a883bf407f8 Mon Sep 17 00:00:00 2001 From: d-netto Date: Fri, 12 Jan 2024 08:41:07 -0300 Subject: [PATCH 026/109] Set the number of GC threads to number of compute threads --- src/threading.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/threading.c b/src/threading.c index 5d0c0c614840f..77b24dcb5208c 100644 --- a/src/threading.c +++ b/src/threading.c @@ -678,13 +678,12 @@ void jl_init_threading(void) } else { // if `--gcthreads` or ENV[NUM_GCTHREADS_NAME] was not specified, - // set the number of mark threads to half of compute threads - // and number of sweep threads to 0 + // set the number of GC threads to the number of compute threads if (nthreads <= 1) { jl_n_markthreads = 0; } else { - jl_n_markthreads = (nthreads / 2) - 1; + jl_n_markthreads = nthreads - 1; } // if `--gcthreads` or ENV[NUM_GCTHREADS_NAME] was not specified, // cap the number of threads that may run the mark phase to From 54c08b9cb3beeb40568595e21890cdaec22d8c0c Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Sun, 21 Jan 2024 16:57:20 -0300 Subject: [PATCH 027/109] reduce contention on page metadata lists during the sweeping phase (#52943) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit **EDIT**: fixes https://github.com/JuliaLang/julia/issues/52937 by decreasing the contention on the page lists and only waking GC threads up if we have a sufficiently large number of pages. Seems to address the regression from the MWE of https://github.com/JuliaLang/julia/issues/52937: - master: ``` ../julia-master/julia --project=. run_benchmarks.jl serial obj_arrays issue-52937 -n5 --gcthreads=1 bench = "issue-52937.jl" ┌─────────┬────────────┬─────────┬───────────┬────────────┬──────────────┬───────────────────┬──────────┬────────────┐ │ │ total time │ gc time │ mark time │ sweep time │ max GC pause │ time to safepoint │ max heap │ percent gc │ │ │ ms │ ms │ ms │ ms │ ms │ us │ MB │ % │ ├─────────┼────────────┼─────────┼───────────┼────────────┼──────────────┼───────────────────┼──────────┼────────────┤ │ minimum │ 24841 │ 818 │ 78 │ 740 │ 44 │ 10088 │ 96 │ 3 │ │ median │ 24881 │ 834 │ 83 │ 751 │ 45 │ 10738 │ 97 │ 3 │ │ maximum │ 25002 │ 891 │ 87 │ 803 │ 48 │ 11074 │ 112 │ 4 │ │ stdev │ 78 │ 29 │ 4 │ 26 │ 1 │ 393 │ 7 │ 0 │ └─────────┴────────────┴─────────┴───────────┴────────────┴──────────────┴───────────────────┴──────────┴────────────┘ ../julia-master/julia --project=. run_benchmarks.jl serial obj_arrays issue-52937 -n5 --gcthreads=8 bench = "issue-52937.jl" ┌─────────┬────────────┬─────────┬───────────┬────────────┬──────────────┬───────────────────┬──────────┬────────────┐ │ │ total time │ gc time │ mark time │ sweep time │ max GC pause │ time to safepoint │ max heap │ percent gc │ │ │ ms │ ms │ ms │ ms │ ms │ us │ MB │ % │ ├─────────┼────────────┼─────────┼───────────┼────────────┼──────────────┼───────────────────┼──────────┼────────────┤ │ minimum │ 29113 │ 5200 │ 68 │ 5130 │ 12 │ 9724 │ 95 │ 18 │ │ median │ 29354 │ 5274 │ 69 │ 5204 │ 12 │ 10456 │ 96 │ 18 │ │ maximum │ 29472 │ 5333 │ 70 │ 5264 │ 14 │ 11913 │ 97 │ 18 │ │ stdev │ 138 │ 54 │ 1 │ 55 │ 1 │ 937 │ 1 │ 0 │ └─────────┴────────────┴─────────┴───────────┴────────────┴──────────────┴───────────────────┴──────────┴────────────┘ ``` - PR: ``` ../julia-master/julia --project=. run_benchmarks.jl serial obj_arrays issue-52937 -n5 --gcthreads=1 bench = "issue-52937.jl" ┌─────────┬────────────┬─────────┬───────────┬────────────┬──────────────┬───────────────────┬──────────┬────────────┐ │ │ total time │ gc time │ mark time │ sweep time │ max GC pause │ time to safepoint │ max heap │ percent gc │ │ │ ms │ ms │ ms │ ms │ ms │ us │ MB │ % │ ├─────────┼────────────┼─────────┼───────────┼────────────┼──────────────┼───────────────────┼──────────┼────────────┤ │ minimum │ 24475 │ 761 │ 77 │ 681 │ 40 │ 9499 │ 94 │ 3 │ │ median │ 24845 │ 775 │ 80 │ 698 │ 43 │ 10793 │ 97 │ 3 │ │ maximum │ 25128 │ 811 │ 85 │ 726 │ 47 │ 12820 │ 113 │ 3 │ │ stdev │ 240 │ 22 │ 3 │ 21 │ 3 │ 1236 │ 8 │ 0 │ └─────────┴────────────┴─────────┴───────────┴────────────┴──────────────┴───────────────────┴──────────┴────────────┘ ../julia-master/julia --project=. run_benchmarks.jl serial obj_arrays issue-52937 -n5 --gcthreads=8 bench = "issue-52937.jl" ┌─────────┬────────────┬─────────┬───────────┬────────────┬──────────────┬───────────────────┬──────────┬────────────┐ │ │ total time │ gc time │ mark time │ sweep time │ max GC pause │ time to safepoint │ max heap │ percent gc │ │ │ ms │ ms │ ms │ ms │ ms │ us │ MB │ % │ ├─────────┼────────────┼─────────┼───────────┼────────────┼──────────────┼───────────────────┼──────────┼────────────┤ │ minimum │ 24709 │ 679 │ 70 │ 609 │ 11 │ 9981 │ 95 │ 3 │ │ median │ 24869 │ 702 │ 70 │ 631 │ 12 │ 10705 │ 96 │ 3 │ │ maximum │ 24911 │ 708 │ 72 │ 638 │ 13 │ 10820 │ 98 │ 3 │ │ stdev │ 79 │ 12 │ 1 │ 12 │ 1 │ 401 │ 1 │ 0 │ └─────────┴────────────┴─────────┴───────────┴────────────┴──────────────┴───────────────────┴──────────┴────────────┘ ``` Also, performance on `objarray.jl` (an example of benchmark in which sweeping parallelizes well with the current implementation) seems fine: - master: ``` ../julia-master/julia --project=. run_benchmarks.jl multithreaded bigarrays -n5 --gcthreads=1 bench = "objarray.jl" ┌─────────┬────────────┬─────────┬───────────┬────────────┬──────────────┬───────────────────┬──────────┬────────────┐ │ │ total time │ gc time │ mark time │ sweep time │ max GC pause │ time to safepoint │ max heap │ percent gc │ │ │ ms │ ms │ ms │ ms │ ms │ us │ MB │ % │ ├─────────┼────────────┼─────────┼───────────┼────────────┼──────────────┼───────────────────┼──────────┼────────────┤ │ minimum │ 19301 │ 10792 │ 7485 │ 3307 │ 1651 │ 196 │ 4519 │ 56 │ │ median │ 21415 │ 12646 │ 9094 │ 3551 │ 1985 │ 241 │ 6576 │ 59 │ │ maximum │ 21873 │ 13118 │ 9353 │ 3765 │ 2781 │ 330 │ 8793 │ 60 │ │ stdev │ 1009 │ 932 │ 757 │ 190 │ 449 │ 50 │ 1537 │ 2 │ └─────────┴────────────┴─────────┴───────────┴────────────┴──────────────┴───────────────────┴──────────┴────────────┘ ../julia-master/julia --project=. run_benchmarks.jl multithreaded bigarrays -n5 --gcthreads=8 bench = "objarray.jl" ┌─────────┬────────────┬─────────┬───────────┬────────────┬──────────────┬───────────────────┬──────────┬────────────┐ │ │ total time │ gc time │ mark time │ sweep time │ max GC pause │ time to safepoint │ max heap │ percent gc │ │ │ ms │ ms │ ms │ ms │ ms │ us │ MB │ % │ ├─────────┼────────────┼─────────┼───────────┼────────────┼──────────────┼───────────────────┼──────────┼────────────┤ │ minimum │ 13135 │ 4377 │ 3350 │ 1007 │ 491 │ 231 │ 6062 │ 33 │ │ median │ 13164 │ 4540 │ 3370 │ 1177 │ 669 │ 256 │ 6383 │ 35 │ │ maximum │ 13525 │ 4859 │ 3675 │ 1184 │ 748 │ 320 │ 7528 │ 36 │ │ stdev │ 183 │ 189 │ 146 │ 77 │ 129 │ 42 │ 584 │ 1 │ └─────────┴────────────┴─────────┴───────────┴────────────┴──────────────┴───────────────────┴──────────┴────────────┘ ``` - PR: ``` ../julia-master/julia --project=. run_benchmarks.jl multithreaded bigarrays -n5 --gcthreads=1 bench = "objarray.jl" ┌─────────┬────────────┬─────────┬───────────┬────────────┬──────────────┬───────────────────┬──────────┬────────────┐ │ │ total time │ gc time │ mark time │ sweep time │ max GC pause │ time to safepoint │ max heap │ percent gc │ │ │ ms │ ms │ ms │ ms │ ms │ us │ MB │ % │ ├─────────┼────────────┼─────────┼───────────┼────────────┼──────────────┼───────────────────┼──────────┼────────────┤ │ minimum │ 19642 │ 10931 │ 7566 │ 3365 │ 1653 │ 204 │ 5688 │ 56 │ │ median │ 21441 │ 12717 │ 8948 │ 3770 │ 1796 │ 217 │ 6972 │ 59 │ │ maximum │ 23494 │ 14643 │ 10576 │ 4067 │ 2513 │ 248 │ 8229 │ 62 │ │ stdev │ 1408 │ 1339 │ 1079 │ 267 │ 393 │ 19 │ 965 │ 2 │ └─────────┴────────────┴─────────┴───────────┴────────────┴──────────────┴───────────────────┴──────────┴────────────┘ ../julia-master/julia --project=. run_benchmarks.jl multithreaded bigarrays -n5 --gcthreads=8 bench = "objarray.jl" ┌─────────┬────────────┬─────────┬───────────┬────────────┬──────────────┬───────────────────┬──────────┬────────────┐ │ │ total time │ gc time │ mark time │ sweep time │ max GC pause │ time to safepoint │ max heap │ percent gc │ │ │ ms │ ms │ ms │ ms │ ms │ us │ MB │ % │ ├─────────┼────────────┼─────────┼───────────┼────────────┼──────────────┼───────────────────┼──────────┼────────────┤ │ minimum │ 13365 │ 4544 │ 3389 │ 1104 │ 516 │ 255 │ 6349 │ 34 │ │ median │ 13445 │ 4624 │ 3404 │ 1233 │ 578 │ 275 │ 6385 │ 34 │ │ maximum │ 14413 │ 5278 │ 3837 │ 1441 │ 753 │ 300 │ 7547 │ 37 │ │ stdev │ 442 │ 303 │ 194 │ 121 │ 89 │ 18 │ 522 │ 1 │ └─────────┴────────────┴─────────┴───────────┴────────────┴──────────────┴───────────────────┴──────────┴────────────┘ ``` --- src/gc.c | 124 +++++++++++++++++++++++++++++++++++++++++++++------- src/gc.h | 46 ++++++++++++++++++- src/partr.c | 2 +- 3 files changed, 154 insertions(+), 18 deletions(-) diff --git a/src/gc.c b/src/gc.c index 693243a415756..562d60905806b 100644 --- a/src/gc.c +++ b/src/gc.c @@ -21,8 +21,8 @@ int jl_n_sweepthreads; _Atomic(int) gc_n_threads_marking; // Number of threads sweeping _Atomic(int) gc_n_threads_sweeping; -// Temporary for the `ptls->page_metadata_allocd` used during parallel sweeping -_Atomic(jl_gc_page_stack_t *) gc_allocd_scratch; +// Temporary for the `ptls->page_metadata_allocd` used during parallel sweeping (padded to avoid false sharing) +_Atomic(jl_gc_padded_page_stack_t *) gc_allocd_scratch; // `tid` of mutator thread that triggered GC _Atomic(int) gc_master_tid; // `tid` of first GC thread @@ -1586,8 +1586,72 @@ static void gc_pool_sync_nfree(jl_gc_pagemeta_t *pg, jl_taggedvalue_t *last) JL_ pg->nfree = nfree; } -void gc_sweep_wake_all(void) +// pre-scan pages to check whether there are enough pages so that's worth parallelizing +// also sweeps pages that don't need to be linearly scanned +int gc_sweep_prescan(jl_ptls_t ptls, jl_gc_padded_page_stack_t *new_gc_allocd_scratch) { + // 4MB worth of pages is worth parallelizing + const int n_pages_worth_parallel_sweep = (int)(4 * (1 << 20) / GC_PAGE_SZ); + int n_pages_to_scan = 0; + gc_page_profiler_serializer_t serializer = gc_page_serializer_create(); + for (int t_i = 0; t_i < gc_n_threads; t_i++) { + jl_ptls_t ptls2 = gc_all_tls_states[t_i]; + if (ptls2 == NULL) { + continue; + } + jl_gc_page_stack_t *dest = &new_gc_allocd_scratch[ptls2->tid].stack; + jl_gc_page_stack_t tmp; + jl_gc_pagemeta_t *tail = NULL; + memset(&tmp, 0, sizeof(tmp)); + while (1) { + jl_gc_pagemeta_t *pg = pop_lf_back_nosync(&ptls2->page_metadata_allocd); + if (pg == NULL) { + break; + } + int should_scan = 1; + if (!pg->has_marked) { + should_scan = 0; + } + if (!current_sweep_full && !pg->has_young) { + assert(!prev_sweep_full || pg->prev_nold >= pg->nold); + if (!prev_sweep_full || pg->prev_nold == pg->nold) { + should_scan = 0; + } + } + if (should_scan) { + if (tail == NULL) { + tail = pg; + } + n_pages_to_scan++; + push_lf_back_nosync(&tmp, pg); + } + else { + gc_sweep_pool_page(&serializer, dest, &ptls2->page_metadata_buffered, pg); + } + if (n_pages_to_scan >= n_pages_worth_parallel_sweep) { + break; + } + } + if (tail != NULL) { + tail->next = jl_atomic_load_relaxed(&ptls2->page_metadata_allocd.bottom); + } + ptls2->page_metadata_allocd = tmp; + if (n_pages_to_scan >= n_pages_worth_parallel_sweep) { + break; + } + } + gc_page_serializer_destroy(&serializer); + return n_pages_to_scan >= n_pages_worth_parallel_sweep; +} + +// wake up all threads to sweep the pages +void gc_sweep_wake_all(jl_ptls_t ptls, jl_gc_padded_page_stack_t *new_gc_allocd_scratch) +{ + int parallel_sweep_worthwhile = gc_sweep_prescan(ptls, new_gc_allocd_scratch); + jl_atomic_store(&gc_allocd_scratch, new_gc_allocd_scratch); + if (!parallel_sweep_worthwhile) { + return; + } uv_mutex_lock(&gc_threads_lock); for (int i = gc_first_tid; i < gc_first_tid + jl_n_markthreads; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; @@ -1597,6 +1661,7 @@ void gc_sweep_wake_all(void) uv_mutex_unlock(&gc_threads_lock); } +// wait for all threads to finish sweeping void gc_sweep_wait_for_all(void) { jl_atomic_store(&gc_allocd_scratch, NULL); @@ -1605,36 +1670,58 @@ void gc_sweep_wait_for_all(void) } } -void gc_sweep_pool_parallel(void) +// sweep all pools +void gc_sweep_pool_parallel(jl_ptls_t ptls) { jl_atomic_fetch_add(&gc_n_threads_sweeping, 1); - jl_gc_page_stack_t *allocd_scratch = jl_atomic_load(&gc_allocd_scratch); + jl_gc_padded_page_stack_t *allocd_scratch = jl_atomic_load(&gc_allocd_scratch); if (allocd_scratch != NULL) { gc_page_profiler_serializer_t serializer = gc_page_serializer_create(); while (1) { int found_pg = 0; + // sequentially walk the threads and sweep the pages for (int t_i = 0; t_i < gc_n_threads; t_i++) { jl_ptls_t ptls2 = gc_all_tls_states[t_i]; + // skip foreign threads that already exited if (ptls2 == NULL) { continue; } - jl_gc_page_stack_t *allocd = &allocd_scratch[t_i]; - jl_gc_pagemeta_t *pg = pop_lf_back(&ptls2->page_metadata_allocd); + jl_gc_page_stack_t *dest = &allocd_scratch[ptls2->tid].stack; + jl_gc_pagemeta_t *pg = try_pop_lf_back(&ptls2->page_metadata_allocd); + // failed steal attempt if (pg == NULL) { continue; } - gc_sweep_pool_page(&serializer, allocd, &ptls2->page_metadata_buffered, pg); + gc_sweep_pool_page(&serializer, dest, &ptls2->page_metadata_buffered, pg); found_pg = 1; } if (!found_pg) { - break; + // check for termination + int no_more_work = 1; + for (int t_i = 0; t_i < gc_n_threads; t_i++) { + jl_ptls_t ptls2 = gc_all_tls_states[t_i]; + // skip foreign threads that already exited + if (ptls2 == NULL) { + continue; + } + jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->page_metadata_allocd.bottom); + if (pg != NULL) { + no_more_work = 0; + break; + } + } + if (no_more_work) { + break; + } } + jl_cpu_pause(); } gc_page_serializer_destroy(&serializer); } jl_atomic_fetch_add(&gc_n_threads_sweeping, -1); } +// free all pages (i.e. through `madvise` on Linux) that were lazily freed void gc_free_pages(void) { while (1) { @@ -1659,7 +1746,7 @@ static void gc_sweep_pool(void) // allocate enough space to hold the end of the free list chain // for every thread and pool size - jl_taggedvalue_t ***pfl = (jl_taggedvalue_t ***) alloca(n_threads * JL_GC_N_POOLS * sizeof(jl_taggedvalue_t**)); + jl_taggedvalue_t ***pfl = (jl_taggedvalue_t ***) malloc_s(n_threads * JL_GC_N_POOLS * sizeof(jl_taggedvalue_t**)); // update metadata of pages that were pointed to by freelist or newpages from a pool // i.e. pages being the current allocation target @@ -1701,17 +1788,18 @@ static void gc_sweep_pool(void) } // the actual sweeping - jl_gc_page_stack_t *tmp = (jl_gc_page_stack_t *)alloca(n_threads * sizeof(jl_gc_page_stack_t)); - memset(tmp, 0, n_threads * sizeof(jl_gc_page_stack_t)); - jl_atomic_store(&gc_allocd_scratch, tmp); - gc_sweep_wake_all(); - gc_sweep_pool_parallel(); + jl_gc_padded_page_stack_t *new_gc_allocd_scratch = (jl_gc_padded_page_stack_t *) malloc_s(n_threads * sizeof(jl_gc_padded_page_stack_t)); + memset(new_gc_allocd_scratch, 0, n_threads * sizeof(jl_gc_padded_page_stack_t)); + jl_ptls_t ptls = jl_current_task->ptls; + gc_sweep_wake_all(ptls, new_gc_allocd_scratch); + gc_sweep_pool_parallel(ptls); gc_sweep_wait_for_all(); + // reset half-pages pointers for (int t_i = 0; t_i < n_threads; t_i++) { jl_ptls_t ptls2 = gc_all_tls_states[t_i]; if (ptls2 != NULL) { - ptls2->page_metadata_allocd = tmp[t_i]; + ptls2->page_metadata_allocd = new_gc_allocd_scratch[t_i].stack; for (int i = 0; i < JL_GC_N_POOLS; i++) { jl_gc_pool_t *p = &ptls2->heap.norm_pools[i]; p->newpages = NULL; @@ -1749,6 +1837,10 @@ static void gc_sweep_pool(void) } } + // cleanup + free(pfl); + free(new_gc_allocd_scratch); + #ifdef _P64 // only enable concurrent sweeping on 64bit // wake thread up to sweep concurrently if (jl_n_sweepthreads > 0) { diff --git a/src/gc.h b/src/gc.h index 1d63c1d96e397..5357dcbc60d00 100644 --- a/src/gc.h +++ b/src/gc.h @@ -195,6 +195,23 @@ extern jl_gc_page_stack_t global_page_pool_freed; // in the sweeping phase, which also doesn't push a node into the // same stack after it's popped +STATIC_INLINE void push_lf_back_nosync(jl_gc_page_stack_t *pool, jl_gc_pagemeta_t *elt) JL_NOTSAFEPOINT +{ + jl_gc_pagemeta_t *old_back = jl_atomic_load_relaxed(&pool->bottom); + elt->next = old_back; + jl_atomic_store_relaxed(&pool->bottom, elt); +} + +STATIC_INLINE jl_gc_pagemeta_t *pop_lf_back_nosync(jl_gc_page_stack_t *pool) JL_NOTSAFEPOINT +{ + jl_gc_pagemeta_t *old_back = jl_atomic_load_relaxed(&pool->bottom); + if (old_back == NULL) { + return NULL; + } + jl_atomic_store_relaxed(&pool->bottom, old_back->next); + return old_back; +} + STATIC_INLINE void push_lf_back(jl_gc_page_stack_t *pool, jl_gc_pagemeta_t *elt) JL_NOTSAFEPOINT { while (1) { @@ -207,6 +224,23 @@ STATIC_INLINE void push_lf_back(jl_gc_page_stack_t *pool, jl_gc_pagemeta_t *elt) } } +#define MAX_POP_ATTEMPTS (1 << 10) + +STATIC_INLINE jl_gc_pagemeta_t *try_pop_lf_back(jl_gc_page_stack_t *pool) JL_NOTSAFEPOINT +{ + for (int i = 0; i < MAX_POP_ATTEMPTS; i++) { + jl_gc_pagemeta_t *old_back = jl_atomic_load_relaxed(&pool->bottom); + if (old_back == NULL) { + return NULL; + } + if (jl_atomic_cmpswap(&pool->bottom, &old_back, old_back->next)) { + return old_back; + } + jl_cpu_pause(); + } + return NULL; +} + STATIC_INLINE jl_gc_pagemeta_t *pop_lf_back(jl_gc_page_stack_t *pool) JL_NOTSAFEPOINT { while (1) { @@ -220,6 +254,16 @@ STATIC_INLINE jl_gc_pagemeta_t *pop_lf_back(jl_gc_page_stack_t *pool) JL_NOTSAFE jl_cpu_pause(); } } +typedef struct { + jl_gc_page_stack_t stack; + // pad to 128 bytes to avoid false-sharing +#ifdef _P64 + void *_pad[15]; +#else + void *_pad[31]; +#endif +} jl_gc_padded_page_stack_t; +static_assert(sizeof(jl_gc_padded_page_stack_t) == 128, "jl_gc_padded_page_stack_t is not 128 bytes"); typedef struct { _Atomic(size_t) n_freed_objs; @@ -461,7 +505,7 @@ void gc_mark_finlist(jl_gc_markqueue_t *mq, arraylist_t *list, size_t start) JL_ void gc_mark_loop_serial_(jl_ptls_t ptls, jl_gc_markqueue_t *mq); void gc_mark_loop_serial(jl_ptls_t ptls); void gc_mark_loop_parallel(jl_ptls_t ptls, int master); -void gc_sweep_pool_parallel(void); +void gc_sweep_pool_parallel(jl_ptls_t ptls); void gc_free_pages(void); void sweep_stack_pools(void); void jl_gc_debug_init(void); diff --git a/src/partr.c b/src/partr.c index 23a252b537f99..ffb8859f1b0ea 100644 --- a/src/partr.c +++ b/src/partr.c @@ -143,7 +143,7 @@ void jl_parallel_gc_threadfun(void *arg) gc_mark_loop_parallel(ptls, 0); } if (may_sweep(ptls)) { // not an else! - gc_sweep_pool_parallel(); + gc_sweep_pool_parallel(ptls); jl_atomic_fetch_add(&ptls->gc_sweeps_requested, -1); } } From a0183a13c77310c9e058abc3cbd9a5e92ad53a8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Drvo=C5=A1t=C4=9Bp?= Date: Thu, 1 Feb 2024 19:34:35 +0100 Subject: [PATCH 028/109] Change to streaming out the heap snapshot data (#52854) This PR is to continue the work on the following PR: Prevent OOMs during heap snapshot: Change to streaming out the snapshot data (#51518 ) Here are the commit history: ``` * Streaming the heap snapshot! This should prevent the engine from OOMing while recording the snapshot! Now we just need to sample the files, either online, before downloading, or offline after downloading :) If we're gonna do it offline, we'll want to gzip the files before downloading them. * Allow custom filename; use original API * Support legacy heap snapshot interface. Add reassembly function. * Add tests * Apply suggestions from code review * Update src/gc-heap-snapshot.cpp * Change to always save the parts in the same directory This way you can always recover from an OOM * Fix bug in reassembler: from_node and to_node were in the wrong order * Fix correctness mistake: The edges have to be reordered according to the node order. That's the whole reason this is tricky. But i'm not sure now whether the SoAs approach is actually an optimization.... It seems like we should probably prefer to inline the Edges right into the vector, rather than having to do another random lookup into the edges table? * Debugging messed up edge array idxs * Disable log message * Write the .nodes and .edges as binary data * Remove unnecessary logging * fix merge issues * attempt to add back the orphan node checking logic ``` --------- Co-authored-by: Nathan Daly Co-authored-by: Nathan Daly --- src/gc-heap-snapshot.cpp | 401 +++++++++--------- src/gc-heap-snapshot.h | 3 +- stdlib/Profile/docs/src/index.md | 19 + stdlib/Profile/src/Profile.jl | 69 ++- stdlib/Profile/src/heapsnapshot_reassemble.jl | 231 ++++++++++ .../Profile/test/heapsnapshot_reassemble.jl | 54 +++ stdlib/Profile/test/runtests.jl | 1 + 7 files changed, 574 insertions(+), 204 deletions(-) create mode 100644 stdlib/Profile/src/heapsnapshot_reassemble.jl create mode 100644 stdlib/Profile/test/heapsnapshot_reassemble.jl diff --git a/src/gc-heap-snapshot.cpp b/src/gc-heap-snapshot.cpp index 00b6934386cd0..a197e70df97fc 100644 --- a/src/gc-heap-snapshot.cpp +++ b/src/gc-heap-snapshot.cpp @@ -6,6 +6,7 @@ #include "julia_assert.h" #include "gc.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/DenseMap.h" @@ -21,6 +22,7 @@ using std::set; using std::ostringstream; using std::pair; using std::make_pair; +using llvm::SmallVector; using llvm::StringMap; using llvm::DenseMap; using llvm::StringRef; @@ -57,8 +59,9 @@ void print_str_escape_json(ios_t *stream, StringRef s) // mimicking https://github.com/nodejs/node/blob/5fd7a72e1c4fbaf37d3723c4c81dce35c149dc84/deps/v8/src/profiler/heap-snapshot-generator.cc#L2598-L2601 struct Edge { - size_t type; // These *must* match the Enums on the JS side; control interpretation of name_or_index. + uint8_t type; // These *must* match the Enums on the JS side; control interpretation of name_or_index. size_t name_or_index; // name of the field (for objects/modules) or index of array + size_t from_node; // This is a deviation from the .heapsnapshot format to support streaming. size_t to_node; }; @@ -67,29 +70,34 @@ struct Edge { // [ "type", "name", "id", "self_size", "edge_count", "trace_node_id", "detachedness" ] // mimicking https://github.com/nodejs/node/blob/5fd7a72e1c4fbaf37d3723c4c81dce35c149dc84/deps/v8/src/profiler/heap-snapshot-generator.cc#L2568-L2575 -const int k_node_number_of_fields = 7; struct Node { - size_t type; // index into snapshot->node_types + uint8_t type; // index into snapshot->node_types size_t name; size_t id; // This should be a globally-unique counter, but we use the memory address size_t self_size; size_t trace_node_id; // This is ALWAYS 0 in Javascript heap-snapshots. // whether the from_node is attached or dettached from the main application state // https://github.com/nodejs/node/blob/5fd7a72e1c4fbaf37d3723c4c81dce35c149dc84/deps/v8/include/v8-profiler.h#L739-L745 - int detachedness; // 0 - unknown, 1 - attached, 2 - detached - vector edges; + uint8_t detachedness; // 0 - unknown, 1 - attached, 2 - detached ~Node() JL_NOTSAFEPOINT = default; }; -struct StringTable { +class StringTable { +protected: StringMap map; - vector strings; + SmallVector strings; + size_t next_id; + +public: + StringTable() JL_NOTSAFEPOINT : map(), strings(), next_id(0) {}; size_t find_or_create_string_id(StringRef key) JL_NOTSAFEPOINT { - auto val = map.insert(make_pair(key, map.size())); - if (val.second) + auto val = map.insert(make_pair(key, next_id)); + if (val.second) { strings.push_back(val.first->first()); + next_id++; + } return val.first->second; } @@ -109,16 +117,65 @@ struct StringTable { } }; -struct HeapSnapshot { - vector nodes; - // edges are stored on each from_node +// a string table with partial strings in memory and all strings serialized to a file +class SerializedStringTable: public StringTable { + public: + + // serialize the string only if it's not already in the table + size_t serialize_if_necessary(ios_t *stream, StringRef key) JL_NOTSAFEPOINT { + auto val = map.insert(make_pair(key, next_id)); + if (val.second) { + strings.push_back(val.first->first()); + // persist the string size first, then the string itself + // so that we could read it back in the same order + size_t s_size = key.size(); + ios_write(stream, reinterpret_cast(&s_size), sizeof(size_t)); + ios_write(stream, key.data(), s_size); + next_id++; + } + return val.first->second; + } - StringTable names; + // serialize the string without checking if it is in the table or not + // and return its index. This means that we might have duplicates in the + // output string file. + size_t serialize(ios_t *stream, StringRef key) JL_NOTSAFEPOINT { + size_t s_size = key.size(); + ios_write(stream, reinterpret_cast(&s_size), sizeof(size_t)); + ios_write(stream, key.data(), s_size); + size_t current = next_id; + next_id++; + return current; + } +}; + +struct HeapSnapshot { + // names could be very large, so we keep them in a separate binary file + // and use a StringTable to keep track of the indices of frequently used strings + // to reduce duplicates in the output file to some degree + SerializedStringTable names; + // node types and edge types are very small and keep them in memory StringTable node_types; StringTable edge_types; DenseMap node_ptr_to_index_map; - size_t num_edges = 0; // For metadata, updated as you add each edge. Needed because edges owned by nodes. + size_t num_nodes = 0; // Since we stream out to files, + size_t num_edges = 0; // we need to track the counts here. + + // Node internal_root; + + // Used for streaming + // Since nodes and edges are just one giant array of integers, we stream them as + // *BINARY DATA*: a sequence of bytes, each of which is a 64-bit integer (big enough to + // fit the pointer ids). + ios_t *nodes; + ios_t *edges; + // strings are serialized to a file in binary format + ios_t *strings; + // the following file is written out as json data. + ios_t *json; + + size_t internal_root_idx = 0; // node index of the internal root node size_t _gc_root_idx = 1; // node index of the GC roots node size_t _gc_finlist_root_idx = 2; // node index of the GC finlist roots node }; @@ -129,17 +186,22 @@ int gc_heap_snapshot_enabled = 0; HeapSnapshot *g_snapshot = nullptr; extern jl_mutex_t heapsnapshot_lock; +void final_serialize_heap_snapshot(ios_t *json, ios_t *strings, HeapSnapshot &snapshot, char all_one); void serialize_heap_snapshot(ios_t *stream, HeapSnapshot &snapshot, char all_one); static inline void _record_gc_edge(const char *edge_type, jl_value_t *a, jl_value_t *b, size_t name_or_index) JL_NOTSAFEPOINT; -void _record_gc_just_edge(const char *edge_type, Node &from_node, size_t to_idx, size_t name_or_idx) JL_NOTSAFEPOINT; -void _add_synthetic_root_entries(HeapSnapshot *snapshot); +void _record_gc_just_edge(const char *edge_type, size_t from_idx, size_t to_idx, size_t name_or_idx) JL_NOTSAFEPOINT; +void _add_synthetic_root_entries(HeapSnapshot *snapshot) JL_NOTSAFEPOINT; -JL_DLLEXPORT void jl_gc_take_heap_snapshot(ios_t *stream, char all_one) +JL_DLLEXPORT void jl_gc_take_heap_snapshot(ios_t *nodes, ios_t *edges, + ios_t *strings, ios_t *json, char all_one) { HeapSnapshot snapshot; - _add_synthetic_root_entries(&snapshot); + snapshot.nodes = nodes; + snapshot.edges = edges; + snapshot.strings = strings; + snapshot.json = json; jl_mutex_lock(&heapsnapshot_lock); @@ -147,6 +209,8 @@ JL_DLLEXPORT void jl_gc_take_heap_snapshot(ios_t *stream, char all_one) g_snapshot = &snapshot; gc_heap_snapshot_enabled = true; + _add_synthetic_root_entries(&snapshot); + // Do a full GC mark (and incremental sweep), which will invoke our callbacks on `g_snapshot` jl_gc_collect(JL_GC_FULL); @@ -158,70 +222,96 @@ JL_DLLEXPORT void jl_gc_take_heap_snapshot(ios_t *stream, char all_one) // When we return, the snapshot is full // Dump the snapshot - serialize_heap_snapshot((ios_t*)stream, snapshot, all_one); + final_serialize_heap_snapshot((ios_t*)json, (ios_t*)strings, snapshot, all_one); +} + +void serialize_node(HeapSnapshot *snapshot, const Node &node) JL_NOTSAFEPOINT +{ + // ["type","name","id","self_size","edge_count","trace_node_id","detachedness"] + ios_write(snapshot->nodes, (char*)&node.type, sizeof(node.type)); + ios_write(snapshot->nodes, (char*)&node.name, sizeof(node.name)); + ios_write(snapshot->nodes, (char*)&node.id, sizeof(node.id)); + ios_write(snapshot->nodes, (char*)&node.self_size, sizeof(node.self_size)); + // NOTE: We don't write edge_count, since it's always 0. It will be reconstructed in + // post-processing. + ios_write(snapshot->nodes, (char*)&node.trace_node_id, sizeof(node.trace_node_id)); + ios_write(snapshot->nodes, (char*)&node.detachedness, sizeof(node.detachedness)); + + g_snapshot->num_nodes += 1; +} + +void serialize_edge(HeapSnapshot *snapshot, const Edge &edge) JL_NOTSAFEPOINT +{ + // ["type","name_or_index","to_node"] + ios_write(snapshot->edges, (char*)&edge.type, sizeof(edge.type)); + ios_write(snapshot->edges, (char*)&edge.name_or_index, sizeof(edge.name_or_index)); + // NOTE: Row numbers for nodes (not adjusted for k_node_number_of_fields, which is 7) + ios_write(snapshot->edges, (char*)&edge.from_node, sizeof(edge.from_node)); + ios_write(snapshot->edges, (char*)&edge.to_node, sizeof(edge.to_node)); + + g_snapshot->num_edges += 1; } // mimicking https://github.com/nodejs/node/blob/5fd7a72e1c4fbaf37d3723c4c81dce35c149dc84/deps/v8/src/profiler/heap-snapshot-generator.cc#L212 // add synthetic nodes for the uber root, the GC roots, and the GC finalizer list roots -void _add_synthetic_root_entries(HeapSnapshot *snapshot) +void _add_synthetic_root_entries(HeapSnapshot *snapshot) JL_NOTSAFEPOINT { // adds a node at id 0 which is the "uber root": // a synthetic node which points to all the GC roots. Node internal_root{ - snapshot->node_types.find_or_create_string_id("synthetic"), - snapshot->names.find_or_create_string_id(""), // name + (uint8_t)snapshot->node_types.find_or_create_string_id("synthetic"), + snapshot->names.serialize_if_necessary(snapshot->strings, ""), // name 0, // id 0, // size 0, // size_t trace_node_id (unused) - 0, // int detachedness; // 0 - unknown, 1 - attached; 2 - detached - vector() // outgoing edges + 0 // int detachedness; // 0 - unknown, 1 - attached; 2 - detached }; - snapshot->nodes.push_back(internal_root); + serialize_node(snapshot, internal_root); // Add a node for the GC roots - snapshot->_gc_root_idx = snapshot->nodes.size(); + snapshot->_gc_root_idx = snapshot->internal_root_idx + 1; Node gc_roots{ - snapshot->node_types.find_or_create_string_id("synthetic"), - snapshot->names.find_or_create_string_id("GC roots"), // name + (uint8_t)snapshot->node_types.find_or_create_string_id("synthetic"), + snapshot->names.serialize_if_necessary(snapshot->strings, "GC roots"), // name snapshot->_gc_root_idx, // id 0, // size 0, // size_t trace_node_id (unused) - 0, // int detachedness; // 0 - unknown, 1 - attached; 2 - detached - vector() // outgoing edges + 0 // int detachedness; // 0 - unknown, 1 - attached; 2 - detached }; - snapshot->nodes.push_back(gc_roots); - snapshot->nodes.front().edges.push_back(Edge{ - snapshot->edge_types.find_or_create_string_id("internal"), - snapshot->names.find_or_create_string_id("GC roots"), // edge label + serialize_node(snapshot, gc_roots); + Edge root_to_gc_roots{ + (uint8_t)snapshot->edge_types.find_or_create_string_id("internal"), + snapshot->names.serialize_if_necessary(snapshot->strings, "GC roots"), // edge label + snapshot->internal_root_idx, // from snapshot->_gc_root_idx // to - }); - snapshot->num_edges += 1; + }; + serialize_edge(snapshot, root_to_gc_roots); // add a node for the gc finalizer list roots - snapshot->_gc_finlist_root_idx = snapshot->nodes.size(); + snapshot->_gc_finlist_root_idx = snapshot->internal_root_idx + 2; Node gc_finlist_roots{ - snapshot->node_types.find_or_create_string_id("synthetic"), - snapshot->names.find_or_create_string_id("GC finalizer list roots"), // name + (uint8_t)snapshot->node_types.find_or_create_string_id("synthetic"), + snapshot->names.serialize_if_necessary(snapshot->strings, "GC finalizer list roots"), // name snapshot->_gc_finlist_root_idx, // id 0, // size 0, // size_t trace_node_id (unused) - 0, // int detachedness; // 0 - unknown, 1 - attached; 2 - detached - vector() // outgoing edges + 0 // int detachedness; // 0 - unknown, 1 - attached; 2 - detached }; - snapshot->nodes.push_back(gc_finlist_roots); - snapshot->nodes.front().edges.push_back(Edge{ - snapshot->edge_types.find_or_create_string_id("internal"), - snapshot->names.find_or_create_string_id("GC finlist roots"), // edge label + serialize_node(snapshot, gc_finlist_roots); + Edge root_to_gc_finlist_roots{ + (uint8_t)snapshot->edge_types.find_or_create_string_id("internal"), + snapshot->names.serialize_if_necessary(snapshot->strings, "GC finalizer list roots"), // edge label + snapshot->internal_root_idx, // from snapshot->_gc_finlist_root_idx // to - }); - snapshot->num_edges += 1; + }; + serialize_edge(snapshot, root_to_gc_finlist_roots); } // mimicking https://github.com/nodejs/node/blob/5fd7a72e1c4fbaf37d3723c4c81dce35c149dc84/deps/v8/src/profiler/heap-snapshot-generator.cc#L597-L597 // returns the index of the new node size_t record_node_to_gc_snapshot(jl_value_t *a) JL_NOTSAFEPOINT { - auto val = g_snapshot->node_ptr_to_index_map.insert(make_pair(a, g_snapshot->nodes.size())); + auto val = g_snapshot->node_ptr_to_index_map.insert(make_pair(a, g_snapshot->num_nodes)); if (!val.second) { return val.first->second; } @@ -291,17 +381,17 @@ size_t record_node_to_gc_snapshot(jl_value_t *a) JL_NOTSAFEPOINT name = StringRef((const char*)str_.buf, str_.size); } - g_snapshot->nodes.push_back(Node{ - g_snapshot->node_types.find_or_create_string_id(node_type), // size_t type; - g_snapshot->names.find_or_create_string_id(name), // size_t name; + auto node = Node{ + (uint8_t)g_snapshot->node_types.find_or_create_string_id(node_type), // size_t type; + g_snapshot->names.serialize(g_snapshot->strings, name), // size_t name; (size_t)a, // size_t id; // We add 1 to self-size for the type tag that all heap-allocated objects have. // Also because the Chrome Snapshot viewer ignores size-0 leaves! sizeof(void*) + self_size, // size_t self_size; 0, // size_t trace_node_id (unused) 0, // int detachedness; // 0 - unknown, 1 - attached; 2 - detached - vector() // outgoing edges - }); + }; + serialize_node(g_snapshot, node); if (ios_need_close) ios_close(&str_); @@ -311,20 +401,20 @@ size_t record_node_to_gc_snapshot(jl_value_t *a) JL_NOTSAFEPOINT static size_t record_pointer_to_gc_snapshot(void *a, size_t bytes, StringRef name) JL_NOTSAFEPOINT { - auto val = g_snapshot->node_ptr_to_index_map.insert(make_pair(a, g_snapshot->nodes.size())); + auto val = g_snapshot->node_ptr_to_index_map.insert(make_pair(a, g_snapshot->num_nodes)); if (!val.second) { return val.first->second; } - g_snapshot->nodes.push_back(Node{ - g_snapshot->node_types.find_or_create_string_id( "object"), // size_t type; - g_snapshot->names.find_or_create_string_id(name), // size_t name; + auto node = Node{ + (uint8_t)g_snapshot->node_types.find_or_create_string_id( "object"), // size_t type; + g_snapshot->names.serialize(g_snapshot->strings, name), // size_t name; (size_t)a, // size_t id; bytes, // size_t self_size; 0, // size_t trace_node_id (unused) 0, // int detachedness; // 0 - unknown, 1 - attached; 2 - detached - vector() // outgoing edges - }); + }; + serialize_node(g_snapshot, node); return val.first->second; } @@ -360,36 +450,29 @@ static string _fieldpath_for_slot(void *obj, void *slot) JL_NOTSAFEPOINT } } - void _gc_heap_snapshot_record_root(jl_value_t *root, char *name) JL_NOTSAFEPOINT { - record_node_to_gc_snapshot(root); - - auto &internal_root = g_snapshot->nodes.front(); - auto to_node_idx = g_snapshot->node_ptr_to_index_map[root]; - auto edge_label = g_snapshot->names.find_or_create_string_id(name); + size_t to_node_idx = record_node_to_gc_snapshot(root); + auto edge_label = g_snapshot->names.serialize(g_snapshot->strings, name); - _record_gc_just_edge("internal", internal_root, to_node_idx, edge_label); + _record_gc_just_edge("internal", g_snapshot->internal_root_idx, to_node_idx, edge_label); } void _gc_heap_snapshot_record_gc_roots(jl_value_t *root, char *name) JL_NOTSAFEPOINT { - record_node_to_gc_snapshot(root); - - auto from_node_idx = g_snapshot->_gc_root_idx; auto to_node_idx = record_node_to_gc_snapshot(root); - auto edge_label = g_snapshot->names.find_or_create_string_id(name); - _record_gc_just_edge("internal", g_snapshot->nodes[from_node_idx], to_node_idx, edge_label); + auto edge_label = g_snapshot->names.serialize(g_snapshot->strings, name); + + _record_gc_just_edge("internal", g_snapshot->_gc_root_idx, to_node_idx, edge_label); } void _gc_heap_snapshot_record_finlist(jl_value_t *obj, size_t index) JL_NOTSAFEPOINT { - auto from_node_idx = g_snapshot->_gc_finlist_root_idx; auto to_node_idx = record_node_to_gc_snapshot(obj); ostringstream ss; ss << "finlist-" << index; - auto edge_label = g_snapshot->names.find_or_create_string_id(ss.str()); - _record_gc_just_edge("internal", g_snapshot->nodes[from_node_idx], to_node_idx, edge_label); + auto edge_label = g_snapshot->names.serialize_if_necessary(g_snapshot->strings, ss.str()); + _record_gc_just_edge("internal", g_snapshot->_gc_finlist_root_idx, to_node_idx, edge_label); } // Add a node to the heap snapshot representing a Julia stack frame. @@ -398,20 +481,20 @@ void _gc_heap_snapshot_record_finlist(jl_value_t *obj, size_t index) JL_NOTSAFEP // Stack frame nodes point at the objects they have as local variables. size_t _record_stack_frame_node(HeapSnapshot *snapshot, void *frame) JL_NOTSAFEPOINT { - auto val = g_snapshot->node_ptr_to_index_map.insert(make_pair(frame, g_snapshot->nodes.size())); + auto val = g_snapshot->node_ptr_to_index_map.insert(make_pair(frame, g_snapshot->num_nodes)); if (!val.second) { return val.first->second; } - snapshot->nodes.push_back(Node{ - snapshot->node_types.find_or_create_string_id("synthetic"), - snapshot->names.find_or_create_string_id("(stack frame)"), // name + auto node = Node{ + (uint8_t)snapshot->node_types.find_or_create_string_id("synthetic"), + snapshot->names.serialize_if_necessary(snapshot->strings, "(stack frame)"), // name (size_t)frame, // id 1, // size 0, // size_t trace_node_id (unused) 0, // int detachedness; // 0 - unknown, 1 - attached; 2 - detached - vector() // outgoing edges - }); + }; + serialize_node(snapshot, node); return val.first->second; } @@ -420,30 +503,27 @@ void _gc_heap_snapshot_record_frame_to_object_edge(void *from, jl_value_t *to) J { auto from_node_idx = _record_stack_frame_node(g_snapshot, (jl_gcframe_t*)from); auto to_idx = record_node_to_gc_snapshot(to); - Node &from_node = g_snapshot->nodes[from_node_idx]; - auto name_idx = g_snapshot->names.find_or_create_string_id("local var"); - _record_gc_just_edge("internal", from_node, to_idx, name_idx); + auto name_idx = g_snapshot->names.serialize_if_necessary(g_snapshot->strings, "local var"); + _record_gc_just_edge("internal", from_node_idx, to_idx, name_idx); } void _gc_heap_snapshot_record_task_to_frame_edge(jl_task_t *from, void *to) JL_NOTSAFEPOINT { auto from_node_idx = record_node_to_gc_snapshot((jl_value_t*)from); auto to_node_idx = _record_stack_frame_node(g_snapshot, to); - Node &from_node = g_snapshot->nodes[from_node_idx]; - auto name_idx = g_snapshot->names.find_or_create_string_id("stack"); - _record_gc_just_edge("internal", from_node, to_node_idx, name_idx); + auto name_idx = g_snapshot->names.serialize_if_necessary(g_snapshot->strings, "stack"); + _record_gc_just_edge("internal", from_node_idx, to_node_idx, name_idx); } void _gc_heap_snapshot_record_frame_to_frame_edge(jl_gcframe_t *from, jl_gcframe_t *to) JL_NOTSAFEPOINT { auto from_node_idx = _record_stack_frame_node(g_snapshot, from); auto to_node_idx = _record_stack_frame_node(g_snapshot, to); - Node &from_node = g_snapshot->nodes[from_node_idx]; - auto name_idx = g_snapshot->names.find_or_create_string_id("next frame"); - _record_gc_just_edge("internal", from_node, to_node_idx, name_idx); + auto name_idx = g_snapshot->names.serialize_if_necessary(g_snapshot->strings, "next frame"); + _record_gc_just_edge("internal", from_node_idx, to_node_idx, name_idx); } void _gc_heap_snapshot_record_array_edge(jl_value_t *from, jl_value_t *to, size_t index) JL_NOTSAFEPOINT @@ -455,7 +535,7 @@ void _gc_heap_snapshot_record_object_edge(jl_value_t *from, jl_value_t *to, void { string path = _fieldpath_for_slot(from, slot); _record_gc_edge("property", from, to, - g_snapshot->names.find_or_create_string_id(path)); + g_snapshot->names.serialize_if_necessary(g_snapshot->strings, path)); } void _gc_heap_snapshot_record_module_to_binding(jl_module_t *module, jl_value_t *bindings, jl_value_t *bindingkeyset) JL_NOTSAFEPOINT @@ -463,46 +543,44 @@ void _gc_heap_snapshot_record_module_to_binding(jl_module_t *module, jl_value_t auto from_node_idx = record_node_to_gc_snapshot((jl_value_t*)module); auto to_bindings_idx = record_node_to_gc_snapshot(bindings); auto to_bindingkeyset_idx = record_node_to_gc_snapshot(bindingkeyset); - auto &from_node = g_snapshot->nodes[from_node_idx]; + if (to_bindings_idx > 0) { - _record_gc_just_edge("internal", from_node, to_bindings_idx, g_snapshot->names.find_or_create_string_id("bindings")); + _record_gc_just_edge("internal", from_node_idx, to_bindings_idx, g_snapshot->names.serialize_if_necessary(g_snapshot->strings, "bindings")); } if (to_bindingkeyset_idx > 0) { - _record_gc_just_edge("internal", from_node, to_bindingkeyset_idx, g_snapshot->names.find_or_create_string_id("bindingkeyset")); + _record_gc_just_edge("internal", from_node_idx, to_bindingkeyset_idx, g_snapshot->names.serialize_if_necessary(g_snapshot->strings, "bindingkeyset")); } } void _gc_heap_snapshot_record_internal_array_edge(jl_value_t *from, jl_value_t *to) JL_NOTSAFEPOINT { _record_gc_edge("internal", from, to, - g_snapshot->names.find_or_create_string_id("")); + g_snapshot->names.serialize_if_necessary(g_snapshot->strings, "")); } void _gc_heap_snapshot_record_hidden_edge(jl_value_t *from, void* to, size_t bytes, uint16_t alloc_type) JL_NOTSAFEPOINT { - size_t name_or_idx = g_snapshot->names.find_or_create_string_id(""); + // valid alloc_type values are 0, 1, 2 + assert(alloc_type <= 2); + size_t name_or_idx = g_snapshot->names.serialize_if_necessary(g_snapshot->strings, ""); auto from_node_idx = record_node_to_gc_snapshot(from); - const char *alloc_kind; + const char *alloc_kind = NULL; switch (alloc_type) { case 0: - alloc_kind = ""; + alloc_kind = ""; break; case 1: - alloc_kind = ""; + alloc_kind = ""; break; case 2: - alloc_kind = ""; - break; - default: - alloc_kind = ""; + alloc_kind = ""; break; } auto to_node_idx = record_pointer_to_gc_snapshot(to, bytes, alloc_kind); - auto &from_node = g_snapshot->nodes[from_node_idx]; - _record_gc_just_edge("hidden", from_node, to_node_idx, name_or_idx); + _record_gc_just_edge("hidden", from_node_idx, to_node_idx, name_or_idx); } static inline void _record_gc_edge(const char *edge_type, jl_value_t *a, @@ -511,104 +589,39 @@ static inline void _record_gc_edge(const char *edge_type, jl_value_t *a, auto from_node_idx = record_node_to_gc_snapshot(a); auto to_node_idx = record_node_to_gc_snapshot(b); - auto &from_node = g_snapshot->nodes[from_node_idx]; - - _record_gc_just_edge(edge_type, from_node, to_node_idx, name_or_idx); + _record_gc_just_edge(edge_type, from_node_idx, to_node_idx, name_or_idx); } -void _record_gc_just_edge(const char *edge_type, Node &from_node, size_t to_idx, size_t name_or_idx) JL_NOTSAFEPOINT +void _record_gc_just_edge(const char *edge_type, size_t from_idx, size_t to_idx, size_t name_or_idx) JL_NOTSAFEPOINT { - from_node.edges.push_back(Edge{ - g_snapshot->edge_types.find_or_create_string_id(edge_type), + auto edge = Edge{ + (uint8_t)g_snapshot->edge_types.find_or_create_string_id(edge_type), name_or_idx, // edge label + from_idx, // from to_idx // to - }); + }; - g_snapshot->num_edges += 1; + serialize_edge(g_snapshot, edge); } -void serialize_heap_snapshot(ios_t *stream, HeapSnapshot &snapshot, char all_one) +void final_serialize_heap_snapshot(ios_t *json, ios_t *strings, HeapSnapshot &snapshot, char all_one) { // mimicking https://github.com/nodejs/node/blob/5fd7a72e1c4fbaf37d3723c4c81dce35c149dc84/deps/v8/src/profiler/heap-snapshot-generator.cc#L2567-L2567 - ios_printf(stream, "{\"snapshot\":{"); - ios_printf(stream, "\"meta\":{"); - ios_printf(stream, "\"node_fields\":[\"type\",\"name\",\"id\",\"self_size\",\"edge_count\",\"trace_node_id\",\"detachedness\"],"); - ios_printf(stream, "\"node_types\":["); - snapshot.node_types.print_json_array(stream, false); - ios_printf(stream, ","); - ios_printf(stream, "\"string\", \"number\", \"number\", \"number\", \"number\", \"number\"],"); - ios_printf(stream, "\"edge_fields\":[\"type\",\"name_or_index\",\"to_node\"],"); - ios_printf(stream, "\"edge_types\":["); - snapshot.edge_types.print_json_array(stream, false); - ios_printf(stream, ","); - ios_printf(stream, "\"string_or_number\",\"from_node\"]"); - ios_printf(stream, "},\n"); // end "meta" - ios_printf(stream, "\"node_count\":%zu,", snapshot.nodes.size()); - ios_printf(stream, "\"edge_count\":%zu", snapshot.num_edges); - ios_printf(stream, "},\n"); // end "snapshot" - - ios_printf(stream, "\"nodes\":["); - bool first_node = true; - // use a set to track the nodes that do not have parents - set orphans; - for (const auto &from_node : snapshot.nodes) { - if (first_node) { - first_node = false; - } - else { - ios_printf(stream, ","); - } - // ["type","name","id","self_size","edge_count","trace_node_id","detachedness"] - ios_printf(stream, "%zu,%zu,%zu,%zu,%zu,%zu,%d\n", - from_node.type, - from_node.name, - from_node.id, - all_one ? (size_t)1 : from_node.self_size, - from_node.edges.size(), - from_node.trace_node_id, - from_node.detachedness); - if (from_node.id != snapshot._gc_root_idx && from_node.id != snapshot._gc_finlist_root_idx) { - // find the node index from the node object pointer - void * ptr = (void*)from_node.id; - size_t n_id = snapshot.node_ptr_to_index_map[ptr]; - orphans.insert(n_id); - } else { - orphans.insert(from_node.id); - } - } - ios_printf(stream, "],\n"); - - ios_printf(stream, "\"edges\":["); - bool first_edge = true; - for (const auto &from_node : snapshot.nodes) { - for (const auto &edge : from_node.edges) { - if (first_edge) { - first_edge = false; - } - else { - ios_printf(stream, ","); - } - ios_printf(stream, "%zu,%zu,%zu\n", - edge.type, - edge.name_or_index, - edge.to_node * k_node_number_of_fields); - auto n_id = edge.to_node; - auto it = orphans.find(n_id); - if (it != orphans.end()) { - // remove the node from the orphans if it has at least one incoming edge - orphans.erase(it); - } - } - } - ios_printf(stream, "],\n"); // end "edges" - - ios_printf(stream, "\"strings\":"); - - snapshot.names.print_json_array(stream, true); - - ios_printf(stream, "}"); - - // remove the uber node from the orphans - orphans.erase(0); - assert(orphans.size() == 0 && "all nodes except the uber node should have at least one incoming edge"); + ios_printf(json, "{\"snapshot\":{"); + ios_printf(json, "\"meta\":{"); + ios_printf(json, "\"node_fields\":[\"type\",\"name\",\"id\",\"self_size\",\"edge_count\",\"trace_node_id\",\"detachedness\"],"); + ios_printf(json, "\"node_types\":["); + snapshot.node_types.print_json_array(json, false); + ios_printf(json, ","); + ios_printf(json, "\"string\", \"number\", \"number\", \"number\", \"number\", \"number\"],"); + ios_printf(json, "\"edge_fields\":[\"type\",\"name_or_index\",\"to_node\"],"); + ios_printf(json, "\"edge_types\":["); + snapshot.edge_types.print_json_array(json, false); + ios_printf(json, ","); + ios_printf(json, "\"string_or_number\",\"from_node\"]"); + ios_printf(json, "},\n"); // end "meta" + ios_printf(json, "\"node_count\":%zu,", snapshot.num_nodes); + ios_printf(json, "\"edge_count\":%zu", snapshot.num_edges); + ios_printf(json, "}\n"); // end "snapshot" + ios_printf(json, "}"); } diff --git a/src/gc-heap-snapshot.h b/src/gc-heap-snapshot.h index 1799063825e83..70884f5f62d6a 100644 --- a/src/gc-heap-snapshot.h +++ b/src/gc-heap-snapshot.h @@ -120,7 +120,8 @@ static inline void gc_heap_snapshot_record_finlist(jl_value_t *finlist, size_t i // --------------------------------------------------------------------- // Functions to call from Julia to take heap snapshot // --------------------------------------------------------------------- -JL_DLLEXPORT void jl_gc_take_heap_snapshot(ios_t *stream, char all_one); +JL_DLLEXPORT void jl_gc_take_heap_snapshot(ios_t *nodes, ios_t *edges, + ios_t *strings, ios_t *json, char all_one); #ifdef __cplusplus diff --git a/stdlib/Profile/docs/src/index.md b/stdlib/Profile/docs/src/index.md index 85a8452ab06df..8832d5734cb98 100644 --- a/stdlib/Profile/docs/src/index.md +++ b/stdlib/Profile/docs/src/index.md @@ -133,5 +133,24 @@ Traces and records julia objects on the heap. This only records objects known to garbage collector. Memory allocated by external libraries not managed by the garbage collector will not show up in the snapshot. +To avoid OOMing while recording the snapshot, we added a streaming option to stream out the heap snapshot +into four files, + +```julia-repl +julia> using Profile + +julia> Profile.take_heap_snapshot("snapshot"; streaming=true) +``` + +where "snapshot" is the filepath as the prefix for the generated files. + +Once the snapshot files are generated, they could be assembled offline with the following command: + +```julia-repl +julia> using Profile + +julia> Profile.HeapSnapshot.assemble_snapshot("snapshot", "snapshot.heapsnapshot") +``` + The resulting heap snapshot file can be uploaded to chrome devtools to be viewed. For more information, see the [chrome devtools docs](https://developer.chrome.com/docs/devtools/memory-problems/heap-snapshots/#view_snapshots). diff --git a/stdlib/Profile/src/Profile.jl b/stdlib/Profile/src/Profile.jl index 24d2512dcbedf..7b5632892fafd 100644 --- a/stdlib/Profile/src/Profile.jl +++ b/stdlib/Profile/src/Profile.jl @@ -1220,9 +1220,8 @@ end """ - Profile.take_heap_snapshot(io::IOStream, all_one::Bool=false) - Profile.take_heap_snapshot(filepath::String, all_one::Bool=false) - Profile.take_heap_snapshot(all_one::Bool=false; dir::String) + Profile.take_heap_snapshot(filepath::String, all_one::Bool=false, streaming=false) + Profile.take_heap_snapshot(all_one::Bool=false; dir::String, streaming=false) Write a snapshot of the heap, in the JSON format expected by the Chrome Devtools Heap Snapshot viewer (.heapsnapshot extension) to a file @@ -1232,16 +1231,67 @@ full file path, or IO stream. If `all_one` is true, then report the size of every object as one so they can be easily counted. Otherwise, report the actual size. + +If `streaming` is true, we will stream the snapshot data out into four files, using filepath +as the prefix, to avoid having to hold the entire snapshot in memory. This option should be +used for any setting where your memory is constrained. These files can then be reassembled +by calling Profile.HeapSnapshot.assemble_snapshot(), which can +be done offline. + +NOTE: We strongly recommend setting streaming=true for performance reasons. Reconstructing +the snapshot from the parts requires holding the entire snapshot in memory, so if the +snapshot is large, you can run out of memory while processing it. Streaming allows you to +reconstruct the snapshot offline, after your workload is done running. +If you do attempt to collect a snapshot with streaming=false (the default, for +backwards-compatibility) and your process is killed, note that this will always save the +parts in the same directory as your provided filepath, so you can still reconstruct the +snapshot after the fact, via `assemble_snapshot()`. """ -function take_heap_snapshot(io::IOStream, all_one::Bool=false) - Base.@_lock_ios(io, ccall(:jl_gc_take_heap_snapshot, Cvoid, (Ptr{Cvoid}, Cchar), io.handle, Cchar(all_one))) -end -function take_heap_snapshot(filepath::String, all_one::Bool=false) - open(filepath, "w") do io - take_heap_snapshot(io, all_one) +function take_heap_snapshot(filepath::AbstractString, all_one::Bool=false; streaming::Bool=false) + if streaming + _stream_heap_snapshot(filepath, all_one) + else + # Support the legacy, non-streaming mode, by first streaming the parts, then + # reassembling it after we're done. + prefix = filepath + _stream_heap_snapshot(prefix, all_one) + Profile.HeapSnapshot.assemble_snapshot(prefix, filepath) end return filepath end +function take_heap_snapshot(io::IO, all_one::Bool=false) + # Support the legacy, non-streaming mode, by first streaming the parts to a tempdir, + # then reassembling it after we're done. + dir = tempdir() + prefix = joinpath(dir, "snapshot") + _stream_heap_snapshot(prefix, all_one) + Profile.HeapSnapshot.assemble_snapshot(prefix, io) +end +function _stream_heap_snapshot(prefix::AbstractString, all_one::Bool) + # Nodes and edges are binary files + open("$prefix.nodes", "w") do nodes + open("$prefix.edges", "w") do edges + open("$prefix.strings", "w") do strings + # The following file is json data + open("$prefix.metadata.json", "w") do json + Base.@_lock_ios(nodes, + Base.@_lock_ios(edges, + Base.@_lock_ios(strings, + Base.@_lock_ios(json, + ccall(:jl_gc_take_heap_snapshot, + Cvoid, + (Ptr{Cvoid},Ptr{Cvoid},Ptr{Cvoid},Ptr{Cvoid}, Cchar), + nodes.handle, edges.handle, strings.handle, json.handle, + Cchar(all_one)) + ) + ) + ) + ) + end + end + end + end +end function take_heap_snapshot(all_one::Bool=false; dir::Union{Nothing,S}=nothing) where {S <: AbstractString} fname = "$(getpid())_$(time_ns()).heapsnapshot" if isnothing(dir) @@ -1277,6 +1327,7 @@ function take_page_profile(filepath::String) end include("Allocs.jl") +include("heapsnapshot_reassemble.jl") include("precompile.jl") end # module diff --git a/stdlib/Profile/src/heapsnapshot_reassemble.jl b/stdlib/Profile/src/heapsnapshot_reassemble.jl new file mode 100644 index 0000000000000..b39f53a8bda03 --- /dev/null +++ b/stdlib/Profile/src/heapsnapshot_reassemble.jl @@ -0,0 +1,231 @@ +# This file is a part of Julia. License is MIT: https://julialang.org/license + +module HeapSnapshot + +""" + assemble_snapshot(filepath::AbstractString, out_file::AbstractString) + +Assemble a .heapsnapshot file from the .json files produced by `Profile.take_snapshot`. +""" + +# SoA layout to reduce padding +struct Edges + type::Vector{Int8} # index into `snapshot.meta.edge_types` + name_or_index::Vector{UInt} # Either an index into `snapshot.strings`, or the index in an array, depending on edge_type + to_pos::Vector{UInt} # index into `snapshot.nodes` +end +function Edges(n::Int) + Edges( + Vector{Int8}(undef, n), + Vector{UInt}(undef, n), + Vector{UInt}(undef, n), + ) +end +Base.length(n::Edges) = length(n.type) + +# trace_node_id and detachedness are always 0 in the snapshots Julia produces so we don't store them +struct Nodes + type::Vector{Int8} # index into `snapshot.meta.node_types` + name_idx::Vector{UInt32} # index into `snapshot.strings` + id::Vector{UInt} # unique id, in julia it is the address of the object + self_size::Vector{Int} # size of the object itself, not including the size of its fields + edge_count::Vector{UInt} # number of outgoing edges + edges::Edges # outgoing edges + # This is the main complexity of the .heapsnapshot format, and it's the reason we need + # to read in all the data before writing it out. The edges vector contains all edges, + # but organized by which node they came from. First, it contains all the edges coming + # out of node 0, then all edges leaving node 1, etc. So we need to have visited all + # edges, and assigned them to their corresponding nodes, before we can emit the file. + edge_idxs::Vector{Vector{UInt}} # indexes into edges, keeping per-node outgoing edge ids +end +function Nodes(n::Int, e::Int) + Nodes( + Vector{Int8}(undef, n), + Vector{UInt32}(undef, n), + Vector{UInt}(undef, n), + Vector{Int}(undef, n), + Vector{UInt32}(undef, n), + Edges(e), + [Vector{UInt}() for _ in 1:n], # Take care to construct n separate empty vectors + ) +end +Base.length(n::Nodes) = length(n.type) + +const k_node_number_of_fields = 7 + +# Like Base.dec, but doesn't allocate a string and writes directly to the io object +# We know all of the numbers we're about to write fit into a UInt and are non-negative +let _dec_d100 = UInt16[(0x30 + i % 10) << 0x8 + (0x30 + i ÷ 10) for i = 0:99] + global _write_decimal_number + _write_decimal_number(io, x::Integer, buf) = _write_decimal_number(io, unsigned(x), buf) + function _write_decimal_number(io, x::Unsigned, digits_buf) + buf = digits_buf + n = ndigits(x) + i = n + @inbounds while i >= 2 + d, r = divrem(x, 0x64) + d100 = _dec_d100[(r % Int)::Int + 1] + buf[i-1] = d100 % UInt8 + buf[i] = (d100 >> 0x8) % UInt8 + x = oftype(x, d) + i -= 2 + end + if i > 0 + @inbounds buf[i] = 0x30 + (rem(x, 0xa) % UInt8)::UInt8 + end + write(io, @view buf[max(i, 1):n]) + end +end + +function assemble_snapshot(in_prefix, out_file::AbstractString = in_prefix) + open(out_file, "w") do io + assemble_snapshot(in_prefix, io) + end +end + +# Manually parse and write the .json files, given that we don't have JSON import/export in +# julia's stdlibs. +function assemble_snapshot(in_prefix, io::IO) + preamble = read(string(in_prefix, ".metadata.json"), String) + pos = last(findfirst("node_count\":", preamble)) + 1 + endpos = findnext(==(','), preamble, pos) - 1 + node_count = parse(Int, String(@view preamble[pos:endpos])) + + pos = last(findnext("edge_count\":", preamble, endpos)) + 1 + endpos = findnext(==('}'), preamble, pos) - 1 + edge_count = parse(Int, String(@view preamble[pos:endpos])) + + nodes = Nodes(node_count, edge_count) + + orphans = Set{UInt}() # nodes that have no incoming edges + # Parse nodes with empty edge counts that we need to fill later + nodes_file = open(string(in_prefix, ".nodes"), "r") + for i in 1:length(nodes) + node_type = read(nodes_file, Int8) + node_name_idx = read(nodes_file, UInt) + id = read(nodes_file, UInt) + self_size = read(nodes_file, Int) + @assert read(nodes_file, Int) == 0 # trace_node_id + @assert read(nodes_file, Int8) == 0 # detachedness + + nodes.type[i] = node_type + nodes.name_idx[i] = node_name_idx + nodes.id[i] = id + nodes.self_size[i] = self_size + nodes.edge_count[i] = 0 # edge_count + # populate the orphans set with node index + push!(orphans, i-1) + end + + # Parse the edges to fill in the edge counts for nodes and correct the to_node offsets + edges_file = open(string(in_prefix, ".edges"), "r") + for i in 1:length(nodes.edges) + edge_type = read(edges_file, Int8) + edge_name_or_index = read(edges_file, UInt) + from_node = read(edges_file, UInt) + to_node = read(edges_file, UInt) + + nodes.edges.type[i] = edge_type + nodes.edges.name_or_index[i] = edge_name_or_index + nodes.edges.to_pos[i] = to_node * k_node_number_of_fields # 7 fields per node, the streaming format doesn't multiply the offset by 7 + nodes.edge_count[from_node + 1] += UInt32(1) # C and JSON use 0-based indexing + push!(nodes.edge_idxs[from_node + 1], i) # Index into nodes.edges + # remove the node from the orphans if it has at least one incoming edge + if to_node in orphans + delete!(orphans, to_node) + end + end + + _digits_buf = zeros(UInt8, ndigits(typemax(UInt))) + println(io, @view(preamble[1:end-2]), ",") # remove trailing "}\n", we don't end the snapshot here + println(io, "\"nodes\":[") + for i in 1:length(nodes) + i > 1 && println(io, ",") + _write_decimal_number(io, nodes.type[i], _digits_buf) + print(io, ",") + _write_decimal_number(io, nodes.name_idx[i], _digits_buf) + print(io, ",") + _write_decimal_number(io, nodes.id[i], _digits_buf) + print(io, ",") + _write_decimal_number(io, nodes.self_size[i], _digits_buf) + print(io, ",") + _write_decimal_number(io, nodes.edge_count[i], _digits_buf) + print(io, ",0,0") + end + print(io, "],\"edges\":[") + e = 1 + for n in 1:length(nodes) + count = nodes.edge_count[n] + len_edges = length(nodes.edge_idxs[n]) + @assert count == len_edges "For node $n: $count != $len_edges" + for i in nodes.edge_idxs[n] + e > 1 && print(io, ",") + println(io) + _write_decimal_number(io, nodes.edges.type[i], _digits_buf) + print(io, ",") + _write_decimal_number(io, nodes.edges.name_or_index[i], _digits_buf) + print(io, ",") + _write_decimal_number(io, nodes.edges.to_pos[i], _digits_buf) + if !(nodes.edges.to_pos[i] % k_node_number_of_fields == 0) + @warn "Bug in to_pos for edge $i from node $n: $(nodes.edges.to_pos[i])" + end + e += 1 + end + end + println(io, "],") + + println(io, "\"strings\":[") + open(string(in_prefix, ".strings"), "r") do strings_io + first = true + while !eof(strings_io) + str_size = read(strings_io, UInt) + str_bytes = read(strings_io, str_size) + str = String(str_bytes) + if first + print_str_escape_json(io, str) + first = false + else + print(io, ",\n") + print_str_escape_json(io, str) + end + end + end + print(io, "]}") + + # remove the uber node from the orphans + if 0 in orphans + delete!(orphans, 0) + end + + @assert isempty(orphans) "Orphaned nodes: $(orphans), node count: $(length(nodes)), orphan node count: $(length(orphans))" + + return nothing +end + +function print_str_escape_json(stream::IO, s::AbstractString) + print(stream, '"') + for c in s + if c == '"' + print(stream, "\\\"") + elseif c == '\\' + print(stream, "\\\\") + elseif c == '\b' + print(stream, "\\b") + elseif c == '\f' + print(stream, "\\f") + elseif c == '\n' + print(stream, "\\n") + elseif c == '\r' + print(stream, "\\r") + elseif c == '\t' + print(stream, "\\t") + elseif '\x00' <= c <= '\x1f' + print(stream, "\\u", lpad(string(UInt16(c), base=16), 4, '0')) + else + print(stream, c) + end + end + print(stream, '"') +end + +end diff --git a/stdlib/Profile/test/heapsnapshot_reassemble.jl b/stdlib/Profile/test/heapsnapshot_reassemble.jl new file mode 100644 index 0000000000000..e1d6621647671 --- /dev/null +++ b/stdlib/Profile/test/heapsnapshot_reassemble.jl @@ -0,0 +1,54 @@ +using Test + +@testset "_write_decimal_number" begin + _digits_buf = zeros(UInt8, ndigits(typemax(UInt))) + io = IOBuffer() + + test_write(d) = begin + Profile.HeapSnapshot._write_decimal_number(io, d, _digits_buf) + s = String(take!(io)) + seekstart(io) + return s + end + @test test_write(0) == "0" + @test test_write(99) == "99" + + @test test_write(UInt8(0)) == "0" + @test test_write(UInt32(0)) == "0" + @test test_write(Int32(0)) == "0" + + @test test_write(UInt8(99)) == "99" + @test test_write(UInt32(99)) == "99" + @test test_write(Int32(99)) == "99" + + # Sample among possible UInts we might print + for x in typemin(UInt8):typemax(UInt8) + @test test_write(x) == string(x) + end + for x in typemin(UInt):typemax(UInt)÷10001:typemax(UInt) + @test test_write(x) == string(x) + end +end + +function test_print_str_escape_json(input::AbstractString, expected::AbstractString) + output = IOBuffer() + Profile.HeapSnapshot.print_str_escape_json(output, input) + @test String(take!(output)) == expected +end + +@testset "print_str_escape_json" begin + # Test basic string escaping + test_print_str_escape_json("\"hello\"", "\"\\\"hello\\\"\"") + + # Test escaping of control characters + test_print_str_escape_json("\x01\x02\x03", "\"\\u0001\\u0002\\u0003\"") + + # Test escaping of other special characters + test_print_str_escape_json("\b\f\n\r\t", "\"\\b\\f\\n\\r\\t\"") + + # Test handling of mixed characters + test_print_str_escape_json("abc\ndef\"ghi", "\"abc\\ndef\\\"ghi\"") + + # Test handling of empty string + test_print_str_escape_json("", "\"\"") +end diff --git a/stdlib/Profile/test/runtests.jl b/stdlib/Profile/test/runtests.jl index f4d64c791956f..7da2ee23a144f 100644 --- a/stdlib/Profile/test/runtests.jl +++ b/stdlib/Profile/test/runtests.jl @@ -305,3 +305,4 @@ end end include("allocs.jl") +include("heapsnapshot_reassemble.jl") From d3268f8c051010c15d2a11a2213f0cfff3e0038c Mon Sep 17 00:00:00 2001 From: Cody Tapscott <84105208+topolarity@users.noreply.github.com> Date: Thu, 7 Mar 2024 11:16:26 -0500 Subject: [PATCH 029/109] Fix condition for `unreachable` code in IRCode conversion (#53512) This is a partial back-port of #50924, where we discovered that the optimizer would ignore: 1. must-throw `%XX = SlotNumber(_)` statements 2. must-throw `goto #bb if not %x` statements This is mostly harmless, except that in the case of (1) we can accidentally fall through the statically deleted (`Const()`-wrapped) code from inference and end up observing a control-flow edge that never existed. If the spurious edge is to a catch block, then the edge is invalid semantically and breaks our SSA conversion. This one-line change fixes (1) but not (2), which is enough for IR validity. Resolves part of https://github.com/JuliaLang/julia/issues/53366. (cherry picked from commit 035d17a499c6aa965c9f5504a66a9e725d242e82) --- base/compiler/optimize.jl | 2 +- test/compiler/inference.jl | 24 ++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/base/compiler/optimize.jl b/base/compiler/optimize.jl index 3a8de06811cc2..7c8413ceaf9af 100644 --- a/base/compiler/optimize.jl +++ b/base/compiler/optimize.jl @@ -561,7 +561,7 @@ function convert_to_ircode(ci::CodeInfo, sv::OptimizationState) idx += 1 prevloc = codeloc end - if code[idx] isa Expr && ssavaluetypes[idx] === Union{} + if ssavaluetypes[idx] === Union{} && code[idx] !== nothing && !(code[idx] isa Core.Const) if !(idx < length(code) && isa(code[idx + 1], ReturnNode) && !isdefined((code[idx + 1]::ReturnNode), :val)) # insert unreachable in the same basic block after the current instruction (splitting it) insert!(code, idx + 1, ReturnNode()) diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 106abc695247e..223794e74fff0 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -5161,3 +5161,27 @@ let x = 1, _Any = Any foo27031() = bar27031((x, 1.0), Val{_Any}) @test foo27031() == "OK" end + +# Issue #53366 +# +# FIXME: This test is quite brittle, since it relies on lowering making a particular +# (and unnecessary) decision to embed a `SlotNumber` in statement position. +# +# This should be re-written to have the bad IR directly, then run type inference + +# SSA conversion. It should also avoid running `compact!` afterward, since that can +# mask bugs by cleaning up unused ϕ nodes that should never have existed. +function issue53366(sc::Threads.Condition) + @lock sc begin + try + if Core.Compiler.inferencebarrier(true) + return nothing + end + return nothing + finally + end + end +end + +let (ir, rt) = only(Base.code_ircode(issue53366, (Threads.Condition,))) + Core.Compiler.verify_ir(ir) +end From 2c226340e26c08ef3ecc35e7069c71327a4532f4 Mon Sep 17 00:00:00 2001 From: N5N3 <2642243996@qq.com> Date: Thu, 7 Mar 2024 05:55:49 +0800 Subject: [PATCH 030/109] typeintersect: fix `UnionAll` unaliasing bug caused by innervars. (#53553) typeintersect: fix `UnionAll` unaliasing bug caused by innervars. (cherry picked from commit 56f1c8ae62c07cb940e0c4fc02d5dfac9ec73147) --- src/subtype.c | 71 ++++++++++++++++++++++++++++++++++++++----------- test/subtype.jl | 26 ++++++++++++++++++ 2 files changed, 81 insertions(+), 16 deletions(-) diff --git a/src/subtype.c b/src/subtype.c index 3d874872d6b44..8f5b34d0a7c3f 100644 --- a/src/subtype.c +++ b/src/subtype.c @@ -872,10 +872,20 @@ static jl_unionall_t *unalias_unionall(jl_unionall_t *u, jl_stenv_t *e) // in the environment, rename to get a fresh var. JL_GC_PUSH1(&u); while (btemp != NULL) { - if (btemp->var == u->var || - // outer var can only refer to inner var if bounds changed + int aliased = btemp->var == u->var || + // outer var can only refer to inner var if bounds changed (mainly for subtyping path) (btemp->lb != btemp->var->lb && jl_has_typevar(btemp->lb, u->var)) || - (btemp->ub != btemp->var->ub && jl_has_typevar(btemp->ub, u->var))) { + (btemp->ub != btemp->var->ub && jl_has_typevar(btemp->ub, u->var)); + if (!aliased && btemp->innervars != NULL) { + for (size_t i = 0; i < jl_array_len(btemp->innervars); i++) { + jl_tvar_t *ivar = (jl_tvar_t*)jl_array_ptr_ref(btemp->innervars, i); + if (ivar == u->var) { + aliased = 1; + break; + } + } + } + if (aliased) { u = jl_rename_unionall(u); break; } @@ -2833,7 +2843,7 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind // I. Handle indirect innervars (make them behave like direct innervars). // 1) record if btemp->lb/ub has indirect innervars. - // 2) subtitute `vb->var` with `varval`/`varval` + // 2) substitute `vb->var` with `varval`/`newvar` // note: We only store the innervar in the outmost `varbinding`, // thus we must check all inner env to ensure the recording/subtitution // is complete @@ -2897,6 +2907,7 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind } envind++; } + // FIXME: innervar that depend on `ivar` should also be updated. } } } @@ -3012,7 +3023,8 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind } if (vb->innervars != NULL) { - for (size_t i = 0; i < jl_array_len(vb->innervars); i++) { + size_t len = jl_array_nrows(vb->innervars), count = 0; + for (size_t i = 0; i < len; i++) { jl_tvar_t *var = (jl_tvar_t*)jl_array_ptr_ref(vb->innervars, i); // the `btemp->prev` walk is only giving a sort of post-order guarantee (since we are // iterating 2 trees at once), so once we set `wrap`, there might remain other branches @@ -3026,11 +3038,45 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind if (wrap) { if (wrap->innervars == NULL) wrap->innervars = jl_alloc_array_1d(jl_array_any_type, 0); + // FIXME: `var`'s dependence should also be pushed into `wrap->innervars`. jl_array_ptr_1d_push(wrap->innervars, (jl_value_t*)var); + jl_array_ptr_set(vb->innervars, i, (jl_value_t*)NULL); + } + } + for (size_t i = 0; i < len; i++) { + jl_tvar_t *var = (jl_tvar_t*)jl_array_ptr_ref(vb->innervars, i); + if (var) { + if (count < i) + jl_array_ptr_set(vb->innervars, count, (jl_value_t*)var); + count++; + } + } + if (count != len) + jl_array_del_end(vb->innervars, len - count); + if (res != jl_bottom_type) { + while (count > 1) { + int changed = 0; + // Now need to re-sort the vb->innervars using the partial-ordering predicate `jl_has_typevar`. + // If this is slow, we could possibly switch to a simpler graph sort than this triple loop, such as Tarjan's SCC. + // But for now we use a variant on selection sort for partial-orders. + for (size_t i = 0; i < count - 1; i++) { + jl_tvar_t *vari = (jl_tvar_t*)jl_array_ptr_ref(vb->innervars, i); + for (size_t j = i+1; j < count; j++) { + jl_tvar_t *varj = (jl_tvar_t*)jl_array_ptr_ref(vb->innervars, j); + if (jl_has_typevar(varj->lb, vari) || jl_has_typevar(varj->ub, vari)) { + jl_array_ptr_set(vb->innervars, j, (jl_value_t*)vari); + jl_array_ptr_set(vb->innervars, i, (jl_value_t*)varj); + changed = 1; + break; + } + } + if (changed) break; + } + if (!changed) break; } - else if (res != jl_bottom_type) { - if (jl_has_typevar(res, var)) - res = jl_type_unionall((jl_tvar_t*)var, res); + for (size_t i = 0; i < count; i++) { + jl_tvar_t *var = (jl_tvar_t*)jl_array_ptr_ref(vb->innervars, i); + res = jl_type_unionall(var, res); } } } @@ -3050,9 +3096,6 @@ static jl_value_t *finish_unionall(jl_value_t *res JL_MAYBE_UNROOTED, jl_varbind static jl_value_t *intersect_unionall_(jl_value_t *t, jl_unionall_t *u, jl_stenv_t *e, int8_t R, int param, jl_varbinding_t *vb) { jl_varbinding_t *btemp = e->vars; - // if the var for this unionall (based on identity) already appears somewhere - // in the environment, rename to get a fresh var. - // TODO: might need to look inside types in btemp->lb and btemp->ub int envsize = 0; while (btemp != NULL) { envsize++; @@ -3060,13 +3103,9 @@ static jl_value_t *intersect_unionall_(jl_value_t *t, jl_unionall_t *u, jl_stenv vb->limited = 1; return t; } - if (btemp->var == u->var || btemp->lb == (jl_value_t*)u->var || - btemp->ub == (jl_value_t*)u->var) { - u = jl_rename_unionall(u); - break; - } btemp = btemp->prev; } + u = unalias_unionall(u, e); JL_GC_PUSH1(&u); vb->var = u->var; e->vars = vb; diff --git a/test/subtype.jl b/test/subtype.jl index cd856b0b7a2ff..3245e0583cda8 100644 --- a/test/subtype.jl +++ b/test/subtype.jl @@ -2563,6 +2563,32 @@ let a = Tuple{Union{Nothing, Type{Pair{T1}} where T1}} @test !Base.has_free_typevars(typeintersect(a, b)) end +#issue 53366 +let Y = Tuple{Val{T}, Val{Val{T}}} where T + A = Val{Val{T}} where T + T = TypeVar(:T, UnionAll(A.var, Val{A.var})) + B = UnionAll(T, Val{T}) + X = Tuple{A, B} + @testintersect(X, Y, !Union{}) +end + +#issue 53621 (requires assertions enabled) +abstract type A53621{T, R, C, U} <: AbstractSet{Union{C, U}} end +struct T53621{T, R<:Real, C, U} <: A53621{T, R, C, U} end +let + U = TypeVar(:U) + C = TypeVar(:C) + T = TypeVar(:T) + R = TypeVar(:R) + CC = TypeVar(:CC, Union{C, U}) + UU = TypeVar(:UU, Union{C, U}) + S1 = UnionAll(T, UnionAll(R, Type{UnionAll(C, UnionAll(U, T53621{T, R, C, U}))})) + S2 = UnionAll(C, UnionAll(U, UnionAll(CC, UnionAll(UU, UnionAll(T, UnionAll(R, T53621{T, R, CC, UU})))))) + S = Tuple{S1, S2} + T = Tuple{Type{T53621{T, R}}, AbstractSet{T}} where {T, R} + @testintersect(S, T, !Union{}) +end + #issue 53371 struct T53371{A,B,C,D,E} end S53371{A} = Union{Int, <:A} From aefe3c9603a475e0965de1f906d5b09965d20419 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Fri, 15 Mar 2024 07:22:10 -0300 Subject: [PATCH 031/109] gc scheduler synchronization fixes to 1.10 (#53661) (#133) Cherry-pick the parts of https://github.com/JuliaLang/julia/pull/53355 which are relevant to the 1.10 GC. --- src/gc.c | 62 ++++++++++++++++++++++---------------------------------- 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/src/gc.c b/src/gc.c index 562d60905806b..085287dd31968 100644 --- a/src/gc.c +++ b/src/gc.c @@ -2960,9 +2960,7 @@ void gc_mark_and_steal(jl_ptls_t ptls) jl_gc_markqueue_t *mq = &ptls->mark_queue; jl_gc_markqueue_t *mq_master = NULL; int master_tid = jl_atomic_load(&gc_master_tid); - if (master_tid == -1) { - return; - } + assert(master_tid != -1); mq_master = &gc_all_tls_states[master_tid]->mark_queue; void *new_obj; jl_gc_chunk_t c; @@ -3053,61 +3051,49 @@ size_t gc_count_work_in_queue(jl_ptls_t ptls) JL_NOTSAFEPOINT * Correctness argument for the mark-loop termination protocol. * * Safety properties: - * - No work items shall be in any thread's queues when `gc_mark_loop_barrier` observes + * - No work items shall be in any thread's queues when `gc_should_mark` observes * that `gc_n_threads_marking` is zero. * * - No work item shall be stolen from the master thread (i.e. mutator thread which started * GC and which helped the `jl_n_markthreads` - 1 threads to mark) after - * `gc_mark_loop_barrier` observes that `gc_n_threads_marking` is zero. This property is + * `gc_should_mark` observes that `gc_n_threads_marking` is zero. This property is * necessary because we call `gc_mark_loop_serial` after marking the finalizer list in * `_jl_gc_collect`, and want to ensure that we have the serial mark-loop semantics there, * and that no work is stolen from us at that point. * * Proof: - * - Suppose the master thread observes that `gc_n_threads_marking` is zero in - * `gc_mark_loop_barrier` and there is a work item left in one thread's queue at that point. - * Since threads try to steal from all threads' queues, this implies that all threads must - * have tried to steal from the queue which still has a work item left, but failed to do so, - * which violates the semantics of Chase-Lev's work-stealing queue. - * - * - Let E1 be the event "master thread writes -1 to gc_master_tid" and E2 be the event - * "master thread observes that `gc_n_threads_marking` is zero". Since we're using - * sequentially consistent atomics, E1 => E2. Now suppose one thread which is spinning in - * `gc_should_mark` tries to enter the mark-loop after E2. In order to do so, it must - * increment `gc_n_threads_marking` to 1 in an event E3, and then read `gc_master_tid` in an - * event E4. Since we're using sequentially consistent atomics, E3 => E4. Since we observed - * `gc_n_threads_marking` as zero in E2, then E2 => E3, and we conclude E1 => E4, so that - * the thread which is spinning in `gc_should_mark` must observe that `gc_master_tid` is -1 - * and therefore won't enter the mark-loop. + * - If a thread observes that `gc_n_threads_marking` is zero inside `gc_should_mark`, that + * means that no thread has work on their queue, this is guaranteed because a thread may only exit + * `gc_mark_and_steal` when its own queue is empty, this information is synchronized by the + * seq-cst fetch_add to a thread that is in `gc_should_mark`. `gc_queue_observer_lock` + * guarantees that once `gc_n_threads_marking` reaches zero, no thread will increment it again, + * because incrementing is only legal from inside the lock. Therefore, no thread will reenter + * the mark-loop after `gc_n_threads_marking` reaches zero. */ -int gc_should_mark(jl_ptls_t ptls) +int gc_should_mark(void) { int should_mark = 0; - int n_threads_marking = jl_atomic_load(&gc_n_threads_marking); - // fast path - if (n_threads_marking == 0) { - return 0; - } uv_mutex_lock(&gc_queue_observer_lock); while (1) { - int tid = jl_atomic_load(&gc_master_tid); - // fast path - if (tid == -1) { - break; - } - n_threads_marking = jl_atomic_load(&gc_n_threads_marking); - // fast path + int n_threads_marking = jl_atomic_load(&gc_n_threads_marking); if (n_threads_marking == 0) { break; } + int tid = jl_atomic_load_relaxed(&gc_master_tid); + assert(tid != -1); size_t work = gc_count_work_in_queue(gc_all_tls_states[tid]); for (tid = gc_first_tid; tid < gc_first_tid + jl_n_markthreads; tid++) { - work += gc_count_work_in_queue(gc_all_tls_states[tid]); + jl_ptls_t ptls2 = gc_all_tls_states[tid]; + if (ptls2 == NULL) { + continue; + } + work += gc_count_work_in_queue(ptls2); } // if there is a lot of work left, enter the mark loop if (work >= 16 * n_threads_marking) { - jl_atomic_fetch_add(&gc_n_threads_marking, 1); + jl_atomic_fetch_add(&gc_n_threads_marking, 1); // A possibility would be to allow a thread that found lots + // of work to increment this should_mark = 1; break; } @@ -3119,9 +3105,7 @@ int gc_should_mark(jl_ptls_t ptls) void gc_wake_all_for_marking(jl_ptls_t ptls) { - jl_atomic_store(&gc_master_tid, ptls->tid); uv_mutex_lock(&gc_threads_lock); - jl_atomic_fetch_add(&gc_n_threads_marking, 1); uv_cond_broadcast(&gc_threads_cond); uv_mutex_unlock(&gc_threads_lock); } @@ -3129,12 +3113,14 @@ void gc_wake_all_for_marking(jl_ptls_t ptls) void gc_mark_loop_parallel(jl_ptls_t ptls, int master) { if (master) { + jl_atomic_store(&gc_master_tid, ptls->tid); + jl_atomic_fetch_add(&gc_n_threads_marking, 1); gc_wake_all_for_marking(ptls); gc_mark_and_steal(ptls); jl_atomic_fetch_add(&gc_n_threads_marking, -1); } while (1) { - int should_mark = gc_should_mark(ptls); + int should_mark = gc_should_mark(); if (!should_mark) { break; } From 9a0475de314b44e17e32274e8d27d6c34035cb38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Drvo=C5=A1t=C4=9Bp?= Date: Tue, 19 Mar 2024 18:35:13 +0100 Subject: [PATCH 032/109] Add GitHub template and workflows needed on the default branch (#135) --- .github/labeler.yml | 4 +++ .github/pull_request_template.md | 14 +++++++++ .github/workflows/labeler.yml | 17 +++++++++++ .github/workflows/stale.yml | 16 ++++++++++ .../workflows/update-upstream-branches.yml | 29 +++++++++++++++++++ 5 files changed, 80 insertions(+) create mode 100644 .github/labeler.yml create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/labeler.yml create mode 100644 .github/workflows/stale.yml create mode 100644 .github/workflows/update-upstream-branches.yml diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 0000000000000..46b32f84a77d5 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,4 @@ +# See https://github.com/actions/labeler +port-to-master: '**' +port-to-v1.10: '**' +port-to-v1.9: '**' diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000000..7ed825781c53b --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,14 @@ + +## PR Description + +_What does this PR do?_ + +## Checklist + +Requirements for merging: +- [ ] I have opened an issue or PR upstream on JuliaLang/julia: +- [ ] I have removed the `port-to-*` labels that don't apply. +- [ ] I have opened a PR on raicode to test these changes: diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000000000..2141a906e96cd --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,17 @@ +# See https://github.com/actions/labeler +name: "Pull Request Labeler" +on: + pull_request_target: + types: + - opened + +jobs: + triage: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v4 + with: + dot: true diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 0000000000000..3df2093491753 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,16 @@ +name: "Close stale PRs" +on: + schedule: + - cron: "0 0 * * *" # every night at midnight + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v8 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + stale-pr-message: 'This PR is stale because it has been open 30 days with no activity. Comment or remove stale label, or this PR will be closed in 5 days.' + days-before-stale: 30 + days-before-close: 5 + stale-pr-label: 'stale' diff --git a/.github/workflows/update-upstream-branches.yml b/.github/workflows/update-upstream-branches.yml new file mode 100644 index 0000000000000..242d59bd4edbc --- /dev/null +++ b/.github/workflows/update-upstream-branches.yml @@ -0,0 +1,29 @@ +name: "Update upstream branches" +on: + schedule: + - cron: "0 0 * * *" # every night at midnight + workflow_dispatch: + +jobs: + PullUpstream: + runs-on: ubuntu-latest + strategy: + fail-fast: false # run all jobs in the matrix even if one fails + matrix: + branch: + - "master" + - "backports-release-1.10" + - "backports-release-1.9" + steps: + - name: Checkout RAI/julia + uses: actions/checkout@v3 + with: + ref: ${{ matrix.branch }} + - name: Update ${{ matrix.branch }} + run: | + git config --global user.email "julia-engineering@relational.ai" + git config --global user.name "RAI CI (GitHub Action Automation)" + + git remote add upstream https://github.com/JuliaLang/julia + git pull upstream ${{ matrix.branch }} + git push origin ${{ matrix.branch }} From 6cd7ce2558576aa28538c1db94cf897aaed839b8 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Tue, 19 Mar 2024 16:37:01 -0300 Subject: [PATCH 033/109] Add `Base.checked_pow(x,y)` to `Base.Checked` library (#52849) (#134) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #52262. Performs `^(x, y)` but throws OverflowError on overflow. Example: ```julia julia> 2^62 4611686018427387904 julia> 2^63 -9223372036854775808 julia> checked_pow(2, 63) ERROR: OverflowError: 2147483648 * 4294967296 overflowed for type Int64 ``` Co-authored-by: Nathan Daly Co-authored-by: Jameson Nash Co-authored-by: Shuhei Kadowaki Co-authored-by: Tomáš Drvoštěp --- base/checked.jl | 15 +++++++++++++- base/intfuncs.jl | 11 ++++++----- doc/src/base/math.md | 1 + test/checked.jl | 22 ++++++++++++++++++++- test/compiler/ssair.jl | 45 +++++++++++++++++++++--------------------- 5 files changed, 64 insertions(+), 30 deletions(-) diff --git a/base/checked.jl b/base/checked.jl index d5b4112397e84..b374d34830280 100644 --- a/base/checked.jl +++ b/base/checked.jl @@ -13,7 +13,7 @@ return both the unchecked results and a boolean value denoting the presence of a module Checked export checked_neg, checked_abs, checked_add, checked_sub, checked_mul, - checked_div, checked_rem, checked_fld, checked_mod, checked_cld, + checked_div, checked_rem, checked_fld, checked_mod, checked_cld, checked_pow, checked_length, add_with_overflow, sub_with_overflow, mul_with_overflow import Core.Intrinsics: @@ -358,6 +358,19 @@ The overflow protection may impose a perceptible performance penalty. """ checked_cld(x::T, y::T) where {T<:Integer} = cld(x, y) # Base.cld already checks +""" + Base.checked_pow(x, y) + +Calculates `^(x,y)`, checking for overflow errors where applicable. + +The overflow protection may impose a perceptible performance penalty. +""" +checked_pow(x::Integer, y::Integer) = checked_power_by_squaring(x, y) + +checked_power_by_squaring(x_, p::Integer) = Base.power_by_squaring(x_, p; mul = checked_mul) +# For Booleans, the default implementation covers all cases. +checked_power_by_squaring(x::Bool, p::Integer) = Base.power_by_squaring(x, p) + """ Base.checked_length(r) diff --git a/base/intfuncs.jl b/base/intfuncs.jl index 90dc393a0e9b4..e4688a7ad5d5e 100644 --- a/base/intfuncs.jl +++ b/base/intfuncs.jl @@ -272,14 +272,15 @@ to_power_type(x) = convert(Base._return_type(*, Tuple{typeof(x), typeof(x)}), x) "\nMake x a float matrix by adding a zero decimal ", "(e.g., [2.0 1.0;1.0 0.0]^", p, " instead of [2 1;1 0]^", p, ")", "or write float(x)^", p, " or Rational.(x)^", p, "."))) -@assume_effects :terminates_locally function power_by_squaring(x_, p::Integer) +# The * keyword supports `*=checked_mul` for `checked_pow` +@assume_effects :terminates_locally function power_by_squaring(x_, p::Integer; mul=*) x = to_power_type(x_) if p == 1 return copy(x) elseif p == 0 return one(x) elseif p == 2 - return x*x + return mul(x, x) elseif p < 0 isone(x) && return copy(x) isone(-x) && return iseven(p) ? one(x) : copy(x) @@ -288,16 +289,16 @@ to_power_type(x) = convert(Base._return_type(*, Tuple{typeof(x), typeof(x)}), x) t = trailing_zeros(p) + 1 p >>= t while (t -= 1) > 0 - x *= x + x = mul(x, x) end y = x while p > 0 t = trailing_zeros(p) + 1 p >>= t while (t -= 1) >= 0 - x *= x + x = mul(x, x) end - y *= x + y = mul(y, x) end return y end diff --git a/doc/src/base/math.md b/doc/src/base/math.md index 62368424629c6..03f06bb6c950a 100644 --- a/doc/src/base/math.md +++ b/doc/src/base/math.md @@ -148,6 +148,7 @@ Base.Checked.checked_rem Base.Checked.checked_fld Base.Checked.checked_mod Base.Checked.checked_cld +Base.Checked.checked_pow Base.Checked.add_with_overflow Base.Checked.sub_with_overflow Base.Checked.mul_with_overflow diff --git a/test/checked.jl b/test/checked.jl index bacda3db75dec..a49dffff0a862 100644 --- a/test/checked.jl +++ b/test/checked.jl @@ -3,7 +3,7 @@ # Checked integer arithmetic import Base: checked_abs, checked_neg, checked_add, checked_sub, checked_mul, - checked_div, checked_rem, checked_fld, checked_mod, checked_cld, + checked_div, checked_rem, checked_fld, checked_mod, checked_cld, checked_pow, add_with_overflow, sub_with_overflow, mul_with_overflow # checked operations @@ -166,6 +166,19 @@ import Base: checked_abs, checked_neg, checked_add, checked_sub, checked_mul, @test checked_cld(typemin(T), T(1)) === typemin(T) @test_throws DivideError checked_cld(typemin(T), T(0)) @test_throws DivideError checked_cld(typemin(T), T(-1)) + + @test checked_pow(T(1), T(0)) === T(1) + @test checked_pow(typemax(T), T(0)) === T(1) + @test checked_pow(typemin(T), T(0)) === T(1) + @test checked_pow(T(1), T(1)) === T(1) + @test checked_pow(T(1), typemax(T)) === T(1) + @test checked_pow(T(2), T(2)) === T(4) + @test_throws OverflowError checked_pow(T(2), typemax(T)) + @test_throws OverflowError checked_pow(T(-2), typemax(T)) + @test_throws OverflowError checked_pow(typemax(T), T(2)) + @test_throws OverflowError checked_pow(typemin(T), T(2)) + @test_throws DomainError checked_pow(T(2), -T(1)) + @test_throws DomainError checked_pow(-T(2), -T(1)) end @testset for T in (UInt8, UInt16, UInt32, UInt64, UInt128) @@ -296,6 +309,10 @@ end @test checked_cld(true, true) === true @test checked_cld(false, true) === false @test_throws DivideError checked_cld(true, false) + + @test checked_pow(true, 1) === true + @test checked_pow(true, 1000000) === true + @test checked_pow(false, 1000000) === false end @testset "BigInt" begin @test checked_abs(BigInt(-1)) == BigInt(1) @@ -310,6 +327,9 @@ end @test checked_fld(BigInt(10), BigInt(3)) == BigInt(3) @test checked_mod(BigInt(9), BigInt(4)) == BigInt(1) @test checked_cld(BigInt(10), BigInt(3)) == BigInt(4) + + @test checked_pow(BigInt(2), 2) == BigInt(4) + @test checked_pow(BigInt(2), 100) == BigInt(1267650600228229401496703205376) end @testset "Additional tests" begin diff --git a/test/compiler/ssair.jl b/test/compiler/ssair.jl index ea833fa4ce5ff..f059aba031226 100644 --- a/test/compiler/ssair.jl +++ b/test/compiler/ssair.jl @@ -549,21 +549,25 @@ import Core.Compiler: NewInstruction, insert_node! let ir = Base.code_ircode((Int,Int); optimize_until="inlining") do a, b a^b end |> only |> first - @test length(ir.stmts) == 2 - @test Meta.isexpr(ir.stmts[1][:inst], :invoke) + nstmts = length(ir.stmts) + invoke_idx = findfirst(@nospecialize(stmt)->Meta.isexpr(stmt, :invoke), ir.stmts.inst) + @test invoke !== nothing - newssa = insert_node!(ir, SSAValue(1), NewInstruction(Expr(:call, println, SSAValue(1)), Nothing), #=attach_after=#true) + invoke_ssa = SSAValue(invoke_idx) + newssa = insert_node!(ir, invoke_ssa, NewInstruction(Expr(:call, println, invoke_ssa), Nothing), #=attach_after=#true) newssa = insert_node!(ir, newssa, NewInstruction(Expr(:call, println, newssa), Nothing), #=attach_after=#true) ir = Core.Compiler.compact!(ir) - @test length(ir.stmts) == 4 - @test Meta.isexpr(ir.stmts[1][:inst], :invoke) - call1 = ir.stmts[2][:inst] + + @test length(ir.stmts) == nstmts + 2 + @test Meta.isexpr(ir.stmts.inst[invoke_idx], :invoke) + call1 = ir.stmts.inst[invoke_idx+1] @test iscall((ir,println), call1) - @test call1.args[2] === SSAValue(1) - call2 = ir.stmts[3][:inst] + @test call1.args[2] === invoke_ssa + call2 = ir.stmts.inst[invoke_idx+2] + @test iscall((ir,println), call2) - @test call2.args[2] === SSAValue(2) + @test call2.args[2] === SSAValue(invoke_idx+1) end # Issue #50379 - insert_node!(::IncrementalCompact, ...) at end of basic block @@ -607,26 +611,23 @@ end let ir = Base.code_ircode((Int,Int); optimize_until="inlining") do a, b a^b end |> only |> first - invoke_idx = findfirst(ir.stmts.inst) do @nospecialize(x) - Meta.isexpr(x, :invoke) - end + invoke_idx = findfirst(@nospecialize(stmt)->Meta.isexpr(stmt, :invoke), ir.stmts.inst) @test invoke_idx !== nothing invoke_expr = ir.stmts.inst[invoke_idx] + invoke_ssa = SSAValue(invoke_idx) # effect-ful node let compact = Core.Compiler.IncrementalCompact(Core.Compiler.copy(ir)) - insert_node!(compact, SSAValue(1), NewInstruction(Expr(:call, println, SSAValue(1)), Nothing), #=attach_after=#true) + insert_node!(compact, invoke_ssa, NewInstruction(Expr(:call, println, invoke_ssa), Nothing), #=attach_after=#true) state = Core.Compiler.iterate(compact) while state !== nothing state = Core.Compiler.iterate(compact, state[2]) end ir = Core.Compiler.finish(compact) - new_invoke_idx = findfirst(ir.stmts.inst) do @nospecialize(x) - x == invoke_expr - end + new_invoke_idx = findfirst(@nospecialize(stmt)->stmt==invoke_expr, ir.stmts.inst) @test new_invoke_idx !== nothing - new_call_idx = findfirst(ir.stmts.inst) do @nospecialize(x) - iscall((ir,println), x) && x.args[2] === SSAValue(invoke_idx) + new_call_idx = findfirst(ir.stmts.inst) do @nospecialize(stmt) + iscall((ir,println), stmt) && stmt.args[2] === SSAValue(new_invoke_idx) end @test new_call_idx !== nothing @test new_call_idx == new_invoke_idx+1 @@ -634,7 +635,7 @@ let ir = Base.code_ircode((Int,Int); optimize_until="inlining") do a, b # effect-free node let compact = Core.Compiler.IncrementalCompact(Core.Compiler.copy(ir)) - insert_node!(compact, SSAValue(1), NewInstruction(Expr(:call, GlobalRef(Base, :add_int), SSAValue(1), SSAValue(1)), Int), #=attach_after=#true) + insert_node!(compact, invoke_ssa, NewInstruction(Expr(:call, GlobalRef(Base, :add_int), invoke_ssa, invoke_ssa), Int), #=attach_after=#true) state = Core.Compiler.iterate(compact) while state !== nothing state = Core.Compiler.iterate(compact, state[2]) @@ -642,12 +643,10 @@ let ir = Base.code_ircode((Int,Int); optimize_until="inlining") do a, b ir = Core.Compiler.finish(compact) ir = Core.Compiler.finish(compact) - new_invoke_idx = findfirst(ir.stmts.inst) do @nospecialize(x) - x == invoke_expr - end + new_invoke_idx = findfirst(@nospecialize(stmt)->stmt==invoke_expr, ir.stmts.inst) @test new_invoke_idx !== nothing new_call_idx = findfirst(ir.stmts.inst) do @nospecialize(x) - iscall((ir,Base.add_int), x) && x.args[2] === SSAValue(invoke_idx) + iscall((ir,Base.add_int), x) && x.args[2] === SSAValue(new_invoke_idx) end @test new_call_idx === nothing # should be deleted during the compaction end From 31f3d1d18dd7f6c441c847358b957765265a0f2c Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Wed, 20 Mar 2024 09:28:56 -0400 Subject: [PATCH 034/109] Remove some duplicates from emitted compilation traces for Julia 1.10 (#53776) When multiple threads concurrently attempt to compile the same method, `--trace-compile` could emit duplicate `precompile` statements. This small tweak eliminates one source of these duplicates. --- src/codegen-stubs.c | 2 +- src/gf.c | 5 +++-- src/jitlayers.cpp | 8 ++++++-- src/julia_internal.h | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/codegen-stubs.c b/src/codegen-stubs.c index de5f2a2770c04..b48ad7b98791f 100644 --- a/src/codegen-stubs.c +++ b/src/codegen-stubs.c @@ -38,7 +38,7 @@ JL_DLLEXPORT void jl_register_fptrs_fallback(uint64_t image_base, const struct _ (void)image_base; (void)fptrs; (void)linfos; (void)n; } -JL_DLLEXPORT jl_code_instance_t *jl_generate_fptr_fallback(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world) +JL_DLLEXPORT jl_code_instance_t *jl_generate_fptr_fallback(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world, int *did_compile) { return NULL; } diff --git a/src/gf.c b/src/gf.c index 1b6251078fa1f..186f8787cf519 100644 --- a/src/gf.c +++ b/src/gf.c @@ -2477,7 +2477,8 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t } } - codeinst = jl_generate_fptr(mi, world); + int did_compile = 0; + codeinst = jl_generate_fptr(mi, world, &did_compile); if (!codeinst) { jl_method_instance_t *unspec = jl_get_unspecialized_from_mi(mi); jl_code_instance_t *ucache = jl_get_method_inferred(unspec, (jl_value_t*)jl_any_type, 1, ~(size_t)0); @@ -2517,7 +2518,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t jl_atomic_store_release(&codeinst->invoke, ucache_invoke); jl_mi_cache_insert(mi, codeinst); } - else { + else if (did_compile) { record_precompile_statement(mi); } jl_atomic_store_relaxed(&codeinst->precompile, 1); diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index 099d74ccb37c1..d55090e161523 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -463,8 +463,10 @@ void jl_extern_c_impl(jl_value_t *declrt, jl_tupletype_t *sigt) // this compiles li and emits fptr extern "C" JL_DLLEXPORT_CODEGEN -jl_code_instance_t *jl_generate_fptr_impl(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world) +jl_code_instance_t *jl_generate_fptr_impl(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world, int *did_compile) { + if (did_compile != NULL) + *did_compile = 0; auto ct = jl_current_task; bool timed = (ct->reentrant_timing & 1) == 0; if (timed) @@ -518,6 +520,8 @@ jl_code_instance_t *jl_generate_fptr_impl(jl_method_instance_t *mi JL_PROPAGATES _jl_compile_codeinst(codeinst, src, world, *jl_ExecutionEngine->getContext(), is_recompile); if (jl_atomic_load_relaxed(&codeinst->invoke) == NULL) codeinst = NULL; + else if (did_compile != NULL) + *did_compile = 1; } else { codeinst = NULL; @@ -605,7 +609,7 @@ jl_value_t *jl_dump_method_asm_impl(jl_method_instance_t *mi, size_t world, char emit_mc, char getwrapper, const char* asm_variant, const char *debuginfo, char binary) { // printing via disassembly - jl_code_instance_t *codeinst = jl_generate_fptr(mi, world); + jl_code_instance_t *codeinst = jl_generate_fptr(mi, world, NULL); if (codeinst) { uintptr_t fptr = (uintptr_t)jl_atomic_load_acquire(&codeinst->invoke); if (getwrapper) diff --git a/src/julia_internal.h b/src/julia_internal.h index b7da156b340a7..3211d0fe7b4d9 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -1690,7 +1690,7 @@ JL_DLLEXPORT uint32_t jl_crc32c(uint32_t crc, const char *buf, size_t len); // -- exports from codegen -- // -JL_DLLIMPORT jl_code_instance_t *jl_generate_fptr(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world); +JL_DLLIMPORT jl_code_instance_t *jl_generate_fptr(jl_method_instance_t *mi JL_PROPAGATES_ROOT, size_t world, int *did_compile); JL_DLLIMPORT void jl_generate_fptr_for_unspecialized(jl_code_instance_t *unspec); JL_DLLIMPORT void jl_generate_fptr_for_oc_wrapper(jl_code_instance_t *unspec); JL_DLLIMPORT int jl_compile_extern_c(LLVMOrcThreadSafeModuleRef llvmmod, void *params, void *sysimg, jl_value_t *declrt, jl_value_t *sigt); From 4859e9cfc1f2a455d74444d1019c4c0073eef368 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Fri, 22 Mar 2024 14:06:26 -0300 Subject: [PATCH 035/109] --safe-crash-log-file flag (#140) * --safe-crash-log-file flag * Update init.c * json escape jl_safe_printf when safe crash log file * add timestamp to json logs * port it to aarch64 darwin * fix minor warning * missing double quote * Suggestion from code review: make sig_stack_size a const in signals-unix.c Co-authored-by: Kiran Pamnany * Suggestion from code review: make sig_stack size a const in signals-win.c Co-authored-by: Kiran Pamnany * more suggestions from Kiran's review * more suggestions from review --------- Co-authored-by: Malte Sandstede Co-authored-by: Adnan Alhomssi Co-authored-by: Kiran Pamnany --- base/options.jl | 1 + src/init.c | 9 ++++++++ src/jl_uv.c | 54 +++++++++++++++++++++++++++++++++++++++++++ src/jloptions.c | 10 +++++++- src/jloptions.h | 1 + src/julia_internal.h | 26 +++++++++++++++++++++ src/signal-handling.c | 2 ++ src/signals-unix.c | 9 +------- src/signals-win.c | 2 +- 9 files changed, 104 insertions(+), 10 deletions(-) diff --git a/base/options.jl b/base/options.jl index a94936391fa8d..cb35b2b3806f4 100644 --- a/base/options.jl +++ b/base/options.jl @@ -57,6 +57,7 @@ struct JLOptions strip_ir::Int8 permalloc_pkgimg::Int8 heap_size_hint::UInt64 + safe_crash_log_file::Ptr{UInt8} end # This runs early in the sysimage != is not defined yet diff --git a/src/init.c b/src/init.c index f7a35e95daa1b..83f528b35ac11 100644 --- a/src/init.c +++ b/src/init.c @@ -823,6 +823,15 @@ JL_DLLEXPORT void julia_init(JL_IMAGE_SEARCH rel) if (jl_options.handle_signals == JL_OPTIONS_HANDLE_SIGNALS_ON) jl_install_default_signal_handlers(); +#if (defined(_OS_LINUX_) && defined(_CPU_X86_64_)) || (defined(_OS_DARWIN_) && defined(_CPU_AARCH64_)) + if (jl_options.safe_crash_log_file != NULL) { + jl_sig_fd = open(jl_options.safe_crash_log_file, O_WRONLY | O_CREAT | O_APPEND, 0600); + if (jl_sig_fd == -1) { + jl_error("fatal error: could not open safe crash log file for writing"); + } + } +#endif + jl_gc_init(); arraylist_new(&jl_linkage_blobs, 0); diff --git a/src/jl_uv.c b/src/jl_uv.c index 62dc3a628d085..a5441e90c96f8 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -15,6 +15,7 @@ #include "errno.h" #include #include +#include #endif #include "julia.h" @@ -677,6 +678,56 @@ JL_DLLEXPORT int jl_printf(uv_stream_t *s, const char *format, ...) return c; } +STATIC_INLINE void print_error_msg_as_json(char *buf) JL_NOTSAFEPOINT +{ + // Our telemetry on SPCS expects a JSON object per line + // The following lines prepare the timestamp string and the JSON object + struct timeval tv; + struct tm* tm_info; + char timestamp_buffer[50]; + // Get current time + gettimeofday(&tv, NULL); + tm_info = gmtime(&tv.tv_sec); + // Format time + int offset = strftime(timestamp_buffer, 25, "%Y-%m-%dT%H:%M:%S", tm_info); + // Append milliseconds + snprintf(timestamp_buffer + offset, 25, ".%03d", tv.tv_usec / 1000); + const char *json_preamble_p1 = "\n{\"level\":\"Error\", \"timestamp\":\""; + const char *json_preamble_p2 = "\", \"message\": \""; + const char *json_postamble = "\"}\n"; + // Ignore write failures because there is nothing we can do + write(jl_sig_fd, json_preamble_p1, strlen(json_preamble_p1)); + write(jl_sig_fd, timestamp_buffer, strlen(timestamp_buffer)); + write(jl_sig_fd, json_preamble_p2, strlen(json_preamble_p2)); + // JSON escape the input string + for(size_t i = 0; i < strlen(buf); i += 1) { + switch (buf[i]) { + case '"': + write(jl_sig_fd, "\\\"", 2); + break; + case '\b': + write(jl_sig_fd, "\\b", 2); + break; + case '\n': + write(jl_sig_fd, "\\n", 2); + break; + case '\r': + write(jl_sig_fd, "\\r", 2); + break; + case '\t': + write(jl_sig_fd, "\\t", 2); + break; + case '\\': + write(jl_sig_fd, "\\\\", 2); + break; + default: + write(jl_sig_fd, buf + i, 1); + } + } + write(jl_sig_fd, json_postamble, strlen(json_postamble)); + fdatasync(jl_sig_fd); +} + JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...) { static char buf[1000]; @@ -693,6 +744,9 @@ JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...) va_end(args); buf[999] = '\0'; + if (jl_inside_signal_handler() && jl_sig_fd != 0) { + print_error_msg_as_json(buf); + } if (write(STDERR_FILENO, buf, strlen(buf)) < 0) { // nothing we can do; ignore the failure } diff --git a/src/jloptions.c b/src/jloptions.c index e81c34d37ef47..47f78f2de2a17 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -90,6 +90,7 @@ JL_DLLEXPORT void jl_init_options(void) 0, // strip-ir 0, // permalloc_pkgimg 0, // heap-size-hint + NULL, // safe_crash_log_file }; jl_options_initialized = 1; } @@ -258,7 +259,8 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) opt_strip_ir, opt_heap_size_hint, opt_gc_threads, - opt_permalloc_pkgimg + opt_permalloc_pkgimg, + opt_safe_crash_log_file, }; static const char* const shortopts = "+vhqH:e:E:L:J:C:it:p:O:g:"; static const struct option longopts[] = { @@ -320,6 +322,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 }, + { "safe-crash-log-file", required_argument, 0, opt_safe_crash_log_file }, { 0, 0, 0, 0 } }; @@ -850,6 +853,11 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) else jl_errorf("julia: invalid argument to --permalloc-pkgimg={yes|no} (%s)", optarg); break; + case opt_safe_crash_log_file: + jl_options.safe_crash_log_file = strdup(optarg); + if (jl_options.safe_crash_log_file == NULL) + jl_error("julia: failed to allocate memory for --safe-crash-log-file"); + break; default: jl_errorf("julia: unhandled option -- %c\n" "This is a bug, please report it.", c); diff --git a/src/jloptions.h b/src/jloptions.h index 8649c405112d7..b633291c6ed41 100644 --- a/src/jloptions.h +++ b/src/jloptions.h @@ -61,6 +61,7 @@ typedef struct { int8_t strip_ir; int8_t permalloc_pkgimg; uint64_t heap_size_hint; + const char *safe_crash_log_file; } jl_options_t; #endif diff --git a/src/julia_internal.h b/src/julia_internal.h index 3211d0fe7b4d9..9940dbf68ba49 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -702,6 +702,32 @@ JL_CALLABLE(jl_f_opaque_closure_call); void jl_install_default_signal_handlers(void); void restore_signals(void); void jl_install_thread_signal_handler(jl_ptls_t ptls); +extern const size_t sig_stack_size; +STATIC_INLINE int is_addr_on_sigstack(jl_ptls_t ptls, void *ptr) +{ + // One guard page for signal_stack. + return !((char*)ptr < (char*)ptls->signal_stack - jl_page_size || + (char*)ptr > (char*)ptls->signal_stack + sig_stack_size); +} +STATIC_INLINE int jl_inside_signal_handler(void) +{ +#if (defined(_OS_LINUX_) && defined(_CPU_X86_64_)) || (defined(_OS_DARWIN_) && defined(_CPU_AARCH64_)) + // Read the stack pointer + size_t sp; +#if defined(_OS_LINUX_) && defined(_CPU_X86_64_) + __asm__ __volatile__("movq %%rsp, %0" : "=r"(sp)); +#elif defined(_OS_DARWIN_) && defined(_CPU_AARCH64_) + __asm__ __volatile__("mov %0, sp" : "=r"(sp)); +#endif + // Check if the stack pointer is within the signal stack + jl_ptls_t ptls = jl_current_task->ptls; + return is_addr_on_sigstack(ptls, (void*)sp); +#else + return 0; +#endif +} +// File-descriptor for safe logging on signal handling +extern int jl_sig_fd; JL_DLLEXPORT jl_fptr_args_t jl_get_builtin_fptr(jl_value_t *b); diff --git a/src/signal-handling.c b/src/signal-handling.c index b280fc1e0aeef..c2a344a752547 100644 --- a/src/signal-handling.c +++ b/src/signal-handling.c @@ -28,6 +28,8 @@ static const uint64_t GIGA = 1000000000ULL; // Timers to take samples at intervals JL_DLLEXPORT void jl_profile_stop_timer(void); JL_DLLEXPORT int jl_profile_start_timer(void); +// File-descriptor for safe logging on signal handling +int jl_sig_fd; /////////////////////// // Utility functions // diff --git a/src/signals-unix.c b/src/signals-unix.c index a79043d78e682..7852b7ebb2618 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -38,7 +38,7 @@ // 8M signal stack, same as default stack size and enough // for reasonable finalizers. // Should also be enough for parallel GC when we have it =) -#define sig_stack_size (8 * 1024 * 1024) +const size_t sig_stack_size = (8 * 1024 * 1024); #include "julia_assert.h" @@ -91,13 +91,6 @@ static inline __attribute__((unused)) uintptr_t jl_get_rsp_from_ctx(const void * #endif } -static int is_addr_on_sigstack(jl_ptls_t ptls, void *ptr) -{ - // One guard page for signal_stack. - return !((char*)ptr < (char*)ptls->signal_stack - jl_page_size || - (char*)ptr > (char*)ptls->signal_stack + sig_stack_size); -} - // Modify signal context `_ctx` so that `fptr` will execute when the signal // returns. `fptr` will execute on the signal stack, and must not return. // jl_call_in_ctx is also currently executing on that signal stack, diff --git a/src/signals-win.c b/src/signals-win.c index cbf3c7436c8ff..bcb3a1fd246f0 100644 --- a/src/signals-win.c +++ b/src/signals-win.c @@ -4,7 +4,7 @@ // Note that this file is `#include`d by "signal-handling.c" #include // hidden by LEAN_AND_MEAN -#define sig_stack_size 131072 // 128k reserved for SEGV handling +const size_t sig_stack_size = 131072; // 128k reserved for SEGV handling // Copied from MINGW_FLOAT_H which may not be found due to a collision with the builtin gcc float.h // eventually we can probably integrate this into OpenLibm. From b5d3e641abc0b891c1a9df0b5187734560ff86db Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Thu, 28 Mar 2024 17:39:35 -0300 Subject: [PATCH 036/109] create phantom task for GC threads (#53815) (#141) A common idiom used throughout the codebase is to get a pointer to thread-local-state through `jl_current_task->ptls`. Create a phantom task for GC threads so that we can make use of this idiom when running in the GC threads as well. Idea originally suggested by @vchuravy, bugs are mine. --- src/jl_uv.c | 5 ++++- src/partr.c | 12 ++++++++++-- src/task.c | 1 + 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/jl_uv.c b/src/jl_uv.c index a5441e90c96f8..5c51c3f8a6cf4 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -744,7 +744,10 @@ JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...) va_end(args); buf[999] = '\0'; - if (jl_inside_signal_handler() && jl_sig_fd != 0) { + // order is important here: we want to ensure that the threading infra + // has been initialized before we start trying to print to the + // safe crash log file + if (jl_sig_fd != 0 && jl_inside_signal_handler()) { print_error_msg_as_json(buf); } if (write(STDERR_FILENO, buf, strlen(buf)) < 0) { diff --git a/src/partr.c b/src/partr.c index ffb8859f1b0ea..f8a87ac9bbc1b 100644 --- a/src/partr.c +++ b/src/partr.c @@ -125,7 +125,11 @@ void jl_parallel_gc_threadfun(void *arg) // initialize this thread (set tid and create heap) jl_ptls_t ptls = jl_init_threadtls(targ->tid); - + void *stack_lo, *stack_hi; + jl_init_stack_limits(0, &stack_lo, &stack_hi); + // warning: this changes `jl_current_task`, so be careful not to call that from this function + jl_task_t *ct = jl_init_root_task(ptls, stack_lo, stack_hi); + JL_GC_PROMISE_ROOTED(ct); // wait for all threads jl_gc_state_set(ptls, JL_GC_STATE_WAITING, 0); uv_barrier_wait(targ->barrier); @@ -156,7 +160,11 @@ void jl_concurrent_gc_threadfun(void *arg) // initialize this thread (set tid and create heap) jl_ptls_t ptls = jl_init_threadtls(targ->tid); - + void *stack_lo, *stack_hi; + jl_init_stack_limits(0, &stack_lo, &stack_hi); + // warning: this changes `jl_current_task`, so be careful not to call that from this function + jl_task_t *ct = jl_init_root_task(ptls, stack_lo, stack_hi); + JL_GC_PROMISE_ROOTED(ct); // wait for all threads jl_gc_state_set(ptls, JL_GC_STATE_WAITING, 0); uv_barrier_wait(targ->barrier); diff --git a/src/task.c b/src/task.c index 1dab8688cb079..86033a81ddf41 100644 --- a/src/task.c +++ b/src/task.c @@ -1685,6 +1685,7 @@ jl_task_t *jl_init_root_task(jl_ptls_t ptls, void *stack_lo, void *stack_hi) JL_GC_PROMISE_ROOTED(ct); jl_set_pgcstack(&ct->gcstack); assert(jl_current_task == ct); + assert(jl_current_task->ptls == ptls); #ifdef _COMPILER_TSAN_ENABLED_ ct->ctx.tsan_state = __tsan_get_current_fiber(); From 703a262853700bf2fdbac3ba6662bb6ed4f49246 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Sun, 7 Apr 2024 14:51:49 -0300 Subject: [PATCH 037/109] Correct GC bug (usage of `not_freed_enough`) (#143) Co-authored-by: K Pamnany --- src/gc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gc.c b/src/gc.c index 085287dd31968..4a74e55e4545d 100644 --- a/src/gc.c +++ b/src/gc.c @@ -3688,7 +3688,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) if (collection == JL_GC_AUTO) { //If we aren't freeing enough or are seeing lots and lots of pointers let it increase faster - if (!not_freed_enough || large_frontier) { + if (not_freed_enough || large_frontier) { int64_t tot = 2 * (live_bytes + actual_allocd) / 3; if (gc_num.interval > tot) { gc_num.interval = tot; From 497385166dd5a5ad6423f515f4bd040a08651491 Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Wed, 10 Apr 2024 05:06:47 -0400 Subject: [PATCH 038/109] Fix the OpenBLAS checksum for Julia 1.10 (#54017) Closes https://github.com/JuliaLang/julia/issues/54015. `diff -r` on the source tree for the original archive vs. the archive that gets downloaded now shows no changes. --- deps/checksums/openblas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/checksums/openblas b/deps/checksums/openblas index dd7c493c22941..0d176cafe7aca 100644 --- a/deps/checksums/openblas +++ b/deps/checksums/openblas @@ -91,4 +91,4 @@ OpenBLAS.v0.3.23+4.x86_64-w64-mingw32-libgfortran4.tar.gz/sha512/03099f50dc81427 OpenBLAS.v0.3.23+4.x86_64-w64-mingw32-libgfortran5.tar.gz/md5/92f18261534ceb1e3181c4b6071b0063 OpenBLAS.v0.3.23+4.x86_64-w64-mingw32-libgfortran5.tar.gz/sha512/38894868b7d7638e61a503a30c88ddf910af4e0ff8b9480b97f4ee7598088ba5c4735d1d85575deb1e593d8b6baf8fc549c85c8ba8d1b9683eb58cffb3f9e670 openblas-394a9fbafe9010b76a2615c562204277a956eb52.tar.gz/md5/7ccaaaafc8176b87dc59d4e527ca4d9f -openblas-394a9fbafe9010b76a2615c562204277a956eb52.tar.gz/sha512/12235f0459469b483a393844c228be5ad4bc60575bbe4b3238198f2480b7b457e4b0609730ce6d99530bb82e1d16fdd2338ceed6d28c952e6fff0da7f571f863 +openblas-394a9fbafe9010b76a2615c562204277a956eb52.tar.gz/sha512/3d1a096a738aa70c6c6c15acb9ac7fb77f3c8f9684c7f22dac1ceb7921c85131e3a7e55c893b6aed01f85f1bdff124d0b3a3fae3ca2dc5c0aae192c38c012417 From f61f92a6ee6f45cfd491c6156f7cc191bed0e3ad Mon Sep 17 00:00:00 2001 From: Nick Robinson Date: Mon, 15 Apr 2024 15:14:21 +0100 Subject: [PATCH 039/109] Stop updating upstream 1.9 branch (#144) * Stop updating upstream 1.9 branch * Stop labelling need to port to 1.9 --- .github/labeler.yml | 1 - .github/workflows/update-upstream-branches.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/labeler.yml b/.github/labeler.yml index 46b32f84a77d5..9359bd0ca70a6 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,4 +1,3 @@ # See https://github.com/actions/labeler port-to-master: '**' port-to-v1.10: '**' -port-to-v1.9: '**' diff --git a/.github/workflows/update-upstream-branches.yml b/.github/workflows/update-upstream-branches.yml index 242d59bd4edbc..247000bbd42cd 100644 --- a/.github/workflows/update-upstream-branches.yml +++ b/.github/workflows/update-upstream-branches.yml @@ -13,7 +13,6 @@ jobs: branch: - "master" - "backports-release-1.10" - - "backports-release-1.9" steps: - name: Checkout RAI/julia uses: actions/checkout@v3 From 01b4a24fdbc27dc7a924ddbca3bbe4cd3073a12b Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Thu, 18 Apr 2024 16:36:27 -0400 Subject: [PATCH 040/109] RAI: do not prepend thread ID to backtraces from signal handler context Also show the signal number when we have it. --- src/signals-unix.c | 2 +- src/stackwalk.c | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/signals-unix.c b/src/signals-unix.c index 7852b7ebb2618..3ebf7954dccfc 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -949,7 +949,7 @@ static void *signal_listener(void *arg) jl_safe_printf("\nsignal (%d): %s\n", sig, strsignal(sig)); size_t i; for (i = 0; i < bt_size; i += jl_bt_entry_size(bt_data + i)) { - jl_print_bt_entry_codeloc(-1, bt_data + i); + jl_print_bt_entry_codeloc(sig, bt_data + i); } } } diff --git a/src/stackwalk.c b/src/stackwalk.c index 5ceea5a8e30e9..ebf56931c2c65 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -660,11 +660,14 @@ void jl_print_native_codeloc(char *pre_str, uintptr_t ip) JL_NOTSAFEPOINT void jl_print_bt_entry_codeloc(int sig, jl_bt_element_t *bt_entry) JL_NOTSAFEPOINT { char sig_str[32], pre_str[64]; - sig_str[0] = '\0'; + sig_str[0] = pre_str[0] = '\0'; if (sig != -1) { snprintf(sig_str, 32, "signal (%d) ", sig); } - snprintf(pre_str, 64, "%sthread (%d) ", sig_str, jl_threadid() + 1); + // do not call jl_threadid if there's no current task + if (jl_get_current_task()) { + snprintf(pre_str, 64, "%sthread (%d) ", sig_str, jl_threadid() + 1); + } if (jl_bt_is_native(bt_entry)) { jl_print_native_codeloc(pre_str, bt_entry[0].uintptr); @@ -1120,7 +1123,11 @@ static void jl_rec_backtrace(jl_task_t *t) JL_NOTSAFEPOINT JL_DLLEXPORT void jl_gdblookup(void* ip) { char pre_str[64]; - snprintf(pre_str, 64, "thread (%d) ", jl_threadid() + 1); + pre_str[0] = '\0'; + // do not call jl_threadid if there's no current task + if (jl_get_current_task()) { + snprintf(pre_str, 64, "thread (%d) ", jl_threadid() + 1); + } jl_print_native_codeloc(pre_str, (uintptr_t)ip); } @@ -1165,7 +1172,11 @@ JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT { size_t nthreads = jl_atomic_load_acquire(&jl_n_threads); jl_ptls_t *allstates = jl_atomic_load_relaxed(&jl_all_tls_states); - int ctid = jl_threadid() + 1; + int ctid = -1; + // do not call jl_threadid if there's no current task + if (jl_get_current_task()) { + ctid = jl_threadid() + 1; + } jl_safe_printf("thread (%d) ++++ Task backtraces\n", ctid); for (size_t i = 0; i < nthreads; i++) { // skip GC threads since they don't have tasks From bcd9f13b49e57b3b7579e01d8330cc5cd9cab9a1 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Sat, 20 Apr 2024 14:09:35 -0300 Subject: [PATCH 041/109] add function to query GC page size (#54115) (#147) --- src/gc-pages.c | 5 +++++ test/gc.jl | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/src/gc-pages.c b/src/gc-pages.c index 40e5454136148..4c27e5a097e58 100644 --- a/src/gc-pages.c +++ b/src/gc-pages.c @@ -9,6 +9,11 @@ extern "C" { #endif +JL_DLLEXPORT uint64_t jl_get_pg_size(void) +{ + return GC_PAGE_SZ; +} + // Try to allocate memory in chunks to permit faster allocation // and improve memory locality of the pools #ifdef _P64 diff --git a/test/gc.jl b/test/gc.jl index e085c1d8658e5..330c136389a4e 100644 --- a/test/gc.jl +++ b/test/gc.jl @@ -15,6 +15,19 @@ function run_gctest(file) end end +function run_nonzero_page_utilization_test() + GC.gc() + page_utilization = Base.gc_page_utilization_data() + # at least one of the pools should have nonzero page_utilization + @test any(page_utilization .> 0) +end + +function run_pg_size_test() + page_size = @ccall jl_get_pg_size()::UInt64 + # supported page sizes: 4KB and 16KB + @test page_size == (1 << 12) || page_size == (1 << 14) +end + # !!! note: # Since we run our tests on 32bit OS as well we confine ourselves # to parameters that allocate about 512MB of objects. Max RSS is lower @@ -25,3 +38,9 @@ end run_gctest("gc/objarray.jl") run_gctest("gc/chunks.jl") end + +@testset "GC page metrics" begin + run_nonzero_page_utilization_test() + run_pg_size_test() +end + From 82d6ee0135181d84d86d38ed982ae5efcdcbdbe0 Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Thu, 4 Apr 2024 08:57:30 -0400 Subject: [PATCH 042/109] RAI: Change optimization aggressiveness for `-O1` from `None` to `Less` --- src/jitlayers.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/jitlayers.cpp b/src/jitlayers.cpp index d55090e161523..3c90ddf915cde 100644 --- a/src/jitlayers.cpp +++ b/src/jitlayers.cpp @@ -677,7 +677,8 @@ CodeGenOpt::Level CodeGenOptLevelFor(int optlevel) #ifdef DISABLE_OPT return CodeGenOpt::None; #else - return optlevel < 2 ? CodeGenOpt::None : + return optlevel == 0 ? CodeGenOpt::None : + optlevel == 1 ? CodeGenOpt::Less : optlevel == 2 ? CodeGenOpt::Default : CodeGenOpt::Aggressive; #endif From 653b24c3b72d350e7fc24852f8c444f76e1363c4 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Mon, 29 Apr 2024 16:37:47 -0300 Subject: [PATCH 043/109] fix typo in gc_mark_memory8 when chunking a large array (#149) Backports https://github.com/JuliaLang/julia/pull/54251. --- src/gc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gc.c b/src/gc.c index 4a74e55e4545d..d44aa068c9c64 100644 --- a/src/gc.c +++ b/src/gc.c @@ -2293,7 +2293,7 @@ STATIC_INLINE void gc_mark_array8(jl_ptls_t ptls, jl_value_t *ary8_parent, jl_va pushed_chunk = 1; } } - for (; ary8_begin < ary8_end; ary8_begin += elsize) { + for (; ary8_begin < scan_end; ary8_begin += elsize) { for (uint8_t *pindex = elem_begin; pindex < elem_end; pindex++) { jl_value_t **slot = &ary8_begin[*pindex]; new_obj = *slot; From 3930d1808d45ec503a69d2361bbe625167fe4051 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Fri, 3 May 2024 11:51:49 -0300 Subject: [PATCH 044/109] correctly track freed bytes in array_to_string (#54309) (#151) Should fix https://github.com/JuliaLang/julia/issues/54275. --- src/array.c | 1 + src/gc.c | 7 +++++++ src/gc.h | 2 -- src/julia_internal.h | 2 ++ 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/array.c b/src/array.c index 5226c729d32e7..c7f71c9695e87 100644 --- a/src/array.c +++ b/src/array.c @@ -479,6 +479,7 @@ JL_DLLEXPORT jl_value_t *jl_array_to_string(jl_array_t *a) return o; } } + jl_gc_count_freed(jl_array_nbytes(a)); a->nrows = 0; a->length = 0; a->maxsize = 0; diff --git a/src/gc.c b/src/gc.c index d44aa068c9c64..0b313e908c519 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1136,6 +1136,13 @@ void jl_gc_count_allocd(size_t sz) JL_NOTSAFEPOINT jl_atomic_load_relaxed(&ptls->gc_num.allocd) + sz); } +void jl_gc_count_freed(size_t sz) JL_NOTSAFEPOINT +{ + jl_ptls_t ptls = jl_current_task->ptls; + jl_atomic_store_relaxed(&ptls->gc_num.freed, + jl_atomic_load_relaxed(&ptls->gc_num.freed) + sz); +} + static void combine_thread_gc_counts(jl_gc_num_t *dest) JL_NOTSAFEPOINT { int gc_n_threads; diff --git a/src/gc.h b/src/gc.h index 5357dcbc60d00..161434e92442d 100644 --- a/src/gc.h +++ b/src/gc.h @@ -697,8 +697,6 @@ void gc_stats_big_obj(void); // For debugging void gc_count_pool(void); -size_t jl_array_nbytes(jl_array_t *a) JL_NOTSAFEPOINT; - JL_DLLEXPORT void jl_enable_gc_logging(int enable); JL_DLLEXPORT uint32_t jl_get_num_stack_mappings(void); void _report_gc_finished(uint64_t pause, uint64_t freed, int full, int recollect) JL_NOTSAFEPOINT; diff --git a/src/julia_internal.h b/src/julia_internal.h index 9940dbf68ba49..41c4304a9205f 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -598,7 +598,9 @@ JL_DLLEXPORT void JL_NORETURN jl_throw_out_of_memory_error(void); JL_DLLEXPORT int64_t jl_gc_diff_total_bytes(void) JL_NOTSAFEPOINT; JL_DLLEXPORT int64_t jl_gc_sync_total_bytes(int64_t offset) JL_NOTSAFEPOINT; void jl_gc_track_malloced_array(jl_ptls_t ptls, jl_array_t *a) JL_NOTSAFEPOINT; +size_t jl_array_nbytes(jl_array_t *a) JL_NOTSAFEPOINT; void jl_gc_count_allocd(size_t sz) JL_NOTSAFEPOINT; +void jl_gc_count_freed(size_t sz) JL_NOTSAFEPOINT; void jl_gc_run_all_finalizers(jl_task_t *ct); void jl_release_task_stack(jl_ptls_t ptls, jl_task_t *task); void jl_gc_add_finalizer_(jl_ptls_t ptls, void *v, void *f) JL_NOTSAFEPOINT; From e8cd7a41fbdb8275369029afe685b494078dac9b Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Wed, 22 May 2024 12:25:02 -0600 Subject: [PATCH 045/109] Make TestLogger thread-safe (introduce a lock) (#152) Fixes https://github.com/JuliaLang/julia/issues/54439. - Lock around concurrent accesses to .logs and .message_limits - Copy the vector out of the logger at the end, to shield against dangling Tasks. Before: ```julia julia> Threads.nthreads() 8 julia> function foo(n) @info "Doing foo with n=$n" @sync for i=1:n Threads.@spawn @info "Iteration $i" end 42 end foo (generic function with 1 method) julia> for _ in 1:1000 @test_logs (:info,"Doing foo with n=10000") match_mode=:any foo(10_000) end julia+RAI(56155,0x1f5157ac0) malloc: double free for ptr 0x128248000 julia+RAI(56155,0x1f5157ac0) malloc: *** set a breakpoint in malloc_error_break to debug [56155] signal (6): Abort trap: 6 in expression starting at REPL[8]:1 signal (6) thread (1) __pthread_kill at /usr/lib/system/libsystem_kernel.dylib (unknown line) Allocations: 54370881 (Pool: 54363911; Big: 6970); GC: 119 [1] 56154 abort julia -tauto ``` After: ```julia julia> Threads.nthreads() 8 julia> function foo(n) @info "Doing foo with n=$n" @sync for i=1:n Threads.@spawn @info "Iteration $i" end 42 end foo (generic function with 1 method) julia> for _ in 1:1000 @test_logs (:info,"Doing foo with n=10000") match_mode=:any foo(10_000) end ``` (no crash) :) --- stdlib/Test/src/logging.jl | 42 +++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 14 deletions(-) diff --git a/stdlib/Test/src/logging.jl b/stdlib/Test/src/logging.jl index 4e444874d0fb8..ee647da10551f 100644 --- a/stdlib/Test/src/logging.jl +++ b/stdlib/Test/src/logging.jl @@ -2,6 +2,7 @@ using Logging: Logging, AbstractLogger, LogLevel, Info, with_logger import Base: occursin +using Base: @lock #------------------------------------------------------------------------------- """ @@ -35,11 +36,15 @@ struct Ignored ; end #------------------------------------------------------------------------------- # Logger with extra test-related state mutable struct TestLogger <: AbstractLogger - logs::Vector{LogRecord} + lock::ReentrantLock + logs::Vector{LogRecord} # Guarded by lock. min_level::LogLevel catch_exceptions::Bool - shouldlog_args - message_limits::Dict{Any,Int} + # Note: shouldlog_args only maintains the info for the most recent log message, which + # may not be meaningful in a multithreaded program. See: + # https://github.com/JuliaLang/julia/pull/54497#discussion_r1603691606 + shouldlog_args # Guarded by lock. + message_limits::Dict{Any,Int} # Guarded by lock. respect_maxlog::Bool end @@ -80,15 +85,17 @@ Test Passed ``` """ TestLogger(; min_level=Info, catch_exceptions=false, respect_maxlog=true) = - TestLogger(LogRecord[], min_level, catch_exceptions, nothing, Dict{Any, Int}(), respect_maxlog) + TestLogger(ReentrantLock(), LogRecord[], min_level, catch_exceptions, nothing, Dict{Any, Int}(), respect_maxlog) Logging.min_enabled_level(logger::TestLogger) = logger.min_level function Logging.shouldlog(logger::TestLogger, level, _module, group, id) - if get(logger.message_limits, id, 1) > 0 - logger.shouldlog_args = (level, _module, group, id) - true - else - false + @lock logger.lock begin + if get(logger.message_limits, id, 1) > 0 + logger.shouldlog_args = (level, _module, group, id) + return true + else + return false + end end end @@ -98,12 +105,17 @@ function Logging.handle_message(logger::TestLogger, level, msg, _module, if logger.respect_maxlog maxlog = get(kwargs, :maxlog, nothing) if maxlog isa Core.BuiltinInts - remaining = get!(logger.message_limits, id, Int(maxlog)::Int) - logger.message_limits[id] = remaining - 1 - remaining > 0 || return + @lock logger.lock begin + remaining = get!(logger.message_limits, id, Int(maxlog)::Int) + logger.message_limits[id] = remaining - 1 + remaining > 0 || return + end end end - push!(logger.logs, LogRecord(level, msg, _module, group, id, file, line, kwargs)) + r = LogRecord(level, msg, _module, group, id, file, line, kwargs) + @lock logger.lock begin + push!(logger.logs, r) + end end # Catch exceptions for the test logger only if specified @@ -112,7 +124,9 @@ Logging.catch_exceptions(logger::TestLogger) = logger.catch_exceptions function collect_test_logs(f; kwargs...) logger = TestLogger(; kwargs...) value = with_logger(f, logger) - logger.logs, value + @lock logger.lock begin + return copy(logger.logs), value + end end From ada3603e9d769d178c38f73db983a6e9eab44926 Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Fri, 24 May 2024 12:11:59 -0400 Subject: [PATCH 046/109] Add `jl_inside_heartbeat_thread()` To allow `jl_safe_printf()` to determine whether it's being called from the heartbeat thread. --- src/threading.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/threading.c b/src/threading.c index 77b24dcb5208c..b0b88cfb7c2a5 100644 --- a/src/threading.c +++ b/src/threading.c @@ -951,6 +951,7 @@ JL_DLLEXPORT int jl_alignment(size_t sz) #include volatile int heartbeat_enabled; +uv_thread_t heartbeat_uvtid; uv_sem_t heartbeat_on_sem, // jl_heartbeat_enable -> thread heartbeat_off_sem; // thread -> jl_heartbeat_enable int heartbeat_interval_s, @@ -965,12 +966,17 @@ void jl_heartbeat_threadfun(void *arg); // start the heartbeat thread with heartbeats disabled void jl_init_heartbeat(void) { - uv_thread_t uvtid; heartbeat_enabled = 0; uv_sem_init(&heartbeat_on_sem, 0); uv_sem_init(&heartbeat_off_sem, 0); - uv_thread_create(&uvtid, jl_heartbeat_threadfun, NULL); - uv_thread_detach(&uvtid); + uv_thread_create(&heartbeat_uvtid, jl_heartbeat_threadfun, NULL); + uv_thread_detach(&heartbeat_uvtid); +} + +int jl_inside_heartbeat_thread(void) +{ + uv_thread_t curr_uvtid = uv_thread_self(); + return curr_uvtid == heartbeat_uvtid; } // enable/disable heartbeats @@ -1143,6 +1149,11 @@ void jl_init_heartbeat(void) { } +int jl_inside_heartbeat_thread(void) +{ + return 0; +} + JL_DLLEXPORT int jl_heartbeat_enable(int heartbeat_s, int show_tasks_after_n, int reset_after_n) { From 96ec5a0de5cf342cacd9e8e2e047a5c65bd27bdf Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Fri, 24 May 2024 12:13:40 -0400 Subject: [PATCH 047/109] Write heartbeat thread output to the safe crash log In `jl_safe_printf()`, we're already writing to the safe crash log if we're in signal handler context (in addition to writing to `stderr`). Now we do the same if we're in the heartbeat thread. --- src/jl_uv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jl_uv.c b/src/jl_uv.c index 5c51c3f8a6cf4..d7c0fac5a9bfa 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -747,7 +747,7 @@ JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...) // order is important here: we want to ensure that the threading infra // has been initialized before we start trying to print to the // safe crash log file - if (jl_sig_fd != 0 && jl_inside_signal_handler()) { + if (jl_sig_fd != 0 && (jl_inside_signal_handler() || jl_inside_heartbeat_thread()) { print_error_msg_as_json(buf); } if (write(STDERR_FILENO, buf, strlen(buf)) < 0) { From 6479c0730f3864fe496b47db3ead16a05ab0dac0 Mon Sep 17 00:00:00 2001 From: K Pamnany Date: Fri, 24 May 2024 12:18:06 -0400 Subject: [PATCH 048/109] Refactor JSON printing code Concurrent `write()` calls to the same file descriptor should be thread-safe, but can result in interleaving. Refactor the JSON printing code used from `jl_safe_printf()` to assemble the message into a buffer and use a single `write()` call. --- src/jl_uv.c | 83 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/src/jl_uv.c b/src/jl_uv.c index d7c0fac5a9bfa..fd8718ebbea26 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -678,56 +678,83 @@ JL_DLLEXPORT int jl_printf(uv_stream_t *s, const char *format, ...) return c; } -STATIC_INLINE void print_error_msg_as_json(char *buf) JL_NOTSAFEPOINT +STATIC_INLINE int copystp(char *dest, const char *src) { - // Our telemetry on SPCS expects a JSON object per line - // The following lines prepare the timestamp string and the JSON object + char *d = stpcpy(dest, src); + return (int)(d - dest); +} + +// RAI-specific +STATIC_INLINE void write_to_safe_crash_log(char *buf) JL_NOTSAFEPOINT +{ + int buflen = strlen(buf); + // Our telemetry on SPCS expects a JSON object per line. + // We ignore write failures because there is nothing we can do. + // We'll use a 2K byte buffer: 69 bytes for JSON message decorations, + // 1 byte for the terminating NUL character, and 3 bytes for an + // ellipsis if we have to truncate the message leaves `max_b` bytes + // for the message. + const int wbuflen = 2048; + const int max_b = wbuflen - 70 - 3; + char wbuf[wbuflen]; + bzero(wbuf, wbuflen); + int wlen = 0; + + // JSON preamble (32 bytes) + wlen += copystp(&wbuf[wlen], "\n{\"level\":\"Error\", \"timestamp\":\""); + + // Timestamp (19 bytes) struct timeval tv; struct tm* tm_info; - char timestamp_buffer[50]; - // Get current time gettimeofday(&tv, NULL); tm_info = gmtime(&tv.tv_sec); - // Format time - int offset = strftime(timestamp_buffer, 25, "%Y-%m-%dT%H:%M:%S", tm_info); - // Append milliseconds - snprintf(timestamp_buffer + offset, 25, ".%03d", tv.tv_usec / 1000); - const char *json_preamble_p1 = "\n{\"level\":\"Error\", \"timestamp\":\""; - const char *json_preamble_p2 = "\", \"message\": \""; - const char *json_postamble = "\"}\n"; - // Ignore write failures because there is nothing we can do - write(jl_sig_fd, json_preamble_p1, strlen(json_preamble_p1)); - write(jl_sig_fd, timestamp_buffer, strlen(timestamp_buffer)); - write(jl_sig_fd, json_preamble_p2, strlen(json_preamble_p2)); - // JSON escape the input string - for(size_t i = 0; i < strlen(buf); i += 1) { + wlen += strftime(&wbuf[wlen], 42, "%Y-%m-%dT%H:%M:%S", tm_info); + sprintf(&wbuf[wlen], ".%03ld", (long)tv.tv_usec / 1000); + wlen += 4; + + // JSON preamble to message (15 bytes) + wlen += copystp(&wbuf[wlen], "\", \"message\": \""); + + // Message + // Each iteration will advance wlen by 1 or 2 + for (size_t i = 0; i < buflen; i++) { + // Truncate the message if the write buffer is full + if (wlen == max_b || wlen == max_b - 1) { + wlen += copystp(&wbuf[wlen], "..."); + break; + } switch (buf[i]) { case '"': - write(jl_sig_fd, "\\\"", 2); + wlen += copystp(&wbuf[wlen], "\\\""); break; case '\b': - write(jl_sig_fd, "\\b", 2); + wlen += copystp(&wbuf[wlen], "\\b"); break; case '\n': - write(jl_sig_fd, "\\n", 2); + wlen += copystp(&wbuf[wlen], "\\n"); break; case '\r': - write(jl_sig_fd, "\\r", 2); + wlen += copystp(&wbuf[wlen], "\\r"); break; case '\t': - write(jl_sig_fd, "\\t", 2); + wlen += copystp(&wbuf[wlen], "\\t"); break; case '\\': - write(jl_sig_fd, "\\\\", 2); + wlen += copystp(&wbuf[wlen], "\\\\"); break; default: - write(jl_sig_fd, buf + i, 1); + wbuf[wlen++] = buf[i]; + break; } } - write(jl_sig_fd, json_postamble, strlen(json_postamble)); + // JSON completion (3 bytes) + wlen += copystp(&wbuf[wlen], "\"}\n"); + write(jl_sig_fd, wbuf, wlen); fdatasync(jl_sig_fd); } +extern int jl_inside_heartbeat_thread(void); + JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...) { static char buf[1000]; @@ -747,8 +774,8 @@ JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...) // order is important here: we want to ensure that the threading infra // has been initialized before we start trying to print to the // safe crash log file - if (jl_sig_fd != 0 && (jl_inside_signal_handler() || jl_inside_heartbeat_thread()) { - print_error_msg_as_json(buf); + if (jl_sig_fd != 0 && (jl_inside_signal_handler() || jl_inside_heartbeat_thread())) { + write_to_safe_crash_log(buf); } if (write(STDERR_FILENO, buf, strlen(buf)) < 0) { // nothing we can do; ignore the failure From 26d610057c3c97d142dcb07c89af05d3ef250d8e Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Mon, 27 May 2024 14:13:15 -0400 Subject: [PATCH 049/109] Revert "Refactor JSON printing code" This reverts commit 6479c0730f3864fe496b47db3ead16a05ab0dac0. --- src/jl_uv.c | 83 ++++++++++++++++++----------------------------------- 1 file changed, 28 insertions(+), 55 deletions(-) diff --git a/src/jl_uv.c b/src/jl_uv.c index fd8718ebbea26..d7c0fac5a9bfa 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -678,83 +678,56 @@ JL_DLLEXPORT int jl_printf(uv_stream_t *s, const char *format, ...) return c; } -STATIC_INLINE int copystp(char *dest, const char *src) +STATIC_INLINE void print_error_msg_as_json(char *buf) JL_NOTSAFEPOINT { - char *d = stpcpy(dest, src); - return (int)(d - dest); -} - -// RAI-specific -STATIC_INLINE void write_to_safe_crash_log(char *buf) JL_NOTSAFEPOINT -{ - int buflen = strlen(buf); - // Our telemetry on SPCS expects a JSON object per line. - // We ignore write failures because there is nothing we can do. - // We'll use a 2K byte buffer: 69 bytes for JSON message decorations, - // 1 byte for the terminating NUL character, and 3 bytes for an - // ellipsis if we have to truncate the message leaves `max_b` bytes - // for the message. - const int wbuflen = 2048; - const int max_b = wbuflen - 70 - 3; - char wbuf[wbuflen]; - bzero(wbuf, wbuflen); - int wlen = 0; - - // JSON preamble (32 bytes) - wlen += copystp(&wbuf[wlen], "\n{\"level\":\"Error\", \"timestamp\":\""); - - // Timestamp (19 bytes) + // Our telemetry on SPCS expects a JSON object per line + // The following lines prepare the timestamp string and the JSON object struct timeval tv; struct tm* tm_info; + char timestamp_buffer[50]; + // Get current time gettimeofday(&tv, NULL); tm_info = gmtime(&tv.tv_sec); - wlen += strftime(&wbuf[wlen], 42, "%Y-%m-%dT%H:%M:%S", tm_info); - sprintf(&wbuf[wlen], ".%03ld", (long)tv.tv_usec / 1000); - wlen += 4; - - // JSON preamble to message (15 bytes) - wlen += copystp(&wbuf[wlen], "\", \"message\": \""); - - // Message - // Each iteration will advance wlen by 1 or 2 - for (size_t i = 0; i < buflen; i++) { - // Truncate the message if the write buffer is full - if (wlen == max_b || wlen == max_b - 1) { - wlen += copystp(&wbuf[wlen], "..."); - break; - } + // Format time + int offset = strftime(timestamp_buffer, 25, "%Y-%m-%dT%H:%M:%S", tm_info); + // Append milliseconds + snprintf(timestamp_buffer + offset, 25, ".%03d", tv.tv_usec / 1000); + const char *json_preamble_p1 = "\n{\"level\":\"Error\", \"timestamp\":\""; + const char *json_preamble_p2 = "\", \"message\": \""; + const char *json_postamble = "\"}\n"; + // Ignore write failures because there is nothing we can do + write(jl_sig_fd, json_preamble_p1, strlen(json_preamble_p1)); + write(jl_sig_fd, timestamp_buffer, strlen(timestamp_buffer)); + write(jl_sig_fd, json_preamble_p2, strlen(json_preamble_p2)); + // JSON escape the input string + for(size_t i = 0; i < strlen(buf); i += 1) { switch (buf[i]) { case '"': - wlen += copystp(&wbuf[wlen], "\\\""); + write(jl_sig_fd, "\\\"", 2); break; case '\b': - wlen += copystp(&wbuf[wlen], "\\b"); + write(jl_sig_fd, "\\b", 2); break; case '\n': - wlen += copystp(&wbuf[wlen], "\\n"); + write(jl_sig_fd, "\\n", 2); break; case '\r': - wlen += copystp(&wbuf[wlen], "\\r"); + write(jl_sig_fd, "\\r", 2); break; case '\t': - wlen += copystp(&wbuf[wlen], "\\t"); + write(jl_sig_fd, "\\t", 2); break; case '\\': - wlen += copystp(&wbuf[wlen], "\\\\"); + write(jl_sig_fd, "\\\\", 2); break; default: - wbuf[wlen++] = buf[i]; - break; + write(jl_sig_fd, buf + i, 1); } } - // JSON completion (3 bytes) - wlen += copystp(&wbuf[wlen], "\"}\n"); - write(jl_sig_fd, wbuf, wlen); + write(jl_sig_fd, json_postamble, strlen(json_postamble)); fdatasync(jl_sig_fd); } -extern int jl_inside_heartbeat_thread(void); - JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...) { static char buf[1000]; @@ -774,8 +747,8 @@ JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...) // order is important here: we want to ensure that the threading infra // has been initialized before we start trying to print to the // safe crash log file - if (jl_sig_fd != 0 && (jl_inside_signal_handler() || jl_inside_heartbeat_thread())) { - write_to_safe_crash_log(buf); + if (jl_sig_fd != 0 && (jl_inside_signal_handler() || jl_inside_heartbeat_thread()) { + print_error_msg_as_json(buf); } if (write(STDERR_FILENO, buf, strlen(buf)) < 0) { // nothing we can do; ignore the failure From 97419309abfda93e074d9deef6f403e267bace64 Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Mon, 27 May 2024 14:13:15 -0400 Subject: [PATCH 050/109] Revert "Write heartbeat thread output to the safe crash log" This reverts commit 96ec5a0de5cf342cacd9e8e2e047a5c65bd27bdf. --- src/jl_uv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jl_uv.c b/src/jl_uv.c index d7c0fac5a9bfa..5c51c3f8a6cf4 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -747,7 +747,7 @@ JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...) // order is important here: we want to ensure that the threading infra // has been initialized before we start trying to print to the // safe crash log file - if (jl_sig_fd != 0 && (jl_inside_signal_handler() || jl_inside_heartbeat_thread()) { + if (jl_sig_fd != 0 && jl_inside_signal_handler()) { print_error_msg_as_json(buf); } if (write(STDERR_FILENO, buf, strlen(buf)) < 0) { From df1244cd9dd6c4a847802c356fca11cb35e8fbbb Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Mon, 27 May 2024 14:13:15 -0400 Subject: [PATCH 051/109] Revert "Add `jl_inside_heartbeat_thread()`" This reverts commit ada3603e9d769d178c38f73db983a6e9eab44926. --- src/threading.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/threading.c b/src/threading.c index b0b88cfb7c2a5..77b24dcb5208c 100644 --- a/src/threading.c +++ b/src/threading.c @@ -951,7 +951,6 @@ JL_DLLEXPORT int jl_alignment(size_t sz) #include volatile int heartbeat_enabled; -uv_thread_t heartbeat_uvtid; uv_sem_t heartbeat_on_sem, // jl_heartbeat_enable -> thread heartbeat_off_sem; // thread -> jl_heartbeat_enable int heartbeat_interval_s, @@ -966,17 +965,12 @@ void jl_heartbeat_threadfun(void *arg); // start the heartbeat thread with heartbeats disabled void jl_init_heartbeat(void) { + uv_thread_t uvtid; heartbeat_enabled = 0; uv_sem_init(&heartbeat_on_sem, 0); uv_sem_init(&heartbeat_off_sem, 0); - uv_thread_create(&heartbeat_uvtid, jl_heartbeat_threadfun, NULL); - uv_thread_detach(&heartbeat_uvtid); -} - -int jl_inside_heartbeat_thread(void) -{ - uv_thread_t curr_uvtid = uv_thread_self(); - return curr_uvtid == heartbeat_uvtid; + uv_thread_create(&uvtid, jl_heartbeat_threadfun, NULL); + uv_thread_detach(&uvtid); } // enable/disable heartbeats @@ -1149,11 +1143,6 @@ void jl_init_heartbeat(void) { } -int jl_inside_heartbeat_thread(void) -{ - return 0; -} - JL_DLLEXPORT int jl_heartbeat_enable(int heartbeat_s, int show_tasks_after_n, int reset_after_n) { From 3f82711625dbb4a505880b90ad1a5b8fc2f2bbed Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Mon, 27 May 2024 15:39:36 -0400 Subject: [PATCH 052/109] Write heartbeat thread output to safe crash log (#155) * Add `jl_inside_heartbeat_thread()` To allow `jl_safe_printf()` to determine whether it's being called from the heartbeat thread. * Write heartbeat thread output to the safe crash log In `jl_safe_printf()`, we're already writing to the safe crash log if we're in signal handler context (in addition to writing to `stderr`). Now we do the same if we're in the heartbeat thread. * Refactor JSON printing code Concurrent `write()` calls to the same file descriptor should be thread-safe, but can result in interleaving. Refactor the JSON printing code used from `jl_safe_printf()` to assemble the message into a buffer and use a single `write()` call. --- src/jl_uv.c | 83 ++++++++++++++++++++++++++++++++----------------- src/threading.c | 17 ++++++++-- 2 files changed, 69 insertions(+), 31 deletions(-) diff --git a/src/jl_uv.c b/src/jl_uv.c index 5c51c3f8a6cf4..fd8718ebbea26 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -678,56 +678,83 @@ JL_DLLEXPORT int jl_printf(uv_stream_t *s, const char *format, ...) return c; } -STATIC_INLINE void print_error_msg_as_json(char *buf) JL_NOTSAFEPOINT +STATIC_INLINE int copystp(char *dest, const char *src) { - // Our telemetry on SPCS expects a JSON object per line - // The following lines prepare the timestamp string and the JSON object + char *d = stpcpy(dest, src); + return (int)(d - dest); +} + +// RAI-specific +STATIC_INLINE void write_to_safe_crash_log(char *buf) JL_NOTSAFEPOINT +{ + int buflen = strlen(buf); + // Our telemetry on SPCS expects a JSON object per line. + // We ignore write failures because there is nothing we can do. + // We'll use a 2K byte buffer: 69 bytes for JSON message decorations, + // 1 byte for the terminating NUL character, and 3 bytes for an + // ellipsis if we have to truncate the message leaves `max_b` bytes + // for the message. + const int wbuflen = 2048; + const int max_b = wbuflen - 70 - 3; + char wbuf[wbuflen]; + bzero(wbuf, wbuflen); + int wlen = 0; + + // JSON preamble (32 bytes) + wlen += copystp(&wbuf[wlen], "\n{\"level\":\"Error\", \"timestamp\":\""); + + // Timestamp (19 bytes) struct timeval tv; struct tm* tm_info; - char timestamp_buffer[50]; - // Get current time gettimeofday(&tv, NULL); tm_info = gmtime(&tv.tv_sec); - // Format time - int offset = strftime(timestamp_buffer, 25, "%Y-%m-%dT%H:%M:%S", tm_info); - // Append milliseconds - snprintf(timestamp_buffer + offset, 25, ".%03d", tv.tv_usec / 1000); - const char *json_preamble_p1 = "\n{\"level\":\"Error\", \"timestamp\":\""; - const char *json_preamble_p2 = "\", \"message\": \""; - const char *json_postamble = "\"}\n"; - // Ignore write failures because there is nothing we can do - write(jl_sig_fd, json_preamble_p1, strlen(json_preamble_p1)); - write(jl_sig_fd, timestamp_buffer, strlen(timestamp_buffer)); - write(jl_sig_fd, json_preamble_p2, strlen(json_preamble_p2)); - // JSON escape the input string - for(size_t i = 0; i < strlen(buf); i += 1) { + wlen += strftime(&wbuf[wlen], 42, "%Y-%m-%dT%H:%M:%S", tm_info); + sprintf(&wbuf[wlen], ".%03ld", (long)tv.tv_usec / 1000); + wlen += 4; + + // JSON preamble to message (15 bytes) + wlen += copystp(&wbuf[wlen], "\", \"message\": \""); + + // Message + // Each iteration will advance wlen by 1 or 2 + for (size_t i = 0; i < buflen; i++) { + // Truncate the message if the write buffer is full + if (wlen == max_b || wlen == max_b - 1) { + wlen += copystp(&wbuf[wlen], "..."); + break; + } switch (buf[i]) { case '"': - write(jl_sig_fd, "\\\"", 2); + wlen += copystp(&wbuf[wlen], "\\\""); break; case '\b': - write(jl_sig_fd, "\\b", 2); + wlen += copystp(&wbuf[wlen], "\\b"); break; case '\n': - write(jl_sig_fd, "\\n", 2); + wlen += copystp(&wbuf[wlen], "\\n"); break; case '\r': - write(jl_sig_fd, "\\r", 2); + wlen += copystp(&wbuf[wlen], "\\r"); break; case '\t': - write(jl_sig_fd, "\\t", 2); + wlen += copystp(&wbuf[wlen], "\\t"); break; case '\\': - write(jl_sig_fd, "\\\\", 2); + wlen += copystp(&wbuf[wlen], "\\\\"); break; default: - write(jl_sig_fd, buf + i, 1); + wbuf[wlen++] = buf[i]; + break; } } - write(jl_sig_fd, json_postamble, strlen(json_postamble)); + // JSON completion (3 bytes) + wlen += copystp(&wbuf[wlen], "\"}\n"); + write(jl_sig_fd, wbuf, wlen); fdatasync(jl_sig_fd); } +extern int jl_inside_heartbeat_thread(void); + JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...) { static char buf[1000]; @@ -747,8 +774,8 @@ JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...) // order is important here: we want to ensure that the threading infra // has been initialized before we start trying to print to the // safe crash log file - if (jl_sig_fd != 0 && jl_inside_signal_handler()) { - print_error_msg_as_json(buf); + if (jl_sig_fd != 0 && (jl_inside_signal_handler() || jl_inside_heartbeat_thread())) { + write_to_safe_crash_log(buf); } if (write(STDERR_FILENO, buf, strlen(buf)) < 0) { // nothing we can do; ignore the failure diff --git a/src/threading.c b/src/threading.c index 77b24dcb5208c..b0b88cfb7c2a5 100644 --- a/src/threading.c +++ b/src/threading.c @@ -951,6 +951,7 @@ JL_DLLEXPORT int jl_alignment(size_t sz) #include volatile int heartbeat_enabled; +uv_thread_t heartbeat_uvtid; uv_sem_t heartbeat_on_sem, // jl_heartbeat_enable -> thread heartbeat_off_sem; // thread -> jl_heartbeat_enable int heartbeat_interval_s, @@ -965,12 +966,17 @@ void jl_heartbeat_threadfun(void *arg); // start the heartbeat thread with heartbeats disabled void jl_init_heartbeat(void) { - uv_thread_t uvtid; heartbeat_enabled = 0; uv_sem_init(&heartbeat_on_sem, 0); uv_sem_init(&heartbeat_off_sem, 0); - uv_thread_create(&uvtid, jl_heartbeat_threadfun, NULL); - uv_thread_detach(&uvtid); + uv_thread_create(&heartbeat_uvtid, jl_heartbeat_threadfun, NULL); + uv_thread_detach(&heartbeat_uvtid); +} + +int jl_inside_heartbeat_thread(void) +{ + uv_thread_t curr_uvtid = uv_thread_self(); + return curr_uvtid == heartbeat_uvtid; } // enable/disable heartbeats @@ -1143,6 +1149,11 @@ void jl_init_heartbeat(void) { } +int jl_inside_heartbeat_thread(void) +{ + return 0; +} + JL_DLLEXPORT int jl_heartbeat_enable(int heartbeat_s, int show_tasks_after_n, int reset_after_n) { From b882d43ad40a6206b586e67f34bb55b67cf835c7 Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Fri, 31 May 2024 13:31:17 -0400 Subject: [PATCH 053/109] Fix `gc_first_tid` setting (#157) --- src/threading.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/threading.c b/src/threading.c index b0b88cfb7c2a5..05607c12085f2 100644 --- a/src/threading.c +++ b/src/threading.c @@ -709,7 +709,7 @@ void jl_init_threading(void) jl_atomic_store_release(&jl_all_tls_states, (jl_ptls_t*)calloc(jl_all_tls_states_size, sizeof(jl_ptls_t))); jl_atomic_store_release(&jl_n_threads, jl_all_tls_states_size); jl_n_gcthreads = ngcthreads; - gc_first_tid = nthreads; + gc_first_tid = nthreads + nthreadsi; } static uv_barrier_t thread_init_done; From 7afe5a0943c35054e1d564b4379be36a62a4991b Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Wed, 5 Jun 2024 09:22:56 -0400 Subject: [PATCH 054/109] Add boundscheck in bindingkey_eq to avoid OOB access due to data race (#54671) (#158) The race here is that svec might be replaced and a new binding introduced into the keyset while we hold a reference to the old svec, which led to a OOB access on the svec with the index a binding introduced at the same time. This now introduces a bounds check which will force taking the lock if we fail the lookup i.e we had a data race. Fixes https://github.com/JuliaLang/julia/issues/54285 --------- Co-authored-by: Gabriel Baraldi Co-authored-by: Jameson Nash --- src/module.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/module.c b/src/module.c index 59bd308d99a41..d39b7e377b2df 100644 --- a/src/module.c +++ b/src/module.c @@ -702,13 +702,15 @@ JL_DLLEXPORT int jl_binding_resolved_p(jl_module_t *m, jl_sym_t *var) static uint_t bindingkey_hash(size_t idx, jl_svec_t *data) { - jl_binding_t *b = (jl_binding_t*)jl_svecref(data, idx); + jl_binding_t *b = (jl_binding_t*)jl_svecref(data, idx); // This must always happen inside the lock jl_sym_t *var = b->globalref->name; return var->hash; } static int bindingkey_eq(size_t idx, const void *var, jl_svec_t *data, uint_t hv) { + if (idx >= jl_svec_len(data)) + return 0; // We got a OOB access, probably due to a data race jl_binding_t *b = (jl_binding_t*)jl_svecref(data, idx); jl_sym_t *name = b->globalref->name; return var == name; From 775c5d25844412c62741b89c8e4ca77b8977bcf0 Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Wed, 19 Jun 2024 13:09:51 -0400 Subject: [PATCH 055/109] Add boundscheck in speccache_eq to avoid OOB access due to data race (#159) --- src/gf.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gf.c b/src/gf.c index 186f8787cf519..88810757dc15c 100644 --- a/src/gf.c +++ b/src/gf.c @@ -112,7 +112,7 @@ static int8_t jl_cachearg_offset(jl_methtable_t *mt) static uint_t speccache_hash(size_t idx, jl_svec_t *data) { - jl_method_instance_t *ml = (jl_method_instance_t*)jl_svecref(data, idx); + jl_method_instance_t *ml = (jl_method_instance_t*)jl_svecref(data, idx); // This must always happen inside the lock jl_value_t *sig = ml->specTypes; if (jl_is_unionall(sig)) sig = jl_unwrap_unionall(sig); @@ -121,6 +121,8 @@ static uint_t speccache_hash(size_t idx, jl_svec_t *data) static int speccache_eq(size_t idx, const void *ty, jl_svec_t *data, uint_t hv) { + if (idx >= jl_svec_len(data)) + return 0; // We got a OOB access, probably due to a data race jl_method_instance_t *ml = (jl_method_instance_t*)jl_svecref(data, idx); jl_value_t *sig = ml->specTypes; if (ty == sig) From 84dc564daf130d50d463d407da052e5720cf4827 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Thu, 27 Jun 2024 20:19:08 -0300 Subject: [PATCH 056/109] make realloc_string explicitely allocate a new string instead of realloc'ing (#160) --- src/gc.c | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) diff --git a/src/gc.c b/src/gc.c index 0b313e908c519..2835f847b8540 100644 --- a/src/gc.c +++ b/src/gc.c @@ -4179,35 +4179,8 @@ jl_value_t *jl_gc_realloc_string(jl_value_t *s, size_t sz) { size_t len = jl_string_len(s); if (sz <= len) return s; - jl_taggedvalue_t *v = jl_astaggedvalue(s); - size_t strsz = len + sizeof(size_t) + 1; - if (strsz <= GC_MAX_SZCLASS || - // TODO: because of issue #17971 we can't resize old objects - gc_marked(v->bits.gc)) { - // pool allocated; can't be grown in place so allocate a new object. - jl_value_t *snew = jl_alloc_string(sz); - memcpy(jl_string_data(snew), jl_string_data(s), len); - return snew; - } - size_t newsz = sz + sizeof(size_t) + 1; - size_t offs = sizeof(bigval_t); - size_t oldsz = LLT_ALIGN(strsz + offs, JL_CACHE_BYTE_ALIGNMENT); - size_t allocsz = LLT_ALIGN(newsz + offs, JL_CACHE_BYTE_ALIGNMENT); - if (allocsz < sz) // overflow in adding offs, size was "negative" - jl_throw(jl_memory_exception); - bigval_t *hdr = bigval_header(v); - jl_ptls_t ptls = jl_current_task->ptls; - maybe_collect(ptls); // don't want this to happen during jl_gc_managed_realloc - gc_big_object_unlink(hdr); - // TODO: this is not safe since it frees the old pointer. ideally we'd like - // the old pointer to be left alone if we can't grow in place. - // for now it's up to the caller to make sure there are no references to the - // old pointer. - bigval_t *newbig = (bigval_t*)gc_managed_realloc_(ptls, hdr, allocsz, oldsz, 1, s, 0); - newbig->sz = allocsz; - gc_big_object_link(newbig, &ptls->heap.big_objects); - jl_value_t *snew = jl_valueof(&newbig->header); - *(size_t*)snew = sz; + jl_value_t *snew = jl_alloc_string(sz); + memcpy(jl_string_data(snew), jl_string_data(s), len); return snew; } From 2ed98a22cf2f768dc2e03ba0c5e81beabee7337d Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Mon, 8 Jan 2024 11:29:29 -0300 Subject: [PATCH 057/109] reset mark queue indices at the end of GC (#52780) Should allow us to access fewer pages on the circular buffers owned by these work-stealing queues. --- src/gc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/gc.c b/src/gc.c index 2835f847b8540..26ac86935b18e 100644 --- a/src/gc.c +++ b/src/gc.c @@ -3166,6 +3166,17 @@ void gc_mark_clean_reclaim_sets(void) free(a); } } + // Reset queue indices + for (int i = 0; i < gc_n_threads; i++) { + jl_ptls_t ptls2 = gc_all_tls_states[i]; + if (ptls2 == NULL) { + continue; + } + jl_atomic_store_relaxed(&ptls2->mark_queue.ptr_queue.bottom, 0); + jl_atomic_store_relaxed(&ptls2->mark_queue.ptr_queue.top, 0); + jl_atomic_store_relaxed(&ptls2->mark_queue.chunk_queue.bottom, 0); + jl_atomic_store_relaxed(&ptls2->mark_queue.chunk_queue.top, 0); + } } static void gc_premark(jl_ptls_t ptls2) From e4b35212d57eb754f8d5872395c02292c79738c6 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Fri, 8 Mar 2024 18:44:48 -0300 Subject: [PATCH 058/109] optimize remset marking (#52476) Tag the lowest bit of a pointer to indicate it's in the remset and enqueue objects in the remset for later processing when GC threads have woken up, instead of sequentially marking them all at once. In principle, this should allow for more parallelism in the mark phase, though I didn't benchmark it yet. --- src/gc.c | 21 ++++++++++----------- src/gc.h | 2 ++ 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/gc.c b/src/gc.c index 26ac86935b18e..7df52da0fbcef 100644 --- a/src/gc.c +++ b/src/gc.c @@ -2618,13 +2618,12 @@ JL_DLLEXPORT void jl_gc_mark_queue_objarray(jl_ptls_t ptls, jl_value_t *parent, gc_mark_objarray(ptls, parent, objs, objs + nobjs, 1, nptr); } -// Enqueue and mark all outgoing references from `new_obj` which have not been marked -// yet. `meta_updated` is mostly used to make sure we don't update metadata twice for -// objects which have been enqueued into the `remset` -FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_new_obj, - int meta_updated) +// Enqueue and mark all outgoing references from `new_obj` which have not been marked yet. +// `_new_obj` has its lowest bit tagged if it's in the remset (in which case we shouldn't update page metadata) +FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_new_obj) { - jl_value_t *new_obj = (jl_value_t *)_new_obj; + int meta_updated = (uintptr_t)_new_obj & GC_REMSET_PTR_TAG; + jl_value_t *new_obj = (jl_value_t *)((uintptr_t)_new_obj & ~(uintptr_t)GC_REMSET_PTR_TAG); mark_obj: { #ifdef JL_DEBUG_BUILD if (new_obj == gc_findval) @@ -2935,7 +2934,7 @@ void gc_mark_loop_serial_(jl_ptls_t ptls, jl_gc_markqueue_t *mq) if (__unlikely(new_obj == NULL)) { return; } - gc_mark_outrefs(ptls, mq, new_obj, 0); + gc_mark_outrefs(ptls, mq, new_obj); } } @@ -2984,7 +2983,7 @@ void gc_mark_and_steal(jl_ptls_t ptls) goto steal; } mark : { - gc_mark_outrefs(ptls, mq, new_obj, 0); + gc_mark_outrefs(ptls, mq, new_obj); goto pop; } // Note that for the stealing heuristics, we try to @@ -3245,9 +3244,9 @@ static void gc_queue_remset(jl_ptls_t ptls, jl_ptls_t ptls2) size_t len = ptls2->heap.last_remset->len; void **items = ptls2->heap.last_remset->items; for (size_t i = 0; i < len; i++) { - // Objects in the `remset` are already marked, - // so a `gc_try_claim_and_push` wouldn't work here - gc_mark_outrefs(ptls, &ptls->mark_queue, (jl_value_t *)items[i], 1); + // Tag the pointer to indicate it's in the remset + jl_value_t *v = (jl_value_t *)((uintptr_t)items[i] | GC_REMSET_PTR_TAG); + gc_ptr_queue_push(&ptls->mark_queue, v); } } diff --git a/src/gc.h b/src/gc.h index 161434e92442d..666fcc23339b0 100644 --- a/src/gc.h +++ b/src/gc.h @@ -116,6 +116,8 @@ typedef struct _jl_gc_chunk_t { #define GC_PTR_QUEUE_INIT_SIZE (1 << 18) // initial size of queue of `jl_value_t *` #define GC_CHUNK_QUEUE_INIT_SIZE (1 << 14) // initial size of chunk-queue +#define GC_REMSET_PTR_TAG (0x1) // lowest bit of `jl_value_t *` is tagged if it's in the remset + // layout for big (>2k) objects JL_EXTENSION typedef struct _bigval_t { From 163e85e74ee6bdd574fa73c82f1ed840e3abfc35 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Thu, 25 Apr 2024 11:32:57 -0300 Subject: [PATCH 059/109] print types more verbosely in page profiler (#53256) Instead of just printing `Tuple`, print the full type signature such as `Tuple{UnionAll, GenericMemory{:not_atomic, Tuple{Int64, Int64, Array{Pair{Any, Any}, 1}}, Core.AddrSpace{Core}(0x00)}, Int64}` --- src/Makefile | 3 +- src/gc-page-profiler.c | 24 ++++++++--- src/gc-page-profiler.h | 93 +++++++++++++++++++++++++++++++++++++++--- src/gc.c | 36 +++++++++++----- src/julia_internal.h | 2 +- 5 files changed, 134 insertions(+), 24 deletions(-) diff --git a/src/Makefile b/src/Makefile index 334a9baa6ade8..0127e513ce144 100644 --- a/src/Makefile +++ b/src/Makefile @@ -302,9 +302,10 @@ $(BUILDDIR)/debuginfo.o $(BUILDDIR)/debuginfo.dbg.obj: $(addprefix $(SRCDIR)/,de $(BUILDDIR)/disasm.o $(BUILDDIR)/disasm.dbg.obj: $(SRCDIR)/debuginfo.h $(SRCDIR)/processor.h $(BUILDDIR)/gc-debug.o $(BUILDDIR)/gc-debug.dbg.obj: $(SRCDIR)/gc.h $(BUILDDIR)/gc-pages.o $(BUILDDIR)/gc-pages.dbg.obj: $(SRCDIR)/gc.h -$(BUILDDIR)/gc.o $(BUILDDIR)/gc.dbg.obj: $(SRCDIR)/gc.h $(SRCDIR)/gc-heap-snapshot.h $(SRCDIR)/gc-alloc-profiler.h +$(BUILDDIR)/gc.o $(BUILDDIR)/gc.dbg.obj: $(SRCDIR)/gc.h $(SRCDIR)/gc-heap-snapshot.h $(SRCDIR)/gc-alloc-profiler.h $(SRCDIR)/gc-page-profiler.h $(BUILDDIR)/gc-heap-snapshot.o $(BUILDDIR)/gc-heap-snapshot.dbg.obj: $(SRCDIR)/gc.h $(SRCDIR)/gc-heap-snapshot.h $(BUILDDIR)/gc-alloc-profiler.o $(BUILDDIR)/gc-alloc-profiler.dbg.obj: $(SRCDIR)/gc.h $(SRCDIR)/gc-alloc-profiler.h +$(BUILDDIR)/gc-page-profiler.o $(BUILDDIR)/gc-page-profiler.dbg.obj: $(SRCDIR)/gc-page-profiler.h $(BUILDDIR)/init.o $(BUILDDIR)/init.dbg.obj: $(SRCDIR)/builtin_proto.h $(BUILDDIR)/interpreter.o $(BUILDDIR)/interpreter.dbg.obj: $(SRCDIR)/builtin_proto.h $(BUILDDIR)/jitlayers.o $(BUILDDIR)/jitlayers.dbg.obj: $(SRCDIR)/jitlayers.h $(SRCDIR)/llvm-codegen-shared.h diff --git a/src/gc-page-profiler.c b/src/gc-page-profiler.c index 5af1c3d014770..2e876e4b7b4d6 100644 --- a/src/gc-page-profiler.c +++ b/src/gc-page-profiler.c @@ -20,6 +20,8 @@ gc_page_profiler_serializer_t gc_page_serializer_create(void) JL_NOTSAFEPOINT gc_page_profiler_serializer_t serializer; if (__unlikely(page_profile_enabled)) { arraylist_new(&serializer.typestrs, GC_PAGE_SZ); + serializer.buffers = (char *)malloc_s(GC_PAGE_PROFILER_SERIALIZER_INIT_CAPACITY); + serializer.cursor = 0; } else { serializer.typestrs.len = 0; @@ -34,6 +36,8 @@ void gc_page_serializer_init(gc_page_profiler_serializer_t *serializer, serializer->typestrs.len = 0; serializer->data = (char *)pg->data; serializer->osize = pg->osize; + serializer->cursor = 0; + serializer->capacity = GC_PAGE_PROFILER_SERIALIZER_INIT_CAPACITY; } } @@ -41,6 +45,7 @@ void gc_page_serializer_destroy(gc_page_profiler_serializer_t *serializer) JL_NO { if (__unlikely(page_profile_enabled)) { arraylist_free(&serializer->typestrs); + free(serializer->buffers); } } @@ -71,8 +76,9 @@ void gc_page_profile_write_preamble(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT { if (__unlikely(page_profile_enabled)) { - char str[GC_TYPE_STR_MAXLEN]; - snprintf(str, GC_TYPE_STR_MAXLEN, + const size_t large_enough_str_size = 4096; + char str[large_enough_str_size]; + snprintf(str, large_enough_str_size, "{\"address\": \"%p\",\"object_size\": %d,\"objects\": [", serializer->data, serializer->osize); ios_write(page_profile_stream, str, strlen(str)); @@ -102,22 +108,27 @@ void gc_page_profile_write_comma(gc_page_profiler_serializer_t *serializer) JL_N void gc_page_profile_write_to_file(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT { + size_t large_enough_str_size = 4096; if (__unlikely(page_profile_enabled)) { // write to file uv_mutex_lock(&page_profile_lock); gc_page_profile_write_comma(serializer); gc_page_profile_write_preamble(serializer); - char str[GC_TYPE_STR_MAXLEN]; + char *str = (char *)malloc_s(large_enough_str_size); for (size_t i = 0; i < serializer->typestrs.len; i++) { const char *name = (const char *)serializer->typestrs.items[i]; if (name == GC_SERIALIZER_EMPTY) { - snprintf(str, GC_TYPE_STR_MAXLEN, "\"empty\","); + snprintf(str, large_enough_str_size, "\"empty\","); } else if (name == GC_SERIALIZER_GARBAGE) { - snprintf(str, GC_TYPE_STR_MAXLEN, "\"garbage\","); + snprintf(str, large_enough_str_size, "\"garbage\","); } else { - snprintf(str, GC_TYPE_STR_MAXLEN, "\"%s\",", name); + while ((strlen(name) + 1) > large_enough_str_size) { + large_enough_str_size *= 2; + str = (char *)realloc_s(str, large_enough_str_size); + } + snprintf(str, large_enough_str_size, "\"%s\",", name); } // remove trailing comma for last element if (i == serializer->typestrs.len - 1) { @@ -125,6 +136,7 @@ void gc_page_profile_write_to_file(gc_page_profiler_serializer_t *serializer) } ios_write(page_profile_stream, str, strlen(str)); } + free(str); gc_page_profile_write_epilogue(serializer); page_profile_pages_written++; uv_mutex_unlock(&page_profile_lock); diff --git a/src/gc-page-profiler.h b/src/gc-page-profiler.h index b103e23905ba5..28989f8f8e206 100644 --- a/src/gc-page-profiler.h +++ b/src/gc-page-profiler.h @@ -9,22 +9,29 @@ extern "C" { #endif -#define GC_TYPE_STR_MAXLEN (512) +#define GC_PAGE_PROFILER_SERIALIZER_INIT_CAPACITY (4096) typedef struct { arraylist_t typestrs; char *data; int osize; + char *buffers; + size_t cursor; + size_t capacity; } gc_page_profiler_serializer_t; // mutex for page profile extern uv_mutex_t page_profile_lock; +// whether page profiling is enabled +extern int page_profile_enabled; // Serializer functions gc_page_profiler_serializer_t gc_page_serializer_create(void) JL_NOTSAFEPOINT; -void gc_page_serializer_init(gc_page_profiler_serializer_t *serializer, jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT; +void gc_page_serializer_init(gc_page_profiler_serializer_t *serializer, + jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT; void gc_page_serializer_destroy(gc_page_profiler_serializer_t *serializer) JL_NOTSAFEPOINT; -void gc_page_serializer_write(gc_page_profiler_serializer_t *serializer, const char *str) JL_NOTSAFEPOINT; +void gc_page_serializer_write(gc_page_profiler_serializer_t *serializer, + const char *str) JL_NOTSAFEPOINT; // Page profile functions #define GC_SERIALIZER_EMPTY ((const char *)0x1) #define GC_SERIALIZER_GARBAGE ((const char *)0x2) @@ -42,13 +49,89 @@ STATIC_INLINE void gc_page_profile_write_garbage(gc_page_profiler_serializer_t * gc_page_serializer_write(serializer, GC_SERIALIZER_GARBAGE); } } +STATIC_INLINE char *gc_page_profile_request_buffer(gc_page_profiler_serializer_t *serializer, size_t size) JL_NOTSAFEPOINT +{ + while (serializer->cursor + size >= serializer->capacity) { + serializer->capacity *= 2; + serializer->buffers = (char *)realloc_s(serializer->buffers, serializer->capacity); + } + char *p = &serializer->buffers[serializer->cursor]; + memset(p, 0, size); + serializer->cursor += size; + return p; +} STATIC_INLINE void gc_page_profile_write_live_obj(gc_page_profiler_serializer_t *serializer, jl_taggedvalue_t *v, int enabled) JL_NOTSAFEPOINT { if (__unlikely(enabled)) { - const char *name = jl_typeof_str(jl_valueof(v)); - gc_page_serializer_write(serializer, name); + jl_value_t *a = jl_valueof(v); + jl_value_t *t = jl_typeof(a); + ios_t str_; + int ios_need_close = 0; + char *type_name = NULL; + char *type_name_in_serializer = NULL; + if (t == (jl_value_t *)jl_get_buff_tag()) { + type_name = "Buffer"; + type_name_in_serializer = + gc_page_profile_request_buffer(serializer, strlen(type_name) + 1); + strcpy(type_name_in_serializer, type_name); + } + else if (jl_is_string(a)) { + type_name = "String"; + type_name_in_serializer = + gc_page_profile_request_buffer(serializer, strlen(type_name) + 1); + strcpy(type_name_in_serializer, type_name); + } + else if (jl_is_symbol(a)) { + type_name = jl_symbol_name((jl_sym_t *)a); + type_name_in_serializer = + gc_page_profile_request_buffer(serializer, strlen(type_name) + 1); + strcpy(type_name_in_serializer, type_name); + } + else if (jl_is_simplevector(a)) { + type_name = "SimpleVector"; + type_name_in_serializer = + gc_page_profile_request_buffer(serializer, strlen(type_name) + 1); + strcpy(type_name_in_serializer, type_name); + } + else if (jl_is_module(a)) { + type_name = jl_symbol_name_(((jl_module_t *)a)->name); + type_name_in_serializer = + gc_page_profile_request_buffer(serializer, strlen(type_name) + 1); + strcpy(type_name_in_serializer, type_name); + } + else if (jl_is_task(a)) { + type_name = "Task"; + type_name_in_serializer = + gc_page_profile_request_buffer(serializer, strlen(type_name) + 1); + strcpy(type_name_in_serializer, type_name); + } + else if (jl_is_datatype(a)) { + ios_need_close = 1; + ios_mem(&str_, 0); + JL_STREAM *str = (JL_STREAM *)&str_; + jl_static_show(str, a); + type_name = str_.buf; + type_name_in_serializer = + gc_page_profile_request_buffer(serializer, str_.size + 1); + memcpy(type_name_in_serializer, type_name, str_.size); + } + else { + ios_need_close = 1; + ios_mem(&str_, 0); + JL_STREAM *str = (JL_STREAM *)&str_; + jl_static_show(str, t); + type_name = str_.buf; + type_name_in_serializer = + gc_page_profile_request_buffer(serializer, str_.size + 1); + memcpy(type_name_in_serializer, type_name, str_.size); + } + gc_page_serializer_write(serializer, type_name_in_serializer); + if (ios_need_close) { + ios_close(&str_); + } + jl_may_leak(type_name_in_serializer); } } void gc_enable_page_profile(void) JL_NOTSAFEPOINT; diff --git a/src/gc.c b/src/gc.c index 7df52da0fbcef..14df2bc338aef 100644 --- a/src/gc.c +++ b/src/gc.c @@ -196,7 +196,7 @@ static size_t last_long_collect_interval; int gc_n_threads; jl_ptls_t* gc_all_tls_states; const uint64_t _jl_buff_tag[3] = {0x4eadc0004eadc000ull, 0x4eadc0004eadc000ull, 0x4eadc0004eadc000ull}; // aka 0xHEADER00 -JL_DLLEXPORT uintptr_t jl_get_buff_tag(void) +JL_DLLEXPORT uintptr_t jl_get_buff_tag(void) JL_NOTSAFEPOINT { return jl_buff_tag; } @@ -1655,17 +1655,32 @@ int gc_sweep_prescan(jl_ptls_t ptls, jl_gc_padded_page_stack_t *new_gc_allocd_sc void gc_sweep_wake_all(jl_ptls_t ptls, jl_gc_padded_page_stack_t *new_gc_allocd_scratch) { int parallel_sweep_worthwhile = gc_sweep_prescan(ptls, new_gc_allocd_scratch); - jl_atomic_store(&gc_allocd_scratch, new_gc_allocd_scratch); - if (!parallel_sweep_worthwhile) { + if (parallel_sweep_worthwhile && !page_profile_enabled) { + jl_atomic_store(&gc_allocd_scratch, new_gc_allocd_scratch); + uv_mutex_lock(&gc_threads_lock); + for (int i = gc_first_tid; i < gc_first_tid + jl_n_markthreads; i++) { + jl_ptls_t ptls2 = gc_all_tls_states[i]; + assert(ptls2 != NULL); // should be a GC thread + jl_atomic_fetch_add(&ptls2->gc_sweeps_requested, 1); + } + uv_cond_broadcast(&gc_threads_cond); + uv_mutex_unlock(&gc_threads_lock); return; } - uv_mutex_lock(&gc_threads_lock); - for (int i = gc_first_tid; i < gc_first_tid + jl_n_markthreads; i++) { - jl_ptls_t ptls2 = gc_all_tls_states[i]; - jl_atomic_fetch_add(&ptls2->gc_sweeps_requested, 1); + if (page_profile_enabled) { + // we need to ensure that no threads are running sweeping when + // collecting a page profile. + // wait for all to leave in order to ensure that a straggler doesn't + // try to enter sweeping after we set `gc_allocd_scratch` below. + for (int i = gc_first_tid; i < gc_first_tid + jl_n_markthreads; i++) { + jl_ptls_t ptls2 = gc_all_tls_states[i]; + assert(ptls2 != NULL); // should be a GC thread + while (jl_atomic_load_acquire(&ptls2->gc_sweeps_requested) != 0) { + jl_cpu_pause(); + } + } } - uv_cond_broadcast(&gc_threads_cond); - uv_mutex_unlock(&gc_threads_lock); + jl_atomic_store(&gc_allocd_scratch, new_gc_allocd_scratch); } // wait for all threads to finish sweeping @@ -1795,8 +1810,7 @@ static void gc_sweep_pool(void) } // the actual sweeping - jl_gc_padded_page_stack_t *new_gc_allocd_scratch = (jl_gc_padded_page_stack_t *) malloc_s(n_threads * sizeof(jl_gc_padded_page_stack_t)); - memset(new_gc_allocd_scratch, 0, n_threads * sizeof(jl_gc_padded_page_stack_t)); + jl_gc_padded_page_stack_t *new_gc_allocd_scratch = (jl_gc_padded_page_stack_t *) calloc_s(n_threads * sizeof(jl_gc_padded_page_stack_t)); jl_ptls_t ptls = jl_current_task->ptls; gc_sweep_wake_all(ptls, new_gc_allocd_scratch); gc_sweep_pool_parallel(ptls); diff --git a/src/julia_internal.h b/src/julia_internal.h index 41c4304a9205f..1ea84c0dc0d4f 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -535,7 +535,7 @@ JL_DLLEXPORT jl_value_t *jl_gc_alloc(jl_ptls_t ptls, size_t sz, void *ty); // defined as uint64_t[3] so that we can get the right alignment of this and a "type tag" on it const extern uint64_t _jl_buff_tag[3]; #define jl_buff_tag ((uintptr_t)LLT_ALIGN((uintptr_t)&_jl_buff_tag[1],16)) -JL_DLLEXPORT uintptr_t jl_get_buff_tag(void); +JL_DLLEXPORT uintptr_t jl_get_buff_tag(void) JL_NOTSAFEPOINT; typedef void jl_gc_tracked_buffer_t; // For the benefit of the static analyzer STATIC_INLINE jl_gc_tracked_buffer_t *jl_gc_alloc_buf(jl_ptls_t ptls, size_t sz) From 546ad08acf4fc8765a6f48e0dffe571dca84ea76 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Sun, 9 Jun 2024 18:50:56 -0300 Subject: [PATCH 060/109] fix stale docstring in gc_sweep_page (#54743) --- src/gc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gc.c b/src/gc.c index 14df2bc338aef..ff7f9cd657f61 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1423,7 +1423,8 @@ STATIC_INLINE void gc_dump_page_utilization_data(void) JL_NOTSAFEPOINT int64_t buffered_pages = 0; -// Returns pointer to terminal pointer of list rooted at *pfl. +// Walks over a page, reconstruting the free lists if the page contains at least one live object. If not, +// queues up the page for later decommit (i.e. through `madvise` on Unix). static void gc_sweep_page(gc_page_profiler_serializer_t *s, jl_gc_pool_t *p, jl_gc_page_stack_t *allocd, jl_gc_page_stack_t *buffered, jl_gc_pagemeta_t *pg, int osize) JL_NOTSAFEPOINT { From ba14e757d8b4da9e99a2fea8f73b0c16fa76a3c7 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Sun, 9 Jun 2024 23:11:37 -0300 Subject: [PATCH 061/109] use atomic-fetch-and in write barrier slow-path (#54744) Not sure why we're not using it, but we probably should. --- src/gc.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/gc.c b/src/gc.c index ff7f9cd657f61..e4bcabdaa9ad3 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1891,13 +1891,15 @@ JL_DLLEXPORT void jl_gc_queue_root(const jl_value_t *ptr) { jl_ptls_t ptls = jl_current_task->ptls; jl_taggedvalue_t *o = jl_astaggedvalue(ptr); - // The modification of the `gc_bits` is not atomic but it - // should be safe here since GC is not allowed to run here and we only - // write GC_OLD to the GC bits outside GC. This could cause - // duplicated objects in the remset but that shouldn't be a problem. - o->bits.gc = GC_MARKED; - arraylist_push(ptls->heap.remset, (jl_value_t*)ptr); - ptls->heap.remset_nptr++; // conservative + // The modification of the `gc_bits` needs to be atomic. + // We need to ensure that objects are in the remset at + // most once, since the mark phase may update page metadata, + // which is not idempotent. See comments in https://github.com/JuliaLang/julia/issues/50419 + uintptr_t header = jl_atomic_fetch_and_relaxed((_Atomic(uintptr_t) *)&o->header, ~GC_OLD); + if (header & GC_OLD) { // write barrier has not been triggered in this object yet + arraylist_push(ptls->heap.remset, (jl_value_t*)ptr); + ptls->heap.remset_nptr++; // conservative + } } void jl_gc_queue_multiroot(const jl_value_t *parent, const jl_value_t *ptr) JL_NOTSAFEPOINT From a47fd205bd0c3671510480856a5f0888e92f4da6 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Thu, 27 Jun 2024 01:03:07 -0300 Subject: [PATCH 062/109] remove a bunch of bit unnecessary bit clearing in bigval's sz field (#54946) We don't store anything in the lowest two bits of `sz` after https://github.com/JuliaLang/julia/pull/49644. --- src/gc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/gc.c b/src/gc.c index e4bcabdaa9ad3..cf08652b24e10 100644 --- a/src/gc.c +++ b/src/gc.c @@ -848,11 +848,11 @@ STATIC_INLINE void gc_setmark_big(jl_ptls_t ptls, jl_taggedvalue_t *o, assert(!gc_alloc_map_is_set((char*)o)); bigval_t *hdr = bigval_header(o); if (mark_mode == GC_OLD_MARKED) { - ptls->gc_cache.perm_scanned_bytes += hdr->sz & ~3; + ptls->gc_cache.perm_scanned_bytes += hdr->sz; gc_queue_big_marked(ptls, hdr, 0); } else { - ptls->gc_cache.scanned_bytes += hdr->sz & ~3; + ptls->gc_cache.scanned_bytes += hdr->sz; // We can't easily tell if the object is old or being promoted // from the gc bits but if the `age` is `0` then the object // must be already on a young list. @@ -862,7 +862,7 @@ STATIC_INLINE void gc_setmark_big(jl_ptls_t ptls, jl_taggedvalue_t *o, } } objprofile_count(jl_typeof(jl_valueof(o)), - mark_mode == GC_OLD_MARKED, hdr->sz & ~3); + mark_mode == GC_OLD_MARKED, hdr->sz); } // This function should be called exactly once during marking for each pool @@ -1074,9 +1074,9 @@ static bigval_t **sweep_big_list(int sweep_full, bigval_t **pv) JL_NOTSAFEPOINT *pv = nxt; if (nxt) nxt->prev = pv; - gc_num.freed += v->sz&~3; + gc_num.freed += v->sz; #ifdef MEMDEBUG - memset(v, 0xbb, v->sz&~3); + memset(v, 0xbb, v->sz); #endif gc_invoke_callbacks(jl_gc_cb_notify_external_free_t, gc_cblist_notify_external_free, (v)); From 454ed8ccb35806d1b2da458f0eb0ab7ddefc4596 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Fri, 28 Jun 2024 12:46:50 -0300 Subject: [PATCH 063/109] simplify handling of buffered pages (#54961) Simplifies handling of buffered pages by keeping them in a single place (`global_page_pool_lazily_freed`) instead of making them thread local. Performance has been assessed on the serial & multithreaded GCBenchmarks and it has shown to be performance neutral. --- src/gc.c | 73 ++++++++++++++++++++------------------------- src/gc.h | 2 ++ src/julia_threads.h | 1 - 3 files changed, 34 insertions(+), 42 deletions(-) diff --git a/src/gc.c b/src/gc.c index cf08652b24e10..3411575dd4c16 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1283,13 +1283,7 @@ static NOINLINE jl_taggedvalue_t *gc_add_page(jl_gc_pool_t *p) JL_NOTSAFEPOINT // Do not pass in `ptls` as argument. This slows down the fast path // in pool_alloc significantly jl_ptls_t ptls = jl_current_task->ptls; - jl_gc_pagemeta_t *pg = pop_lf_back(&ptls->page_metadata_buffered); - if (pg != NULL) { - gc_alloc_map_set(pg->data, GC_PAGE_ALLOCATED); - } - else { - pg = jl_gc_alloc_page(); - } + jl_gc_pagemeta_t *pg = jl_gc_alloc_page(); pg->osize = p->osize; pg->thread_n = ptls->tid; set_page_metadata(pg); @@ -1421,12 +1415,9 @@ STATIC_INLINE void gc_dump_page_utilization_data(void) JL_NOTSAFEPOINT } } -int64_t buffered_pages = 0; - // Walks over a page, reconstruting the free lists if the page contains at least one live object. If not, // queues up the page for later decommit (i.e. through `madvise` on Unix). -static void gc_sweep_page(gc_page_profiler_serializer_t *s, jl_gc_pool_t *p, jl_gc_page_stack_t *allocd, jl_gc_page_stack_t *buffered, - jl_gc_pagemeta_t *pg, int osize) JL_NOTSAFEPOINT +static void gc_sweep_page(gc_page_profiler_serializer_t *s, jl_gc_pool_t *p, jl_gc_page_stack_t *allocd, jl_gc_pagemeta_t *pg, int osize) JL_NOTSAFEPOINT { char *data = pg->data; jl_taggedvalue_t *v0 = (jl_taggedvalue_t*)(data + GC_PAGE_OFFSET); @@ -1442,22 +1433,10 @@ static void gc_sweep_page(gc_page_profiler_serializer_t *s, jl_gc_pool_t *p, jl_ gc_page_serializer_init(s, pg); int re_use_page = 1; - int keep_as_local_buffer = 0; int freedall = 1; int pg_skpd = 1; if (!pg->has_marked) { re_use_page = 0; - #ifdef _P64 // TODO: re-enable on `_P32`? - // lazy version: (empty) if the whole page was already unused, free it (return it to the pool) - // eager version: (freedall) free page as soon as possible - // the eager one uses less memory. - // FIXME - need to do accounting on a per-thread basis - // on quick sweeps, keep a few pages empty but allocated for performance - if (!current_sweep_full && buffered_pages <= default_collect_interval / GC_PAGE_SZ) { - buffered_pages++; - keep_as_local_buffer = 1; - } - #endif nfree = (GC_PAGE_SZ - GC_PAGE_OFFSET) / osize; gc_page_profile_write_empty_page(s, page_profile_enabled); goto done; @@ -1544,12 +1523,7 @@ static void gc_sweep_page(gc_page_profiler_serializer_t *s, jl_gc_pool_t *p, jl_ } else { gc_alloc_map_set(pg->data, GC_PAGE_LAZILY_FREED); - if (keep_as_local_buffer) { - push_lf_back(buffered, pg); - } - else { - push_lf_back(&global_page_pool_lazily_freed, pg); - } + push_lf_back(&global_page_pool_lazily_freed, pg); } gc_page_profile_write_to_file(s); gc_update_page_fragmentation_data(pg); @@ -1560,15 +1534,14 @@ static void gc_sweep_page(gc_page_profiler_serializer_t *s, jl_gc_pool_t *p, jl_ } // the actual sweeping over all allocated pages in a memory pool -STATIC_INLINE void gc_sweep_pool_page(gc_page_profiler_serializer_t *s, jl_gc_page_stack_t *allocd, jl_gc_page_stack_t *lazily_freed, - jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT +STATIC_INLINE void gc_sweep_pool_page(gc_page_profiler_serializer_t *s, jl_gc_page_stack_t *allocd, jl_gc_pagemeta_t *pg) JL_NOTSAFEPOINT { int p_n = pg->pool_n; int t_n = pg->thread_n; jl_ptls_t ptls2 = gc_all_tls_states[t_n]; jl_gc_pool_t *p = &ptls2->heap.norm_pools[p_n]; int osize = pg->osize; - gc_sweep_page(s, p, allocd, lazily_freed, pg, osize); + gc_sweep_page(s, p, allocd, pg, osize); } // sweep over all memory that is being used and not in a pool @@ -1634,7 +1607,7 @@ int gc_sweep_prescan(jl_ptls_t ptls, jl_gc_padded_page_stack_t *new_gc_allocd_sc push_lf_back_nosync(&tmp, pg); } else { - gc_sweep_pool_page(&serializer, dest, &ptls2->page_metadata_buffered, pg); + gc_sweep_pool_page(&serializer, dest, pg); } if (n_pages_to_scan >= n_pages_worth_parallel_sweep) { break; @@ -1715,7 +1688,7 @@ void gc_sweep_pool_parallel(jl_ptls_t ptls) if (pg == NULL) { continue; } - gc_sweep_pool_page(&serializer, dest, &ptls2->page_metadata_buffered, pg); + gc_sweep_pool_page(&serializer, dest, pg); found_pg = 1; } if (!found_pg) { @@ -1747,21 +1720,45 @@ void gc_sweep_pool_parallel(jl_ptls_t ptls) // free all pages (i.e. through `madvise` on Linux) that were lazily freed void gc_free_pages(void) { + size_t n_pages_seen = 0; + jl_gc_page_stack_t tmp; + memset(&tmp, 0, sizeof(tmp)); while (1) { jl_gc_pagemeta_t *pg = pop_lf_back(&global_page_pool_lazily_freed); if (pg == NULL) { break; } + n_pages_seen++; + // keep the last few pages around for a while + if (n_pages_seen * GC_PAGE_SZ <= default_collect_interval) { + push_lf_back(&tmp, pg); + continue; + } jl_gc_free_page(pg); push_lf_back(&global_page_pool_freed, pg); } + // If concurrent page sweeping is disabled, then `gc_free_pages` will be called in the stop-the-world + // phase. We can guarantee, therefore, that there won't be any concurrent modifications to + // `global_page_pool_lazily_freed`, so it's safe to assign `tmp` back to `global_page_pool_lazily_freed`. + // Otherwise, we need to use the thread-safe push_lf_back/pop_lf_back functions. + if (jl_n_sweepthreads == 0) { + global_page_pool_lazily_freed = tmp; + } + else { + while (1) { + jl_gc_pagemeta_t *pg = pop_lf_back(&tmp); + if (pg == NULL) { + break; + } + push_lf_back(&global_page_pool_lazily_freed, pg); + } + } } // setup the data-structures for a sweep over all memory pools static void gc_sweep_pool(void) { gc_time_pool_start(); - buffered_pages = 0; // For the benefit of the analyzer, which doesn't know that gc_n_threads // doesn't change over the course of this function @@ -1802,12 +1799,6 @@ static void gc_sweep_pool(void) pg->has_young = 1; } } - jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->page_metadata_buffered.bottom); - while (pg != NULL) { - jl_gc_pagemeta_t *pg2 = pg->next; - buffered_pages++; - pg = pg2; - } } // the actual sweeping diff --git a/src/gc.h b/src/gc.h index 666fcc23339b0..bcba63a613b1f 100644 --- a/src/gc.h +++ b/src/gc.h @@ -150,6 +150,8 @@ typedef struct _mallocarray_t { // pool page metadata typedef struct _jl_gc_pagemeta_t { + // next metadata structure in per-thread list + // or in one of the `jl_gc_page_stack_t` struct _jl_gc_pagemeta_t *next; // index of pool that owns this page uint8_t pool_n; diff --git a/src/julia_threads.h b/src/julia_threads.h index 56c74c2cff698..a80084a86f4b3 100644 --- a/src/julia_threads.h +++ b/src/julia_threads.h @@ -261,7 +261,6 @@ typedef struct _jl_tls_states_t { jl_thread_t system_id; arraylist_t finalizers; jl_gc_page_stack_t page_metadata_allocd; - jl_gc_page_stack_t page_metadata_buffered; jl_gc_markqueue_t mark_queue; jl_gc_mark_cache_t gc_cache; arraylist_t sweep_objs; From efd3744de7959361fffe5535da068974f4bcbb40 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Sat, 29 Jun 2024 15:24:32 -0300 Subject: [PATCH 064/109] address a TODO in gc_sweep_page (i.e. save an unnecessary fetch-add) (#54976) --- src/gc.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/gc.c b/src/gc.c index 3411575dd4c16..a1d9cc9e8132f 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1528,9 +1528,16 @@ static void gc_sweep_page(gc_page_profiler_serializer_t *s, jl_gc_pool_t *p, jl_ gc_page_profile_write_to_file(s); gc_update_page_fragmentation_data(pg); gc_time_count_page(freedall, pg_skpd); - jl_ptls_t ptls = gc_all_tls_states[pg->thread_n]; - jl_atomic_fetch_add(&ptls->gc_num.pool_live_bytes, GC_PAGE_SZ - GC_PAGE_OFFSET - nfree * osize); - jl_atomic_fetch_add((_Atomic(int64_t) *)&gc_num.freed, (nfree - old_nfree) * osize); + jl_ptls_t ptls = jl_current_task->ptls; + // Note that we aggregate the `pool_live_bytes` over all threads before returning this + // value to the user. It doesn't matter how the `pool_live_bytes` are partitioned among + // the threads as long as the sum is correct. Let's add the `pool_live_bytes` to the current thread + // instead of adding it to the thread that originally allocated the page, so we can avoid + // an atomic-fetch-add here. + size_t delta = (GC_PAGE_SZ - GC_PAGE_OFFSET - nfree * osize); + jl_atomic_store_relaxed(&ptls->gc_num.pool_live_bytes, + jl_atomic_load_relaxed(&ptls->gc_num.pool_live_bytes) + delta); + jl_atomic_fetch_add_relaxed((_Atomic(int64_t) *)&gc_num.freed, (nfree - old_nfree) * osize); } // the actual sweeping over all allocated pages in a memory pool From 01e101522a027b851dda3b488e2e185609ebaf07 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Mon, 1 Jul 2024 16:28:23 -0300 Subject: [PATCH 065/109] NFC: create an actual set of functions to manipulate GC thread ids (#54984) Also adds a bunch of integrity constraint checks to ensure we don't repeat the bug from https://github.com/JuliaLang/julia/pull/54645. --- src/gc.c | 52 +++++++++++++++++++++++++++++---------------- src/gc.h | 48 +++++++++++++++++++++++++++++++++++++++++ src/julia_threads.h | 6 ++++++ src/partr.c | 13 ++++++------ 4 files changed, 95 insertions(+), 24 deletions(-) diff --git a/src/gc.c b/src/gc.c index a1d9cc9e8132f..42d682b496e98 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1639,9 +1639,11 @@ void gc_sweep_wake_all(jl_ptls_t ptls, jl_gc_padded_page_stack_t *new_gc_allocd_ if (parallel_sweep_worthwhile && !page_profile_enabled) { jl_atomic_store(&gc_allocd_scratch, new_gc_allocd_scratch); uv_mutex_lock(&gc_threads_lock); - for (int i = gc_first_tid; i < gc_first_tid + jl_n_markthreads; i++) { + int first = gc_first_parallel_collector_thread_id(); + int last = gc_last_parallel_collector_thread_id(); + for (int i = first; i <= last; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; - assert(ptls2 != NULL); // should be a GC thread + gc_check_ptls_of_parallel_collector_thread(ptls2); jl_atomic_fetch_add(&ptls2->gc_sweeps_requested, 1); } uv_cond_broadcast(&gc_threads_cond); @@ -1653,9 +1655,11 @@ void gc_sweep_wake_all(jl_ptls_t ptls, jl_gc_padded_page_stack_t *new_gc_allocd_ // collecting a page profile. // wait for all to leave in order to ensure that a straggler doesn't // try to enter sweeping after we set `gc_allocd_scratch` below. - for (int i = gc_first_tid; i < gc_first_tid + jl_n_markthreads; i++) { + int first = gc_first_parallel_collector_thread_id(); + int last = gc_last_parallel_collector_thread_id(); + for (int i = first; i <= last; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; - assert(ptls2 != NULL); // should be a GC thread + gc_check_ptls_of_parallel_collector_thread(ptls2); while (jl_atomic_load_acquire(&ptls2->gc_sweeps_requested) != 0) { jl_cpu_pause(); } @@ -3006,10 +3010,14 @@ void gc_mark_and_steal(jl_ptls_t ptls) // since we know chunks will likely expand into a lot // of work for the mark loop steal : { + int first = gc_first_parallel_collector_thread_id(); + int last = gc_last_parallel_collector_thread_id(); // Try to steal chunk from random GC thread for (int i = 0; i < 4 * jl_n_markthreads; i++) { - uint32_t v = gc_first_tid + cong(UINT64_MAX, UINT64_MAX, &ptls->rngseed) % jl_n_markthreads; - jl_gc_markqueue_t *mq2 = &gc_all_tls_states[v]->mark_queue; + int v = gc_random_parallel_collector_thread_id(ptls); + jl_ptls_t ptls2 = gc_all_tls_states[v]; + gc_check_ptls_of_parallel_collector_thread(ptls2); + jl_gc_markqueue_t *mq2 = &ptls2->mark_queue; c = gc_chunkqueue_steal_from(mq2); if (c.cid != GC_empty_chunk) { gc_mark_chunk(ptls, mq, &c); @@ -3017,8 +3025,10 @@ void gc_mark_and_steal(jl_ptls_t ptls) } } // Sequentially walk GC threads to try to steal chunk - for (int i = gc_first_tid; i < gc_first_tid + jl_n_markthreads; i++) { - jl_gc_markqueue_t *mq2 = &gc_all_tls_states[i]->mark_queue; + for (int i = first; i <= last; i++) { + jl_ptls_t ptls2 = gc_all_tls_states[i]; + gc_check_ptls_of_parallel_collector_thread(ptls2); + jl_gc_markqueue_t *mq2 = &ptls2->mark_queue; c = gc_chunkqueue_steal_from(mq2); if (c.cid != GC_empty_chunk) { gc_mark_chunk(ptls, mq, &c); @@ -3035,15 +3045,19 @@ void gc_mark_and_steal(jl_ptls_t ptls) } // Try to steal pointer from random GC thread for (int i = 0; i < 4 * jl_n_markthreads; i++) { - uint32_t v = gc_first_tid + cong(UINT64_MAX, UINT64_MAX, &ptls->rngseed) % jl_n_markthreads; - jl_gc_markqueue_t *mq2 = &gc_all_tls_states[v]->mark_queue; + int v = gc_random_parallel_collector_thread_id(ptls); + jl_ptls_t ptls2 = gc_all_tls_states[v]; + gc_check_ptls_of_parallel_collector_thread(ptls2); + jl_gc_markqueue_t *mq2 = &ptls2->mark_queue; new_obj = gc_ptr_queue_steal_from(mq2); if (new_obj != NULL) goto mark; } // Sequentially walk GC threads to try to steal pointer - for (int i = gc_first_tid; i < gc_first_tid + jl_n_markthreads; i++) { - jl_gc_markqueue_t *mq2 = &gc_all_tls_states[i]->mark_queue; + for (int i = first; i <= last; i++) { + jl_ptls_t ptls2 = gc_all_tls_states[i]; + gc_check_ptls_of_parallel_collector_thread(ptls2); + jl_gc_markqueue_t *mq2 = &ptls2->mark_queue; new_obj = gc_ptr_queue_steal_from(mq2); if (new_obj != NULL) goto mark; @@ -3103,12 +3117,13 @@ int gc_should_mark(void) } int tid = jl_atomic_load_relaxed(&gc_master_tid); assert(tid != -1); + assert(gc_all_tls_states != NULL); size_t work = gc_count_work_in_queue(gc_all_tls_states[tid]); - for (tid = gc_first_tid; tid < gc_first_tid + jl_n_markthreads; tid++) { - jl_ptls_t ptls2 = gc_all_tls_states[tid]; - if (ptls2 == NULL) { - continue; - } + int first = gc_first_parallel_collector_thread_id(); + int last = gc_last_parallel_collector_thread_id(); + for (int i = first; i <= last; i++) { + jl_ptls_t ptls2 = gc_all_tls_states[i]; + gc_check_ptls_of_parallel_collector_thread(ptls2); work += gc_count_work_in_queue(ptls2); } // if there is a lot of work left, enter the mark loop @@ -3486,7 +3501,8 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) jl_ptls_t ptls_dest = ptls; jl_gc_markqueue_t *mq_dest = mq; if (!single_threaded_mark) { - ptls_dest = gc_all_tls_states[gc_first_tid + t_i % jl_n_markthreads]; + int dest_tid = gc_ith_parallel_collector_thread_id(t_i % jl_n_markthreads); + ptls_dest = gc_all_tls_states[dest_tid]; mq_dest = &ptls_dest->mark_queue; } if (ptls2 != NULL) { diff --git a/src/gc.h b/src/gc.h index bcba63a613b1f..b8da8b81a5423 100644 --- a/src/gc.h +++ b/src/gc.h @@ -439,6 +439,54 @@ extern int gc_first_tid; extern int gc_n_threads; extern jl_ptls_t* gc_all_tls_states; +STATIC_INLINE int gc_first_parallel_collector_thread_id(void) JL_NOTSAFEPOINT +{ + if (jl_n_markthreads == 0) { + return 0; + } + return gc_first_tid; +} + +STATIC_INLINE int gc_last_parallel_collector_thread_id(void) JL_NOTSAFEPOINT +{ + if (jl_n_markthreads == 0) { + return -1; + } + return gc_first_tid + jl_n_markthreads - 1; +} + +STATIC_INLINE int gc_ith_parallel_collector_thread_id(int i) JL_NOTSAFEPOINT +{ + assert(i >= 0 && i < jl_n_markthreads); + return gc_first_tid + i; +} + +STATIC_INLINE int gc_is_parallel_collector_thread(int tid) JL_NOTSAFEPOINT +{ + return tid >= gc_first_tid && tid <= gc_last_parallel_collector_thread_id(); +} + +STATIC_INLINE int gc_random_parallel_collector_thread_id(jl_ptls_t ptls) JL_NOTSAFEPOINT +{ + assert(jl_n_markthreads > 0); + int v = gc_first_tid + (int)cong(jl_n_markthreads, UINT64_MAX, &ptls->rngseed); + assert(v >= gc_first_tid && v <= gc_last_parallel_collector_thread_id()); + return v; +} + +STATIC_INLINE int gc_parallel_collector_threads_enabled(void) JL_NOTSAFEPOINT +{ + return jl_n_markthreads > 0; +} + +STATIC_INLINE void gc_check_ptls_of_parallel_collector_thread(jl_ptls_t ptls) JL_NOTSAFEPOINT +{ + (void)ptls; + assert(gc_parallel_collector_threads_enabled()); + assert(ptls != NULL); + assert(jl_atomic_load_relaxed(&ptls->gc_state) == JL_GC_PARALLEL_COLLECTOR_THREAD); +} + STATIC_INLINE bigval_t *bigval_header(jl_taggedvalue_t *o) JL_NOTSAFEPOINT { return container_of(o, bigval_t, header); diff --git a/src/julia_threads.h b/src/julia_threads.h index a80084a86f4b3..f6dbb7763b63e 100644 --- a/src/julia_threads.h +++ b/src/julia_threads.h @@ -215,6 +215,10 @@ typedef struct _jl_tls_states_t { #define JL_GC_STATE_SAFE 2 // gc_state = 2 means the thread is running unmanaged code that can be // execute at the same time with the GC. +#define JL_GC_PARALLEL_COLLECTOR_THREAD 3 + // gc_state = 3 means the thread is a parallel collector thread (i.e. never runs Julia code) +#define JL_GC_CONCURRENT_COLLECTOR_THREAD 4 + // gc_state = 4 means the thread is a concurrent collector thread (background sweeper thread that never runs Julia code) _Atomic(int8_t) gc_state; // read from foreign threads // execution of certain certain impure // statements is prohibited from certain @@ -343,6 +347,8 @@ void jl_sigint_safepoint(jl_ptls_t tls); STATIC_INLINE int8_t jl_gc_state_set(jl_ptls_t ptls, int8_t state, int8_t old_state) { + assert(old_state != JL_GC_PARALLEL_COLLECTOR_THREAD); + assert(old_state != JL_GC_CONCURRENT_COLLECTOR_THREAD); jl_atomic_store_release(&ptls->gc_state, state); // A safe point is required if we transition from GC-safe region to // non GC-safe region. diff --git a/src/partr.c b/src/partr.c index f8a87ac9bbc1b..b0b4ee77a9ec5 100644 --- a/src/partr.c +++ b/src/partr.c @@ -131,7 +131,7 @@ void jl_parallel_gc_threadfun(void *arg) jl_task_t *ct = jl_init_root_task(ptls, stack_lo, stack_hi); JL_GC_PROMISE_ROOTED(ct); // wait for all threads - jl_gc_state_set(ptls, JL_GC_STATE_WAITING, 0); + jl_gc_state_set(ptls, JL_GC_PARALLEL_COLLECTOR_THREAD, 0); uv_barrier_wait(targ->barrier); // free the thread argument here @@ -143,10 +143,10 @@ void jl_parallel_gc_threadfun(void *arg) uv_cond_wait(&gc_threads_cond, &gc_threads_lock); } uv_mutex_unlock(&gc_threads_lock); - if (may_mark()) { - gc_mark_loop_parallel(ptls, 0); - } - if (may_sweep(ptls)) { // not an else! + assert(jl_atomic_load_relaxed(&ptls->gc_state) == JL_GC_PARALLEL_COLLECTOR_THREAD); + gc_mark_loop_parallel(ptls, 0); + if (may_sweep(ptls)) { + assert(jl_atomic_load_relaxed(&ptls->gc_state) == JL_GC_PARALLEL_COLLECTOR_THREAD); gc_sweep_pool_parallel(ptls); jl_atomic_fetch_add(&ptls->gc_sweeps_requested, -1); } @@ -166,13 +166,14 @@ void jl_concurrent_gc_threadfun(void *arg) jl_task_t *ct = jl_init_root_task(ptls, stack_lo, stack_hi); JL_GC_PROMISE_ROOTED(ct); // wait for all threads - jl_gc_state_set(ptls, JL_GC_STATE_WAITING, 0); + jl_gc_state_set(ptls, JL_GC_CONCURRENT_COLLECTOR_THREAD, 0); uv_barrier_wait(targ->barrier); // free the thread argument here free(targ); while (1) { + assert(jl_atomic_load_relaxed(&ptls->gc_state) == JL_GC_CONCURRENT_COLLECTOR_THREAD); uv_sem_wait(&gc_sweep_assists_needed); gc_free_pages(); } From abdd89434414af909dc09b2b375f83fd593b186b Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Tue, 2 Jul 2024 16:32:22 -0300 Subject: [PATCH 066/109] remove stale objprofile (#54991) As mentioned in https://github.com/JuliaLang/julia/issues/54968, `OBJPROFILE` exposes a functionality which is quite similar to what the heap snapshot does, but has a considerably worse visualization tool (i.e. raw printf's compared to the snapshot viewer from Chrome). Closes https://github.com/JuliaLang/julia/issues/54968. --- src/gc-debug.c | 92 -------------------------------------------------- src/gc.c | 24 ------------- src/gc.h | 18 ---------- src/options.h | 3 -- 4 files changed, 137 deletions(-) diff --git a/src/gc-debug.c b/src/gc-debug.c index 1f1aca1a467f5..6faee6b1de97f 100644 --- a/src/gc-debug.c +++ b/src/gc-debug.c @@ -603,91 +603,6 @@ void jl_gc_debug_print_status(void) } #endif -#ifdef OBJPROFILE -static htable_t obj_counts[3]; -static htable_t obj_sizes[3]; -void objprofile_count(void *ty, int old, int sz) -{ - if (gc_verifying) return; - if ((intptr_t)ty <= 0x10) { - ty = (void*)jl_buff_tag; - } - else if (ty != (void*)jl_buff_tag && ty != jl_malloc_tag && - jl_typeof(ty) == (jl_value_t*)jl_datatype_type && - ((jl_datatype_t*)ty)->instance) { - ty = jl_singleton_tag; - } - void **bp = ptrhash_bp(&obj_counts[old], ty); - if (*bp == HT_NOTFOUND) - *bp = (void*)2; - else - (*((intptr_t*)bp))++; - bp = ptrhash_bp(&obj_sizes[old], ty); - if (*bp == HT_NOTFOUND) - *bp = (void*)(intptr_t)(1 + sz); - else - *((intptr_t*)bp) += sz; -} - -void objprofile_reset(void) -{ - for (int g = 0; g < 3; g++) { - htable_reset(&obj_counts[g], 0); - htable_reset(&obj_sizes[g], 0); - } -} - -static void objprofile_print(htable_t nums, htable_t sizes) -{ - for(int i=0; i < nums.size; i+=2) { - if (nums.table[i+1] != HT_NOTFOUND) { - void *ty = nums.table[i]; - int num = (intptr_t)nums.table[i + 1] - 1; - size_t sz = (uintptr_t)ptrhash_get(&sizes, ty) - 1; - static const int ptr_hex_width = 2 * sizeof(void*); - if (sz > 2e9) { - jl_safe_printf(" %6d : %*.1f GB of (%*p) ", - num, 6, ((double)sz) / 1024 / 1024 / 1024, - ptr_hex_width, ty); - } - else if (sz > 2e6) { - jl_safe_printf(" %6d : %*.1f MB of (%*p) ", - num, 6, ((double)sz) / 1024 / 1024, - ptr_hex_width, ty); - } - else if (sz > 2e3) { - jl_safe_printf(" %6d : %*.1f kB of (%*p) ", - num, 6, ((double)sz) / 1024, - ptr_hex_width, ty); - } - else { - jl_safe_printf(" %6d : %*d B of (%*p) ", - num, 6, (int)sz, ptr_hex_width, ty); - } - if (ty == (void*)jl_buff_tag) - jl_safe_printf("#"); - else if (ty == jl_malloc_tag) - jl_safe_printf("#"); - else if (ty == jl_singleton_tag) - jl_safe_printf("#"); - else - jl_static_show(JL_STDERR, (jl_value_t*)ty); - jl_safe_printf("\n"); - } - } -} - -void objprofile_printall(void) -{ - jl_safe_printf("Transient mark :\n"); - objprofile_print(obj_counts[0], obj_sizes[0]); - jl_safe_printf("Perm mark :\n"); - objprofile_print(obj_counts[1], obj_sizes[1]); - jl_safe_printf("Remset :\n"); - objprofile_print(obj_counts[2], obj_sizes[2]); -} -#endif - #if defined(GC_TIME) || defined(GC_FINAL_STATS) STATIC_INLINE double jl_ns2ms(int64_t t) { @@ -996,13 +911,6 @@ void jl_gc_debug_init(void) arraylist_new(&lostval_parents_done, 0); #endif -#ifdef OBJPROFILE - for (int g = 0; g < 3; g++) { - htable_new(&obj_counts[g], 0); - htable_new(&obj_sizes[g], 0); - } -#endif - #ifdef GC_FINAL_STATS process_t0 = jl_hrtime(); #endif diff --git a/src/gc.c b/src/gc.c index 42d682b496e98..a3b18effc3b8a 100644 --- a/src/gc.c +++ b/src/gc.c @@ -861,8 +861,6 @@ STATIC_INLINE void gc_setmark_big(jl_ptls_t ptls, jl_taggedvalue_t *o, gc_queue_big_marked(ptls, hdr, 1); } } - objprofile_count(jl_typeof(jl_valueof(o)), - mark_mode == GC_OLD_MARKED, hdr->sz); } // This function should be called exactly once during marking for each pool @@ -884,8 +882,6 @@ STATIC_INLINE void gc_setmark_pool_(jl_ptls_t ptls, jl_taggedvalue_t *o, page->has_young = 1; } } - objprofile_count(jl_typeof(jl_valueof(o)), - mark_mode == GC_OLD_MARKED, page->osize); page->has_marked = 1; #endif } @@ -2677,8 +2673,6 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_ size_t dtsz = l * sizeof(void *) + sizeof(jl_svec_t); if (update_meta) gc_setmark(ptls, o, bits, dtsz); - else if (foreign_alloc) - objprofile_count(jl_simplevector_type, bits == GC_OLD_MARKED, dtsz); jl_value_t *objary_parent = new_obj; jl_value_t **objary_begin = data; jl_value_t **objary_end = data + l; @@ -2689,8 +2683,6 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_ else if (vtag == jl_module_tag << 4) { if (update_meta) gc_setmark(ptls, o, bits, sizeof(jl_module_t)); - else if (foreign_alloc) - objprofile_count(jl_module_type, bits == GC_OLD_MARKED, sizeof(jl_module_t)); jl_module_t *mb_parent = (jl_module_t *)new_obj; uintptr_t nptr = ((mb_parent->usings.len + 1) << 2) | (bits & GC_OLD); gc_mark_module_binding(ptls, mb_parent, nptr, bits); @@ -2698,8 +2690,6 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_ else if (vtag == jl_task_tag << 4) { if (update_meta) gc_setmark(ptls, o, bits, sizeof(jl_task_t)); - else if (foreign_alloc) - objprofile_count(jl_task_type, bits == GC_OLD_MARKED, sizeof(jl_task_t)); jl_task_t *ta = (jl_task_t *)new_obj; gc_scrub_record_task(ta); if (gc_cblist_task_scanner) { @@ -2768,16 +2758,12 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_ size_t dtsz = jl_string_len(new_obj) + sizeof(size_t) + 1; if (update_meta) gc_setmark(ptls, o, bits, dtsz); - else if (foreign_alloc) - objprofile_count(jl_string_type, bits == GC_OLD_MARKED, dtsz); } else { jl_datatype_t *vt = ijl_small_typeof[vtag / sizeof(*ijl_small_typeof)]; size_t dtsz = jl_datatype_size(vt); if (update_meta) gc_setmark(ptls, o, bits, dtsz); - else if (foreign_alloc) - objprofile_count(vt, bits == GC_OLD_MARKED, dtsz); } return; } @@ -2796,9 +2782,6 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_ else gc_setmark_big(ptls, o, bits); } - else if (foreign_alloc) { - objprofile_count(vt, bits == GC_OLD_MARKED, sizeof(jl_array_t)); - } if (flags.how == 0) { void *data_ptr = (char*)a + sizeof(jl_array_t) +jl_array_ndimwords(a->flags.ndims) * sizeof(size_t); gc_heap_snapshot_record_hidden_edge(new_obj, data_ptr, jl_array_nbytes(a), 2); @@ -2813,8 +2796,6 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_ } else if (flags.how == 2) { if (update_meta || foreign_alloc) { - objprofile_count(jl_malloc_tag, bits == GC_OLD_MARKED, - jl_array_nbytes(a)); gc_heap_snapshot_record_hidden_edge(new_obj, a->data, jl_array_nbytes(a), flags.pooled); if (bits == GC_OLD_MARKED) { ptls->gc_cache.perm_scanned_bytes += jl_array_nbytes(a); @@ -2881,8 +2862,6 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_ size_t dtsz = jl_datatype_size(vt); if (update_meta) gc_setmark(ptls, o, bits, dtsz); - else if (foreign_alloc) - objprofile_count(vt, bits == GC_OLD_MARKED, dtsz); if (vt == jl_weakref_type) return; const jl_datatype_layout_t *layout = vt->layout; @@ -3221,7 +3200,6 @@ static void gc_premark(jl_ptls_t ptls2) void **items = remset->items; for (size_t i = 0; i < len; i++) { jl_value_t *item = (jl_value_t *)items[i]; - objprofile_count(jl_typeof(item), 2, 0); jl_astaggedvalue(item)->bits.gc = GC_OLD_MARKED; } } @@ -3586,8 +3564,6 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) gc_stats_all_pool(); gc_stats_big_obj(); - objprofile_printall(); - objprofile_reset(); gc_num.total_allocd += gc_num.allocd; if (!prev_sweep_full) promoted_bytes += perm_scanned_bytes - last_perm_scanned_bytes; diff --git a/src/gc.h b/src/gc.h index b8da8b81a5423..1a74d334c98f4 100644 --- a/src/gc.h +++ b/src/gc.h @@ -720,24 +720,6 @@ static inline void gc_scrub(void) } #endif -#ifdef OBJPROFILE -void objprofile_count(void *ty, int old, int sz) JL_NOTSAFEPOINT; -void objprofile_printall(void); -void objprofile_reset(void); -#else -static inline void objprofile_count(void *ty, int old, int sz) JL_NOTSAFEPOINT -{ -} - -static inline void objprofile_printall(void) -{ -} - -static inline void objprofile_reset(void) -{ -} -#endif - #ifdef MEMPROFILE void gc_stats_all_pool(void); void gc_stats_big_obj(void); diff --git a/src/options.h b/src/options.h index f4a052ddc1cb4..285f849eee216 100644 --- a/src/options.h +++ b/src/options.h @@ -75,9 +75,6 @@ // GC_TIME prints time taken by each phase of GC // #define GC_TIME -// OBJPROFILE counts objects by type -// #define OBJPROFILE - // pool allocator configuration options // GC_SMALL_PAGE allocates objects in 4k pages From 6b0d990c23d099d87d8ee30e4c053c0e30503026 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Wed, 3 Jul 2024 20:00:43 -0300 Subject: [PATCH 067/109] delete possibly stale reset_gc_stats (#55015) See discussion in https://github.com/JuliaLang/julia/issues/55014. Doesn't seem breaking, but I can close the PR if it is. Closes https://github.com/JuliaLang/julia/issues/55014. --- base/timing.jl | 1 - src/gc.c | 7 ------- 2 files changed, 8 deletions(-) diff --git a/base/timing.jl b/base/timing.jl index 4b14161aa89d2..bdbb32936b56f 100644 --- a/base/timing.jl +++ b/base/timing.jl @@ -29,7 +29,6 @@ struct GC_Num end gc_num() = ccall(:jl_gc_num, GC_Num, ()) -reset_gc_stats() = ccall(:jl_gc_reset_stats, Cvoid, ()) # This type is to represent differences in the counters, so fields may be negative struct GC_Diff diff --git a/src/gc.c b/src/gc.c index a3b18effc3b8a..2b2c0f132f622 100644 --- a/src/gc.c +++ b/src/gc.c @@ -3399,13 +3399,6 @@ JL_DLLEXPORT jl_gc_num_t jl_gc_num(void) return num; } -JL_DLLEXPORT void jl_gc_reset_stats(void) -{ - gc_num.max_pause = 0; - gc_num.max_memory = 0; - gc_num.max_time_to_safepoint = 0; -} - // TODO: these were supposed to be thread local JL_DLLEXPORT int64_t jl_gc_diff_total_bytes(void) JL_NOTSAFEPOINT { From a19c7b196e32fb419bd628da93aaa90a15e423b9 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Fri, 5 Jul 2024 11:23:31 -0300 Subject: [PATCH 068/109] remove unused jl_gc_alloc_*w (#55026) Closes https://github.com/JuliaLang/julia/issues/55024. --- src/gc.c | 24 ------------------------ src/jl_exported_funcs.inc | 4 ---- src/julia.h | 4 ---- src/runtime_intrinsics.c | 3 +-- 4 files changed, 1 insertion(+), 34 deletions(-) diff --git a/src/gc.c b/src/gc.c index 2b2c0f132f622..3c1c69b6493c2 100644 --- a/src/gc.c +++ b/src/gc.c @@ -4308,30 +4308,6 @@ JL_DLLEXPORT jl_value_t *jl_gc_allocobj(size_t sz) return jl_gc_alloc(ptls, sz, NULL); } -JL_DLLEXPORT jl_value_t *jl_gc_alloc_0w(void) -{ - jl_ptls_t ptls = jl_current_task->ptls; - return jl_gc_alloc(ptls, 0, NULL); -} - -JL_DLLEXPORT jl_value_t *jl_gc_alloc_1w(void) -{ - jl_ptls_t ptls = jl_current_task->ptls; - return jl_gc_alloc(ptls, sizeof(void*), NULL); -} - -JL_DLLEXPORT jl_value_t *jl_gc_alloc_2w(void) -{ - jl_ptls_t ptls = jl_current_task->ptls; - return jl_gc_alloc(ptls, sizeof(void*) * 2, NULL); -} - -JL_DLLEXPORT jl_value_t *jl_gc_alloc_3w(void) -{ - jl_ptls_t ptls = jl_current_task->ptls; - return jl_gc_alloc(ptls, sizeof(void*) * 3, NULL); -} - JL_DLLEXPORT int jl_gc_enable_conservative_gc_support(void) { if (jl_is_initialized()) { diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index f52ef7f794442..a98158f3d3e5e 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -152,10 +152,6 @@ XX(jl_gc_add_ptr_finalizer) \ XX(jl_gc_add_quiescent) \ XX(jl_gc_allocobj) \ - XX(jl_gc_alloc_0w) \ - XX(jl_gc_alloc_1w) \ - XX(jl_gc_alloc_2w) \ - XX(jl_gc_alloc_3w) \ XX(jl_gc_alloc_typed) \ XX(jl_gc_big_alloc) \ XX(jl_gc_big_alloc_instrumented) \ diff --git a/src/julia.h b/src/julia.h index 1f85f06dd35dc..096b01ad23de2 100644 --- a/src/julia.h +++ b/src/julia.h @@ -998,10 +998,6 @@ JL_DLLEXPORT void jl_gc_add_ptr_finalizer(jl_ptls_t ptls, jl_value_t *v, void *f JL_DLLEXPORT void jl_gc_add_quiescent(jl_ptls_t ptls, void **v, void *f) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_finalize(jl_value_t *o); JL_DLLEXPORT jl_weakref_t *jl_gc_new_weakref(jl_value_t *value); -JL_DLLEXPORT jl_value_t *jl_gc_alloc_0w(void); -JL_DLLEXPORT jl_value_t *jl_gc_alloc_1w(void); -JL_DLLEXPORT jl_value_t *jl_gc_alloc_2w(void); -JL_DLLEXPORT jl_value_t *jl_gc_alloc_3w(void); JL_DLLEXPORT jl_value_t *jl_gc_allocobj(size_t sz); JL_DLLEXPORT void *jl_malloc_stack(size_t *bufsz, struct _jl_task_t *owner) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_free_stack(void *stkbuf, size_t bufsz); diff --git a/src/runtime_intrinsics.c b/src/runtime_intrinsics.c index 844a5ca8338c7..2d99521a82802 100644 --- a/src/runtime_intrinsics.c +++ b/src/runtime_intrinsics.c @@ -513,8 +513,7 @@ JL_DLLEXPORT jl_value_t *jl_cglobal(jl_value_t *v, jl_value_t *ty) void *ptr; jl_dlsym(jl_get_library(f_lib), f_name, &ptr, 1); - jl_value_t *jv = jl_gc_alloc_1w(); - jl_set_typeof(jv, rt); + jl_value_t *jv = jl_gc_alloc(jl_current_task->ptls, sizeof(void*), rt); *(void**)jl_data_ptr(jv) = ptr; JL_GC_POP(); return jv; From c8f56c69b3ad8905295ce77b1c82d511aedd7dde Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Fri, 5 Jul 2024 22:30:00 -0300 Subject: [PATCH 069/109] cleanup remset logic a bit (#55021) I think that keeping a single `remset` (instead of two and keep alternating between them) should be a bit easier to understand and possibly even a bit faster (since we will be accessing the `remset` only once), though that should be a very small difference. --- src/gc.c | 87 +++++++++++++++++++-------------------------- src/julia_threads.h | 6 ++-- 2 files changed, 39 insertions(+), 54 deletions(-) diff --git a/src/gc.c b/src/gc.c index 3c1c69b6493c2..71d66a3eefff6 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1895,7 +1895,7 @@ JL_DLLEXPORT void jl_gc_queue_root(const jl_value_t *ptr) // which is not idempotent. See comments in https://github.com/JuliaLang/julia/issues/50419 uintptr_t header = jl_atomic_fetch_and_relaxed((_Atomic(uintptr_t) *)&o->header, ~GC_OLD); if (header & GC_OLD) { // write barrier has not been triggered in this object yet - arraylist_push(ptls->heap.remset, (jl_value_t*)ptr); + arraylist_push(&ptls->heap.remset, (jl_value_t*)ptr); ptls->heap.remset_nptr++; // conservative } } @@ -2002,7 +2002,7 @@ STATIC_INLINE void gc_mark_push_remset(jl_ptls_t ptls, jl_value_t *obj, { if (__unlikely((nptr & 0x3) == 0x3)) { ptls->heap.remset_nptr += nptr >> 2; - arraylist_t *remset = ptls->heap.remset; + arraylist_t *remset = &ptls->heap.remset; size_t len = remset->len; if (__unlikely(len >= remset->max)) { arraylist_push(remset, obj); @@ -3187,23 +3187,6 @@ void gc_mark_clean_reclaim_sets(void) } } -static void gc_premark(jl_ptls_t ptls2) -{ - arraylist_t *remset = ptls2->heap.remset; - ptls2->heap.remset = ptls2->heap.last_remset; - ptls2->heap.last_remset = remset; - ptls2->heap.remset->len = 0; - ptls2->heap.remset_nptr = 0; - // avoid counting remembered objects - // in `perm_scanned_bytes` - size_t len = remset->len; - void **items = remset->items; - for (size_t i = 0; i < len; i++) { - jl_value_t *item = (jl_value_t *)items[i]; - jl_astaggedvalue(item)->bits.gc = GC_OLD_MARKED; - } -} - static void gc_queue_thread_local(jl_gc_markqueue_t *mq, jl_ptls_t ptls2) { jl_task_t *task; @@ -3247,14 +3230,29 @@ static void gc_queue_bt_buf(jl_gc_markqueue_t *mq, jl_ptls_t ptls2) } } -static void gc_queue_remset(jl_ptls_t ptls, jl_ptls_t ptls2) +static void gc_queue_remset(jl_gc_markqueue_t *mq, jl_ptls_t ptls2) { - size_t len = ptls2->heap.last_remset->len; - void **items = ptls2->heap.last_remset->items; + void **items = ptls2->heap.remset.items; + size_t len = ptls2->heap.remset.len; for (size_t i = 0; i < len; i++) { - // Tag the pointer to indicate it's in the remset - jl_value_t *v = (jl_value_t *)((uintptr_t)items[i] | GC_REMSET_PTR_TAG); - gc_ptr_queue_push(&ptls->mark_queue, v); + void *_v = items[i]; + jl_astaggedvalue(_v)->bits.gc = GC_OLD_MARKED; + jl_value_t *v = (jl_value_t *)((uintptr_t)_v | GC_REMSET_PTR_TAG); + gc_ptr_queue_push(mq, v); + } + // Don't forget to clear the remset + ptls2->heap.remset.len = 0; + ptls2->heap.remset_nptr = 0; +} + +static void gc_check_all_remsets_are_empty(void) +{ + for (int i = 0; i < gc_n_threads; i++) { + jl_ptls_t ptls2 = gc_all_tls_states[i]; + if (ptls2 != NULL) { + assert(ptls2->heap.remset.len == 0); + assert(ptls2->heap.remset_nptr == 0); + } } } @@ -3456,15 +3454,6 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) JL_PROBE_GC_MARK_BEGIN(); { JL_TIMING(GC, GC_Mark); - - // 1. fix GC bits of objects in the remset. - assert(gc_n_threads); - for (int t_i = 0; t_i < gc_n_threads; t_i++) { - jl_ptls_t ptls2 = gc_all_tls_states[t_i]; - if (ptls2 != NULL) - gc_premark(ptls2); - } - assert(gc_n_threads); int single_threaded_mark = (jl_n_markthreads == 0 || gc_heap_snapshot_enabled); for (int t_i = 0; t_i < gc_n_threads; t_i++) { @@ -3477,17 +3466,18 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) mq_dest = &ptls_dest->mark_queue; } if (ptls2 != NULL) { - // 2.1. mark every thread local root + // 1.1. mark every thread local root gc_queue_thread_local(mq_dest, ptls2); - // 2.2. mark any managed objects in the backtrace buffer + // 1.2. mark any managed objects in the backtrace buffer // TODO: treat these as roots for gc_heap_snapshot_record gc_queue_bt_buf(mq_dest, ptls2); - // 2.3. mark every object in the `last_remsets` and `rem_binding` - gc_queue_remset(ptls_dest, ptls2); + // 1.3. mark every object in the remset + gc_queue_remset(mq_dest, ptls2); } } + gc_check_all_remsets_are_empty(); - // 3. walk roots + // 2. walk roots gc_mark_roots(mq); if (gc_cblist_root_scanner) { gc_invoke_callbacks(jl_gc_cb_root_scanner_t, @@ -3497,7 +3487,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) gc_mark_loop_barrier(); gc_mark_clean_reclaim_sets(); - // 4. check for objects to finalize + // 3. check for objects to finalize clear_weak_refs(); // Record the length of the marked list since we need to // mark the object moved to the marked list from the @@ -3560,7 +3550,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) gc_num.total_allocd += gc_num.allocd; if (!prev_sweep_full) promoted_bytes += perm_scanned_bytes - last_perm_scanned_bytes; - // 5. next collection decision + // 4. next collection decision int not_freed_enough = (collection == JL_GC_AUTO) && estimate_freed < (7*(actual_allocd/10)); int nptr = 0; assert(gc_n_threads); @@ -3619,7 +3609,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) last_long_collect_interval = gc_num.interval; } scanned_bytes = 0; - // 6. start sweeping + // 5. start sweeping uint64_t start_sweep_time = jl_hrtime(); JL_PROBE_GC_SWEEP_BEGIN(sweep_full); { @@ -3658,7 +3648,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) } // sweeping is over - // 7. if it is a quick sweep, put back the remembered objects in queued state + // 6. if it is a quick sweep, put back the remembered objects in queued state // so that we don't trigger the barrier again on them. assert(gc_n_threads); for (int t_i = 0; t_i < gc_n_threads; t_i++) { @@ -3666,13 +3656,13 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) if (ptls2 == NULL) continue; if (!sweep_full) { - for (int i = 0; i < ptls2->heap.remset->len; i++) { - void *ptr = ptls2->heap.remset->items[i]; + for (int i = 0; i < ptls2->heap.remset.len; i++) { + void *ptr = ptls2->heap.remset.items[i]; jl_astaggedvalue(ptr)->bits.gc = GC_MARKED; } } else { - ptls2->heap.remset->len = 0; + ptls2->heap.remset.len = 0; } } @@ -3887,10 +3877,7 @@ void jl_init_thread_heap(jl_ptls_t ptls) heap->mallocarrays = NULL; heap->mafreelist = NULL; heap->big_objects = NULL; - heap->remset = &heap->_remset[0]; - heap->last_remset = &heap->_remset[1]; - arraylist_new(heap->remset, 0); - arraylist_new(heap->last_remset, 0); + arraylist_new(&heap->remset, 0); arraylist_new(&ptls->finalizers, 0); arraylist_new(&ptls->sweep_objs, 0); diff --git a/src/julia_threads.h b/src/julia_threads.h index f6dbb7763b63e..9bca500604b0e 100644 --- a/src/julia_threads.h +++ b/src/julia_threads.h @@ -153,12 +153,10 @@ typedef struct { // variables for tracking big objects struct _bigval_t *big_objects; - // variables for tracking "remembered set" - arraylist_t _remset[2]; // contains jl_value_t* // lower bound of the number of pointers inside remembered values int remset_nptr; - arraylist_t *remset; - arraylist_t *last_remset; + // remembered set + arraylist_t remset; // variables for allocating objects from pools #define JL_GC_N_MAX_POOLS 51 // conservative. must be kept in sync with `src/julia_internal.h` From 145375dddfa714771d257d040a778cf3e4b7c16d Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Fri, 12 Jul 2024 15:48:57 -0300 Subject: [PATCH 070/109] change memory parameters to signed integers to prevent signed to unsigned comparison (#167) --- src/gc.c | 24 ++++++++++++++---------- src/julia.h | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/gc.c b/src/gc.c index 71d66a3eefff6..ec43e6b6db600 100644 --- a/src/gc.c +++ b/src/gc.c @@ -681,16 +681,16 @@ static int64_t last_gc_total_bytes = 0; // max_total_memory is a suggestion. We try very hard to stay // under this limit, but we will go above it rather than halting. #ifdef _P64 -typedef uint64_t memsize_t; -static const size_t default_collect_interval = 5600 * 1024 * sizeof(void*); -static const size_t max_collect_interval = 1250000000UL; -static size_t total_mem; +typedef int64_t memsize_t; +static const int64_t default_collect_interval = 5600 * 1024 * sizeof(void*); +static const int64_t max_collect_interval = 1250000000UL; +static int64_t total_mem; // We expose this to the user/ci as jl_gc_set_max_memory static memsize_t max_total_memory = (memsize_t) 2 * 1024 * 1024 * 1024 * 1024 * 1024; #else -typedef uint32_t memsize_t; -static const size_t default_collect_interval = 3200 * 1024 * sizeof(void*); -static const size_t max_collect_interval = 500000000UL; +typedef int32_t memsize_t; +static const int32_t default_collect_interval = 3200 * 1024 * sizeof(void*); +static const int32_t max_collect_interval = 500000000UL; // Work really hard to stay within 2GB // Alternative is to risk running out of address space // on 32 bit architectures. @@ -3948,13 +3948,17 @@ void jl_gc_init(void) JL_DLLEXPORT void jl_gc_set_max_memory(uint64_t max_mem) { - if (max_mem > 0 - && max_mem < (uint64_t)1 << (sizeof(memsize_t) * 8 - 1)) { +#ifdef _P64 + const int64_t max_allowed_value = INT64_MAX; +#else + const int32_t max_allowed_value = INT32_MAX; +#endif + if (max_mem > 0 && max_mem < max_allowed_value) { max_total_memory = max_mem; } } -JL_DLLEXPORT uint64_t jl_gc_get_max_memory(void) +JL_DLLEXPORT int64_t jl_gc_get_max_memory(void) { return max_total_memory; } diff --git a/src/julia.h b/src/julia.h index 096b01ad23de2..fb188785176d1 100644 --- a/src/julia.h +++ b/src/julia.h @@ -1004,7 +1004,7 @@ JL_DLLEXPORT void jl_free_stack(void *stkbuf, size_t bufsz); JL_DLLEXPORT void jl_gc_use(jl_value_t *a); // Set GC memory trigger in bytes for greedy memory collecting JL_DLLEXPORT void jl_gc_set_max_memory(uint64_t max_mem); -JL_DLLEXPORT uint64_t jl_gc_get_max_memory(void); +JL_DLLEXPORT int64_t jl_gc_get_max_memory(void); JL_DLLEXPORT void jl_clear_malloc_data(void); From 14b94415c3cbda093c6c89c10a3e0d49de3aaf4c Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Tue, 9 Jul 2024 17:57:24 -0300 Subject: [PATCH 071/109] drop jl_gc_pool_alloc in favor of instrumented version (#55085) And do some re-naming. --- src/gc.c | 23 ++++------------------- src/jl_exported_funcs.inc | 2 -- src/llvm-pass-helpers.cpp | 4 ++-- test/llvmpasses/alloc-opt-gcframe.ll | 10 +++++----- test/llvmpasses/final-lower-gc.ll | 4 ++-- test/llvmpasses/julia-licm-fail.ll | 2 +- test/llvmpasses/julia-licm-missed.ll | 2 +- test/llvmpasses/julia-licm.ll | 2 +- 8 files changed, 16 insertions(+), 33 deletions(-) diff --git a/src/gc.c b/src/gc.c index ec43e6b6db600..3b83ce13c4732 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1027,15 +1027,9 @@ STATIC_INLINE jl_value_t *jl_gc_big_alloc_inner(jl_ptls_t ptls, size_t sz) return jl_valueof(&v->header); } -// Deprecated version, supported for legacy code. -JL_DLLEXPORT jl_value_t *jl_gc_big_alloc(jl_ptls_t ptls, size_t sz) -{ - jl_value_t *val = jl_gc_big_alloc_inner(ptls, sz); - maybe_record_alloc_to_profile(val, sz, jl_gc_unknown_type_tag); - return val; -} + // Instrumented version of jl_gc_big_alloc_inner, called into by LLVM-generated code. -JL_DLLEXPORT jl_value_t *jl_gc_big_alloc_instrumented(jl_ptls_t ptls, size_t sz, jl_value_t *type) +JL_DLLEXPORT jl_value_t *jl_gc_big_alloc(jl_ptls_t ptls, size_t sz, jl_value_t *type) { jl_value_t *val = jl_gc_big_alloc_inner(ptls, sz); maybe_record_alloc_to_profile(val, sz, (jl_datatype_t*)type); @@ -1299,7 +1293,7 @@ STATIC_INLINE jl_value_t *jl_gc_pool_alloc_inner(jl_ptls_t ptls, int pool_offset jl_gc_pool_t *p = (jl_gc_pool_t*)((char*)ptls + pool_offset); assert(jl_atomic_load_relaxed(&ptls->gc_state) == 0); #ifdef MEMDEBUG - return jl_gc_big_alloc(ptls, osize); + return jl_gc_big_alloc(ptls, osize, NULL); #endif maybe_collect(ptls); jl_atomic_store_relaxed(&ptls->gc_num.allocd, @@ -1347,17 +1341,8 @@ STATIC_INLINE jl_value_t *jl_gc_pool_alloc_inner(jl_ptls_t ptls, int pool_offset return jl_valueof(v); } -// Deprecated version, supported for legacy code. -JL_DLLEXPORT jl_value_t *jl_gc_pool_alloc(jl_ptls_t ptls, int pool_offset, - int osize) -{ - jl_value_t *val = jl_gc_pool_alloc_inner(ptls, pool_offset, osize); - maybe_record_alloc_to_profile(val, osize, jl_gc_unknown_type_tag); - return val; -} // Instrumented version of jl_gc_pool_alloc_inner, called into by LLVM-generated code. -JL_DLLEXPORT jl_value_t *jl_gc_pool_alloc_instrumented(jl_ptls_t ptls, int pool_offset, - int osize, jl_value_t* type) +JL_DLLEXPORT jl_value_t *jl_gc_pool_alloc(jl_ptls_t ptls, int pool_offset, int osize, jl_value_t* type) { jl_value_t *val = jl_gc_pool_alloc_inner(ptls, pool_offset, osize); maybe_record_alloc_to_profile(val, osize, (jl_datatype_t*)type); diff --git a/src/jl_exported_funcs.inc b/src/jl_exported_funcs.inc index a98158f3d3e5e..ad49bfd7b3b9f 100644 --- a/src/jl_exported_funcs.inc +++ b/src/jl_exported_funcs.inc @@ -154,7 +154,6 @@ XX(jl_gc_allocobj) \ XX(jl_gc_alloc_typed) \ XX(jl_gc_big_alloc) \ - XX(jl_gc_big_alloc_instrumented) \ XX(jl_gc_collect) \ XX(jl_gc_conservative_gc_support_enabled) \ XX(jl_gc_counted_calloc) \ @@ -183,7 +182,6 @@ XX(jl_gc_new_weakref_th) \ XX(jl_gc_num) \ XX(jl_gc_pool_alloc) \ - XX(jl_gc_pool_alloc_instrumented) \ XX(jl_gc_queue_multiroot) \ XX(jl_gc_queue_root) \ XX(jl_gc_safepoint) \ diff --git a/src/llvm-pass-helpers.cpp b/src/llvm-pass-helpers.cpp index 39d37cee3928b..005b17186f10f 100644 --- a/src/llvm-pass-helpers.cpp +++ b/src/llvm-pass-helpers.cpp @@ -238,8 +238,8 @@ namespace jl_intrinsics { } namespace jl_well_known { - static const char *GC_BIG_ALLOC_NAME = XSTR(jl_gc_big_alloc_instrumented); - static const char *GC_POOL_ALLOC_NAME = XSTR(jl_gc_pool_alloc_instrumented); + static const char *GC_BIG_ALLOC_NAME = XSTR(jl_gc_big_alloc); + static const char *GC_POOL_ALLOC_NAME = XSTR(jl_gc_pool_alloc); static const char *GC_QUEUE_ROOT_NAME = XSTR(jl_gc_queue_root); static const char *GC_ALLOC_TYPED_NAME = XSTR(jl_gc_alloc_typed); diff --git a/test/llvmpasses/alloc-opt-gcframe.ll b/test/llvmpasses/alloc-opt-gcframe.ll index f600399ac2a7a..91d687cac1eb3 100644 --- a/test/llvmpasses/alloc-opt-gcframe.ll +++ b/test/llvmpasses/alloc-opt-gcframe.ll @@ -24,7 +24,7 @@ target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" ; OPAQUE: %current_task = getelementptr inbounds ptr, ptr %gcstack, i64 -12 ; OPAQUE: [[ptls_field:%.*]] = getelementptr inbounds ptr, ptr %current_task, i64 16 ; OPAQUE-NEXT: [[ptls_load:%.*]] = load ptr, ptr [[ptls_field]], align 8, !tbaa !0 -; OPAQUE-NEXT: %v = call noalias nonnull dereferenceable({{[0-9]+}}) ptr addrspace(10) @ijl_gc_pool_alloc_instrumented(ptr [[ptls_load]], i32 [[SIZE_T:[0-9]+]], i32 16, i64 {{.*}} @tag {{.*}}) +; OPAQUE-NEXT: %v = call noalias nonnull dereferenceable({{[0-9]+}}) ptr addrspace(10) @ijl_gc_pool_alloc(ptr [[ptls_load]], i32 [[SIZE_T:[0-9]+]], i32 16, i64 {{.*}} @tag {{.*}}) ; OPAQUE: store atomic ptr addrspace(10) @tag, ptr addrspace(10) {{.*}} unordered, align 8, !tbaa !4 define {} addrspace(10)* @return_obj() { @@ -270,11 +270,11 @@ L3: } ; CHECK-LABEL: }{{$}} -; TYPED: declare noalias nonnull {} addrspace(10)* @ijl_gc_pool_alloc_instrumented(i8*, -; TYPED: declare noalias nonnull {} addrspace(10)* @ijl_gc_big_alloc_instrumented(i8*, +; TYPED: declare noalias nonnull {} addrspace(10)* @ijl_gc_pool_alloc(i8*, +; TYPED: declare noalias nonnull {} addrspace(10)* @ijl_gc_big_alloc(i8*, -; OPAQUE: declare noalias nonnull ptr addrspace(10) @ijl_gc_pool_alloc_instrumented(ptr, -; OPAQUE: declare noalias nonnull ptr addrspace(10) @ijl_gc_big_alloc_instrumented(ptr, +; OPAQUE: declare noalias nonnull ptr addrspace(10) @ijl_gc_pool_alloc(ptr, +; OPAQUE: declare noalias nonnull ptr addrspace(10) @ijl_gc_big_alloc(ptr, declare void @external_function() declare {}*** @julia.get_pgcstack() declare noalias nonnull {} addrspace(10)* @julia.gc_alloc_obj({}**, i64, {} addrspace(10)*) diff --git a/test/llvmpasses/final-lower-gc.ll b/test/llvmpasses/final-lower-gc.ll index 64d2c06e534b2..493f1d501cb8e 100644 --- a/test/llvmpasses/final-lower-gc.ll +++ b/test/llvmpasses/final-lower-gc.ll @@ -80,8 +80,8 @@ top: %pgcstack = call {}*** @julia.get_pgcstack() %ptls = call {}*** @julia.ptls_states() %ptls_i8 = bitcast {}*** %ptls to i8* -; TYPED: %v = call noalias nonnull dereferenceable({{[0-9]+}}) {} addrspace(10)* @ijl_gc_pool_alloc_instrumented -; OPAQUE: %v = call noalias nonnull dereferenceable({{[0-9]+}}) ptr addrspace(10) @ijl_gc_pool_alloc_instrumented +; TYPED: %v = call noalias nonnull dereferenceable({{[0-9]+}}) {} addrspace(10)* @ijl_gc_pool_alloc +; OPAQUE: %v = call noalias nonnull dereferenceable({{[0-9]+}}) ptr addrspace(10) @ijl_gc_pool_alloc %v = call {} addrspace(10)* @julia.gc_alloc_bytes(i8* %ptls_i8, i64 8, i64 12341234) %0 = bitcast {} addrspace(10)* %v to {} addrspace(10)* addrspace(10)* %1 = getelementptr {} addrspace(10)*, {} addrspace(10)* addrspace(10)* %0, i64 -1 diff --git a/test/llvmpasses/julia-licm-fail.ll b/test/llvmpasses/julia-licm-fail.ll index 464a96f1413d9..78640a28aeb01 100644 --- a/test/llvmpasses/julia-licm-fail.ll +++ b/test/llvmpasses/julia-licm-fail.ll @@ -82,7 +82,7 @@ declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #2 declare void @ijl_gc_queue_root({} addrspace(10)*) #3 ; Function Attrs: allocsize(1) -declare noalias nonnull {} addrspace(10)* @ijl_gc_pool_alloc(i8*, i32, i32) #1 +declare noalias nonnull {} addrspace(10)* @ijl_gc_pool_alloc(i8*, i32, i32, i8*) #1 ; Function Attrs: allocsize(1) declare noalias nonnull {} addrspace(10)* @ijl_gc_big_alloc(i8*, i64) #1 diff --git a/test/llvmpasses/julia-licm-missed.ll b/test/llvmpasses/julia-licm-missed.ll index 941b2d072a1cc..990dc02442360 100644 --- a/test/llvmpasses/julia-licm-missed.ll +++ b/test/llvmpasses/julia-licm-missed.ll @@ -96,7 +96,7 @@ declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #2 declare void @ijl_gc_queue_root({} addrspace(10)*) #3 ; Function Attrs: allocsize(1) -declare noalias nonnull {} addrspace(10)* @ijl_gc_pool_alloc(i8*, i32, i32) #1 +declare noalias nonnull {} addrspace(10)* @ijl_gc_pool_alloc(i8*, i32, i32, i8*) #1 ; Function Attrs: allocsize(1) declare noalias nonnull {} addrspace(10)* @ijl_gc_big_alloc(i8*, i64) #1 diff --git a/test/llvmpasses/julia-licm.ll b/test/llvmpasses/julia-licm.ll index 8bedc5db75d96..886e0c9716f61 100644 --- a/test/llvmpasses/julia-licm.ll +++ b/test/llvmpasses/julia-licm.ll @@ -164,7 +164,7 @@ declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #2 declare void @ijl_gc_queue_root({} addrspace(10)*) #3 ; Function Attrs: allocsize(1) -declare noalias nonnull {} addrspace(10)* @ijl_gc_pool_alloc(i8*, i32, i32) #1 +declare noalias nonnull {} addrspace(10)* @ijl_gc_pool_alloc(i8*, i32, i32, i8*) #1 ; Function Attrs: allocsize(1) declare noalias nonnull {} addrspace(10)* @ijl_gc_big_alloc(i8*, i64) #1 From 9490ee3a4aa4c2e44d4988a42d54e06c88689eb5 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Wed, 10 Jul 2024 16:54:31 -0300 Subject: [PATCH 072/109] create GC TLS (#55086) Encapsulates all relevant GC thread-local-state into a separate structure. Motivation is that MMTk will have its own version of GC thread-local-state, so doesn't need all of the Julia GC TLS. In the future, folks who would be using MMTk would be setting a pre-processor flag which would lead to either the stock Julia GC TLS or MMTk's GC TLS to be included in `julia_threads.h`. I.e., we would have something like: ```C jl_gc_mmtk_tls_states mmtk_gc_tls; jl_gc_tls_states gc_tls; ``` --- src/Makefile | 2 +- src/array.c | 2 +- src/gc-debug.c | 73 +++------ src/gc-stacks.c | 16 +- src/gc-tls.h | 103 +++++++++++++ src/gc.c | 344 ++++++++++++++++++++++--------------------- src/julia_internal.h | 2 +- src/julia_threads.h | 83 +---------- src/partr.c | 4 +- src/stackwalk.c | 2 +- 10 files changed, 314 insertions(+), 317 deletions(-) create mode 100644 src/gc-tls.h diff --git a/src/Makefile b/src/Makefile index 0127e513ce144..fbbd7461e3c9c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -99,7 +99,7 @@ ifeq ($(USE_SYSTEM_LIBUV),0) UV_HEADERS += uv.h UV_HEADERS += uv/*.h endif -PUBLIC_HEADERS := $(BUILDDIR)/julia_version.h $(wildcard $(SRCDIR)/support/*.h) $(addprefix $(SRCDIR)/,work-stealing-queue.h julia.h julia_assert.h julia_threads.h julia_fasttls.h julia_locks.h julia_atomics.h jloptions.h) +PUBLIC_HEADERS := $(BUILDDIR)/julia_version.h $(wildcard $(SRCDIR)/support/*.h) $(addprefix $(SRCDIR)/,work-stealing-queue.h gc-tls.h julia.h julia_assert.h julia_threads.h julia_fasttls.h julia_locks.h julia_atomics.h jloptions.h) ifeq ($(OS),WINNT) PUBLIC_HEADERS += $(addprefix $(SRCDIR)/,win32_ucontext.h) endif diff --git a/src/array.c b/src/array.c index c7f71c9695e87..bfa62e0f75273 100644 --- a/src/array.c +++ b/src/array.c @@ -499,7 +499,7 @@ JL_DLLEXPORT jl_value_t *jl_alloc_string(size_t len) const size_t allocsz = sz + sizeof(jl_taggedvalue_t); if (sz <= GC_MAX_SZCLASS) { int pool_id = jl_gc_szclass_align8(allocsz); - jl_gc_pool_t *p = &ptls->heap.norm_pools[pool_id]; + jl_gc_pool_t *p = &ptls->gc_tls.heap.norm_pools[pool_id]; int osize = jl_gc_sizeclasses[pool_id]; // We call `jl_gc_pool_alloc_noinline` instead of `jl_gc_pool_alloc` to avoid double-counting in // the Allocations Profiler. (See https://github.com/JuliaLang/julia/pull/43868 for more details.) diff --git a/src/gc-debug.c b/src/gc-debug.c index 6faee6b1de97f..5b90ce7cd955b 100644 --- a/src/gc-debug.c +++ b/src/gc-debug.c @@ -97,7 +97,7 @@ static arraylist_t bits_save[4]; static void gc_clear_mark_page(jl_gc_pagemeta_t *pg, int bits) { jl_ptls_t ptls2 = gc_all_tls_states[pg->thread_n]; - jl_gc_pool_t *pool = &ptls2->heap.norm_pools[pg->pool_n]; + jl_gc_pool_t *pool = &ptls2->gc_tls.heap.norm_pools[pg->pool_n]; jl_taggedvalue_t *pv = (jl_taggedvalue_t*)(pg->data + GC_PAGE_OFFSET); char *lim = (char*)pv + GC_PAGE_SZ - GC_PAGE_OFFSET - pool->osize; while ((char*)pv <= lim) { @@ -112,7 +112,7 @@ static void gc_clear_mark_outer(int bits) { for (int i = 0; i < gc_n_threads; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; - jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->page_metadata_allocd.bottom); + jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->gc_tls.page_metadata_allocd.bottom); while (pg != NULL) { gc_clear_mark_page(pg, bits); pg = pg->next; @@ -132,7 +132,7 @@ static void clear_mark(int bits) } bigval_t *v; for (int i = 0; i < gc_n_threads; i++) { - v = gc_all_tls_states[i]->heap.big_objects; + v = gc_all_tls_states[i]->gc_tls.heap.big_objects; while (v != NULL) { void *gcv = &v->header; if (!gc_verifying) @@ -170,7 +170,7 @@ static void gc_verify_track(jl_ptls_t ptls) return; do { jl_gc_markqueue_t mq; - jl_gc_markqueue_t *mq2 = &ptls->mark_queue; + jl_gc_markqueue_t *mq2 = &ptls->gc_tls.mark_queue; ws_queue_t *cq = &mq.chunk_queue; ws_queue_t *q = &mq.ptr_queue; jl_atomic_store_relaxed(&cq->top, 0); @@ -230,7 +230,7 @@ void gc_verify(jl_ptls_t ptls) return; } jl_gc_markqueue_t mq; - jl_gc_markqueue_t *mq2 = &ptls->mark_queue; + jl_gc_markqueue_t *mq2 = &ptls->gc_tls.mark_queue; ws_queue_t *cq = &mq.chunk_queue; ws_queue_t *q = &mq.ptr_queue; jl_atomic_store_relaxed(&cq->top, 0); @@ -289,7 +289,7 @@ static void gc_verify_tags_page(jl_gc_pagemeta_t *pg) int p_n = pg->pool_n; int t_n = pg->thread_n; jl_ptls_t ptls2 = gc_all_tls_states[t_n]; - jl_gc_pool_t *p = &ptls2->heap.norm_pools[p_n]; + jl_gc_pool_t *p = &ptls2->gc_tls.heap.norm_pools[p_n]; int osize = pg->osize; char *data = pg->data; char *page_begin = data + GC_PAGE_OFFSET; @@ -349,42 +349,13 @@ static void gc_verify_tags_page(jl_gc_pagemeta_t *pg) static void gc_verify_tags_pagetable0(pagetable0_t *pagetable0) { - for (int pg_i = 0; pg_i < REGION0_PG_COUNT / 32; pg_i++) { - uint32_t line = pagetable0->allocmap[pg_i]; - if (line) { - for (int j = 0; j < 32; j++) { - if ((line >> j) & 1) { - gc_verify_tags_page(pagetable0->meta[pg_i * 32 + j]); - } - } - } - } -} - -static void gc_verify_tags_pagetable1(pagetable1_t *pagetable1) -{ - for (int pg_i = 0; pg_i < REGION1_PG_COUNT / 32; pg_i++) { - uint32_t line = pagetable1->allocmap0[pg_i]; - if (line) { - for (int j = 0; j < 32; j++) { - if ((line >> j) & 1) { - gc_verify_tags_pagetable0(pagetable1->meta0[pg_i * 32 + j]); - } - } - } - } -} - -static void gc_verify_tags_pagetable(void) -{ - for (int pg_i = 0; pg_i < (REGION2_PG_COUNT + 31) / 32; pg_i++) { - uint32_t line = memory_map.allocmap1[pg_i]; - if (line) { - for (int j = 0; j < 32; j++) { - if ((line >> j) & 1) { - gc_verify_tags_pagetable1(memory_map.meta1[pg_i * 32 + j]); - } - } + for (int i = 0; i < gc_n_threads; i++) { + jl_ptls_t ptls2 = gc_all_tls_states[i]; + jl_gc_page_stack_t *pgstk = &ptls2->gc_tls.page_metadata_allocd; + jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&pgstk->bottom); + while (pg != NULL) { + gc_verify_tags_page(pg); + pg = pg->next; } } } @@ -396,7 +367,7 @@ void gc_verify_tags(void) jl_ptls_t ptls2 = gc_all_tls_states[t_i]; for (int i = 0; i < JL_GC_N_POOLS; i++) { // for all pools, iterate its freelist - jl_gc_pool_t *p = &ptls2->heap.norm_pools[i]; + jl_gc_pool_t *p = &ptls2->gc_tls.heap.norm_pools[i]; jl_taggedvalue_t *next = p->freelist; jl_taggedvalue_t *last = NULL; char *allocating = gc_page_data(next); @@ -837,8 +808,8 @@ void gc_time_mark_pause(int64_t t0, int64_t scanned_bytes, int64_t remset_nptr = 0; for (int t_i = 0; t_i < gc_n_threads; t_i++) { jl_ptls_t ptls2 = gc_all_tls_states[t_i]; - last_remset_len += ptls2->heap.last_remset->len; - remset_nptr = ptls2->heap.remset_nptr; + last_remset_len += ptls2->gc_tls.heap.last_remset->len; + remset_nptr = ptls2->gc_tls.heap.remset_nptr; } jl_safe_printf("GC mark pause %.2f ms | " "scanned %" PRId64 " kB = %" PRId64 " + %" PRId64 " | " @@ -969,13 +940,13 @@ void gc_stats_all_pool(void) for (int i = 0; i < JL_GC_N_POOLS; i++) { for (int t_i = 0; t_i < gc_n_threads; t_i++) { jl_ptls_t ptls2 = gc_all_tls_states[t_i]; - size_t b = pool_stats(&ptls2->heap.norm_pools[i], &w, &np, &nol); + size_t b = pool_stats(&ptls2->gc_tls.heap.norm_pools[i], &w, &np, &nol); nb += b; - no += (b / ptls2->heap.norm_pools[i].osize); + no += (b / ptls2->gc_tls.heap.norm_pools[i].osize); tw += w; tp += np; nold += nol; - noldbytes += nol * ptls2->heap.norm_pools[i].osize; + noldbytes += nol * ptls2->gc_tls.heap.norm_pools[i].osize; } } jl_safe_printf("%lld objects (%lld%% old), %lld kB (%lld%% old) total allocated, " @@ -994,7 +965,7 @@ void gc_stats_big_obj(void) size_t nused=0, nbytes=0, nused_old=0, nbytes_old=0; for (int t_i = 0; t_i < gc_n_threads; t_i++) { jl_ptls_t ptls2 = gc_all_tls_states[t_i]; - bigval_t *v = ptls2->heap.big_objects; + bigval_t *v = ptls2->gc_tls.heap.big_objects; while (v != NULL) { if (gc_marked(v->bits.gc)) { nused++; @@ -1011,7 +982,7 @@ void gc_stats_big_obj(void) v = v->next; } - mallocarray_t *ma = ptls2->heap.mallocarrays; + mallocarray_t *ma = ptls2->gc_tls.heap.mallocarrays; while (ma != NULL) { if (gc_marked(jl_astaggedvalue(ma->a)->bits.gc)) { nused++; @@ -1057,7 +1028,7 @@ static void gc_count_pool_pagetable(void) { for (int i = 0; i < gc_n_threads; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; - jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->page_metadata_allocd.bottom); + jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->gc_tls.page_metadata_allocd.bottom); while (pg != NULL) { if (gc_alloc_map_is_set(pg->data)) { gc_count_pool_page(pg); diff --git a/src/gc-stacks.c b/src/gc-stacks.c index 693cb8d0eadf0..1c1e286960762 100644 --- a/src/gc-stacks.c +++ b/src/gc-stacks.c @@ -119,7 +119,7 @@ static void _jl_free_stack(jl_ptls_t ptls, void *stkbuf, size_t bufsz) if (bufsz <= pool_sizes[JL_N_STACK_POOLS - 1]) { unsigned pool_id = select_pool(bufsz); if (pool_sizes[pool_id] == bufsz) { - small_arraylist_push(&ptls->heap.free_stacks[pool_id], stkbuf); + small_arraylist_push(&ptls->gc_tls.heap.free_stacks[pool_id], stkbuf); return; } } @@ -148,7 +148,7 @@ void jl_release_task_stack(jl_ptls_t ptls, jl_task_t *task) #ifdef _COMPILER_ASAN_ENABLED_ __asan_unpoison_stack_memory((uintptr_t)stkbuf, bufsz); #endif - small_arraylist_push(&ptls->heap.free_stacks[pool_id], stkbuf); + small_arraylist_push(&ptls->gc_tls.heap.free_stacks[pool_id], stkbuf); } } } @@ -163,7 +163,7 @@ JL_DLLEXPORT void *jl_malloc_stack(size_t *bufsz, jl_task_t *owner) JL_NOTSAFEPO if (ssize <= pool_sizes[JL_N_STACK_POOLS - 1]) { unsigned pool_id = select_pool(ssize); ssize = pool_sizes[pool_id]; - small_arraylist_t *pool = &ptls->heap.free_stacks[pool_id]; + small_arraylist_t *pool = &ptls->gc_tls.heap.free_stacks[pool_id]; if (pool->len > 0) { stk = small_arraylist_pop(pool); } @@ -184,7 +184,7 @@ JL_DLLEXPORT void *jl_malloc_stack(size_t *bufsz, jl_task_t *owner) JL_NOTSAFEPO } *bufsz = ssize; if (owner) { - small_arraylist_t *live_tasks = &ptls->heap.live_tasks; + small_arraylist_t *live_tasks = &ptls->gc_tls.heap.live_tasks; mtarraylist_push(live_tasks, owner); } return stk; @@ -209,7 +209,7 @@ void sweep_stack_pools(void) // free half of stacks that remain unused since last sweep for (int p = 0; p < JL_N_STACK_POOLS; p++) { - small_arraylist_t *al = &ptls2->heap.free_stacks[p]; + small_arraylist_t *al = &ptls2->gc_tls.heap.free_stacks[p]; size_t n_to_free; if (al->len > MIN_STACK_MAPPINGS_PER_POOL) { n_to_free = al->len / 2; @@ -225,7 +225,7 @@ void sweep_stack_pools(void) } } - small_arraylist_t *live_tasks = &ptls2->heap.live_tasks; + small_arraylist_t *live_tasks = &ptls2->gc_tls.heap.live_tasks; size_t n = 0; size_t ndel = 0; size_t l = live_tasks->len; @@ -280,7 +280,7 @@ JL_DLLEXPORT jl_array_t *jl_live_tasks(void) jl_ptls_t ptls2 = allstates[i]; if (ptls2 == NULL) continue; - small_arraylist_t *live_tasks = &ptls2->heap.live_tasks; + small_arraylist_t *live_tasks = &ptls2->gc_tls.heap.live_tasks; size_t n = mtarraylist_length(live_tasks); l += n + (ptls2->root_task->stkbuf != NULL); } @@ -303,7 +303,7 @@ JL_DLLEXPORT jl_array_t *jl_live_tasks(void) goto restart; ((void**)jl_array_data(a))[j++] = t; } - small_arraylist_t *live_tasks = &ptls2->heap.live_tasks; + small_arraylist_t *live_tasks = &ptls2->gc_tls.heap.live_tasks; size_t n = mtarraylist_length(live_tasks); for (size_t i = 0; i < n; i++) { jl_task_t *t = (jl_task_t*)mtarraylist_get(live_tasks, i); diff --git a/src/gc-tls.h b/src/gc-tls.h new file mode 100644 index 0000000000000..3f8662b467e30 --- /dev/null +++ b/src/gc-tls.h @@ -0,0 +1,103 @@ +// This file is a part of Julia. License is MIT: https://julialang.org/license + +// Meant to be included in "julia_threads.h" +#ifndef JL_GC_TLS_H +#define JL_GC_TLS_H + +#include "julia_atomics.h" +#include "work-stealing-queue.h" +// GC threading ------------------------------------------------------------------ + +#include "arraylist.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + struct _jl_taggedvalue_t *freelist; // root of list of free objects + struct _jl_taggedvalue_t *newpages; // root of list of chunks of free objects + uint16_t osize; // size of objects in this pool +} jl_gc_pool_t; + +typedef struct { + // variable for tracking weak references + small_arraylist_t weak_refs; + // live tasks started on this thread + // that are holding onto a stack from the pool + small_arraylist_t live_tasks; + + // variables for tracking malloc'd arrays + struct _mallocarray_t *mallocarrays; + struct _mallocarray_t *mafreelist; + + // variables for tracking big objects + struct _bigval_t *big_objects; + + // lower bound of the number of pointers inside remembered values + int remset_nptr; + // remembered set + arraylist_t remset; + + // variables for allocating objects from pools +#define JL_GC_N_MAX_POOLS 51 // conservative. must be kept in sync with `src/julia_internal.h` + jl_gc_pool_t norm_pools[JL_GC_N_MAX_POOLS]; + +#define JL_N_STACK_POOLS 16 + small_arraylist_t free_stacks[JL_N_STACK_POOLS]; +} jl_thread_heap_t; + +typedef struct { + _Atomic(int64_t) allocd; + _Atomic(int64_t) pool_live_bytes; + _Atomic(int64_t) freed; + _Atomic(uint64_t) malloc; + _Atomic(uint64_t) realloc; + _Atomic(uint64_t) poolalloc; + _Atomic(uint64_t) bigalloc; + _Atomic(uint64_t) freecall; +} jl_thread_gc_num_t; + +typedef struct { + ws_queue_t chunk_queue; + ws_queue_t ptr_queue; + arraylist_t reclaim_set; +} jl_gc_markqueue_t; + +typedef struct { + // thread local increment of `perm_scanned_bytes` + size_t perm_scanned_bytes; + // thread local increment of `scanned_bytes` + size_t scanned_bytes; + // Number of queued big objects (<= 1024) + size_t nbig_obj; + // Array of queued big objects to be moved between the young list + // and the old list. + // A set low bit means that the object should be moved from the old list + // to the young list (`mark_reset_age`). + // Objects can only be put into this list when the mark bit is flipped to + // `1` (atomically). Combining with the sync after marking, + // this makes sure that a single objects can only appear once in + // the lists (the mark bit cannot be flipped to `0` without sweeping) + void *big_obj[1024]; +} jl_gc_mark_cache_t; + +typedef struct { + _Atomic(struct _jl_gc_pagemeta_t *) bottom; +} jl_gc_page_stack_t; + +typedef struct { + jl_thread_heap_t heap; + jl_gc_page_stack_t page_metadata_allocd; + jl_thread_gc_num_t gc_num; + jl_gc_markqueue_t mark_queue; + jl_gc_mark_cache_t gc_cache; + _Atomic(size_t) gc_sweeps_requested; + arraylist_t sweep_objs; +} jl_gc_tls_states_t; + +#ifdef __cplusplus +} +#endif + +#endif // JL_GC_TLS_H diff --git a/src/gc.c b/src/gc.c index 3b83ce13c4732..e96fc9637d6f9 100644 --- a/src/gc.c +++ b/src/gc.c @@ -21,7 +21,7 @@ int jl_n_sweepthreads; _Atomic(int) gc_n_threads_marking; // Number of threads sweeping _Atomic(int) gc_n_threads_sweeping; -// Temporary for the `ptls->page_metadata_allocd` used during parallel sweeping (padded to avoid false sharing) +// Temporary for the `ptls->gc_tls.page_metadata_allocd` used during parallel sweeping (padded to avoid false sharing) _Atomic(jl_gc_padded_page_stack_t *) gc_allocd_scratch; // `tid` of mutator thread that triggered GC _Atomic(int) gc_master_tid; @@ -670,7 +670,7 @@ static void gc_sweep_foreign_objs(void) for (int i = 0; i < gc_n_threads; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; if (ptls2 != NULL) - gc_sweep_foreign_objs_in_list(&ptls2->sweep_objs); + gc_sweep_foreign_objs_in_list(&ptls2->gc_tls.sweep_objs); } } @@ -767,7 +767,7 @@ static void gc_sync_cache_nolock(jl_ptls_t ptls, jl_gc_mark_cache_t *gc_cache) J bigval_t *hdr = (bigval_t*)gc_ptr_clear_tag(ptr, 1); gc_big_object_unlink(hdr); if (gc_ptr_tag(ptr, 1)) { - gc_big_object_link(hdr, &ptls->heap.big_objects); + gc_big_object_link(hdr, &ptls->gc_tls.heap.big_objects); } else { // Move hdr from `big_objects` list to `big_objects_marked list` @@ -784,7 +784,7 @@ static void gc_sync_cache_nolock(jl_ptls_t ptls, jl_gc_mark_cache_t *gc_cache) J static void gc_sync_cache(jl_ptls_t ptls) JL_NOTSAFEPOINT { uv_mutex_lock(&gc_cache_lock); - gc_sync_cache_nolock(ptls, &ptls->gc_cache); + gc_sync_cache_nolock(ptls, &ptls->gc_tls.gc_cache); uv_mutex_unlock(&gc_cache_lock); } @@ -795,22 +795,22 @@ static void gc_sync_all_caches_nolock(jl_ptls_t ptls) for (int t_i = 0; t_i < gc_n_threads; t_i++) { jl_ptls_t ptls2 = gc_all_tls_states[t_i]; if (ptls2 != NULL) - gc_sync_cache_nolock(ptls, &ptls2->gc_cache); + gc_sync_cache_nolock(ptls, &ptls2->gc_tls.gc_cache); } } STATIC_INLINE void gc_queue_big_marked(jl_ptls_t ptls, bigval_t *hdr, int toyoung) JL_NOTSAFEPOINT { - const int nentry = sizeof(ptls->gc_cache.big_obj) / sizeof(void*); - size_t nobj = ptls->gc_cache.nbig_obj; + const int nentry = sizeof(ptls->gc_tls.gc_cache.big_obj) / sizeof(void*); + size_t nobj = ptls->gc_tls.gc_cache.nbig_obj; if (__unlikely(nobj >= nentry)) { gc_sync_cache(ptls); nobj = 0; } uintptr_t v = (uintptr_t)hdr; - ptls->gc_cache.big_obj[nobj] = (void*)(toyoung ? (v | 1) : v); - ptls->gc_cache.nbig_obj = nobj + 1; + ptls->gc_tls.gc_cache.big_obj[nobj] = (void*)(toyoung ? (v | 1) : v); + ptls->gc_tls.gc_cache.nbig_obj = nobj + 1; } // Atomically set the mark bit for object and return whether it was previously unmarked @@ -848,11 +848,11 @@ STATIC_INLINE void gc_setmark_big(jl_ptls_t ptls, jl_taggedvalue_t *o, assert(!gc_alloc_map_is_set((char*)o)); bigval_t *hdr = bigval_header(o); if (mark_mode == GC_OLD_MARKED) { - ptls->gc_cache.perm_scanned_bytes += hdr->sz; + ptls->gc_tls.gc_cache.perm_scanned_bytes += hdr->sz; gc_queue_big_marked(ptls, hdr, 0); } else { - ptls->gc_cache.scanned_bytes += hdr->sz; + ptls->gc_tls.gc_cache.scanned_bytes += hdr->sz; // We can't easily tell if the object is old or being promoted // from the gc bits but if the `age` is `0` then the object // must be already on a young list. @@ -872,12 +872,12 @@ STATIC_INLINE void gc_setmark_pool_(jl_ptls_t ptls, jl_taggedvalue_t *o, gc_setmark_big(ptls, o, mark_mode); #else if (mark_mode == GC_OLD_MARKED) { - ptls->gc_cache.perm_scanned_bytes += page->osize; + ptls->gc_tls.gc_cache.perm_scanned_bytes += page->osize; static_assert(sizeof(_Atomic(uint16_t)) == sizeof(page->nold), ""); jl_atomic_fetch_add_relaxed((_Atomic(uint16_t)*)&page->nold, 1); } else { - ptls->gc_cache.scanned_bytes += page->osize; + ptls->gc_tls.gc_cache.scanned_bytes += page->osize; if (mark_reset_age) { page->has_young = 1; } @@ -930,7 +930,7 @@ void gc_setmark_buf(jl_ptls_t ptls, void *o, uint8_t mark_mode, size_t minsz) JL STATIC_INLINE void maybe_collect(jl_ptls_t ptls) { - if (jl_atomic_load_relaxed(&ptls->gc_num.allocd) >= 0 || jl_gc_debug_check_other()) { + if (jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.allocd) >= 0 || jl_gc_debug_check_other()) { jl_gc_collect(JL_GC_AUTO); } else { @@ -946,7 +946,7 @@ JL_DLLEXPORT jl_weakref_t *jl_gc_new_weakref_th(jl_ptls_t ptls, jl_weakref_t *wr = (jl_weakref_t*)jl_gc_alloc(ptls, sizeof(void*), jl_weakref_type); wr->value = value; // NOTE: wb not needed here - small_arraylist_push(&ptls->heap.weak_refs, wr); + small_arraylist_push(&ptls->gc_tls.heap.weak_refs, wr); return wr; } @@ -956,8 +956,8 @@ static void clear_weak_refs(void) for (int i = 0; i < gc_n_threads; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; if (ptls2 != NULL) { - size_t n, l = ptls2->heap.weak_refs.len; - void **lst = ptls2->heap.weak_refs.items; + size_t n, l = ptls2->gc_tls.heap.weak_refs.len; + void **lst = ptls2->gc_tls.heap.weak_refs.items; for (n = 0; n < l; n++) { jl_weakref_t *wr = (jl_weakref_t*)lst[n]; if (!gc_marked(jl_astaggedvalue(wr->value)->bits.gc)) @@ -975,8 +975,8 @@ static void sweep_weak_refs(void) if (ptls2 != NULL) { size_t n = 0; size_t ndel = 0; - size_t l = ptls2->heap.weak_refs.len; - void **lst = ptls2->heap.weak_refs.items; + size_t l = ptls2->gc_tls.heap.weak_refs.len; + void **lst = ptls2->gc_tls.heap.weak_refs.items; if (l == 0) continue; while (1) { @@ -991,7 +991,7 @@ static void sweep_weak_refs(void) lst[n] = lst[n + ndel]; lst[n + ndel] = tmp; } - ptls2->heap.weak_refs.len -= ndel; + ptls2->gc_tls.heap.weak_refs.len -= ndel; } } } @@ -1015,15 +1015,15 @@ STATIC_INLINE jl_value_t *jl_gc_big_alloc_inner(jl_ptls_t ptls, size_t sz) jl_throw(jl_memory_exception); gc_invoke_callbacks(jl_gc_cb_notify_external_alloc_t, gc_cblist_notify_external_alloc, (v, allocsz)); - jl_atomic_store_relaxed(&ptls->gc_num.allocd, - jl_atomic_load_relaxed(&ptls->gc_num.allocd) + allocsz); - jl_atomic_store_relaxed(&ptls->gc_num.bigalloc, - jl_atomic_load_relaxed(&ptls->gc_num.bigalloc) + 1); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.allocd, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.allocd) + allocsz); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.bigalloc, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.bigalloc) + 1); #ifdef MEMDEBUG memset(v, 0xee, allocsz); #endif v->sz = allocsz; - gc_big_object_link(v, &ptls->heap.big_objects); + gc_big_object_link(v, &ptls->gc_tls.heap.big_objects); return jl_valueof(&v->header); } @@ -1085,17 +1085,17 @@ static void sweep_big(jl_ptls_t ptls, int sweep_full) JL_NOTSAFEPOINT for (int i = 0; i < gc_n_threads; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; if (ptls2 != NULL) - sweep_big_list(sweep_full, &ptls2->heap.big_objects); + sweep_big_list(sweep_full, &ptls2->gc_tls.heap.big_objects); } if (sweep_full) { bigval_t **last_next = sweep_big_list(sweep_full, &big_objects_marked); // Move all survivors from big_objects_marked list to the big_objects list of this thread. - if (ptls->heap.big_objects) - ptls->heap.big_objects->prev = last_next; - *last_next = ptls->heap.big_objects; - ptls->heap.big_objects = big_objects_marked; - if (ptls->heap.big_objects) - ptls->heap.big_objects->prev = &ptls->heap.big_objects; + if (ptls->gc_tls.heap.big_objects) + ptls->gc_tls.heap.big_objects->prev = last_next; + *last_next = ptls->gc_tls.heap.big_objects; + ptls->gc_tls.heap.big_objects = big_objects_marked; + if (ptls->gc_tls.heap.big_objects) + ptls->gc_tls.heap.big_objects->prev = &ptls->gc_tls.heap.big_objects; big_objects_marked = NULL; } gc_time_big_end(); @@ -1107,30 +1107,30 @@ void jl_gc_track_malloced_array(jl_ptls_t ptls, jl_array_t *a) JL_NOTSAFEPOINT { // This is **NOT** a GC safe point. mallocarray_t *ma; - if (ptls->heap.mafreelist == NULL) { + if (ptls->gc_tls.heap.mafreelist == NULL) { ma = (mallocarray_t*)malloc_s(sizeof(mallocarray_t)); } else { - ma = ptls->heap.mafreelist; - ptls->heap.mafreelist = ma->next; + ma = ptls->gc_tls.heap.mafreelist; + ptls->gc_tls.heap.mafreelist = ma->next; } ma->a = a; - ma->next = ptls->heap.mallocarrays; - ptls->heap.mallocarrays = ma; + ma->next = ptls->gc_tls.heap.mallocarrays; + ptls->gc_tls.heap.mallocarrays = ma; } void jl_gc_count_allocd(size_t sz) JL_NOTSAFEPOINT { jl_ptls_t ptls = jl_current_task->ptls; - jl_atomic_store_relaxed(&ptls->gc_num.allocd, - jl_atomic_load_relaxed(&ptls->gc_num.allocd) + sz); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.allocd, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.allocd) + sz); } void jl_gc_count_freed(size_t sz) JL_NOTSAFEPOINT { jl_ptls_t ptls = jl_current_task->ptls; - jl_atomic_store_relaxed(&ptls->gc_num.freed, - jl_atomic_load_relaxed(&ptls->gc_num.freed) + sz); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.freed, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.freed) + sz); } static void combine_thread_gc_counts(jl_gc_num_t *dest) JL_NOTSAFEPOINT @@ -1142,13 +1142,13 @@ static void combine_thread_gc_counts(jl_gc_num_t *dest) JL_NOTSAFEPOINT for (int i = 0; i < gc_n_threads; i++) { jl_ptls_t ptls = gc_all_tls_states[i]; if (ptls) { - dest->allocd += (jl_atomic_load_relaxed(&ptls->gc_num.allocd) + gc_num.interval); - dest->freed += jl_atomic_load_relaxed(&ptls->gc_num.freed); - dest->malloc += jl_atomic_load_relaxed(&ptls->gc_num.malloc); - dest->realloc += jl_atomic_load_relaxed(&ptls->gc_num.realloc); - dest->poolalloc += jl_atomic_load_relaxed(&ptls->gc_num.poolalloc); - dest->bigalloc += jl_atomic_load_relaxed(&ptls->gc_num.bigalloc); - dest->freecall += jl_atomic_load_relaxed(&ptls->gc_num.freecall); + dest->allocd += (jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.allocd) + gc_num.interval); + dest->freed += jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.freed); + dest->malloc += jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.malloc); + dest->realloc += jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.realloc); + dest->poolalloc += jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.poolalloc); + dest->bigalloc += jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.bigalloc); + dest->freecall += jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.freecall); } } } @@ -1163,13 +1163,13 @@ static void reset_thread_gc_counts(void) JL_NOTSAFEPOINT jl_ptls_t ptls = gc_all_tls_states[i]; if (ptls != NULL) { // don't reset `pool_live_bytes` here - jl_atomic_store_relaxed(&ptls->gc_num.allocd, -(int64_t)gc_num.interval); - jl_atomic_store_relaxed(&ptls->gc_num.freed, 0); - jl_atomic_store_relaxed(&ptls->gc_num.malloc, 0); - jl_atomic_store_relaxed(&ptls->gc_num.realloc, 0); - jl_atomic_store_relaxed(&ptls->gc_num.poolalloc, 0); - jl_atomic_store_relaxed(&ptls->gc_num.bigalloc, 0); - jl_atomic_store_relaxed(&ptls->gc_num.freecall, 0); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.allocd, -(int64_t)gc_num.interval); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.freed, 0); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.malloc, 0); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.realloc, 0); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.poolalloc, 0); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.bigalloc, 0); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.freecall, 0); } } } @@ -1223,8 +1223,8 @@ static void sweep_malloced_arrays(void) JL_NOTSAFEPOINT for (int t_i = 0; t_i < gc_n_threads; t_i++) { jl_ptls_t ptls2 = gc_all_tls_states[t_i]; if (ptls2 != NULL) { - mallocarray_t *ma = ptls2->heap.mallocarrays; - mallocarray_t **pma = &ptls2->heap.mallocarrays; + mallocarray_t *ma = ptls2->gc_tls.heap.mallocarrays; + mallocarray_t **pma = &ptls2->gc_tls.heap.mallocarrays; while (ma != NULL) { mallocarray_t *nxt = ma->next; int bits = jl_astaggedvalue(ma->a)->bits.gc; @@ -1235,8 +1235,8 @@ static void sweep_malloced_arrays(void) JL_NOTSAFEPOINT *pma = nxt; assert(ma->a->flags.how == 2); jl_gc_free_array(ma->a); - ma->next = ptls2->heap.mafreelist; - ptls2->heap.mafreelist = ma; + ma->next = ptls2->gc_tls.heap.mafreelist; + ptls2->gc_tls.heap.mafreelist = ma; } gc_time_count_mallocd_array(bits); ma = nxt; @@ -1251,7 +1251,7 @@ STATIC_INLINE jl_taggedvalue_t *gc_reset_page(jl_ptls_t ptls2, const jl_gc_pool_ { assert(GC_PAGE_OFFSET >= sizeof(void*)); pg->nfree = (GC_PAGE_SZ - GC_PAGE_OFFSET) / p->osize; - pg->pool_n = p - ptls2->heap.norm_pools; + pg->pool_n = p - ptls2->gc_tls.heap.norm_pools; jl_taggedvalue_t *beg = (jl_taggedvalue_t*)(pg->data + GC_PAGE_OFFSET); pg->has_young = 0; pg->has_marked = 0; @@ -1277,7 +1277,7 @@ static NOINLINE jl_taggedvalue_t *gc_add_page(jl_gc_pool_t *p) JL_NOTSAFEPOINT pg->osize = p->osize; pg->thread_n = ptls->tid; set_page_metadata(pg); - push_lf_back(&ptls->page_metadata_allocd, pg); + push_lf_back(&ptls->gc_tls.page_metadata_allocd, pg); jl_taggedvalue_t *fl = gc_reset_page(ptls, p, pg); p->newpages = fl; return fl; @@ -1296,12 +1296,12 @@ STATIC_INLINE jl_value_t *jl_gc_pool_alloc_inner(jl_ptls_t ptls, int pool_offset return jl_gc_big_alloc(ptls, osize, NULL); #endif maybe_collect(ptls); - jl_atomic_store_relaxed(&ptls->gc_num.allocd, - jl_atomic_load_relaxed(&ptls->gc_num.allocd) + osize); - jl_atomic_store_relaxed(&ptls->gc_num.pool_live_bytes, - jl_atomic_load_relaxed(&ptls->gc_num.pool_live_bytes) + osize); - jl_atomic_store_relaxed(&ptls->gc_num.poolalloc, - jl_atomic_load_relaxed(&ptls->gc_num.poolalloc) + 1); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.allocd, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.allocd) + osize); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.pool_live_bytes, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.pool_live_bytes) + osize); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.poolalloc, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.poolalloc) + 1); // first try to use the freelist jl_taggedvalue_t *v = p->freelist; if (v != NULL) { @@ -1363,7 +1363,7 @@ int jl_gc_classify_pools(size_t sz, int *osize) size_t allocsz = sz + sizeof(jl_taggedvalue_t); int klass = jl_gc_szclass(allocsz); *osize = jl_gc_sizeclasses[klass]; - return (int)(intptr_t)(&((jl_ptls_t)0)->heap.norm_pools[klass]); + return (int)(intptr_t)(&((jl_ptls_t)0)->gc_tls.heap.norm_pools[klass]); } // sweep phase @@ -1516,8 +1516,8 @@ static void gc_sweep_page(gc_page_profiler_serializer_t *s, jl_gc_pool_t *p, jl_ // instead of adding it to the thread that originally allocated the page, so we can avoid // an atomic-fetch-add here. size_t delta = (GC_PAGE_SZ - GC_PAGE_OFFSET - nfree * osize); - jl_atomic_store_relaxed(&ptls->gc_num.pool_live_bytes, - jl_atomic_load_relaxed(&ptls->gc_num.pool_live_bytes) + delta); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.pool_live_bytes, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.pool_live_bytes) + delta); jl_atomic_fetch_add_relaxed((_Atomic(int64_t) *)&gc_num.freed, (nfree - old_nfree) * osize); } @@ -1527,7 +1527,7 @@ STATIC_INLINE void gc_sweep_pool_page(gc_page_profiler_serializer_t *s, jl_gc_pa int p_n = pg->pool_n; int t_n = pg->thread_n; jl_ptls_t ptls2 = gc_all_tls_states[t_n]; - jl_gc_pool_t *p = &ptls2->heap.norm_pools[p_n]; + jl_gc_pool_t *p = &ptls2->gc_tls.heap.norm_pools[p_n]; int osize = pg->osize; gc_sweep_page(s, p, allocd, pg, osize); } @@ -1573,7 +1573,7 @@ int gc_sweep_prescan(jl_ptls_t ptls, jl_gc_padded_page_stack_t *new_gc_allocd_sc jl_gc_pagemeta_t *tail = NULL; memset(&tmp, 0, sizeof(tmp)); while (1) { - jl_gc_pagemeta_t *pg = pop_lf_back_nosync(&ptls2->page_metadata_allocd); + jl_gc_pagemeta_t *pg = pop_lf_back_nosync(&ptls2->gc_tls.page_metadata_allocd); if (pg == NULL) { break; } @@ -1602,9 +1602,9 @@ int gc_sweep_prescan(jl_ptls_t ptls, jl_gc_padded_page_stack_t *new_gc_allocd_sc } } if (tail != NULL) { - tail->next = jl_atomic_load_relaxed(&ptls2->page_metadata_allocd.bottom); + tail->next = jl_atomic_load_relaxed(&ptls2->gc_tls.page_metadata_allocd.bottom); } - ptls2->page_metadata_allocd = tmp; + ptls2->gc_tls.page_metadata_allocd = tmp; if (n_pages_to_scan >= n_pages_worth_parallel_sweep) { break; } @@ -1625,7 +1625,7 @@ void gc_sweep_wake_all(jl_ptls_t ptls, jl_gc_padded_page_stack_t *new_gc_allocd_ for (int i = first; i <= last; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; gc_check_ptls_of_parallel_collector_thread(ptls2); - jl_atomic_fetch_add(&ptls2->gc_sweeps_requested, 1); + jl_atomic_fetch_add(&ptls2->gc_tls.gc_sweeps_requested, 1); } uv_cond_broadcast(&gc_threads_cond); uv_mutex_unlock(&gc_threads_lock); @@ -1641,7 +1641,7 @@ void gc_sweep_wake_all(jl_ptls_t ptls, jl_gc_padded_page_stack_t *new_gc_allocd_ for (int i = first; i <= last; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; gc_check_ptls_of_parallel_collector_thread(ptls2); - while (jl_atomic_load_acquire(&ptls2->gc_sweeps_requested) != 0) { + while (jl_atomic_load_acquire(&ptls2->gc_tls.gc_sweeps_requested) != 0) { jl_cpu_pause(); } } @@ -1675,7 +1675,7 @@ void gc_sweep_pool_parallel(jl_ptls_t ptls) continue; } jl_gc_page_stack_t *dest = &allocd_scratch[ptls2->tid].stack; - jl_gc_pagemeta_t *pg = try_pop_lf_back(&ptls2->page_metadata_allocd); + jl_gc_pagemeta_t *pg = try_pop_lf_back(&ptls2->gc_tls.page_metadata_allocd); // failed steal attempt if (pg == NULL) { continue; @@ -1692,7 +1692,7 @@ void gc_sweep_pool_parallel(jl_ptls_t ptls) if (ptls2 == NULL) { continue; } - jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->page_metadata_allocd.bottom); + jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->gc_tls.page_metadata_allocd.bottom); if (pg != NULL) { no_more_work = 0; break; @@ -1770,9 +1770,9 @@ static void gc_sweep_pool(void) } continue; } - jl_atomic_store_relaxed(&ptls2->gc_num.pool_live_bytes, 0); + jl_atomic_store_relaxed(&ptls2->gc_tls.gc_num.pool_live_bytes, 0); for (int i = 0; i < JL_GC_N_POOLS; i++) { - jl_gc_pool_t *p = &ptls2->heap.norm_pools[i]; + jl_gc_pool_t *p = &ptls2->gc_tls.heap.norm_pools[i]; jl_taggedvalue_t *last = p->freelist; if (last != NULL) { jl_gc_pagemeta_t *pg = jl_assume(page_metadata_unsafe(last)); @@ -1804,9 +1804,9 @@ static void gc_sweep_pool(void) for (int t_i = 0; t_i < n_threads; t_i++) { jl_ptls_t ptls2 = gc_all_tls_states[t_i]; if (ptls2 != NULL) { - ptls2->page_metadata_allocd = new_gc_allocd_scratch[t_i].stack; + ptls2->gc_tls.page_metadata_allocd = new_gc_allocd_scratch[t_i].stack; for (int i = 0; i < JL_GC_N_POOLS; i++) { - jl_gc_pool_t *p = &ptls2->heap.norm_pools[i]; + jl_gc_pool_t *p = &ptls2->gc_tls.heap.norm_pools[i]; p->newpages = NULL; } } @@ -1818,7 +1818,7 @@ static void gc_sweep_pool(void) if (ptls2 == NULL) { continue; } - jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->page_metadata_allocd.bottom); + jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->gc_tls.page_metadata_allocd.bottom); while (pg != NULL) { jl_gc_pagemeta_t *pg2 = pg->next; if (pg->fl_begin_offset != UINT16_MAX) { @@ -1880,8 +1880,8 @@ JL_DLLEXPORT void jl_gc_queue_root(const jl_value_t *ptr) // which is not idempotent. See comments in https://github.com/JuliaLang/julia/issues/50419 uintptr_t header = jl_atomic_fetch_and_relaxed((_Atomic(uintptr_t) *)&o->header, ~GC_OLD); if (header & GC_OLD) { // write barrier has not been triggered in this object yet - arraylist_push(&ptls->heap.remset, (jl_value_t*)ptr); - ptls->heap.remset_nptr++; // conservative + arraylist_push(&ptls->gc_tls.heap.remset, (jl_value_t*)ptr); + ptls->gc_tls.heap.remset_nptr++; // conservative } } @@ -1986,8 +1986,8 @@ STATIC_INLINE void gc_mark_push_remset(jl_ptls_t ptls, jl_value_t *obj, uintptr_t nptr) JL_NOTSAFEPOINT { if (__unlikely((nptr & 0x3) == 0x3)) { - ptls->heap.remset_nptr += nptr >> 2; - arraylist_t *remset = &ptls->heap.remset; + ptls->gc_tls.heap.remset_nptr += nptr >> 2; + arraylist_t *remset = &ptls->gc_tls.heap.remset; size_t len = remset->len; if (__unlikely(len >= remset->max)) { arraylist_push(remset, obj); @@ -2051,7 +2051,7 @@ JL_NORETURN NOINLINE void gc_dump_queue_and_abort(jl_ptls_t ptls, jl_datatype_t if (jl_n_gcthreads == 0) { jl_safe_printf("\n"); jl_value_t *new_obj; - jl_gc_markqueue_t *mq = &ptls->mark_queue; + jl_gc_markqueue_t *mq = &ptls->gc_tls.mark_queue; jl_safe_printf("thread %d ptr queue:\n", ptls->tid); jl_safe_printf("~~~~~~~~~~ ptr queue top ~~~~~~~~~~\n"); while ((new_obj = gc_ptr_queue_steal_from(mq)) != NULL) { @@ -2090,7 +2090,7 @@ STATIC_INLINE jl_value_t *gc_mark_obj8(jl_ptls_t ptls, char *obj8_parent, uint8_ uint8_t *obj8_end, uintptr_t nptr) JL_NOTSAFEPOINT { (void)jl_assume(obj8_begin < obj8_end); - jl_gc_markqueue_t *mq = &ptls->mark_queue; + jl_gc_markqueue_t *mq = &ptls->gc_tls.mark_queue; jl_value_t **slot = NULL; jl_value_t *new_obj = NULL; for (; obj8_begin < obj8_end; obj8_begin++) { @@ -2122,7 +2122,7 @@ STATIC_INLINE jl_value_t *gc_mark_obj16(jl_ptls_t ptls, char *obj16_parent, uint uint16_t *obj16_end, uintptr_t nptr) JL_NOTSAFEPOINT { (void)jl_assume(obj16_begin < obj16_end); - jl_gc_markqueue_t *mq = &ptls->mark_queue; + jl_gc_markqueue_t *mq = &ptls->gc_tls.mark_queue; jl_value_t **slot = NULL; jl_value_t *new_obj = NULL; for (; obj16_begin < obj16_end; obj16_begin++) { @@ -2154,7 +2154,7 @@ STATIC_INLINE jl_value_t *gc_mark_obj32(jl_ptls_t ptls, char *obj32_parent, uint uint32_t *obj32_end, uintptr_t nptr) JL_NOTSAFEPOINT { (void)jl_assume(obj32_begin < obj32_end); - jl_gc_markqueue_t *mq = &ptls->mark_queue; + jl_gc_markqueue_t *mq = &ptls->gc_tls.mark_queue; jl_value_t **slot = NULL; jl_value_t *new_obj = NULL; for (; obj32_begin < obj32_end; obj32_begin++) { @@ -2185,7 +2185,7 @@ STATIC_INLINE jl_value_t *gc_mark_obj32(jl_ptls_t ptls, char *obj32_parent, uint STATIC_INLINE void gc_mark_objarray(jl_ptls_t ptls, jl_value_t *obj_parent, jl_value_t **obj_begin, jl_value_t **obj_end, uint32_t step, uintptr_t nptr) JL_NOTSAFEPOINT { - jl_gc_markqueue_t *mq = &ptls->mark_queue; + jl_gc_markqueue_t *mq = &ptls->gc_tls.mark_queue; jl_value_t *new_obj; // Decide whether need to chunk objary (void)jl_assume(step > 0); @@ -2252,7 +2252,7 @@ STATIC_INLINE void gc_mark_array8(jl_ptls_t ptls, jl_value_t *ary8_parent, jl_va jl_value_t **ary8_end, uint8_t *elem_begin, uint8_t *elem_end, uintptr_t nptr) JL_NOTSAFEPOINT { - jl_gc_markqueue_t *mq = &ptls->mark_queue; + jl_gc_markqueue_t *mq = &ptls->gc_tls.mark_queue; jl_value_t *new_obj; size_t elsize = ((jl_array_t *)ary8_parent)->elsize / sizeof(jl_value_t *); assert(elsize > 0); @@ -2329,7 +2329,7 @@ STATIC_INLINE void gc_mark_array16(jl_ptls_t ptls, jl_value_t *ary16_parent, jl_ jl_value_t **ary16_end, uint16_t *elem_begin, uint16_t *elem_end, uintptr_t nptr) JL_NOTSAFEPOINT { - jl_gc_markqueue_t *mq = &ptls->mark_queue; + jl_gc_markqueue_t *mq = &ptls->gc_tls.mark_queue; jl_value_t *new_obj; size_t elsize = ((jl_array_t *)ary16_parent)->elsize / sizeof(jl_value_t *); assert(elsize > 0); @@ -2456,7 +2456,7 @@ STATIC_INLINE void gc_mark_chunk(jl_ptls_t ptls, jl_gc_markqueue_t *mq, jl_gc_ch STATIC_INLINE void gc_mark_stack(jl_ptls_t ptls, jl_gcframe_t *s, uint32_t nroots, uintptr_t offset, uintptr_t lb, uintptr_t ub) JL_NOTSAFEPOINT { - jl_gc_markqueue_t *mq = &ptls->mark_queue; + jl_gc_markqueue_t *mq = &ptls->gc_tls.mark_queue; jl_value_t *new_obj; uint32_t nr = nroots >> 2; while (1) { @@ -2501,7 +2501,7 @@ STATIC_INLINE void gc_mark_stack(jl_ptls_t ptls, jl_gcframe_t *s, uint32_t nroot // Mark exception stack STATIC_INLINE void gc_mark_excstack(jl_ptls_t ptls, jl_excstack_t *excstack, size_t itr) JL_NOTSAFEPOINT { - jl_gc_markqueue_t *mq = &ptls->mark_queue; + jl_gc_markqueue_t *mq = &ptls->gc_tls.mark_queue; jl_value_t *new_obj; while (itr > 0) { size_t bt_size = jl_excstack_bt_size(excstack, itr); @@ -2532,7 +2532,7 @@ STATIC_INLINE void gc_mark_excstack(jl_ptls_t ptls, jl_excstack_t *excstack, siz STATIC_INLINE void gc_mark_module_binding(jl_ptls_t ptls, jl_module_t *mb_parent, uintptr_t nptr, uint8_t bits) JL_NOTSAFEPOINT { - jl_gc_markqueue_t *mq = &ptls->mark_queue; + jl_gc_markqueue_t *mq = &ptls->gc_tls.mark_queue; jl_value_t *bindings = (jl_value_t *)jl_atomic_load_relaxed(&mb_parent->bindings); gc_assert_parent_validity((jl_value_t *)mb_parent, bindings); gc_try_claim_and_push(mq, bindings, &nptr); @@ -2607,7 +2607,7 @@ JL_DLLEXPORT int jl_gc_mark_queue_obj(jl_ptls_t ptls, jl_value_t *obj) { int may_claim = gc_try_setmark_tag(jl_astaggedvalue(obj), GC_MARKED); if (may_claim) - gc_ptr_queue_push(&ptls->mark_queue, obj); + gc_ptr_queue_push(&ptls->gc_tls.mark_queue, obj); return may_claim; } @@ -2783,10 +2783,10 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_ if (update_meta || foreign_alloc) { gc_heap_snapshot_record_hidden_edge(new_obj, a->data, jl_array_nbytes(a), flags.pooled); if (bits == GC_OLD_MARKED) { - ptls->gc_cache.perm_scanned_bytes += jl_array_nbytes(a); + ptls->gc_tls.gc_cache.perm_scanned_bytes += jl_array_nbytes(a); } else { - ptls->gc_cache.scanned_bytes += jl_array_nbytes(a); + ptls->gc_tls.gc_cache.scanned_bytes += jl_array_nbytes(a); } } } @@ -2912,7 +2912,7 @@ FORCE_INLINE void gc_mark_outrefs(jl_ptls_t ptls, jl_gc_markqueue_t *mq, void *_ void gc_mark_loop_serial_(jl_ptls_t ptls, jl_gc_markqueue_t *mq) { while (1) { - void *new_obj = (void *)gc_ptr_queue_pop(&ptls->mark_queue); + void *new_obj = (void *)gc_ptr_queue_pop(&ptls->gc_tls.mark_queue); // No more objects to mark if (__unlikely(new_obj == NULL)) { return; @@ -2940,17 +2940,16 @@ void gc_drain_own_chunkqueue(jl_ptls_t ptls, jl_gc_markqueue_t *mq) // makes it easier to implement parallel marking via work-stealing JL_EXTENSION NOINLINE void gc_mark_loop_serial(jl_ptls_t ptls) { - gc_mark_loop_serial_(ptls, &ptls->mark_queue); - gc_drain_own_chunkqueue(ptls, &ptls->mark_queue); + gc_mark_loop_serial_(ptls, &ptls->gc_tls.mark_queue); + gc_drain_own_chunkqueue(ptls, &ptls->gc_tls.mark_queue); } void gc_mark_and_steal(jl_ptls_t ptls) { - jl_gc_markqueue_t *mq = &ptls->mark_queue; - jl_gc_markqueue_t *mq_master = NULL; int master_tid = jl_atomic_load(&gc_master_tid); assert(master_tid != -1); - mq_master = &gc_all_tls_states[master_tid]->mark_queue; + jl_gc_markqueue_t *mq = &ptls->gc_tls.mark_queue; + jl_gc_markqueue_t *mq_master = &gc_all_tls_states[master_tid]->gc_tls.mark_queue; void *new_obj; jl_gc_chunk_t c; pop : { @@ -2981,7 +2980,7 @@ void gc_mark_and_steal(jl_ptls_t ptls) int v = gc_random_parallel_collector_thread_id(ptls); jl_ptls_t ptls2 = gc_all_tls_states[v]; gc_check_ptls_of_parallel_collector_thread(ptls2); - jl_gc_markqueue_t *mq2 = &ptls2->mark_queue; + jl_gc_markqueue_t *mq2 = &ptls2->gc_tls.mark_queue; c = gc_chunkqueue_steal_from(mq2); if (c.cid != GC_empty_chunk) { gc_mark_chunk(ptls, mq, &c); @@ -2992,7 +2991,7 @@ void gc_mark_and_steal(jl_ptls_t ptls) for (int i = first; i <= last; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; gc_check_ptls_of_parallel_collector_thread(ptls2); - jl_gc_markqueue_t *mq2 = &ptls2->mark_queue; + jl_gc_markqueue_t *mq2 = &ptls2->gc_tls.mark_queue; c = gc_chunkqueue_steal_from(mq2); if (c.cid != GC_empty_chunk) { gc_mark_chunk(ptls, mq, &c); @@ -3012,7 +3011,7 @@ void gc_mark_and_steal(jl_ptls_t ptls) int v = gc_random_parallel_collector_thread_id(ptls); jl_ptls_t ptls2 = gc_all_tls_states[v]; gc_check_ptls_of_parallel_collector_thread(ptls2); - jl_gc_markqueue_t *mq2 = &ptls2->mark_queue; + jl_gc_markqueue_t *mq2 = &ptls2->gc_tls.mark_queue; new_obj = gc_ptr_queue_steal_from(mq2); if (new_obj != NULL) goto mark; @@ -3021,7 +3020,7 @@ void gc_mark_and_steal(jl_ptls_t ptls) for (int i = first; i <= last; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; gc_check_ptls_of_parallel_collector_thread(ptls2); - jl_gc_markqueue_t *mq2 = &ptls2->mark_queue; + jl_gc_markqueue_t *mq2 = &ptls2->gc_tls.mark_queue; new_obj = gc_ptr_queue_steal_from(mq2); if (new_obj != NULL) goto mark; @@ -3039,10 +3038,10 @@ size_t gc_count_work_in_queue(jl_ptls_t ptls) JL_NOTSAFEPOINT { // assume each chunk is worth 256 units of work and each pointer // is worth 1 unit of work - size_t work = 256 * (jl_atomic_load_relaxed(&ptls->mark_queue.chunk_queue.bottom) - - jl_atomic_load_relaxed(&ptls->mark_queue.chunk_queue.top)); - work += (jl_atomic_load_relaxed(&ptls->mark_queue.ptr_queue.bottom) - - jl_atomic_load_relaxed(&ptls->mark_queue.ptr_queue.top)); + size_t work = 256 * (jl_atomic_load_relaxed(&ptls->gc_tls.mark_queue.chunk_queue.bottom) - + jl_atomic_load_relaxed(&ptls->gc_tls.mark_queue.chunk_queue.top)); + work += (jl_atomic_load_relaxed(&ptls->gc_tls.mark_queue.ptr_queue.bottom) - + jl_atomic_load_relaxed(&ptls->gc_tls.mark_queue.ptr_queue.top)); return work; } @@ -3152,7 +3151,10 @@ void gc_mark_clean_reclaim_sets(void) // Clean up `reclaim-sets` for (int i = 0; i < gc_n_threads; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; - arraylist_t *reclaim_set2 = &ptls2->mark_queue.reclaim_set; + if (ptls2 == NULL) { + continue; + } + arraylist_t *reclaim_set2 = &ptls2->gc_tls.mark_queue.reclaim_set; ws_array_t *a = NULL; while ((a = (ws_array_t *)arraylist_pop(reclaim_set2)) != NULL) { free(a->buffer); @@ -3165,10 +3167,10 @@ void gc_mark_clean_reclaim_sets(void) if (ptls2 == NULL) { continue; } - jl_atomic_store_relaxed(&ptls2->mark_queue.ptr_queue.bottom, 0); - jl_atomic_store_relaxed(&ptls2->mark_queue.ptr_queue.top, 0); - jl_atomic_store_relaxed(&ptls2->mark_queue.chunk_queue.bottom, 0); - jl_atomic_store_relaxed(&ptls2->mark_queue.chunk_queue.top, 0); + jl_atomic_store_relaxed(&ptls2->gc_tls.mark_queue.ptr_queue.bottom, 0); + jl_atomic_store_relaxed(&ptls2->gc_tls.mark_queue.ptr_queue.top, 0); + jl_atomic_store_relaxed(&ptls2->gc_tls.mark_queue.chunk_queue.bottom, 0); + jl_atomic_store_relaxed(&ptls2->gc_tls.mark_queue.chunk_queue.top, 0); } } @@ -3217,8 +3219,8 @@ static void gc_queue_bt_buf(jl_gc_markqueue_t *mq, jl_ptls_t ptls2) static void gc_queue_remset(jl_gc_markqueue_t *mq, jl_ptls_t ptls2) { - void **items = ptls2->heap.remset.items; - size_t len = ptls2->heap.remset.len; + void **items = ptls2->gc_tls.heap.remset.items; + size_t len = ptls2->gc_tls.heap.remset.len; for (size_t i = 0; i < len; i++) { void *_v = items[i]; jl_astaggedvalue(_v)->bits.gc = GC_OLD_MARKED; @@ -3226,8 +3228,8 @@ static void gc_queue_remset(jl_gc_markqueue_t *mq, jl_ptls_t ptls2) gc_ptr_queue_push(mq, v); } // Don't forget to clear the remset - ptls2->heap.remset.len = 0; - ptls2->heap.remset_nptr = 0; + ptls2->gc_tls.heap.remset.len = 0; + ptls2->gc_tls.heap.remset_nptr = 0; } static void gc_check_all_remsets_are_empty(void) @@ -3235,8 +3237,8 @@ static void gc_check_all_remsets_are_empty(void) for (int i = 0; i < gc_n_threads; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; if (ptls2 != NULL) { - assert(ptls2->heap.remset.len == 0); - assert(ptls2->heap.remset_nptr == 0); + assert(ptls2->gc_tls.heap.remset.len == 0); + assert(ptls2->gc_tls.heap.remset_nptr == 0); } } } @@ -3409,7 +3411,7 @@ JL_DLLEXPORT int64_t jl_gc_pool_live_bytes(void) for (int i = 0; i < n_threads; i++) { jl_ptls_t ptls2 = all_tls_states[i]; if (ptls2 != NULL) { - pool_live_bytes += jl_atomic_load_relaxed(&ptls2->gc_num.pool_live_bytes); + pool_live_bytes += jl_atomic_load_relaxed(&ptls2->gc_tls.gc_num.pool_live_bytes); } } return pool_live_bytes; @@ -3431,7 +3433,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) // so that the sweep shows a downward trend in memory usage. jl_timing_counter_inc(JL_TIMING_COUNTER_HeapSize, gc_num.allocd); - jl_gc_markqueue_t *mq = &ptls->mark_queue; + jl_gc_markqueue_t *mq = &ptls->gc_tls.mark_queue; uint64_t gc_start_time = jl_hrtime(); int64_t last_perm_scanned_bytes = perm_scanned_bytes; @@ -3448,7 +3450,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) if (!single_threaded_mark) { int dest_tid = gc_ith_parallel_collector_thread_id(t_i % jl_n_markthreads); ptls_dest = gc_all_tls_states[dest_tid]; - mq_dest = &ptls_dest->mark_queue; + mq_dest = &ptls_dest->gc_tls.mark_queue; } if (ptls2 != NULL) { // 1.1. mark every thread local root @@ -3542,7 +3544,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) for (int i = 0; i < gc_n_threads; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; if (ptls2 != NULL) - nptr += ptls2->heap.remset_nptr; + nptr += ptls2->gc_tls.heap.remset_nptr; } // many pointers in the intergen frontier => "quick" mark is not quick @@ -3641,13 +3643,13 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) if (ptls2 == NULL) continue; if (!sweep_full) { - for (int i = 0; i < ptls2->heap.remset.len; i++) { - void *ptr = ptls2->heap.remset.items[i]; + for (int i = 0; i < ptls2->gc_tls.heap.remset.len; i++) { + void *ptr = ptls2->gc_tls.heap.remset.items[i]; jl_astaggedvalue(ptr)->bits.gc = GC_MARKED; } } else { - ptls2->heap.remset.len = 0; + ptls2->gc_tls.heap.remset.len = 0; } } @@ -3735,8 +3737,8 @@ JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection) jl_task_t *ct = jl_current_task; jl_ptls_t ptls = ct->ptls; if (jl_atomic_load_acquire(&jl_gc_disable_counter)) { - size_t localbytes = jl_atomic_load_relaxed(&ptls->gc_num.allocd) + gc_num.interval; - jl_atomic_store_relaxed(&ptls->gc_num.allocd, -(int64_t)gc_num.interval); + size_t localbytes = jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.allocd) + gc_num.interval; + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.allocd, -(int64_t)gc_num.interval); static_assert(sizeof(_Atomic(uint64_t)) == sizeof(gc_num.deferred_alloc), ""); jl_atomic_fetch_add((_Atomic(uint64_t)*)&gc_num.deferred_alloc, localbytes); return; @@ -3848,7 +3850,7 @@ JL_DLLEXPORT jl_value_t *(jl_gc_alloc)(jl_ptls_t ptls, size_t sz, void *ty) // Per-thread initialization void jl_init_thread_heap(jl_ptls_t ptls) { - jl_thread_heap_t *heap = &ptls->heap; + jl_thread_heap_t *heap = &ptls->gc_tls.heap; jl_gc_pool_t *p = heap->norm_pools; for (int i = 0; i < JL_GC_N_POOLS; i++) { p[i].osize = jl_gc_sizeclasses[i]; @@ -3864,15 +3866,15 @@ void jl_init_thread_heap(jl_ptls_t ptls) heap->big_objects = NULL; arraylist_new(&heap->remset, 0); arraylist_new(&ptls->finalizers, 0); - arraylist_new(&ptls->sweep_objs, 0); + arraylist_new(&ptls->gc_tls.sweep_objs, 0); - jl_gc_mark_cache_t *gc_cache = &ptls->gc_cache; + jl_gc_mark_cache_t *gc_cache = &ptls->gc_tls.gc_cache; gc_cache->perm_scanned_bytes = 0; gc_cache->scanned_bytes = 0; gc_cache->nbig_obj = 0; // Initialize GC mark-queue - jl_gc_markqueue_t *mq = &ptls->mark_queue; + jl_gc_markqueue_t *mq = &ptls->gc_tls.mark_queue; ws_queue_t *cq = &mq->chunk_queue; ws_array_t *wsa = create_ws_array(GC_CHUNK_QUEUE_INIT_SIZE, sizeof(jl_gc_chunk_t)); jl_atomic_store_relaxed(&cq->top, 0); @@ -3885,8 +3887,8 @@ void jl_init_thread_heap(jl_ptls_t ptls) jl_atomic_store_relaxed(&q->array, wsa2); arraylist_new(&mq->reclaim_set, 32); - memset(&ptls->gc_num, 0, sizeof(ptls->gc_num)); - jl_atomic_store_relaxed(&ptls->gc_num.allocd, -(int64_t)gc_num.interval); + memset(&ptls->gc_tls.gc_num, 0, sizeof(ptls->gc_tls.gc_num)); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.allocd, -(int64_t)gc_num.interval); } // System-wide initializations @@ -3964,10 +3966,10 @@ JL_DLLEXPORT void *jl_gc_counted_malloc(size_t sz) if (data != NULL && pgcstack != NULL && ct->world_age) { jl_ptls_t ptls = ct->ptls; maybe_collect(ptls); - jl_atomic_store_relaxed(&ptls->gc_num.allocd, - 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_store_relaxed(&ptls->gc_tls.gc_num.allocd, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.allocd) + sz); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.malloc, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.malloc) + 1); } return data; } @@ -3980,10 +3982,10 @@ JL_DLLEXPORT void *jl_gc_counted_calloc(size_t nm, size_t sz) if (data != NULL && pgcstack != NULL && ct->world_age) { jl_ptls_t ptls = ct->ptls; maybe_collect(ptls); - jl_atomic_store_relaxed(&ptls->gc_num.allocd, - 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_store_relaxed(&ptls->gc_tls.gc_num.allocd, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.allocd) + nm*sz); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.malloc, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.malloc) + 1); } return data; } @@ -3995,10 +3997,10 @@ JL_DLLEXPORT void jl_gc_counted_free_with_size(void *p, size_t sz) free(p); if (pgcstack != NULL && ct->world_age) { jl_ptls_t ptls = ct->ptls; - jl_atomic_store_relaxed(&ptls->gc_num.freed, - 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_store_relaxed(&ptls->gc_tls.gc_num.freed, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.freed) + sz); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.freecall, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.freecall) + 1); } } @@ -4011,13 +4013,13 @@ JL_DLLEXPORT void *jl_gc_counted_realloc_with_old_size(void *p, size_t old, size jl_ptls_t ptls = ct->ptls; maybe_collect(ptls); if (sz < old) - jl_atomic_store_relaxed(&ptls->gc_num.freed, - jl_atomic_load_relaxed(&ptls->gc_num.freed) + (old - sz)); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.freed, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.freed) + (old - sz)); else - jl_atomic_store_relaxed(&ptls->gc_num.allocd, - jl_atomic_load_relaxed(&ptls->gc_num.allocd) + (sz - old)); - jl_atomic_store_relaxed(&ptls->gc_num.realloc, - jl_atomic_load_relaxed(&ptls->gc_num.realloc) + 1); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.allocd, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.allocd) + (sz - old)); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.realloc, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.realloc) + 1); } return data; } @@ -4097,10 +4099,10 @@ JL_DLLEXPORT void *jl_gc_managed_malloc(size_t sz) if (b == NULL) jl_throw(jl_memory_exception); - jl_atomic_store_relaxed(&ptls->gc_num.allocd, - jl_atomic_load_relaxed(&ptls->gc_num.allocd) + allocsz); - jl_atomic_store_relaxed(&ptls->gc_num.malloc, - jl_atomic_load_relaxed(&ptls->gc_num.malloc) + 1); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.allocd, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.allocd) + allocsz); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.malloc, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.malloc) + 1); #ifdef _OS_WINDOWS_ SetLastError(last_error); #endif @@ -4137,17 +4139,17 @@ static void *gc_managed_realloc_(jl_ptls_t ptls, void *d, size_t sz, size_t olds errno = last_errno; // gc_managed_realloc_ is currently used exclusively for resizing array buffers. if (is_old_marked) { - ptls->gc_cache.perm_scanned_bytes += allocsz - oldsz; + ptls->gc_tls.gc_cache.perm_scanned_bytes += allocsz - oldsz; inc_live_bytes(allocsz - oldsz); } else if (allocsz < oldsz) - jl_atomic_store_relaxed(&ptls->gc_num.freed, - jl_atomic_load_relaxed(&ptls->gc_num.freed) + (oldsz - allocsz)); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.freed, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.freed) + (oldsz - allocsz)); else - jl_atomic_store_relaxed(&ptls->gc_num.allocd, - jl_atomic_load_relaxed(&ptls->gc_num.allocd) + (allocsz - oldsz)); - jl_atomic_store_relaxed(&ptls->gc_num.realloc, - jl_atomic_load_relaxed(&ptls->gc_num.realloc) + 1); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.allocd, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.allocd) + (allocsz - oldsz)); + jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.realloc, + jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.realloc) + 1); if (allocsz > oldsz) { maybe_record_alloc_to_profile((jl_value_t*)b, allocsz - oldsz, (jl_datatype_t*)jl_buff_tag); } @@ -4338,7 +4340,7 @@ JL_DLLEXPORT jl_value_t *jl_gc_internal_obj_base_ptr(void *p) goto valid_object; } jl_gc_pool_t *pool = - gc_all_tls_states[meta->thread_n]->heap.norm_pools + + gc_all_tls_states[meta->thread_n]->gc_tls.heap.norm_pools + meta->pool_n; if (meta->fl_begin_offset == UINT16_MAX) { // case 2: this is a page on the newpages list @@ -4418,7 +4420,7 @@ JL_DLLEXPORT void * jl_gc_alloc_typed(jl_ptls_t ptls, size_t sz, void *ty) JL_DLLEXPORT void jl_gc_schedule_foreign_sweepfunc(jl_ptls_t ptls, jl_value_t *obj) { - arraylist_push(&ptls->sweep_objs, obj); + arraylist_push(&ptls->gc_tls.sweep_objs, obj); } #ifdef __cplusplus diff --git a/src/julia_internal.h b/src/julia_internal.h index 1ea84c0dc0d4f..75ebad73a4546 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -498,7 +498,7 @@ STATIC_INLINE jl_value_t *jl_gc_alloc_(jl_ptls_t ptls, size_t sz, void *ty) const size_t allocsz = sz + sizeof(jl_taggedvalue_t); if (sz <= GC_MAX_SZCLASS) { int pool_id = jl_gc_szclass(allocsz); - jl_gc_pool_t *p = &ptls->heap.norm_pools[pool_id]; + jl_gc_pool_t *p = &ptls->gc_tls.heap.norm_pools[pool_id]; int osize = jl_gc_sizeclasses[pool_id]; // We call `jl_gc_pool_alloc_noinline` instead of `jl_gc_pool_alloc` to avoid double-counting in // the Allocations Profiler. (See https://github.com/JuliaLang/julia/pull/43868 for more details.) diff --git a/src/julia_threads.h b/src/julia_threads.h index 9bca500604b0e..3d06d380d10c2 100644 --- a/src/julia_threads.h +++ b/src/julia_threads.h @@ -4,8 +4,8 @@ #ifndef JL_THREADS_H #define JL_THREADS_H +#include "gc-tls.h" #include "julia_atomics.h" -#include "work-stealing-queue.h" #ifndef _OS_WINDOWS_ #include "pthread.h" #endif @@ -122,80 +122,7 @@ typedef struct { uint32_t count; } jl_mutex_t; -typedef struct { - jl_taggedvalue_t *freelist; // root of list of free objects - jl_taggedvalue_t *newpages; // root of list of chunks of free objects - uint16_t osize; // size of objects in this pool -} jl_gc_pool_t; - -typedef struct { - _Atomic(int64_t) allocd; - _Atomic(int64_t) pool_live_bytes; - _Atomic(int64_t) freed; - _Atomic(uint64_t) malloc; - _Atomic(uint64_t) realloc; - _Atomic(uint64_t) poolalloc; - _Atomic(uint64_t) bigalloc; - _Atomic(uint64_t) freecall; -} jl_thread_gc_num_t; - -typedef struct { - // variable for tracking weak references - small_arraylist_t weak_refs; - // live tasks started on this thread - // that are holding onto a stack from the pool - small_arraylist_t live_tasks; - - // variables for tracking malloc'd arrays - struct _mallocarray_t *mallocarrays; - struct _mallocarray_t *mafreelist; - - // variables for tracking big objects - struct _bigval_t *big_objects; - - // lower bound of the number of pointers inside remembered values - int remset_nptr; - // remembered set - arraylist_t remset; - - // variables for allocating objects from pools -#define JL_GC_N_MAX_POOLS 51 // conservative. must be kept in sync with `src/julia_internal.h` - jl_gc_pool_t norm_pools[JL_GC_N_MAX_POOLS]; - -#define JL_N_STACK_POOLS 16 - small_arraylist_t free_stacks[JL_N_STACK_POOLS]; -} jl_thread_heap_t; - -typedef struct { - ws_queue_t chunk_queue; - ws_queue_t ptr_queue; - arraylist_t reclaim_set; -} jl_gc_markqueue_t; - -typedef struct { - // thread local increment of `perm_scanned_bytes` - size_t perm_scanned_bytes; - // thread local increment of `scanned_bytes` - size_t scanned_bytes; - // Number of queued big objects (<= 1024) - size_t nbig_obj; - // Array of queued big objects to be moved between the young list - // and the old list. - // A set low bit means that the object should be moved from the old list - // to the young list (`mark_reset_age`). - // Objects can only be put into this list when the mark bit is flipped to - // `1` (atomically). Combining with the sync after marking, - // this makes sure that a single objects can only appear once in - // the lists (the mark bit cannot be flipped to `0` without sweeping) - void *big_obj[1024]; -} jl_gc_mark_cache_t; - struct _jl_bt_element_t; -struct _jl_gc_pagemeta_t; - -typedef struct { - _Atomic(struct _jl_gc_pagemeta_t *) bottom; -} jl_gc_page_stack_t; // This includes all the thread local states we care about for a thread. // Changes to TLS field types must be reflected in codegen. @@ -227,8 +154,7 @@ typedef struct _jl_tls_states_t { int8_t disable_gc; // Counter to disable finalizer **on the current thread** int finalizers_inhibited; - jl_thread_heap_t heap; // this is very large, and the offset is baked into codegen - jl_thread_gc_num_t gc_num; + jl_gc_tls_states_t gc_tls; // this is very large, and the offset of the first member is baked into codegen volatile sig_atomic_t defer_signal; _Atomic(struct _jl_task_t*) current_task; struct _jl_task_t *next_task; @@ -262,11 +188,6 @@ typedef struct _jl_tls_states_t { #endif jl_thread_t system_id; arraylist_t finalizers; - jl_gc_page_stack_t page_metadata_allocd; - jl_gc_markqueue_t mark_queue; - jl_gc_mark_cache_t gc_cache; - arraylist_t sweep_objs; - _Atomic(int64_t) gc_sweeps_requested; // Saved exception for previous *external* API call or NULL if cleared. // Access via jl_exception_occurred(). struct _jl_value_t *previous_exception; diff --git a/src/partr.c b/src/partr.c index b0b4ee77a9ec5..33631dc83c05a 100644 --- a/src/partr.c +++ b/src/partr.c @@ -115,7 +115,7 @@ static inline int may_mark(void) JL_NOTSAFEPOINT static inline int may_sweep(jl_ptls_t ptls) JL_NOTSAFEPOINT { - return (jl_atomic_load(&ptls->gc_sweeps_requested) > 0); + return (jl_atomic_load(&ptls->gc_tls.gc_sweeps_requested) > 0); } // parallel gc thread function @@ -148,7 +148,7 @@ void jl_parallel_gc_threadfun(void *arg) if (may_sweep(ptls)) { assert(jl_atomic_load_relaxed(&ptls->gc_state) == JL_GC_PARALLEL_COLLECTOR_THREAD); gc_sweep_pool_parallel(ptls); - jl_atomic_fetch_add(&ptls->gc_sweeps_requested, -1); + jl_atomic_fetch_add(&ptls->gc_tls.gc_sweeps_requested, -1); } } } diff --git a/src/stackwalk.c b/src/stackwalk.c index ebf56931c2c65..8a12fb2a28143 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -1187,7 +1187,7 @@ JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT if (ptls2 == NULL) { continue; } - small_arraylist_t *live_tasks = &ptls2->heap.live_tasks; + small_arraylist_t *live_tasks = &ptls2->gc_tls.heap.live_tasks; size_t n = mtarraylist_length(live_tasks); int t_state = JL_TASK_STATE_DONE; jl_task_t *t = ptls2->root_task; From 1f66e0d9ee47695a7eeb863a7abfabd2ee846df3 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Mon, 15 Jul 2024 19:20:23 -0300 Subject: [PATCH 073/109] Simplify sweeping of big values (#54936) Simplifies the layout of the doubly linked list of big objects to make it a bit more canonical: let's just store a pointer to the previous element, instead of storing a "pointer to the next element of the previous element". This should make the implementation a bit easier to understand without incurring any memory overhead. I ran the serial and multithreaded benchmarks from GCBenchmarks and this seems fairly close to performance neutral on my machine. We also ran our internal benchmarks on it at RAI and it looks fine from a correctness and performance point of view. --------- Co-authored-by: Kiran Pamnany --- src/gc-debug.c | 8 +-- src/gc-tls.h | 4 +- src/gc.c | 158 ++++++++++++++++++++++++------------------------- src/gc.h | 35 +++++++---- 4 files changed, 105 insertions(+), 100 deletions(-) diff --git a/src/gc-debug.c b/src/gc-debug.c index 5b90ce7cd955b..91e8b7fa9f63d 100644 --- a/src/gc-debug.c +++ b/src/gc-debug.c @@ -132,7 +132,7 @@ static void clear_mark(int bits) } bigval_t *v; for (int i = 0; i < gc_n_threads; i++) { - v = gc_all_tls_states[i]->gc_tls.heap.big_objects; + v = gc_all_tls_states[i]->gc_tls.heap.young_generation_of_bigvals; while (v != NULL) { void *gcv = &v->header; if (!gc_verifying) @@ -142,7 +142,7 @@ static void clear_mark(int bits) } } - v = big_objects_marked; + v = oldest_generation_of_bigvals; while (v != NULL) { void *gcv = &v->header; if (!gc_verifying) @@ -965,7 +965,7 @@ void gc_stats_big_obj(void) size_t nused=0, nbytes=0, nused_old=0, nbytes_old=0; for (int t_i = 0; t_i < gc_n_threads; t_i++) { jl_ptls_t ptls2 = gc_all_tls_states[t_i]; - bigval_t *v = ptls2->gc_tls.heap.big_objects; + bigval_t *v = ptls2->gc_tls.heap.young_generation_of_bigvals; while (v != NULL) { if (gc_marked(v->bits.gc)) { nused++; @@ -973,7 +973,7 @@ void gc_stats_big_obj(void) } v = v->next; } - v = big_objects_marked; + v = oldest_generation_of_bigvals; while (v != NULL) { if (gc_marked(v->bits.gc)) { nused_old++; diff --git a/src/gc-tls.h b/src/gc-tls.h index 3f8662b467e30..dc15cda48fa58 100644 --- a/src/gc-tls.h +++ b/src/gc-tls.h @@ -31,8 +31,8 @@ typedef struct { struct _mallocarray_t *mallocarrays; struct _mallocarray_t *mafreelist; - // variables for tracking big objects - struct _bigval_t *big_objects; + // variable for tracking young (i.e. not in `GC_OLD_MARKED`/last generation) large objects + struct _bigval_t *young_generation_of_bigvals; // lower bound of the number of pointers inside remembered values int remset_nptr; diff --git a/src/gc.c b/src/gc.c index e96fc9637d6f9..c70eee6905ee9 100644 --- a/src/gc.c +++ b/src/gc.c @@ -34,6 +34,8 @@ uv_cond_t gc_threads_cond; uv_sem_t gc_sweep_assists_needed; // Mutex used to coordinate entry of GC threads in the mark loop uv_mutex_t gc_queue_observer_lock; +// Tag for sentinel nodes in bigval list +uintptr_t gc_bigval_sentinel_tag; // Linked list of callback functions @@ -150,7 +152,6 @@ JL_DLLEXPORT void jl_gc_set_cb_notify_gc_pressure(jl_gc_cb_notify_gc_pressure_t // is going to realloc the buffer (of its own list) or accessing the // list of another thread static jl_mutex_t finalizers_lock; -static uv_mutex_t gc_cache_lock; // mutex for gc-heap-snapshot. jl_mutex_t heapsnapshot_lock; @@ -201,8 +202,8 @@ JL_DLLEXPORT uintptr_t jl_get_buff_tag(void) JL_NOTSAFEPOINT return jl_buff_tag; } -// List of marked big objects. Not per-thread. Accessed only by master thread. -bigval_t *big_objects_marked = NULL; +// List of big objects in oldest generation (`GC_OLD_MARKED`). Not per-thread. Accessed only by master thread. +bigval_t *oldest_generation_of_bigvals = NULL; // -- Finalization -- // `ptls->finalizers` and `finalizer_list_marked` might have tagged pointers. @@ -759,60 +760,25 @@ static int64_t t_start = 0; // Time GC starts; static int64_t last_trim_maxrss = 0; #endif -static void gc_sync_cache_nolock(jl_ptls_t ptls, jl_gc_mark_cache_t *gc_cache) JL_NOTSAFEPOINT +static void gc_sync_cache(jl_ptls_t ptls, jl_gc_mark_cache_t *gc_cache) JL_NOTSAFEPOINT { - const int nbig = gc_cache->nbig_obj; - for (int i = 0; i < nbig; i++) { - void *ptr = gc_cache->big_obj[i]; - bigval_t *hdr = (bigval_t*)gc_ptr_clear_tag(ptr, 1); - gc_big_object_unlink(hdr); - if (gc_ptr_tag(ptr, 1)) { - gc_big_object_link(hdr, &ptls->gc_tls.heap.big_objects); - } - else { - // Move hdr from `big_objects` list to `big_objects_marked list` - gc_big_object_link(hdr, &big_objects_marked); - } - } - gc_cache->nbig_obj = 0; perm_scanned_bytes += gc_cache->perm_scanned_bytes; scanned_bytes += gc_cache->scanned_bytes; gc_cache->perm_scanned_bytes = 0; gc_cache->scanned_bytes = 0; } -static void gc_sync_cache(jl_ptls_t ptls) JL_NOTSAFEPOINT -{ - uv_mutex_lock(&gc_cache_lock); - gc_sync_cache_nolock(ptls, &ptls->gc_tls.gc_cache); - uv_mutex_unlock(&gc_cache_lock); -} - // No other threads can be running marking at the same time -static void gc_sync_all_caches_nolock(jl_ptls_t ptls) +static void gc_sync_all_caches(jl_ptls_t ptls) { assert(gc_n_threads); for (int t_i = 0; t_i < gc_n_threads; t_i++) { jl_ptls_t ptls2 = gc_all_tls_states[t_i]; if (ptls2 != NULL) - gc_sync_cache_nolock(ptls, &ptls2->gc_tls.gc_cache); + gc_sync_cache(ptls, &ptls2->gc_tls.gc_cache); } } -STATIC_INLINE void gc_queue_big_marked(jl_ptls_t ptls, bigval_t *hdr, - int toyoung) JL_NOTSAFEPOINT -{ - const int nentry = sizeof(ptls->gc_tls.gc_cache.big_obj) / sizeof(void*); - size_t nobj = ptls->gc_tls.gc_cache.nbig_obj; - if (__unlikely(nobj >= nentry)) { - gc_sync_cache(ptls); - nobj = 0; - } - uintptr_t v = (uintptr_t)hdr; - ptls->gc_tls.gc_cache.big_obj[nobj] = (void*)(toyoung ? (v | 1) : v); - ptls->gc_tls.gc_cache.nbig_obj = nobj + 1; -} - // Atomically set the mark bit for object and return whether it was previously unmarked FORCE_INLINE int gc_try_setmark_tag(jl_taggedvalue_t *o, uint8_t mark_mode) JL_NOTSAFEPOINT { @@ -849,16 +815,14 @@ STATIC_INLINE void gc_setmark_big(jl_ptls_t ptls, jl_taggedvalue_t *o, bigval_t *hdr = bigval_header(o); if (mark_mode == GC_OLD_MARKED) { ptls->gc_tls.gc_cache.perm_scanned_bytes += hdr->sz; - gc_queue_big_marked(ptls, hdr, 0); } else { ptls->gc_tls.gc_cache.scanned_bytes += hdr->sz; - // We can't easily tell if the object is old or being promoted - // from the gc bits but if the `age` is `0` then the object - // must be already on a young list. if (mark_reset_age) { + assert(jl_atomic_load(&gc_n_threads_marking) == 0); // `mark_reset_age` is only used during single-threaded marking // Reset the object as if it was just allocated - gc_queue_big_marked(ptls, hdr, 1); + gc_big_object_unlink(hdr); + gc_big_object_link(ptls->gc_tls.heap.young_generation_of_bigvals, hdr); } } } @@ -1023,7 +987,7 @@ STATIC_INLINE jl_value_t *jl_gc_big_alloc_inner(jl_ptls_t ptls, size_t sz) memset(v, 0xee, allocsz); #endif v->sz = allocsz; - gc_big_object_link(v, &ptls->gc_tls.heap.big_objects); + gc_big_object_link(ptls->gc_tls.heap.young_generation_of_bigvals, v); return jl_valueof(&v->header); } @@ -1043,60 +1007,85 @@ jl_value_t *jl_gc_big_alloc_noinline(jl_ptls_t ptls, size_t sz) { return jl_gc_big_alloc_inner(ptls, sz); } -// Sweep list rooted at *pv, removing and freeing any unmarked objects. -// Return pointer to last `next` field in the culled list. -static bigval_t **sweep_big_list(int sweep_full, bigval_t **pv) JL_NOTSAFEPOINT +FORCE_INLINE void sweep_unlink_and_free(bigval_t *v) JL_NOTSAFEPOINT +{ + gc_big_object_unlink(v); + gc_num.freed += v->sz; +#ifdef MEMDEBUG + memset(v, 0xbb, v->sz); +#endif + gc_invoke_callbacks(jl_gc_cb_notify_external_free_t, gc_cblist_notify_external_free, (v)); + jl_free_aligned(v); +} + +static bigval_t *sweep_list_of_young_bigvals(bigval_t *young) JL_NOTSAFEPOINT { - bigval_t *v = *pv; + bigval_t *last_node = young; + bigval_t *v = young->next; // skip the sentinel + bigval_t *old = oldest_generation_of_bigvals; + int sweep_full = current_sweep_full; // don't load the global in the hot loop while (v != NULL) { bigval_t *nxt = v->next; int bits = v->bits.gc; int old_bits = bits; if (gc_marked(bits)) { - pv = &v->next; if (sweep_full || bits == GC_MARKED) { bits = GC_OLD; + last_node = v; + } + else { // `bits == GC_OLD_MARKED` + assert(bits == GC_OLD_MARKED); + // reached oldest generation, move from young list to old list + gc_big_object_unlink(v); + gc_big_object_link(old, v); } v->bits.gc = bits; } else { - // Remove v from list and free it - *pv = nxt; - if (nxt) - nxt->prev = pv; - gc_num.freed += v->sz; -#ifdef MEMDEBUG - memset(v, 0xbb, v->sz); -#endif - gc_invoke_callbacks(jl_gc_cb_notify_external_free_t, - gc_cblist_notify_external_free, (v)); - jl_free_aligned(v); + sweep_unlink_and_free(v); } gc_time_count_big(old_bits, bits); v = nxt; } - return pv; + return last_node; +} + +static void sweep_list_of_oldest_bigvals(bigval_t *young) JL_NOTSAFEPOINT +{ + bigval_t *v = oldest_generation_of_bigvals->next; // skip the sentinel + while (v != NULL) { + bigval_t *nxt = v->next; + assert(v->bits.gc == GC_OLD_MARKED); + v->bits.gc = GC_OLD; + gc_time_count_big(GC_OLD_MARKED, GC_OLD); + v = nxt; + } } -static void sweep_big(jl_ptls_t ptls, int sweep_full) JL_NOTSAFEPOINT +static void sweep_big(jl_ptls_t ptls) JL_NOTSAFEPOINT { gc_time_big_start(); assert(gc_n_threads); + bigval_t *last_node_in_my_list = NULL; for (int i = 0; i < gc_n_threads; i++) { jl_ptls_t ptls2 = gc_all_tls_states[i]; - if (ptls2 != NULL) - sweep_big_list(sweep_full, &ptls2->gc_tls.heap.big_objects); + if (ptls2 != NULL) { + bigval_t *last_node = sweep_list_of_young_bigvals(ptls2->gc_tls.heap.young_generation_of_bigvals); + if (ptls == ptls2) { + last_node_in_my_list = last_node; + } + } } - if (sweep_full) { - bigval_t **last_next = sweep_big_list(sweep_full, &big_objects_marked); - // Move all survivors from big_objects_marked list to the big_objects list of this thread. - if (ptls->gc_tls.heap.big_objects) - ptls->gc_tls.heap.big_objects->prev = last_next; - *last_next = ptls->gc_tls.heap.big_objects; - ptls->gc_tls.heap.big_objects = big_objects_marked; - if (ptls->gc_tls.heap.big_objects) - ptls->gc_tls.heap.big_objects->prev = &ptls->gc_tls.heap.big_objects; - big_objects_marked = NULL; + if (current_sweep_full) { + sweep_list_of_oldest_bigvals(ptls->gc_tls.heap.young_generation_of_bigvals); + // move all nodes in `oldest_generation_of_bigvals` to my list of bigvals + assert(last_node_in_my_list != NULL); + assert(last_node_in_my_list->next == NULL); + last_node_in_my_list->next = oldest_generation_of_bigvals->next; // skip the sentinel + if (oldest_generation_of_bigvals->next != NULL) { + oldest_generation_of_bigvals->next->prev = last_node_in_my_list; + } + oldest_generation_of_bigvals->next = NULL; } gc_time_big_end(); } @@ -1536,7 +1525,7 @@ STATIC_INLINE void gc_sweep_pool_page(gc_page_profiler_serializer_t *s, jl_gc_pa static void gc_sweep_other(jl_ptls_t ptls, int sweep_full) JL_NOTSAFEPOINT { sweep_malloced_arrays(); - sweep_big(ptls, sweep_full); + sweep_big(ptls); } static void gc_pool_sync_nfree(jl_gc_pagemeta_t *pg, jl_taggedvalue_t *last) JL_NOTSAFEPOINT @@ -3524,7 +3513,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) // marking is over // Flush everything in mark cache - gc_sync_all_caches_nolock(ptls); + gc_sync_all_caches(ptls); int64_t live_sz_ub = live_bytes + actual_allocd; int64_t live_sz_est = scanned_bytes + perm_scanned_bytes; @@ -3863,7 +3852,9 @@ void jl_init_thread_heap(jl_ptls_t ptls) small_arraylist_new(&heap->free_stacks[i], 0); heap->mallocarrays = NULL; heap->mafreelist = NULL; - heap->big_objects = NULL; + heap->young_generation_of_bigvals = (bigval_t*)calloc_s(sizeof(bigval_t)); // sentinel + assert(gc_bigval_sentinel_tag != 0); // make sure the sentinel is initialized + heap->young_generation_of_bigvals->header = gc_bigval_sentinel_tag; arraylist_new(&heap->remset, 0); arraylist_new(&ptls->finalizers, 0); arraylist_new(&ptls->gc_tls.sweep_objs, 0); @@ -3871,7 +3862,6 @@ void jl_init_thread_heap(jl_ptls_t ptls) jl_gc_mark_cache_t *gc_cache = &ptls->gc_tls.gc_cache; gc_cache->perm_scanned_bytes = 0; gc_cache->scanned_bytes = 0; - gc_cache->nbig_obj = 0; // Initialize GC mark-queue jl_gc_markqueue_t *mq = &ptls->gc_tls.mark_queue; @@ -3897,12 +3887,16 @@ void jl_gc_init(void) JL_MUTEX_INIT(&heapsnapshot_lock, "heapsnapshot_lock"); JL_MUTEX_INIT(&finalizers_lock, "finalizers_lock"); uv_mutex_init(&page_profile_lock); - uv_mutex_init(&gc_cache_lock); uv_mutex_init(&gc_perm_lock); uv_mutex_init(&gc_threads_lock); uv_cond_init(&gc_threads_cond); uv_sem_init(&gc_sweep_assists_needed, 0); uv_mutex_init(&gc_queue_observer_lock); + void *_addr = (void*)calloc_s(1); // dummy allocation to get the sentinel tag + uintptr_t addr = (uintptr_t)_addr; + gc_bigval_sentinel_tag = addr; + oldest_generation_of_bigvals = (bigval_t*)calloc_s(sizeof(bigval_t)); // sentinel + oldest_generation_of_bigvals->header = gc_bigval_sentinel_tag; jl_gc_init_page(); jl_gc_debug_init(); diff --git a/src/gc.h b/src/gc.h index 1a74d334c98f4..2ec249d322d94 100644 --- a/src/gc.h +++ b/src/gc.h @@ -120,9 +120,11 @@ typedef struct _jl_gc_chunk_t { // layout for big (>2k) objects +extern uintptr_t gc_bigval_sentinel_tag; + JL_EXTENSION typedef struct _bigval_t { struct _bigval_t *next; - struct _bigval_t **prev; // pointer to the next field of the prev entry + struct _bigval_t *prev; size_t sz; #ifdef _P64 // Add padding so that the value is 64-byte aligned // (8 pointers of 8 bytes each) - (4 other pointers in struct) @@ -431,7 +433,7 @@ STATIC_INLINE unsigned ffs_u32(uint32_t bitvec) #endif extern jl_gc_num_t gc_num; -extern bigval_t *big_objects_marked; +extern bigval_t *oldest_generation_of_bigvals; extern arraylist_t finalizer_list_marked; extern arraylist_t to_finalize; extern int64_t buffered_pages; @@ -529,21 +531,30 @@ STATIC_INLINE void *gc_ptr_clear_tag(void *v, uintptr_t mask) JL_NOTSAFEPOINT NOINLINE uintptr_t gc_get_stack_ptr(void); -STATIC_INLINE void gc_big_object_unlink(const bigval_t *hdr) JL_NOTSAFEPOINT +FORCE_INLINE void gc_big_object_unlink(const bigval_t *node) JL_NOTSAFEPOINT { - *hdr->prev = hdr->next; - if (hdr->next) { - hdr->next->prev = hdr->prev; + assert(node != oldest_generation_of_bigvals); + assert(node->header != gc_bigval_sentinel_tag); + assert(node->prev != NULL); + if (node->next != NULL) { + node->next->prev = node->prev; } + node->prev->next = node->next; } -STATIC_INLINE void gc_big_object_link(bigval_t *hdr, bigval_t **list) JL_NOTSAFEPOINT +FORCE_INLINE void gc_big_object_link(bigval_t *sentinel_node, bigval_t *node) JL_NOTSAFEPOINT { - hdr->next = *list; - hdr->prev = list; - if (*list) - (*list)->prev = &hdr->next; - *list = hdr; + assert(sentinel_node != NULL); + assert(sentinel_node->header == gc_bigval_sentinel_tag); + assert(sentinel_node->prev == NULL); + assert(node->header != gc_bigval_sentinel_tag); + // a new node gets linked in at the head of the list + node->next = sentinel_node->next; + node->prev = sentinel_node; + if (sentinel_node->next != NULL) { + sentinel_node->next->prev = node; + } + sentinel_node->next = node; } extern uv_mutex_t gc_threads_lock; From 7ae4e328fee4b8827082bb8c4581443a044b320e Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Mon, 15 Jul 2024 23:42:14 -0300 Subject: [PATCH 074/109] delete some unused fields of jl_gc_mark_cache_t (#55138) They should have been deleted in https://github.com/JuliaLang/julia/pull/54936, but were not. --- src/gc-tls.h | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/gc-tls.h b/src/gc-tls.h index dc15cda48fa58..a9f711198e914 100644 --- a/src/gc-tls.h +++ b/src/gc-tls.h @@ -69,17 +69,6 @@ typedef struct { size_t perm_scanned_bytes; // thread local increment of `scanned_bytes` size_t scanned_bytes; - // Number of queued big objects (<= 1024) - size_t nbig_obj; - // Array of queued big objects to be moved between the young list - // and the old list. - // A set low bit means that the object should be moved from the old list - // to the young list (`mark_reset_age`). - // Objects can only be put into this list when the mark bit is flipped to - // `1` (atomically). Combining with the sync after marking, - // this makes sure that a single objects can only appear once in - // the lists (the mark bit cannot be flipped to `0` without sweeping) - void *big_obj[1024]; } jl_gc_mark_cache_t; typedef struct { From 5f234f0fb5d047014b82232c744f0fd5c7ddcef9 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Tue, 16 Jul 2024 19:00:06 -0300 Subject: [PATCH 075/109] create separate function to spawn GC threads (#55108) Third-party GCs (e.g. MMTk) will probably have their own function to spawn GC threads. --- src/gc.c | 20 ++++++++++++++++++++ src/gc.h | 1 + src/init.c | 2 ++ src/julia_internal.h | 2 ++ src/threading.c | 26 ++++++++------------------ src/threading.h | 2 ++ 6 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/gc.c b/src/gc.c index c70eee6905ee9..15d48f600ed80 100644 --- a/src/gc.c +++ b/src/gc.c @@ -3881,6 +3881,26 @@ void jl_init_thread_heap(jl_ptls_t ptls) jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.allocd, -(int64_t)gc_num.interval); } +void jl_start_gc_threads(void) +{ + int nthreads = jl_atomic_load_relaxed(&jl_n_threads); + int ngcthreads = jl_n_gcthreads; + int nmutator_threads = nthreads - ngcthreads; + uv_thread_t uvtid; + for (int i = nmutator_threads; i < nthreads; ++i) { + jl_threadarg_t *t = (jl_threadarg_t *)malloc_s(sizeof(jl_threadarg_t)); // ownership will be passed to the thread + t->tid = i; + t->barrier = &thread_init_done; + if (i == nthreads - 1 && jl_n_sweepthreads == 1) { + uv_thread_create(&uvtid, jl_concurrent_gc_threadfun, t); + } + else { + uv_thread_create(&uvtid, jl_parallel_gc_threadfun, t); + } + uv_thread_detach(&uvtid); + } +} + // System-wide initializations void jl_gc_init(void) { diff --git a/src/gc.h b/src/gc.h index 2ec249d322d94..b4d421c708547 100644 --- a/src/gc.h +++ b/src/gc.h @@ -562,6 +562,7 @@ extern uv_cond_t gc_threads_cond; extern uv_sem_t gc_sweep_assists_needed; extern _Atomic(int) gc_n_threads_marking; extern _Atomic(int) gc_n_threads_sweeping; +extern uv_barrier_t thread_init_done; void gc_mark_queue_all_roots(jl_ptls_t ptls, jl_gc_markqueue_t *mq); void gc_mark_finlist_(jl_gc_markqueue_t *mq, jl_value_t *fl_parent, jl_value_t **fl_begin, jl_value_t **fl_end) JL_NOTSAFEPOINT; void gc_mark_finlist(jl_gc_markqueue_t *mq, arraylist_t *list, size_t start) JL_NOTSAFEPOINT; diff --git a/src/init.c b/src/init.c index 83f528b35ac11..0a0878a081e28 100644 --- a/src/init.c +++ b/src/init.c @@ -899,6 +899,8 @@ static NOINLINE void _finish_julia_init(JL_IMAGE_SEARCH rel, jl_ptls_t ptls, jl_ jl_n_threads_per_pool[1] = 0; } jl_start_threads(); + jl_start_gc_threads(); + uv_barrier_wait(&thread_init_done); jl_init_heartbeat(); diff --git a/src/julia_internal.h b/src/julia_internal.h index 75ebad73a4546..9ced95a8f027a 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -942,8 +942,10 @@ extern JL_DLLEXPORT ssize_t jl_tls_offset; extern JL_DLLEXPORT const int jl_tls_elf_support; void jl_init_threading(void); void jl_start_threads(void); +void jl_start_gc_threads(void); // Whether the GC is running +extern uv_mutex_t safepoint_lock; extern char *jl_safepoint_pages; STATIC_INLINE int jl_addr_is_safepoint(uintptr_t addr) { diff --git a/src/threading.c b/src/threading.c index 05607c12085f2..8f350d41f64b1 100644 --- a/src/threading.c +++ b/src/threading.c @@ -712,7 +712,7 @@ void jl_init_threading(void) gc_first_tid = nthreads + nthreadsi; } -static uv_barrier_t thread_init_done; +uv_barrier_t thread_init_done; void jl_start_threads(void) { @@ -751,30 +751,20 @@ void jl_start_threads(void) uv_barrier_init(&thread_init_done, nthreads); // GC/System threads need to be after the worker threads. - int nworker_threads = nthreads - ngcthreads; + int nmutator_threads = nthreads - ngcthreads; - for (i = 1; i < nthreads; ++i) { + for (i = 1; i < nmutator_threads; ++i) { jl_threadarg_t *t = (jl_threadarg_t *)malloc_s(sizeof(jl_threadarg_t)); // ownership will be passed to the thread t->tid = i; t->barrier = &thread_init_done; - if (i < nworker_threads) { - uv_thread_create(&uvtid, jl_threadfun, t); - if (exclusive) { - mask[i] = 1; - uv_thread_setaffinity(&uvtid, mask, NULL, cpumasksize); - mask[i] = 0; - } - } - else if (i == nthreads - 1 && jl_n_sweepthreads == 1) { - uv_thread_create(&uvtid, jl_concurrent_gc_threadfun, t); - } - else { - uv_thread_create(&uvtid, jl_parallel_gc_threadfun, t); + uv_thread_create(&uvtid, jl_threadfun, t); + if (exclusive) { + mask[i] = 1; + uv_thread_setaffinity(&uvtid, mask, NULL, cpumasksize); + mask[i] = 0; } uv_thread_detach(&uvtid); } - - uv_barrier_wait(&thread_init_done); } _Atomic(unsigned) _threadedregion; // HACK: keep track of whether to prioritize IO or threading diff --git a/src/threading.h b/src/threading.h index 260ecffa30dd5..cb26537699713 100644 --- a/src/threading.h +++ b/src/threading.h @@ -12,6 +12,8 @@ extern "C" { #define PROFILE_JL_THREADING 0 +extern uv_barrier_t thread_init_done; + extern _Atomic(jl_ptls_t*) jl_all_tls_states JL_GLOBALLY_ROOTED; /* thread local storage */ typedef struct _jl_threadarg_t { From 1c192fd6adafed257fe707932288a92a8d151bf4 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Mon, 12 Aug 2024 15:46:23 -0300 Subject: [PATCH 076/109] cap live_bytes to zero in a few places where GC intervals are computed (#170) * cap live_bytes to zero in a few places where GC intervals are computed * mem / log(mem) for interval upper bound --- src/gc.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/gc.c b/src/gc.c index 15d48f600ed80..77f60bdc9673e 100644 --- a/src/gc.c +++ b/src/gc.c @@ -8,6 +8,7 @@ #ifdef __GLIBC__ #include // for malloc_trim #endif +#include #ifdef __cplusplus extern "C" { @@ -3669,10 +3670,15 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) last_live_bytes = live_bytes; live_bytes += -gc_num.freed + actual_allocd; + // XXX: we've observed that the `live_bytes` was negative in a few cases + // which is not expected. We should investigate this further, but let's just + // cap it to 0 for now. + int64_t live_bytes_for_interval_computation = live_bytes < 0 ? 0 : live_bytes; + if (collection == JL_GC_AUTO) { //If we aren't freeing enough or are seeing lots and lots of pointers let it increase faster if (not_freed_enough || large_frontier) { - int64_t tot = 2 * (live_bytes + actual_allocd) / 3; + int64_t tot = 2 * (live_bytes_for_interval_computation + actual_allocd) / 3; if (gc_num.interval > tot) { gc_num.interval = tot; last_long_collect_interval = tot; @@ -3680,18 +3686,23 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) } // If the current interval is larger than half the live data decrease the interval else { - int64_t half = (live_bytes / 2); + int64_t half = (live_bytes_for_interval_computation / 2); if (gc_num.interval > half) gc_num.interval = half; } // But never go below default - if (gc_num.interval < default_collect_interval) gc_num.interval = default_collect_interval; + if (gc_num.interval < default_collect_interval) + gc_num.interval = default_collect_interval; + // And never go above the upper bound + const int64_t interval_upper_bound = (int64_t)((double)max_total_memory / log2((double)max_total_memory)); + if (gc_num.interval > interval_upper_bound) + gc_num.interval = interval_upper_bound; } - if (gc_num.interval + live_bytes > max_total_memory) { - if (live_bytes < max_total_memory) { - gc_num.interval = max_total_memory - live_bytes; - last_long_collect_interval = max_total_memory - live_bytes; + if (gc_num.interval + live_bytes_for_interval_computation > max_total_memory) { + if (live_bytes_for_interval_computation < max_total_memory) { + gc_num.interval = max_total_memory - live_bytes_for_interval_computation; + last_long_collect_interval = max_total_memory - live_bytes_for_interval_computation; } else { // We can't stay under our goal so let's go back to From ec21f11718ca881e026ce4a2ce808575bfb58a75 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Wed, 14 Aug 2024 16:33:47 -0300 Subject: [PATCH 077/109] dont reset maxsize in jl_array_to_string (#172) --- src/array.c | 2 -- src/gc.c | 7 ------- src/julia_internal.h | 1 - 3 files changed, 10 deletions(-) diff --git a/src/array.c b/src/array.c index bfa62e0f75273..5b0d13e1e229d 100644 --- a/src/array.c +++ b/src/array.c @@ -479,10 +479,8 @@ JL_DLLEXPORT jl_value_t *jl_array_to_string(jl_array_t *a) return o; } } - jl_gc_count_freed(jl_array_nbytes(a)); a->nrows = 0; a->length = 0; - a->maxsize = 0; return jl_pchar_to_string((const char*)jl_array_data(a), len); } diff --git a/src/gc.c b/src/gc.c index 77f60bdc9673e..4cb48ba72dfe1 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1116,13 +1116,6 @@ void jl_gc_count_allocd(size_t sz) JL_NOTSAFEPOINT jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.allocd) + sz); } -void jl_gc_count_freed(size_t sz) JL_NOTSAFEPOINT -{ - jl_ptls_t ptls = jl_current_task->ptls; - jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.freed, - jl_atomic_load_relaxed(&ptls->gc_tls.gc_num.freed) + sz); -} - static void combine_thread_gc_counts(jl_gc_num_t *dest) JL_NOTSAFEPOINT { int gc_n_threads; diff --git a/src/julia_internal.h b/src/julia_internal.h index 9ced95a8f027a..94b1f85112d7d 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -600,7 +600,6 @@ JL_DLLEXPORT int64_t jl_gc_sync_total_bytes(int64_t offset) JL_NOTSAFEPOINT; void jl_gc_track_malloced_array(jl_ptls_t ptls, jl_array_t *a) JL_NOTSAFEPOINT; size_t jl_array_nbytes(jl_array_t *a) JL_NOTSAFEPOINT; void jl_gc_count_allocd(size_t sz) JL_NOTSAFEPOINT; -void jl_gc_count_freed(size_t sz) JL_NOTSAFEPOINT; void jl_gc_run_all_finalizers(jl_task_t *ct); void jl_release_task_stack(jl_ptls_t ptls, jl_task_t *task); void jl_gc_add_finalizer_(jl_ptls_t ptls, void *v, void *f) JL_NOTSAFEPOINT; From 53e658cf04c265cccbf399c749b92ca0f49515f4 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:10:53 -0300 Subject: [PATCH 078/109] simple dynamic race detector for jl_array_to_string (#173) --- src/array.c | 32 ++++++++++++++++++++++++++++++++ src/init.c | 4 ++++ src/julia.h | 7 ++++++- 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/array.c b/src/array.c index 5b0d13e1e229d..fe92390f39245 100644 --- a/src/array.c +++ b/src/array.c @@ -457,13 +457,43 @@ JL_DLLEXPORT jl_array_t *jl_pchar_to_array(const char *str, size_t len) return a; } +uv_mutex_t array_to_string_print_lock; + +void jl_set_in_flight_bit_for_array_to_string(jl_array_t *a) +{ + uintptr_t msk = (1 << ARRAY_TO_STRING_IN_FLIGHT_BIT_OFFSET); + uintptr_t header = jl_atomic_fetch_or((_Atomic(uintptr_t) *)jl_astaggedvalue(a), msk); + if (header & msk) { + uv_mutex_lock(&array_to_string_print_lock); + // Race detected... Someone already set the in-flight bit. + jl_safe_printf("Race detected... Someone already set the in-flight bit.\n"); + jlbacktracet(jl_current_task); + uv_mutex_unlock(&array_to_string_print_lock); + } +} + +void jl_reset_in_flight_bit_for_array_to_string(jl_array_t *a) +{ + uintptr_t msk = (1 << ARRAY_TO_STRING_IN_FLIGHT_BIT_OFFSET); + uintptr_t header = jl_atomic_fetch_and((_Atomic(uintptr_t) *)jl_astaggedvalue(a), ~msk); + if (!(header & msk)) { + uv_mutex_lock(&array_to_string_print_lock); + // Race detected... Someone reset the in-flight bit before we could. + jl_safe_printf("Race detected... Someone reset the in-flight bit before we could.\n"); + jlbacktracet(jl_current_task); + uv_mutex_unlock(&array_to_string_print_lock); + } +} + JL_DLLEXPORT jl_value_t *jl_array_to_string(jl_array_t *a) { + jl_set_in_flight_bit_for_array_to_string(a); size_t len = jl_array_len(a); if (len == 0) { // this may seem like purely an optimization (which it also is), but it // also ensures that calling `String(a)` doesn't corrupt a previous // string also created the same way, where `a = StringVector(_)`. + jl_reset_in_flight_bit_for_array_to_string(a); return jl_an_empty_string; } if (a->flags.how == 3 && a->offset == 0 && a->elsize == 1 && @@ -476,11 +506,13 @@ JL_DLLEXPORT jl_value_t *jl_array_to_string(jl_array_t *a) a->nrows = 0; a->length = 0; a->maxsize = 0; + jl_reset_in_flight_bit_for_array_to_string(a); return o; } } a->nrows = 0; a->length = 0; + jl_reset_in_flight_bit_for_array_to_string(a); return jl_pchar_to_string((const char*)jl_array_data(a), len); } diff --git a/src/init.c b/src/init.c index 0a0878a081e28..e482f8b77ee9b 100644 --- a/src/init.c +++ b/src/init.c @@ -855,6 +855,8 @@ JL_DLLEXPORT void julia_init(JL_IMAGE_SEARCH rel) void jl_init_heartbeat(void); +extern uv_mutex_t array_to_string_print_lock; + static NOINLINE void _finish_julia_init(JL_IMAGE_SEARCH rel, jl_ptls_t ptls, jl_task_t *ct) { JL_TIMING(JULIA_INIT, JULIA_INIT); @@ -902,6 +904,8 @@ static NOINLINE void _finish_julia_init(JL_IMAGE_SEARCH rel, jl_ptls_t ptls, jl_ jl_start_gc_threads(); uv_barrier_wait(&thread_init_done); + uv_mutex_init(&array_to_string_print_lock); + jl_init_heartbeat(); jl_gc_enable(1); diff --git a/src/julia.h b/src/julia.h index fb188785176d1..110e5bfbff2fd 100644 --- a/src/julia.h +++ b/src/julia.h @@ -95,7 +95,11 @@ typedef struct _jl_value_t jl_value_t; struct _jl_taggedvalue_bits { uintptr_t gc:2; uintptr_t in_image:1; - uintptr_t unused:1; + // Bit to indicate whether a call to `jl_array_to_string` is in-flight + // Mostly used to implement a poor-man's dynamic race detector. + // See usage in `jl_array_to_string`. +#define ARRAY_TO_STRING_IN_FLIGHT_BIT_OFFSET (3) + uintptr_t array_to_string_in_flight:1; #ifdef _P64 uintptr_t tag:60; #else @@ -2228,6 +2232,7 @@ JL_DLLEXPORT size_t jl_static_show(JL_STREAM *out, jl_value_t *v) JL_NOTSAFEPOIN JL_DLLEXPORT size_t jl_static_show_func_sig(JL_STREAM *s, jl_value_t *type) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_print_backtrace(void) JL_NOTSAFEPOINT; JL_DLLEXPORT void jlbacktrace(void) JL_NOTSAFEPOINT; // deprecated +JL_DLLEXPORT void jlbacktracet(jl_task_t *t) JL_NOTSAFEPOINT; // Mainly for debugging, use `void*` so that no type cast is needed in C++. JL_DLLEXPORT void jl_(void *jl_value) JL_NOTSAFEPOINT; From 0e5b029ae532427dffec09232297920ba8f0be2b Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Mon, 26 Aug 2024 13:19:53 -0400 Subject: [PATCH 079/109] Redact object data in heap snapshots, with option to opt-out (#55326) (#174) The contents of strings can contain user data which may be proprietary and emitting them in the heap snapshot makes the heap snapshot a potential vulnerability rather than a useful debugging artifact. There are likely other tweaks necessary to make heap snapshots "safe", but this is one less. --------- Co-authored-by: Nathan Daly Co-authored-by: Ian Butterworth --- src/gc-heap-snapshot.cpp | 7 +++++-- src/gc-heap-snapshot.h | 2 +- stdlib/Profile/src/Profile.jl | 28 ++++++++++++++++------------ stdlib/Profile/test/runtests.jl | 21 ++++++++++++++++++--- 4 files changed, 40 insertions(+), 18 deletions(-) diff --git a/src/gc-heap-snapshot.cpp b/src/gc-heap-snapshot.cpp index a197e70df97fc..e21e3efea6153 100644 --- a/src/gc-heap-snapshot.cpp +++ b/src/gc-heap-snapshot.cpp @@ -183,6 +183,7 @@ struct HeapSnapshot { // global heap snapshot, mutated by garbage collector // when snapshotting is on. int gc_heap_snapshot_enabled = 0; +int gc_heap_snapshot_redact_data = 0; HeapSnapshot *g_snapshot = nullptr; extern jl_mutex_t heapsnapshot_lock; @@ -195,7 +196,7 @@ void _add_synthetic_root_entries(HeapSnapshot *snapshot) JL_NOTSAFEPOINT; JL_DLLEXPORT void jl_gc_take_heap_snapshot(ios_t *nodes, ios_t *edges, - ios_t *strings, ios_t *json, char all_one) + ios_t *strings, ios_t *json, char all_one, char redact_data) { HeapSnapshot snapshot; snapshot.nodes = nodes; @@ -207,6 +208,7 @@ JL_DLLEXPORT void jl_gc_take_heap_snapshot(ios_t *nodes, ios_t *edges, // Enable snapshotting g_snapshot = &snapshot; + gc_heap_snapshot_redact_data = redact_data; gc_heap_snapshot_enabled = true; _add_synthetic_root_entries(&snapshot); @@ -216,6 +218,7 @@ JL_DLLEXPORT void jl_gc_take_heap_snapshot(ios_t *nodes, ios_t *edges, // Disable snapshotting gc_heap_snapshot_enabled = false; + gc_heap_snapshot_redact_data = 0; g_snapshot = nullptr; jl_mutex_unlock(&heapsnapshot_lock); @@ -328,7 +331,7 @@ size_t record_node_to_gc_snapshot(jl_value_t *a) JL_NOTSAFEPOINT if (jl_is_string(a)) { node_type = "String"; - name = jl_string_data(a); + name = gc_heap_snapshot_redact_data ? "" : jl_string_data(a); self_size = jl_string_len(a); } else if (jl_is_symbol(a)) { diff --git a/src/gc-heap-snapshot.h b/src/gc-heap-snapshot.h index 70884f5f62d6a..a173fd2d8ea7f 100644 --- a/src/gc-heap-snapshot.h +++ b/src/gc-heap-snapshot.h @@ -121,7 +121,7 @@ static inline void gc_heap_snapshot_record_finlist(jl_value_t *finlist, size_t i // Functions to call from Julia to take heap snapshot // --------------------------------------------------------------------- JL_DLLEXPORT void jl_gc_take_heap_snapshot(ios_t *nodes, ios_t *edges, - ios_t *strings, ios_t *json, char all_one); + ios_t *strings, ios_t *json, char all_one, char redact_data); #ifdef __cplusplus diff --git a/stdlib/Profile/src/Profile.jl b/stdlib/Profile/src/Profile.jl index 7b5632892fafd..a0a1ecd1964ed 100644 --- a/stdlib/Profile/src/Profile.jl +++ b/stdlib/Profile/src/Profile.jl @@ -1220,8 +1220,10 @@ end """ - Profile.take_heap_snapshot(filepath::String, all_one::Bool=false, streaming=false) - Profile.take_heap_snapshot(all_one::Bool=false; dir::String, streaming=false) + Profile.take_heap_snapshot(filepath::String, all_one::Bool=false; + redact_data::Bool=true, streaming::Bool=false) + Profile.take_heap_snapshot(all_one::Bool=false; redact_data:Bool=true, + dir::String=nothing, streaming::Bool=false) Write a snapshot of the heap, in the JSON format expected by the Chrome Devtools Heap Snapshot viewer (.heapsnapshot extension) to a file @@ -1232,6 +1234,8 @@ full file path, or IO stream. If `all_one` is true, then report the size of every object as one so they can be easily counted. Otherwise, report the actual size. +If `redact_data` is true (default), then do not emit the contents of any object. + If `streaming` is true, we will stream the snapshot data out into four files, using filepath as the prefix, to avoid having to hold the entire snapshot in memory. This option should be used for any setting where your memory is constrained. These files can then be reassembled @@ -1247,27 +1251,27 @@ backwards-compatibility) and your process is killed, note that this will always parts in the same directory as your provided filepath, so you can still reconstruct the snapshot after the fact, via `assemble_snapshot()`. """ -function take_heap_snapshot(filepath::AbstractString, all_one::Bool=false; streaming::Bool=false) +function take_heap_snapshot(filepath::AbstractString, all_one::Bool=false; redact_data::Bool=true, streaming::Bool=false) if streaming - _stream_heap_snapshot(filepath, all_one) + _stream_heap_snapshot(filepath, all_one, redact_data) else # Support the legacy, non-streaming mode, by first streaming the parts, then # reassembling it after we're done. prefix = filepath - _stream_heap_snapshot(prefix, all_one) + _stream_heap_snapshot(prefix, all_one, redact_data) Profile.HeapSnapshot.assemble_snapshot(prefix, filepath) end return filepath end -function take_heap_snapshot(io::IO, all_one::Bool=false) +function take_heap_snapshot(io::IO, all_one::Bool=false; redact_data::Bool=true) # Support the legacy, non-streaming mode, by first streaming the parts to a tempdir, # then reassembling it after we're done. dir = tempdir() prefix = joinpath(dir, "snapshot") - _stream_heap_snapshot(prefix, all_one) + _stream_heap_snapshot(prefix, all_one, redact_data) Profile.HeapSnapshot.assemble_snapshot(prefix, io) end -function _stream_heap_snapshot(prefix::AbstractString, all_one::Bool) +function _stream_heap_snapshot(prefix::AbstractString, all_one::Bool, redact_data::Bool) # Nodes and edges are binary files open("$prefix.nodes", "w") do nodes open("$prefix.edges", "w") do edges @@ -1280,9 +1284,9 @@ function _stream_heap_snapshot(prefix::AbstractString, all_one::Bool) Base.@_lock_ios(json, ccall(:jl_gc_take_heap_snapshot, Cvoid, - (Ptr{Cvoid},Ptr{Cvoid},Ptr{Cvoid},Ptr{Cvoid}, Cchar), + (Ptr{Cvoid},Ptr{Cvoid},Ptr{Cvoid},Ptr{Cvoid}, Cchar, Cchar), nodes.handle, edges.handle, strings.handle, json.handle, - Cchar(all_one)) + Cchar(all_one), Cchar(redact_data)) ) ) ) @@ -1292,7 +1296,7 @@ function _stream_heap_snapshot(prefix::AbstractString, all_one::Bool) end end end -function take_heap_snapshot(all_one::Bool=false; dir::Union{Nothing,S}=nothing) where {S <: AbstractString} +function take_heap_snapshot(all_one::Bool=false; dir::Union{Nothing,S}=nothing, kwargs...) where {S <: AbstractString} fname = "$(getpid())_$(time_ns()).heapsnapshot" if isnothing(dir) wd = pwd() @@ -1307,7 +1311,7 @@ function take_heap_snapshot(all_one::Bool=false; dir::Union{Nothing,S}=nothing) else fpath = joinpath(expanduser(dir), fname) end - return take_heap_snapshot(fpath, all_one) + return take_heap_snapshot(fpath, all_one; kwargs...) end """ diff --git a/stdlib/Profile/test/runtests.jl b/stdlib/Profile/test/runtests.jl index 7da2ee23a144f..cb40d80d9b756 100644 --- a/stdlib/Profile/test/runtests.jl +++ b/stdlib/Profile/test/runtests.jl @@ -280,16 +280,31 @@ end @testset "HeapSnapshot" begin tmpdir = mktempdir() + + # ensure that we can prevent redacting data fname = cd(tmpdir) do - read(`$(Base.julia_cmd()) --startup-file=no -e "using Profile; print(Profile.take_heap_snapshot())"`, String) + read(`$(Base.julia_cmd()) --startup-file=no -e "using Profile; const x = \"redact_this\"; print(Profile.take_heap_snapshot(; redact_data=false))"`, String) end @test isfile(fname) - open(fname) do fs - @test readline(fs) != "" + sshot = read(fname, String) + @test sshot != "" + @test contains(sshot, "redact_this") + + rm(fname) + + # ensure that string data is redacted by default + fname = cd(tmpdir) do + read(`$(Base.julia_cmd()) --startup-file=no -e "using Profile; const x = \"redact_this\"; print(Profile.take_heap_snapshot())"`, String) end + @test isfile(fname) + + sshot = read(fname, String) + @test sshot != "" + @test !contains(sshot, "redact_this") + rm(fname) rm(tmpdir, force = true, recursive = true) end From 7843330672716e6607fcb4606864de939678e870 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Wed, 4 Sep 2024 11:14:53 -0300 Subject: [PATCH 080/109] instrument GC to breakdown times spent in each step of sweeping (#176) --- base/timing.jl | 3 ++ src/gc.c | 97 ++++++++++++++++++++++++++++---------------------- src/gc.h | 3 ++ 3 files changed, 60 insertions(+), 43 deletions(-) diff --git a/base/timing.jl b/base/timing.jl index bdbb32936b56f..73a3c5dc7d5e5 100644 --- a/base/timing.jl +++ b/base/timing.jl @@ -23,6 +23,9 @@ struct GC_Num sweep_time ::Int64 mark_time ::Int64 total_sweep_time ::Int64 + total_sweep_page_walk_time ::Int64 + total_sweep_madvise_time ::Int64 + total_sweep_free_mallocd_memory_time ::Int64 total_mark_time ::Int64 last_full_sweep ::Int64 last_incremental_sweep ::Int64 diff --git a/src/gc.c b/src/gc.c index 4cb48ba72dfe1..dad5768732545 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1518,8 +1518,11 @@ STATIC_INLINE void gc_sweep_pool_page(gc_page_profiler_serializer_t *s, jl_gc_pa // sweep over all memory that is being used and not in a pool static void gc_sweep_other(jl_ptls_t ptls, int sweep_full) JL_NOTSAFEPOINT { + uint64_t t_free_mallocd_memory_start = jl_hrtime(); sweep_malloced_arrays(); sweep_big(ptls); + uint64_t t_free_mallocd_memory_end = jl_hrtime(); + gc_num.total_sweep_free_mallocd_memory_time += t_free_mallocd_memory_end - t_free_mallocd_memory_start; } static void gc_pool_sync_nfree(jl_gc_pagemeta_t *pg, jl_taggedvalue_t *last) JL_NOTSAFEPOINT @@ -1776,58 +1779,63 @@ static void gc_sweep_pool(void) } } - // the actual sweeping - jl_gc_padded_page_stack_t *new_gc_allocd_scratch = (jl_gc_padded_page_stack_t *) calloc_s(n_threads * sizeof(jl_gc_padded_page_stack_t)); - jl_ptls_t ptls = jl_current_task->ptls; - gc_sweep_wake_all(ptls, new_gc_allocd_scratch); - gc_sweep_pool_parallel(ptls); - gc_sweep_wait_for_all(); - - // reset half-pages pointers - for (int t_i = 0; t_i < n_threads; t_i++) { - jl_ptls_t ptls2 = gc_all_tls_states[t_i]; - if (ptls2 != NULL) { - ptls2->gc_tls.page_metadata_allocd = new_gc_allocd_scratch[t_i].stack; - for (int i = 0; i < JL_GC_N_POOLS; i++) { - jl_gc_pool_t *p = &ptls2->gc_tls.heap.norm_pools[i]; - p->newpages = NULL; + uint64_t t_page_walk_start = jl_hrtime(); + { + // the actual sweeping + jl_gc_padded_page_stack_t *new_gc_allocd_scratch = (jl_gc_padded_page_stack_t *) calloc_s(n_threads * sizeof(jl_gc_padded_page_stack_t)); + jl_ptls_t ptls = jl_current_task->ptls; + gc_sweep_wake_all(ptls, new_gc_allocd_scratch); + gc_sweep_pool_parallel(ptls); + gc_sweep_wait_for_all(); + + // reset half-pages pointers + for (int t_i = 0; t_i < n_threads; t_i++) { + jl_ptls_t ptls2 = gc_all_tls_states[t_i]; + if (ptls2 != NULL) { + ptls2->gc_tls.page_metadata_allocd = new_gc_allocd_scratch[t_i].stack; + for (int i = 0; i < JL_GC_N_POOLS; i++) { + jl_gc_pool_t *p = &ptls2->gc_tls.heap.norm_pools[i]; + p->newpages = NULL; + } } } - } - // merge free lists - for (int t_i = 0; t_i < n_threads; t_i++) { - jl_ptls_t ptls2 = gc_all_tls_states[t_i]; - if (ptls2 == NULL) { - continue; - } - jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->gc_tls.page_metadata_allocd.bottom); - while (pg != NULL) { - jl_gc_pagemeta_t *pg2 = pg->next; - if (pg->fl_begin_offset != UINT16_MAX) { - char *cur_pg = pg->data; - jl_taggedvalue_t *fl_beg = (jl_taggedvalue_t*)(cur_pg + pg->fl_begin_offset); - jl_taggedvalue_t *fl_end = (jl_taggedvalue_t*)(cur_pg + pg->fl_end_offset); - *pfl[t_i * JL_GC_N_POOLS + pg->pool_n] = fl_beg; - pfl[t_i * JL_GC_N_POOLS + pg->pool_n] = &fl_end->next; + // merge free lists + for (int t_i = 0; t_i < n_threads; t_i++) { + jl_ptls_t ptls2 = gc_all_tls_states[t_i]; + if (ptls2 == NULL) { + continue; + } + jl_gc_pagemeta_t *pg = jl_atomic_load_relaxed(&ptls2->gc_tls.page_metadata_allocd.bottom); + while (pg != NULL) { + jl_gc_pagemeta_t *pg2 = pg->next; + if (pg->fl_begin_offset != UINT16_MAX) { + char *cur_pg = pg->data; + jl_taggedvalue_t *fl_beg = (jl_taggedvalue_t*)(cur_pg + pg->fl_begin_offset); + jl_taggedvalue_t *fl_end = (jl_taggedvalue_t*)(cur_pg + pg->fl_end_offset); + *pfl[t_i * JL_GC_N_POOLS + pg->pool_n] = fl_beg; + pfl[t_i * JL_GC_N_POOLS + pg->pool_n] = &fl_end->next; + } + pg = pg2; } - pg = pg2; } - } - // null out terminal pointers of free lists - for (int t_i = 0; t_i < n_threads; t_i++) { - jl_ptls_t ptls2 = gc_all_tls_states[t_i]; - if (ptls2 != NULL) { - for (int i = 0; i < JL_GC_N_POOLS; i++) { - *pfl[t_i * JL_GC_N_POOLS + i] = NULL; + // null out terminal pointers of free lists + for (int t_i = 0; t_i < n_threads; t_i++) { + jl_ptls_t ptls2 = gc_all_tls_states[t_i]; + if (ptls2 != NULL) { + for (int i = 0; i < JL_GC_N_POOLS; i++) { + *pfl[t_i * JL_GC_N_POOLS + i] = NULL; + } } } - } - // cleanup - free(pfl); - free(new_gc_allocd_scratch); + // cleanup + free(pfl); + free(new_gc_allocd_scratch); + } + uint64_t t_page_walk_end = jl_hrtime(); + gc_num.total_sweep_page_walk_time += t_page_walk_end - t_page_walk_start; #ifdef _P64 // only enable concurrent sweeping on 64bit // wake thread up to sweep concurrently @@ -1835,7 +1843,10 @@ static void gc_sweep_pool(void) uv_sem_post(&gc_sweep_assists_needed); } else { + uint64_t t_madvise_start = jl_hrtime(); gc_free_pages(); + uint64_t t_madvise_end = jl_hrtime(); + gc_num.total_sweep_madvise_time += t_madvise_end - t_madvise_start; } #else gc_free_pages(); diff --git a/src/gc.h b/src/gc.h index b4d421c708547..b06deec9d7238 100644 --- a/src/gc.h +++ b/src/gc.h @@ -83,6 +83,9 @@ typedef struct { uint64_t sweep_time; uint64_t mark_time; uint64_t total_sweep_time; + uint64_t total_sweep_page_walk_time; + uint64_t total_sweep_madvise_time; + uint64_t total_sweep_free_mallocd_memory_time; uint64_t total_mark_time; uint64_t last_full_sweep; uint64_t last_incremental_sweep; From c69060304650c538693f5306adf93b36855b3050 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Fri, 20 Sep 2024 19:56:44 -0300 Subject: [PATCH 081/109] fix cmdlineargs test in our fork (#182) --- test/cmdlineargs.jl | 2 +- test/gc.jl | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index 12e0c1fe2d502..e82d9afde7ce5 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -363,7 +363,7 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no` # --gcthreads code = "print(Threads.ngcthreads())" cpu_threads = ccall(:jl_effective_threads, Int32, ()) - @test (cpu_threads == 1 ? "1" : string(div(cpu_threads, 2))) == + @test string(cpu_threads) == read(`$exename --threads auto -e $code`, String) == read(`$exename --threads=auto -e $code`, String) == read(`$exename -tauto -e $code`, String) == diff --git a/test/gc.jl b/test/gc.jl index 330c136389a4e..3b8677568df45 100644 --- a/test/gc.jl +++ b/test/gc.jl @@ -43,4 +43,3 @@ end run_nonzero_page_utilization_test() run_pg_size_test() end - From a911d007cceb447952733a00689bc1aa57b1b6e4 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Mon, 23 Sep 2024 13:35:25 -0300 Subject: [PATCH 082/109] [Dates] Make test more robust against non-UTC timezones (#55829) (#184) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `%M` is the format specifier for the minutes, not the month (which should be `%m`), and it was used twice. Also, on macOS `Libc.strptime` internally calls `mktime` which depends on the local timezone. We now temporarily set `TZ=UTC` to avoid depending on the local timezone. Fix #55827. Co-authored-by: Mosè Giordano <765740+giordano@users.noreply.github.com> --- stdlib/Dates/test/types.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/stdlib/Dates/test/types.jl b/stdlib/Dates/test/types.jl index 8823e56e41a2f..1cff685ae7beb 100644 --- a/stdlib/Dates/test/types.jl +++ b/stdlib/Dates/test/types.jl @@ -256,7 +256,11 @@ end end @testset "issue #31524" begin - dt1 = Libc.strptime("%Y-%M-%dT%H:%M:%SZ", "2018-11-16T10:26:14Z") + # Ensure the result doesn't depend on local timezone, especially on macOS + # where an extra internal call to `mktime` is affected by timezone settings. + dt1 = withenv("TZ" => "UTC") do + Libc.strptime("%Y-%m-%dT%H:%M:%SZ", "2018-11-16T10:26:14Z") + end dt2 = Libc.TmStruct(14, 30, 5, 10, 1, 99, 3, 40, 0) time = Time(dt1) From 037dc51b198a24feb992ff59b16706c8f5ef5acd Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Tue, 24 Sep 2024 12:47:53 -0400 Subject: [PATCH 083/109] Adjust heartbeat behavior (#180) * Add heartbeat pause/resume capability * Add check to avoid negative sleep duration * Disable heartbeats in `jl_print_task_backtraces()` `jl_print_task_backtraces()` can take long enough that there can be heartbeat loss, which can trigger printing task backtraces again, unless it is called from the heartbeat thread which takes care of that possible problem. * Pause heartbeats for GC * Address review comment * Address review comment --- src/gc.c | 5 +++++ src/stackwalk.c | 18 ++++++++++++++- src/threading.c | 59 +++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 77 insertions(+), 5 deletions(-) diff --git a/src/gc.c b/src/gc.c index dad5768732545..ccafc05e02621 100644 --- a/src/gc.c +++ b/src/gc.c @@ -3734,6 +3734,9 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) return recollect; } +extern int jl_heartbeat_pause(void); +extern int jl_heartbeat_resume(void); + JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection) { JL_PROBE_GC_BEGIN(collection); @@ -3775,6 +3778,7 @@ JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection) // existence of the thread in the jl_n_threads count. // // TODO: concurrently queue objects + jl_heartbeat_pause(); jl_fence(); gc_n_threads = jl_atomic_load_acquire(&jl_n_threads); gc_all_tls_states = jl_atomic_load_relaxed(&jl_all_tls_states); @@ -3806,6 +3810,7 @@ JL_DLLEXPORT void jl_gc_collect(jl_gc_collection_t collection) gc_n_threads = 0; gc_all_tls_states = NULL; + jl_heartbeat_resume(); jl_safepoint_end_gc(); jl_gc_state_set(ptls, old_state, JL_GC_STATE_WAITING); JL_PROBE_GC_END(); diff --git a/src/stackwalk.c b/src/stackwalk.c index 8a12fb2a28143..ab3f13c8e9746 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -1166,10 +1166,22 @@ JL_DLLEXPORT void jl_print_backtrace(void) JL_NOTSAFEPOINT } extern int gc_first_tid; +extern int jl_inside_heartbeat_thread(void); +extern int jl_heartbeat_pause(void); +extern int jl_heartbeat_resume(void); -// Print backtraces for all live tasks, for all threads, to jl_safe_printf stderr +// Print backtraces for all live tasks, for all threads, to jl_safe_printf +// stderr. This can take a _long_ time! JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT { + // disable heartbeats to prevent heartbeat loss while running this, + // unless this is called from the heartbeat thread itself; in that + // situation, the thread is busy running this and it will not be + // updating the missed heartbeats counter + if (!jl_inside_heartbeat_thread()) { + jl_heartbeat_pause(); + } + size_t nthreads = jl_atomic_load_acquire(&jl_n_threads); jl_ptls_t *allstates = jl_atomic_load_relaxed(&jl_all_tls_states); int ctid = -1; @@ -1232,6 +1244,10 @@ JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT jl_safe_printf("thread (%d) ==== End thread %d\n", ctid, ptls2->tid + 1); } jl_safe_printf("thread (%d) ++++ Done\n", ctid); + + if (!jl_inside_heartbeat_thread()) { + jl_heartbeat_resume(); + } } #ifdef __cplusplus diff --git a/src/threading.c b/src/threading.c index 8f350d41f64b1..d89e8d09745fc 100644 --- a/src/threading.c +++ b/src/threading.c @@ -1008,6 +1008,45 @@ JL_DLLEXPORT int jl_heartbeat_enable(int heartbeat_s, int show_tasks_after_n, return 0; } +// temporarily pause the heartbeat thread +JL_DLLEXPORT int jl_heartbeat_pause(void) +{ + if (!heartbeat_enabled) { + return -1; + } + heartbeat_enabled = 0; + return 0; +} + +// resume the paused heartbeat thread +JL_DLLEXPORT int jl_heartbeat_resume(void) +{ + // cannot resume if the heartbeat thread is already running + if (heartbeat_enabled) { + return -1; + } + + // cannot resume if we weren't paused (disabled != paused) + if (heartbeat_interval_s == 0) { + return -1; + } + + // heartbeat thread must be ready + if (uv_sem_trywait(&heartbeat_off_sem) != 0) { + return -1; + } + + // reset state as we've been paused + n_hbs_missed = 0; + n_hbs_recvd = 0; + tasks_showed = 0; + + // resume + heartbeat_enabled = 1; + uv_sem_post(&heartbeat_on_sem); // wake the heartbeat thread + return 0; +} + // heartbeat JL_DLLEXPORT void jl_heartbeat(void) { @@ -1099,7 +1138,7 @@ void jl_heartbeat_threadfun(void *arg) uv_sem_post(&heartbeat_off_sem); // sleep the thread here; this semaphore is posted in - // jl_heartbeat_enable() + // jl_heartbeat_enable() or jl_heartbeat_resume() uv_sem_wait(&heartbeat_on_sem); // Set the sleep duration. @@ -1111,7 +1150,7 @@ void jl_heartbeat_threadfun(void *arg) // heartbeat is enabled; sleep, waiting for the desired interval sleep_for(s, ns); - // if heartbeats were turned off while we were sleeping, reset + // if heartbeats were turned off/paused while we were sleeping, reset if (!heartbeat_enabled) { continue; } @@ -1122,13 +1161,15 @@ void jl_heartbeat_threadfun(void *arg) tchb = jl_hrtime() - t0; // adjust the next sleep duration based on how long the heartbeat - // check took + // check took, but if it took too long then use the normal duration rs = 1; while (tchb > 1e9) { rs++; tchb -= 1e9; } - s = heartbeat_interval_s - rs; + if (rs < heartbeat_interval_s) { + s = heartbeat_interval_s - rs; + } ns = 1e9 - tchb; } } @@ -1150,6 +1191,16 @@ JL_DLLEXPORT int jl_heartbeat_enable(int heartbeat_s, int show_tasks_after_n, return -1; } +JL_DLLEXPORT int jl_heartbeat_pause(void) +{ + return -1; +} + +JL_DLLEXPORT int jl_heartbeat_resume(void) +{ + return -1; +} + JL_DLLEXPORT void jl_heartbeat(void) { } From 8e9f7deed1462268f82c922b6fd31e7ffc3c8cab Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Wed, 25 Sep 2024 19:05:19 -0300 Subject: [PATCH 084/109] Revert "[Dates] Make test more robust against non-UTC timezones (#55829) (#184)" (#188) This reverts commit a911d007cceb447952733a00689bc1aa57b1b6e4. --- stdlib/Dates/test/types.jl | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/stdlib/Dates/test/types.jl b/stdlib/Dates/test/types.jl index 1cff685ae7beb..8823e56e41a2f 100644 --- a/stdlib/Dates/test/types.jl +++ b/stdlib/Dates/test/types.jl @@ -256,11 +256,7 @@ end end @testset "issue #31524" begin - # Ensure the result doesn't depend on local timezone, especially on macOS - # where an extra internal call to `mktime` is affected by timezone settings. - dt1 = withenv("TZ" => "UTC") do - Libc.strptime("%Y-%m-%dT%H:%M:%SZ", "2018-11-16T10:26:14Z") - end + dt1 = Libc.strptime("%Y-%M-%dT%H:%M:%SZ", "2018-11-16T10:26:14Z") dt2 = Libc.TmStruct(14, 30, 5, 10, 1, 99, 3, 40, 0) time = Time(dt1) From 3d458df4382f62163264951ba44308a3b557b277 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Mon, 30 Sep 2024 15:30:52 -0300 Subject: [PATCH 085/109] expose metric to report reasons why full GCs were triggered (#55826) (#189) Additional GC observability tool. This will help us to diagnose why some of our servers are triggering so many full GCs in certain circumstances. --- base/timing.jl | 33 +++++++++++++++++++++++++++++++++ src/gc.c | 7 +++++++ src/gc.h | 15 +++++++++++++++ src/threading.c | 2 +- test/gc.jl | 11 +++++++++++ 5 files changed, 67 insertions(+), 1 deletion(-) diff --git a/base/timing.jl b/base/timing.jl index 73a3c5dc7d5e5..64d2a0a6f054e 100644 --- a/base/timing.jl +++ b/base/timing.jl @@ -107,6 +107,39 @@ function gc_page_utilization_data() return Base.unsafe_wrap(Array, page_utilization_raw, JL_GC_N_MAX_POOLS, own=false) end +# must be kept in sync with `src/gc.h`` +const FULL_SWEEP_REASONS = [:FULL_SWEEP_REASON_SWEEP_ALWAYS_FULL, :FULL_SWEEP_REASON_FORCED_FULL_SWEEP, + :FULL_SWEEP_REASON_ALLOCATION_INTERVAL_ABOVE_MAXMEM, :FULL_SWEEP_REASON_LIVE_BYTES_ABOVE_MAX_TOTAL_MEMORY, + :FULL_SWEEP_REASON_LARGE_INTERGEN_FRONTIER] + +""" + Base.full_sweep_reasons() + +Return a dictionary of the number of times each full sweep reason has occurred. + +The reasons are: +- `:FULL_SWEEP_REASON_SWEEP_ALWAYS_FULL`: Full sweep was caused due to `always_full` being set in the GC debug environment +- `:FULL_SWEEP_REASON_FORCED_FULL_SWEEP`: Full sweep was forced by `GC.gc(true)` +- `:FULL_SWEEP_REASON_ALLOCATION_INTERVAL_ABOVE_MAXMEM`: Full sweep was forced by the allocation interval being above the total + memory in the machine (as returned by LibUV) divided by the number of mutator threads +- `:FULL_SWEEP_REASON_LIVE_BYTES_ABOVE_MAX_TOTAL_MEMORY`: Full sweep was caused due to live bytes being above the + soft heap limit size (which is either automatically computed at initialization based on the total memory provided by LibUV, + or set by the user via `--heap-size-hint`) +- `:FULL_SWEEP_REASON_LARGE_INTERGEN_FRONTIER`: Full sweep was forced by the intergenerational frontier being too large + (i.e. too many pointers in the remembered set) + +Note that the set of reasons is not guaranteed to be stable across minor versions of Julia. +""" +function full_sweep_reasons() + reason = cglobal(:jl_full_sweep_reasons, UInt64) + reasons_as_array = Base.unsafe_wrap(Vector{UInt64}, reason, length(FULL_SWEEP_REASONS), own=false) + d = Dict{Symbol, Int64}() + for (i, r) in enumerate(FULL_SWEEP_REASONS) + d[r] = reasons_as_array[i] + end + return d +end + """ Base.jit_total_bytes() diff --git a/src/gc.c b/src/gc.c index ccafc05e02621..334bd8f83ada7 100644 --- a/src/gc.c +++ b/src/gc.c @@ -37,6 +37,8 @@ uv_sem_t gc_sweep_assists_needed; uv_mutex_t gc_queue_observer_lock; // Tag for sentinel nodes in bigval list uintptr_t gc_bigval_sentinel_tag; +// Table recording number of full GCs due to each reason +JL_DLLEXPORT uint64_t jl_full_sweep_reasons[FULL_SWEEP_NUM_REASONS]; // Linked list of callback functions @@ -3551,6 +3553,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) if (large_frontier) { sweep_full = 1; gc_num.interval = last_long_collect_interval; + gc_count_full_sweep_reason(FULL_SWEEP_REASON_LARGE_INTERGEN_FRONTIER); } if (not_freed_enough || large_frontier) { gc_num.interval = gc_num.interval * 2; @@ -3566,6 +3569,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) if (gc_num.interval > maxmem) { sweep_full = 1; gc_num.interval = maxmem; + gc_count_full_sweep_reason(FULL_SWEEP_REASON_ALLOCATION_INTERVAL_ABOVE_MAXMEM); } } @@ -3574,13 +3578,16 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) if (live_bytes > max_total_memory) { under_memory_pressure = 1; sweep_full = 1; + gc_count_full_sweep_reason(FULL_SWEEP_REASON_LIVE_BYTES_ABOVE_MAX_TOTAL_MEMORY); } if (gc_sweep_always_full) { sweep_full = 1; + gc_count_full_sweep_reason(FULL_SWEEP_REASON_SWEEP_ALWAYS_FULL); } if (collection == JL_GC_FULL && !prev_sweep_full) { sweep_full = 1; recollect = 1; + gc_count_full_sweep_reason(FULL_SWEEP_REASON_FORCED_FULL_SWEEP); } if (sweep_full) { // these are the difference between the number of gc-perm bytes scanned diff --git a/src/gc.h b/src/gc.h index b06deec9d7238..61c7c835db34a 100644 --- a/src/gc.h +++ b/src/gc.h @@ -560,6 +560,21 @@ FORCE_INLINE void gc_big_object_link(bigval_t *sentinel_node, bigval_t *node) JL sentinel_node->next = node; } +// Must be kept in sync with `base/timing.jl` +#define FULL_SWEEP_REASON_SWEEP_ALWAYS_FULL (0) +#define FULL_SWEEP_REASON_FORCED_FULL_SWEEP (1) +#define FULL_SWEEP_REASON_ALLOCATION_INTERVAL_ABOVE_MAXMEM (2) +#define FULL_SWEEP_REASON_LIVE_BYTES_ABOVE_MAX_TOTAL_MEMORY (3) +#define FULL_SWEEP_REASON_LARGE_INTERGEN_FRONTIER (4) +#define FULL_SWEEP_NUM_REASONS (5) + +extern JL_DLLEXPORT uint64_t jl_full_sweep_reasons[FULL_SWEEP_NUM_REASONS]; +STATIC_INLINE void gc_count_full_sweep_reason(int reason) JL_NOTSAFEPOINT +{ + assert(reason >= 0 && reason < FULL_SWEEP_NUM_REASONS); + jl_full_sweep_reasons[reason]++; +} + extern uv_mutex_t gc_threads_lock; extern uv_cond_t gc_threads_cond; extern uv_sem_t gc_sweep_assists_needed; diff --git a/src/threading.c b/src/threading.c index d89e8d09745fc..d0f25de374462 100644 --- a/src/threading.c +++ b/src/threading.c @@ -1035,7 +1035,7 @@ JL_DLLEXPORT int jl_heartbeat_resume(void) if (uv_sem_trywait(&heartbeat_off_sem) != 0) { return -1; } - + // reset state as we've been paused n_hbs_missed = 0; n_hbs_recvd = 0; diff --git a/test/gc.jl b/test/gc.jl index 3b8677568df45..a07abd48c0152 100644 --- a/test/gc.jl +++ b/test/gc.jl @@ -28,6 +28,13 @@ function run_pg_size_test() @test page_size == (1 << 12) || page_size == (1 << 14) end +function full_sweep_reasons_test() + GC.gc() + reasons = Base.full_sweep_reasons() + @test reasons[:FULL_SWEEP_REASON_FORCED_FULL_SWEEP] >= 1 + @test keys(reasons) == Set(Base.FULL_SWEEP_REASONS) +end + # !!! note: # Since we run our tests on 32bit OS as well we confine ourselves # to parameters that allocate about 512MB of objects. Max RSS is lower @@ -43,3 +50,7 @@ end run_nonzero_page_utilization_test() run_pg_size_test() end + +@testset "Full GC reasons" begin + full_sweep_reasons_test() +end From 75cf8dcf13501fa5914551fb38780603baedccf3 Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Mon, 30 Sep 2024 16:45:51 -0400 Subject: [PATCH 086/109] Add `--trace-dispatch` (#183) Similar to `--trace-compile`, emit the `precompile` statement for a method once, but only when it is dynamically dispatched. For this, we rename the `precompiled` field in `jl_method_instance_t` to `flags` and use bit 0 as `precompiled` and bit 1 as `dispatched`. When the method is dispatched, the `dispatched` bit is set to 1 and the precompile statement is emitted. This check is done in `jl_gf_invoke_by_method` and in the slow path (cache miss) of `jl_apply_generic`. --- base/options.jl | 1 + src/gf.c | 57 ++++++++++++++++++++++++++++++++++++++++-- src/jloptions.c | 8 ++++++ src/jloptions.h | 1 + src/jltypes.c | 2 +- src/julia.h | 8 +++++- src/method.c | 2 +- src/staticdata.c | 2 +- src/staticdata_utils.c | 3 ++- test/cmdlineargs.jl | 22 ++++++++++++++++ test/core.jl | 2 +- 11 files changed, 100 insertions(+), 8 deletions(-) diff --git a/base/options.jl b/base/options.jl index cb35b2b3806f4..2b2906bf86e82 100644 --- a/base/options.jl +++ b/base/options.jl @@ -34,6 +34,7 @@ struct JLOptions can_inline::Int8 polly::Int8 trace_compile::Ptr{UInt8} + trace_dispatch::Ptr{UInt8} fast_math::Int8 worker::Int8 cookie::Ptr{UInt8} diff --git a/src/gf.c b/src/gf.c index 88810757dc15c..1aee075c8d15a 100644 --- a/src/gf.c +++ b/src/gf.c @@ -2365,6 +2365,38 @@ static void record_precompile_statement(jl_method_instance_t *mi) JL_UNLOCK(&precomp_statement_out_lock); } +jl_mutex_t dispatch_statement_out_lock; + +static void record_dispatch_statement(jl_method_instance_t *mi) +{ + static ios_t f_dispatch; + static JL_STREAM* s_dispatch = NULL; + jl_method_t *def = mi->def.method; + if (!jl_is_method(def)) + return; + + JL_LOCK(&dispatch_statement_out_lock); + if (s_dispatch == NULL) { + const char *t = jl_options.trace_dispatch; + if (!strncmp(t, "stderr", 6)) { + s_dispatch = JL_STDERR; + } + else { + if (ios_file(&f_dispatch, t, 1, 1, 1, 1) == NULL) + jl_errorf("cannot open dispatch statement file \"%s\" for writing", t); + s_dispatch = (JL_STREAM*) &f_dispatch; + } + } + if (!jl_has_free_typevars(mi->specTypes)) { + jl_printf(s_dispatch, "precompile("); + jl_static_show(s_dispatch, mi->specTypes); + jl_printf(s_dispatch, ")\n"); + if (s_dispatch != JL_STDERR) + ios_flush(&f_dispatch); + } + JL_UNLOCK(&dispatch_statement_out_lock); +} + jl_method_instance_t *jl_normalize_to_compilable_mi(jl_method_instance_t *mi JL_PROPAGATES_ROOT); jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t world) @@ -2779,7 +2811,8 @@ static void jl_compile_now(jl_method_instance_t *mi) JL_DLLEXPORT void jl_compile_method_instance(jl_method_instance_t *mi, jl_tupletype_t *types, size_t world) { size_t tworld = jl_typeinf_world; - jl_atomic_store_relaxed(&mi->precompiled, 1); + uint8_t miflags = jl_atomic_load_relaxed(&mi->flags) | JL_MI_FLAGS_MASK_PRECOMPILED; + jl_atomic_store_relaxed(&mi->flags, miflags); if (jl_generating_output()) { jl_compile_now(mi); // In addition to full compilation of the compilation-signature, if `types` is more specific (e.g. due to nospecialize), @@ -2794,7 +2827,8 @@ JL_DLLEXPORT void jl_compile_method_instance(jl_method_instance_t *mi, jl_tuplet types2 = jl_type_intersection_env((jl_value_t*)types, (jl_value_t*)mi->def.method->sig, &tpenv2); jl_method_instance_t *mi2 = jl_specializations_get_linfo(mi->def.method, (jl_value_t*)types2, tpenv2); JL_GC_POP(); - jl_atomic_store_relaxed(&mi2->precompiled, 1); + miflags = jl_atomic_load_relaxed(&mi2->flags) | JL_MI_FLAGS_MASK_PRECOMPILED; + jl_atomic_store_relaxed(&mi2->flags, miflags); if (jl_rettype_inferred(mi2, world, world) == jl_nothing) (void)jl_type_infer(mi2, world, 1); if (jl_typeinf_func && mi->def.method->primary_world <= tworld) { @@ -3060,6 +3094,16 @@ STATIC_INLINE jl_method_instance_t *jl_lookup_generic_(jl_value_t *F, jl_value_t jl_method_error(F, args, nargs, world); // unreachable } + // mfunc is about to be dispatched + if (jl_options.trace_dispatch != NULL) { + uint8_t miflags = jl_atomic_load_relaxed(&mfunc->flags); + uint8_t was_dispatched = miflags & JL_MI_FLAGS_MASK_DISPATCHED; + if (!was_dispatched) { + miflags |= JL_MI_FLAGS_MASK_DISPATCHED; + jl_atomic_store_relaxed(&mfunc->flags, miflags); + record_dispatch_statement(mfunc); + } + } } #ifdef JL_TRACE @@ -3182,6 +3226,15 @@ jl_value_t *jl_gf_invoke_by_method(jl_method_t *method, jl_value_t *gf, jl_value jl_gc_sync_total_bytes(last_alloc); // discard allocation count from compilation } JL_GC_PROMISE_ROOTED(mfunc); + if (jl_options.trace_dispatch != NULL) { + uint8_t miflags = jl_atomic_load_relaxed(&mfunc->flags); + uint8_t was_dispatched = miflags & JL_MI_FLAGS_MASK_DISPATCHED; + if (!was_dispatched) { + miflags |= JL_MI_FLAGS_MASK_DISPATCHED; + jl_atomic_store_relaxed(&mfunc->flags, miflags); + record_dispatch_statement(mfunc); + } + } size_t world = jl_current_task->world_age; return _jl_invoke(gf, args, nargs - 1, mfunc, world); } diff --git a/src/jloptions.c b/src/jloptions.c index 47f78f2de2a17..14d2242284ae1 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -67,6 +67,7 @@ JL_DLLEXPORT void jl_init_options(void) 1, // can_inline JL_OPTIONS_POLLY_ON, // polly NULL, // trace_compile + NULL, // trace_dispatch JL_OPTIONS_FAST_MATH_DEFAULT, 0, // worker NULL, // cookie @@ -234,6 +235,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) opt_inline, opt_polly, opt_trace_compile, + opt_trace_dispatch, opt_math_mode, opt_worker, opt_bind_to, @@ -310,6 +312,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) { "inline", required_argument, 0, opt_inline }, { "polly", required_argument, 0, opt_polly }, { "trace-compile", required_argument, 0, opt_trace_compile }, + { "trace-dispatch", required_argument, 0, opt_trace_dispatch }, { "math-mode", required_argument, 0, opt_math_mode }, { "handle-signals", required_argument, 0, opt_handle_signals }, // hidden command line options @@ -752,6 +755,11 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) if (!jl_options.trace_compile) jl_errorf("fatal error: failed to allocate memory: %s", strerror(errno)); break; + case opt_trace_dispatch: + jl_options.trace_dispatch = strdup(optarg); + if (!jl_options.trace_dispatch) + jl_errorf("fatal error: failed to allocate memory: %s", strerror(errno)); + break; case opt_math_mode: if (!strcmp(optarg,"ieee")) jl_options.fast_math = JL_OPTIONS_FAST_MATH_OFF; diff --git a/src/jloptions.h b/src/jloptions.h index b633291c6ed41..20027ebfff24a 100644 --- a/src/jloptions.h +++ b/src/jloptions.h @@ -38,6 +38,7 @@ typedef struct { int8_t can_inline; int8_t polly; const char *trace_compile; + const char *trace_dispatch; int8_t fast_math; int8_t worker; const char *cookie; diff --git a/src/jltypes.c b/src/jltypes.c index 66db26a575e90..e9d843c383a9c 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3089,7 +3089,7 @@ void jl_init_types(void) JL_GC_DISABLED "cache", "inInference", "cache_with_orig", - "precompiled"), + "flags"), jl_svec(10, jl_new_struct(jl_uniontype_type, jl_method_type, jl_module_type), jl_any_type, diff --git a/src/julia.h b/src/julia.h index 110e5bfbff2fd..f34bb1623eed5 100644 --- a/src/julia.h +++ b/src/julia.h @@ -397,8 +397,14 @@ struct _jl_method_instance_t { _Atomic(struct _jl_code_instance_t*) cache; uint8_t inInference; // flags to tell if inference is running on this object uint8_t cache_with_orig; // !cache_with_specTypes - _Atomic(uint8_t) precompiled; // true if this instance was generated by an explicit `precompile(...)` call + + // flags for this method instance + // bit 0: generated by an explicit `precompile(...)` + // bit 1: dispatched + _Atomic(uint8_t) flags; }; +#define JL_MI_FLAGS_MASK_PRECOMPILED 0x01 +#define JL_MI_FLAGS_MASK_DISPATCHED 0x02 // OpaqueClosure typedef struct _jl_opaque_closure_t { diff --git a/src/method.c b/src/method.c index e96d1008e3056..d46302127534e 100644 --- a/src/method.c +++ b/src/method.c @@ -453,7 +453,7 @@ JL_DLLEXPORT jl_method_instance_t *jl_new_method_instance_uninit(void) jl_atomic_store_relaxed(&mi->cache, NULL); mi->inInference = 0; mi->cache_with_orig = 0; - jl_atomic_store_relaxed(&mi->precompiled, 0); + jl_atomic_store_relaxed(&mi->flags, 0); return mi; } diff --git a/src/staticdata.c b/src/staticdata.c index c130c2e7569fe..945593034a890 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -1482,7 +1482,7 @@ static void jl_write_values(jl_serializer_state *s) JL_GC_DISABLED else if (jl_is_method_instance(v)) { assert(f == s->s); jl_method_instance_t *newmi = (jl_method_instance_t*)&f->buf[reloc_offset]; - jl_atomic_store_relaxed(&newmi->precompiled, 0); + jl_atomic_store_relaxed(&newmi->flags, 0); } else if (jl_is_code_instance(v)) { assert(f == s->s); diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index b488934606671..2fe01d919e885 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -158,7 +158,8 @@ static int has_backedge_to_worklist(jl_method_instance_t *mi, htable_t *visited, if (jl_is_method(mod)) mod = ((jl_method_t*)mod)->module; assert(jl_is_module(mod)); - if (mi->precompiled || !jl_object_in_image((jl_value_t*)mod) || type_in_worklist(mi->specTypes)) { + uint8_t is_precompiled = jl_atomic_load_relaxed(&mi->flags) & JL_MI_FLAGS_MASK_PRECOMPILED; + if (is_precompiled || !jl_object_in_image((jl_value_t*)mod) || type_in_worklist(mi->specTypes)) { return 1; } if (!mi->backedges) { diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index e82d9afde7ce5..e5659b7c2439f 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -750,6 +750,28 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no` # tested in test/parallel.jl) @test errors_not_signals(`$exename --worker=true`) + # --trace-compile + let + io = IOBuffer() + v = writereadpipeline( + "foo(x) = begin Base.Experimental.@force_compile; x; end; foo(1)", + `$exename --trace-compile=stderr -i`, + stderr=io) + _stderr = String(take!(io)) + @test occursin("precompile(Tuple{typeof(Main.foo), Int", _stderr) + end + + # --trace-dispatch + let + io = IOBuffer() + v = writereadpipeline( + "foo(x) = begin Base.Experimental.@force_compile; x; end; foo(1)", + `$exename --trace-dispatch=stderr -i`, + stderr=io) + _stderr = String(take!(io)) + @test occursin("precompile(Tuple{typeof(Main.foo), Int", _stderr) + end + # test passing arguments mktempdir() do dir testfile, io = mktemp(dir) diff --git a/test/core.jl b/test/core.jl index eefeeb8d1240d..0212193a0206b 100644 --- a/test/core.jl +++ b/test/core.jl @@ -32,7 +32,7 @@ for (T, c) in ( (Core.CodeInfo, []), (Core.CodeInstance, [:next, :inferred, :purity_bits, :invoke, :specptr, :precompile]), (Core.Method, []), - (Core.MethodInstance, [:uninferred, :cache, :precompiled]), + (Core.MethodInstance, [:uninferred, :cache, :flags]), (Core.MethodTable, [:defs, :leafcache, :cache, :max_args]), (Core.TypeMapEntry, [:next]), (Core.TypeMapLevel, [:arg1, :targ, :name1, :tname, :list, :any]), From 01980b3b086de1e34af1b39a80d1363cb1a07d08 Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Thu, 17 Oct 2024 15:35:48 -0400 Subject: [PATCH 087/109] stackwalk: fix jl_thread_suspend_and_get_state race (#56047) (#192) There was a missing re-assignment of old = -1; at the end of that loop which means in the ABA case, we accidentally actually acquire the lock on the thread despite not actually having stopped the thread; or in the counter-case, we try to run through this logic with old==-1 on the next iteration, and that isn't valid either (jl_thread_suspend_and_get_state should return failure and the loop will abort too early). Fix #56046 Co-authored-by: Jameson Nash --- src/stackwalk.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stackwalk.c b/src/stackwalk.c index ab3f13c8e9746..def7dd9fd6b9f 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -881,8 +881,8 @@ static void jl_rec_backtrace(jl_task_t *t) JL_NOTSAFEPOINT } bt_context_t *context = NULL; bt_context_t c; - int16_t old = -1; - while (!jl_atomic_cmpswap(&t->tid, &old, ptls->tid) && old != ptls->tid) { + int16_t old; + for (old = -1; !jl_atomic_cmpswap(&t->tid, &old, ptls->tid) && old != ptls->tid; old = -1) { int lockret = jl_lock_stackwalk(); // if this task is already running somewhere, we need to stop the thread it is running on and query its state if (!jl_thread_suspend_and_get_state(old, 0, &c)) { From f481fc9d72062da81dc1dd2367b88bd9246af80b Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Wed, 23 Oct 2024 12:58:19 -0400 Subject: [PATCH 088/109] add `--trace-compile-timing` arg to add compile timing comments (#54662) (#187) Co-authored-by: Ian Butterworth --- base/options.jl | 1 + doc/man/julia.1 | 4 ++++ doc/src/manual/command-line-interface.md | 3 ++- src/gf.c | 13 +++++++++---- src/jloptions.c | 12 +++++++++--- src/jloptions.h | 1 + test/cmdlineargs.jl | 11 +++++++++++ 7 files changed, 37 insertions(+), 8 deletions(-) diff --git a/base/options.jl b/base/options.jl index 2b2906bf86e82..a01a3f553b157 100644 --- a/base/options.jl +++ b/base/options.jl @@ -58,6 +58,7 @@ struct JLOptions strip_ir::Int8 permalloc_pkgimg::Int8 heap_size_hint::UInt64 + trace_compile_timing::Int8 safe_crash_log_file::Ptr{UInt8} end diff --git a/doc/man/julia.1 b/doc/man/julia.1 index b112cb80d94c3..e7da6e352a96a 100644 --- a/doc/man/julia.1 +++ b/doc/man/julia.1 @@ -266,6 +266,10 @@ Generate an incremental output file (rather than complete) --trace-compile={stderr,name} Print precompile statements for methods compiled during execution or save to a path +.TP +--trace-compile-timing= +If --trace-compile is enabled show how long each took to compile in ms + .TP -image-codegen Force generate code in imaging mode diff --git a/doc/src/manual/command-line-interface.md b/doc/src/manual/command-line-interface.md index fdf165d411f5e..d08e3fbfd2181 100644 --- a/doc/src/manual/command-line-interface.md +++ b/doc/src/manual/command-line-interface.md @@ -140,7 +140,8 @@ The following is a complete list of command-line switches available when launchi |`--output-bc ` |Generate LLVM bitcode (.bc)| |`--output-asm ` |Generate an assembly file (.s)| |`--output-incremental={yes\|no*}` |Generate an incremental output file (rather than complete)| -|`--trace-compile={stderr,name}` |Print precompile statements for methods compiled during execution or save to a path| +|`--trace-compile={stderr\|name}` |Print precompile statements for methods compiled during execution or save to a path| +|`--trace-compile-timing` |If --trace-compile is enabled show how long each took to compile in ms| |`--image-codegen` |Force generate code in imaging mode| |`--heap-size-hint=` |Forces garbage collection if memory usage is higher than that value. The memory hint might be specified in megabytes (e.g., 500M) or gigabytes (e.g., 1G)| diff --git a/src/gf.c b/src/gf.c index 1aee075c8d15a..559a23fdda725 100644 --- a/src/gf.c +++ b/src/gf.c @@ -2333,7 +2333,7 @@ jl_code_instance_t *jl_method_compiled(jl_method_instance_t *mi, size_t world) jl_mutex_t precomp_statement_out_lock; -static void record_precompile_statement(jl_method_instance_t *mi) +static void record_precompile_statement(jl_method_instance_t *mi, double compilation_time) { static ios_t f_precompile; static JL_STREAM* s_precompile = NULL; @@ -2356,6 +2356,8 @@ static void record_precompile_statement(jl_method_instance_t *mi) } } if (!jl_has_free_typevars(mi->specTypes)) { + if (jl_options.trace_compile_timing) + jl_printf(s_precompile, "#= %6.1f =# ", compilation_time / 1e6); jl_printf(s_precompile, "precompile("); jl_static_show(s_precompile, mi->specTypes); jl_printf(s_precompile, ")\n"); @@ -2484,7 +2486,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t codeinst->rettype_const = unspec->rettype_const; jl_atomic_store_release(&codeinst->invoke, unspec_invoke); jl_mi_cache_insert(mi, codeinst); - record_precompile_statement(mi); + record_precompile_statement(mi, 0); return codeinst; } } @@ -2501,7 +2503,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t 0, 1, ~(size_t)0, 0, 0, jl_nothing, 0); jl_atomic_store_release(&codeinst->invoke, jl_fptr_interpret_call); jl_mi_cache_insert(mi, codeinst); - record_precompile_statement(mi); + record_precompile_statement(mi, 0); return codeinst; } if (compile_option == JL_OPTIONS_COMPILE_OFF) { @@ -2511,8 +2513,11 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t } } + double compile_time = jl_hrtime(); int did_compile = 0; codeinst = jl_generate_fptr(mi, world, &did_compile); + compile_time = jl_hrtime() - compile_time; + if (!codeinst) { jl_method_instance_t *unspec = jl_get_unspecialized_from_mi(mi); jl_code_instance_t *ucache = jl_get_method_inferred(unspec, (jl_value_t*)jl_any_type, 1, ~(size_t)0); @@ -2553,7 +2558,7 @@ jl_code_instance_t *jl_compile_method_internal(jl_method_instance_t *mi, size_t jl_mi_cache_insert(mi, codeinst); } else if (did_compile) { - record_precompile_statement(mi); + record_precompile_statement(mi, compile_time); } jl_atomic_store_relaxed(&codeinst->precompile, 1); return codeinst; diff --git a/src/jloptions.c b/src/jloptions.c index 14d2242284ae1..40fc3fe7f4ab5 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -91,6 +91,7 @@ JL_DLLEXPORT void jl_init_options(void) 0, // strip-ir 0, // permalloc_pkgimg 0, // heap-size-hint + 0, // trace_compile_timing NULL, // safe_crash_log_file }; jl_options_initialized = 1; @@ -213,6 +214,7 @@ static const char opts_hidden[] = " Generate an incremental output file (rather than complete)\n" " --trace-compile={stderr,name}\n" " Print precompile statements for methods compiled during execution or save to a path\n" + " --trace-compile-timing If --trace-compile is enabled show how long each took to compile in ms\n" " --image-codegen Force generate code in imaging mode\n" " --permalloc-pkgimg={yes|no*} Copy the data section of package images into memory\n" ; @@ -235,6 +237,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) opt_inline, opt_polly, opt_trace_compile, + opt_trace_compile_timing, opt_trace_dispatch, opt_math_mode, opt_worker, @@ -741,7 +744,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) jl_errorf("julia: invalid argument to --inline (%s)", optarg); } break; - case opt_polly: + case opt_polly: if (!strcmp(optarg,"yes")) jl_options.polly = JL_OPTIONS_POLLY_ON; else if (!strcmp(optarg,"no")) @@ -750,12 +753,15 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) jl_errorf("julia: invalid argument to --polly (%s)", optarg); } break; - case opt_trace_compile: + case opt_trace_compile: jl_options.trace_compile = strdup(optarg); if (!jl_options.trace_compile) jl_errorf("fatal error: failed to allocate memory: %s", strerror(errno)); break; - case opt_trace_dispatch: + case opt_trace_compile_timing: + jl_options.trace_compile_timing = 1; + break; + case opt_trace_dispatch: jl_options.trace_dispatch = strdup(optarg); if (!jl_options.trace_dispatch) jl_errorf("fatal error: failed to allocate memory: %s", strerror(errno)); diff --git a/src/jloptions.h b/src/jloptions.h index 20027ebfff24a..63f639805b300 100644 --- a/src/jloptions.h +++ b/src/jloptions.h @@ -62,6 +62,7 @@ typedef struct { int8_t strip_ir; int8_t permalloc_pkgimg; uint64_t heap_size_hint; + int8_t trace_compile_timing; const char *safe_crash_log_file; } jl_options_t; diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index e5659b7c2439f..094fa8741087f 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -761,6 +761,17 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no` @test occursin("precompile(Tuple{typeof(Main.foo), Int", _stderr) end + # --trace-compile-timing + let + io = IOBuffer() + v = writereadpipeline( + "foo(x) = begin Base.Experimental.@force_compile; x; end; foo(1)", + `$exename --trace-compile=stderr --trace-compile-timing -i`, + stderr=io) + _stderr = String(take!(io)) + @test occursin(" ms =# precompile(Tuple{typeof(Main.foo), Int", _stderr) + end + # --trace-dispatch let io = IOBuffer() From fc4ae84acfce87bb79e62e522072ff60a05a85bc Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:21:16 -0300 Subject: [PATCH 089/109] Wall-time/all tasks profiler (#55889) (#193) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit One limitation of sampling CPU/thread profiles, as is currently done in Julia, is that they primarily capture samples from CPU-intensive tasks. If many tasks are performing IO or contending for concurrency primitives like semaphores, these tasks won’t appear in the profile, as they aren't scheduled on OS threads sampled by the profiler. A wall-time profiler, like the one implemented in this PR, samples tasks regardless of OS thread scheduling. This enables profiling of IO-heavy tasks and detecting areas of heavy contention in the system. Co-developed with @nickrobinson251. --- NEWS.md | 2 + doc/src/manual/img/cpu-profile.png | Bin 0 -> 147343 bytes doc/src/manual/img/task-sampling-failure.png | Bin 0 -> 359826 bytes .../wall-time-profiler-channel-example.png | Bin 0 -> 191682 bytes ...ll-time-profiler-compute-bound-example.png | Bin 0 -> 435521 bytes doc/src/manual/profile.md | 214 ++++++++++++++++++ src/gc-stacks.c | 33 +++ src/gc.c | 29 ++- src/gc.h | 10 + src/init.c | 5 + src/julia_internal.h | 29 +++ src/julia_threads.h | 1 + src/mtarraylist.c | 2 +- src/signal-handling.c | 135 +++++++++-- src/signals-mach.c | 178 ++++++++------- src/signals-unix.c | 170 ++++++++------ src/signals-win.c | 45 ++-- src/stackwalk.c | 77 +++++-- stdlib/Profile/src/Profile.jl | 77 +++++-- stdlib/Profile/test/runtests.jl | 61 ++++- 20 files changed, 827 insertions(+), 241 deletions(-) create mode 100644 doc/src/manual/img/cpu-profile.png create mode 100644 doc/src/manual/img/task-sampling-failure.png create mode 100644 doc/src/manual/img/wall-time-profiler-channel-example.png create mode 100644 doc/src/manual/img/wall-time-profiler-compute-bound-example.png diff --git a/NEWS.md b/NEWS.md index 9e5ab91b1749b..7077aa8e3a8dc 100644 --- a/NEWS.md +++ b/NEWS.md @@ -133,6 +133,8 @@ Deprecated or removed * The `@pure` macro is now deprecated. Use `Base.@assume_effects :foldable` instead ([#48682]). +- A wall-time profiler is now available for users who need a sampling profiler that captures tasks regardless of their scheduling or running state. This type of profiler enables profiling of I/O-heavy tasks and helps detect areas of heavy contention in the system ([#55889]). + [#31836]: https://github.com/JuliaLang/julia/issues/31836 [#40105]: https://github.com/JuliaLang/julia/issues/40105 diff --git a/doc/src/manual/img/cpu-profile.png b/doc/src/manual/img/cpu-profile.png new file mode 100644 index 0000000000000000000000000000000000000000..ec48b41f6e78b9975c1bf1fc670d8221514f249f GIT binary patch literal 147343 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%0DlU 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д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�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 z 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

gq!7n(IsL)&H8$Ml%d96QRO>Rv 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

;`arX$fO(N*1UWRDSh*sDK+UZL97*D9v@)%9{0 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ƋF3Qs{u)$ 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 literal 0 HcmV?d00001 diff --git a/doc/src/manual/profile.md b/doc/src/manual/profile.md index 6e9f98d3f1780..f15dec5d36d43 100644 --- a/doc/src/manual/profile.md +++ b/doc/src/manual/profile.md @@ -297,6 +297,220 @@ Of course, you can decrease the delay as well as increase it; however, the overh grows once the delay becomes similar to the amount of time needed to take a backtrace (~30 microseconds on the author's laptop). +## Wall-time Profiler + +### Introduction & Problem Motivation + +The profiler described in the previous section is a sampling CPU profiler. At a high level, the profiler periodically stops all Julia compute threads to collect their backtraces and estimates the time spent in each function based on the number of backtrace samples that include a frame from that function. However, note that only tasks currently running on system threads just before the profiler stops them will have their backtraces collected. + +While this profiler is typically well-suited for workloads where the majority of tasks are compute-bound, it is less helpful for systems where most tasks are IO-heavy or for diagnosing contention on synchronization primitives in your code. + +Let's consider this simple workload: + +```Julia +using Base.Threads +using Profile +using PProf + +ch = Channel(1) + +const N_SPAWNED_TASKS = (1 << 10) +const WAIT_TIME_NS = 10_000_000 + +function spawn_a_bunch_of_tasks_waiting_on_channel() + for i in 1:N_SPAWNED_TASKS + Threads.@spawn begin + take!(ch) + end + end +end + +function busywait() + t0 = time_ns() + while true + if time_ns() - t0 > WAIT_TIME_NS + break + end + end +end + +function main() + spawn_a_bunch_of_tasks_waiting_on_channel() + for i in 1:N_SPAWNED_TASKS + put!(ch, i) + busywait() + end +end + +Profile.@profile main() +``` + +Our goal is to detect whether there is contention on the `ch` channel—i.e., whether the number of waiters is excessive given the rate at which work items are being produced in the channel. + +If we run this, we obtain the following [PProf](https://github.com/JuliaPerf/PProf.jl) flame graph: + +![CPU Profile](./img/cpu-profile.png) + +This profile provides no information to help determine where contention occurs in the system’s synchronization primitives. Waiters on a channel will be blocked and descheduled, meaning no system thread will be running the tasks assigned to those waiters, and as a result, they won't be sampled by the profiler. + +### Wall-time Profiler + +Instead of sampling threads—and thus only sampling tasks that are running—a wall-time task profiler samples tasks independently of their scheduling state. For example, tasks that are sleeping on a synchronization primitive at the time the profiler is running will be sampled with the same probability as tasks that were actively running when the profiler attempted to capture backtraces. + +This approach allows us to construct a profile where backtraces from tasks blocked on the `ch` channel, as in the example above, are actually represented. + +Let's run the same example, but now with a wall-time profiler: + + +```Julia +using Base.Threads +using Profile +using PProf + +ch = Channel(1) + +const N_SPAWNED_TASKS = (1 << 10) +const WAIT_TIME_NS = 10_000_000 + +function spawn_a_bunch_of_tasks_waiting_on_channel() + for i in 1:N_SPAWNED_TASKS + Threads.@spawn begin + take!(ch) + end + end +end + +function busywait() + t0 = time_ns() + while true + if time_ns() - t0 > WAIT_TIME_NS + break + end + end +end + +function main() + spawn_a_bunch_of_tasks_waiting_on_channel() + for i in 1:N_SPAWNED_TASKS + put!(ch, i) + busywait() + end +end + +Profile.@profile_walltime main() +``` + +We obtain the following flame graph: + +![Wall-time Profile Channel](./img/wall-time-profiler-channel-example.png) + +We see that a large number of samples come from channel-related `take!` functions, which allows us to determine that there is indeed an excessive number of waiters in `ch`. + +### A Compute-Bound Workload + +Despite the wall-time profiler sampling all live tasks in the system and not just the currently running ones, it can still be helpful for identifying performance hotspots, even if your code is compute-bound. Let’s consider a simple example: + +```Julia +using Base.Threads +using Profile +using PProf + +ch = Channel(1) + +const MAX_ITERS = (1 << 22) +const N_TASKS = (1 << 12) + +function spawn_a_task_waiting_on_channel() + Threads.@spawn begin + take!(ch) + end +end + +function sum_of_sqrt() + sum_of_sqrt = 0.0 + for i in 1:MAX_ITERS + sum_of_sqrt += sqrt(i) + end + return sum_of_sqrt +end + +function spawn_a_bunch_of_compute_heavy_tasks() + Threads.@sync begin + for i in 1:N_TASKS + Threads.@spawn begin + sum_of_sqrt() + end + end + end +end + +function main() + spawn_a_task_waiting_on_channel() + spawn_a_bunch_of_compute_heavy_tasks() +end + +Profile.@profile_walltime main() +``` + +After collecting a wall-time profile, we get the following flame graph: + +![Wall-time Profile Compute-Bound](./img/wall-time-profiler-compute-bound-example.png) + +Notice how many of the samples contain `sum_of_sqrt`, which is the expensive compute function in our example. + +### Identifying Task Sampling Failures in your Profile + +In the current implementation, the wall-time profiler attempts to sample from tasks that have been alive since the last garbage collection, along with those created afterward. However, if most tasks are extremely short-lived, you may end up sampling tasks that have already completed, resulting in missed backtrace captures. + +If you encounter samples containing `failed_to_sample_task_fun` or `failed_to_stop_thread_fun`, this likely indicates a high volume of short-lived tasks, which prevented their backtraces from being collected. + +Let's consider this simple example: + +```Julia +using Base.Threads +using Profile +using PProf + +const N_SPAWNED_TASKS = (1 << 16) +const WAIT_TIME_NS = 100_000 + +function spawn_a_bunch_of_short_lived_tasks() + for i in 1:N_SPAWNED_TASKS + Threads.@spawn begin + # Do nothing + end + end +end + +function busywait() + t0 = time_ns() + while true + if time_ns() - t0 > WAIT_TIME_NS + break + end + end +end + +function main() + GC.enable(false) + spawn_a_bunch_of_short_lived_tasks() + for i in 1:N_SPAWNED_TASKS + busywait() + end + GC.enable(true) +end + +Profile.@profile_walltime main() +``` + +Notice that the tasks spawned in `spawn_a_bunch_of_short_lived_tasks` are extremely short-lived. Since these tasks constitute the majority in the system, we will likely miss capturing a backtrace for most sampled tasks. + +After collecting a wall-time profile, we obtain the following flame graph: + +![Task Sampling Failure](./img/task-sampling-failure.png) + +The large number of samples from `failed_to_stop_thread_fun` confirms that we have a significant number of short-lived tasks in the system. + ## Memory allocation analysis One of the most common techniques to improve performance is to reduce memory allocation. Julia diff --git a/src/gc-stacks.c b/src/gc-stacks.c index 1c1e286960762..8e4297b0a4b8a 100644 --- a/src/gc-stacks.c +++ b/src/gc-stacks.c @@ -266,6 +266,39 @@ void sweep_stack_pools(void) } } +// Builds a list of the live tasks. Racy: `live_tasks` can expand at any time. +arraylist_t *jl_get_all_tasks_arraylist(void) JL_NOTSAFEPOINT +{ + arraylist_t *tasks = (arraylist_t*)malloc_s(sizeof(arraylist_t)); + arraylist_new(tasks, 0); + size_t nthreads = jl_atomic_load_acquire(&jl_n_threads); + jl_ptls_t *allstates = jl_atomic_load_relaxed(&jl_all_tls_states); + for (size_t i = 0; i < nthreads; i++) { + // skip GC threads... + if (gc_is_parallel_collector_thread(i) || gc_is_concurrent_collector_thread(i)) { + continue; + } + jl_ptls_t ptls2 = allstates[i]; + if (ptls2 == NULL) { + continue; + } + jl_task_t *t = ptls2->root_task; + if (t->stkbuf != NULL) { + arraylist_push(tasks, t); + } + small_arraylist_t *live_tasks = &ptls2->gc_tls.heap.live_tasks; + size_t n = mtarraylist_length(live_tasks); + for (size_t i = 0; i < n; i++) { + jl_task_t *t = (jl_task_t*)mtarraylist_get(live_tasks, i); + assert(t != NULL); + if (t->stkbuf != NULL) { + arraylist_push(tasks, t); + } + } + } + return tasks; +} + JL_DLLEXPORT jl_array_t *jl_live_tasks(void) { size_t nthreads = jl_atomic_load_acquire(&jl_n_threads); diff --git a/src/gc.c b/src/gc.c index 334bd8f83ada7..12d312dea1fb2 100644 --- a/src/gc.c +++ b/src/gc.c @@ -1527,6 +1527,31 @@ static void gc_sweep_other(jl_ptls_t ptls, int sweep_full) JL_NOTSAFEPOINT gc_num.total_sweep_free_mallocd_memory_time += t_free_mallocd_memory_end - t_free_mallocd_memory_start; } +void sweep_mtarraylist_buffers(void) JL_NOTSAFEPOINT +{ + for (int i = 0; i < gc_n_threads; i++) { + jl_ptls_t ptls = gc_all_tls_states[i]; + if (ptls == NULL) { + continue; + } + small_arraylist_t *buffers = &ptls->lazily_freed_mtarraylist_buffers; + void *buf; + while ((buf = small_arraylist_pop(buffers)) != NULL) { + free(buf); + } + } +} + +void sweep_stack_pools_and_mtarraylist_buffers(jl_ptls_t ptls) JL_NOTSAFEPOINT +{ + // initialize ptls index for parallel sweeping of stack pools + assert(gc_n_threads); + uv_mutex_lock(&live_tasks_lock); + sweep_stack_pools(); + sweep_mtarraylist_buffers(); + uv_mutex_unlock(&live_tasks_lock); +} + static void gc_pool_sync_nfree(jl_gc_pagemeta_t *pg, jl_taggedvalue_t *last) JL_NOTSAFEPOINT { assert(pg->fl_begin_offset != UINT16_MAX); @@ -3611,7 +3636,7 @@ static int _jl_gc_collect(jl_ptls_t ptls, jl_gc_collection_t collection) #endif current_sweep_full = sweep_full; sweep_weak_refs(); - sweep_stack_pools(); + sweep_stack_pools_and_mtarraylist_buffers(ptls); gc_sweep_foreign_objs(); gc_sweep_other(ptls, sweep_full); gc_scrub(); @@ -3903,6 +3928,8 @@ void jl_init_thread_heap(jl_ptls_t ptls) jl_atomic_store_relaxed(&q->bottom, 0); jl_atomic_store_relaxed(&q->array, wsa2); arraylist_new(&mq->reclaim_set, 32); + // Initialize `lazily_freed_mtarraylist_buffers` + small_arraylist_new(&ptls->lazily_freed_mtarraylist_buffers, 0); memset(&ptls->gc_tls.gc_num, 0, sizeof(ptls->gc_tls.gc_num)); jl_atomic_store_relaxed(&ptls->gc_tls.gc_num.allocd, -(int64_t)gc_num.interval); diff --git a/src/gc.h b/src/gc.h index 61c7c835db34a..be80e4bcbbd71 100644 --- a/src/gc.h +++ b/src/gc.h @@ -471,6 +471,16 @@ STATIC_INLINE int gc_is_parallel_collector_thread(int tid) JL_NOTSAFEPOINT return tid >= gc_first_tid && tid <= gc_last_parallel_collector_thread_id(); } +STATIC_INLINE int gc_is_concurrent_collector_thread(int tid) JL_NOTSAFEPOINT +{ + if (jl_n_sweepthreads == 0) { + return 0; + } + int last_parallel_collector_thread_id = gc_last_parallel_collector_thread_id(); + int concurrent_collector_thread_id = last_parallel_collector_thread_id + 1; + return tid == concurrent_collector_thread_id; +} + STATIC_INLINE int gc_random_parallel_collector_thread_id(jl_ptls_t ptls) JL_NOTSAFEPOINT { assert(jl_n_markthreads > 0); diff --git a/src/init.c b/src/init.c index e482f8b77ee9b..9a49ad60c02f4 100644 --- a/src/init.c +++ b/src/init.c @@ -747,6 +747,11 @@ JL_DLLEXPORT void julia_init(JL_IMAGE_SEARCH rel) // Make sure we finalize the tls callback before starting any threads. (void)jl_get_pgcstack(); + // initialize the live tasks lock + uv_mutex_init(&live_tasks_lock); + // initialize the profiler buffer lock + uv_mutex_init(&bt_data_prof_lock); + // initialize backtraces jl_init_profile_lock(); #ifdef _OS_WINDOWS_ diff --git a/src/julia_internal.h b/src/julia_internal.h index 94b1f85112d7d..fc719c45c5753 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -206,6 +206,35 @@ JL_DLLEXPORT void jl_unlock_profile_wr(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEA int jl_lock_stackwalk(void) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_ENTER; void jl_unlock_stackwalk(int lockret) JL_NOTSAFEPOINT JL_NOTSAFEPOINT_LEAVE; +arraylist_t *jl_get_all_tasks_arraylist(void) JL_NOTSAFEPOINT; +typedef struct { + size_t bt_size; + int tid; +} jl_record_backtrace_result_t; +JL_DLLEXPORT jl_record_backtrace_result_t jl_record_backtrace(jl_task_t *t, struct _jl_bt_element_t *bt_data, + size_t max_bt_size, int all_tasks_profiler) JL_NOTSAFEPOINT; +extern volatile struct _jl_bt_element_t *profile_bt_data_prof; +extern volatile size_t profile_bt_size_max; +extern volatile size_t profile_bt_size_cur; +extern volatile int profile_running; +extern volatile int profile_all_tasks; +// Ensures that we can safely read the `live_tasks`field of every TLS when profiling. +// We want to avoid the case that a GC gets interleaved with `jl_profile_task` and shrinks +// the `live_tasks` array while we are reading it or frees tasks that are being profiled. +// Because of that, this lock must be held in `jl_profile_task` and `sweep_stack_pools_and_mtarraylist_buffers`. +extern uv_mutex_t live_tasks_lock; +// Ensures that we can safely write to `profile_bt_data_prof` and `profile_bt_size_cur`. +// We want to avoid the case that: +// - We start to profile a task very close to the profiling time window end. +// - The profiling time window ends and we start to read the profile data in a compute thread. +// - We write to the profile in a profiler thread while the compute thread is reading it. +// Locking discipline: `bt_data_prof_lock` must be held inside the scope of `live_tasks_lock`. +extern uv_mutex_t bt_data_prof_lock; +#define PROFILE_STATE_THREAD_NOT_SLEEPING (1) +#define PROFILE_STATE_THREAD_SLEEPING (2) +#define PROFILE_STATE_WALL_TIME_PROFILING (3) +void jl_profile_task(void); + // number of cycles since power-on static inline uint64_t cycleclock(void) JL_NOTSAFEPOINT { diff --git a/src/julia_threads.h b/src/julia_threads.h index 3d06d380d10c2..141098f7dce49 100644 --- a/src/julia_threads.h +++ b/src/julia_threads.h @@ -155,6 +155,7 @@ typedef struct _jl_tls_states_t { // Counter to disable finalizer **on the current thread** int finalizers_inhibited; jl_gc_tls_states_t gc_tls; // this is very large, and the offset of the first member is baked into codegen + small_arraylist_t lazily_freed_mtarraylist_buffers; volatile sig_atomic_t defer_signal; _Atomic(struct _jl_task_t*) current_task; struct _jl_task_t *next_task; diff --git a/src/mtarraylist.c b/src/mtarraylist.c index 8bad44797dab4..7af265a86ab63 100644 --- a/src/mtarraylist.c +++ b/src/mtarraylist.c @@ -37,7 +37,7 @@ static void mtarraylist_resizeto(small_mtarraylist_t *a, size_t len, size_t newl a->max = nm; if (olditems != (void*)&a->_space[0]) { jl_task_t *ct = jl_current_task; - jl_gc_add_quiescent(ct->ptls, (void**)olditems, free); + small_arraylist_push(&ct->ptls->lazily_freed_mtarraylist_buffers, olditems); } } } diff --git a/src/signal-handling.c b/src/signal-handling.c index c2a344a752547..98c0b0896f347 100644 --- a/src/signal-handling.c +++ b/src/signal-handling.c @@ -18,16 +18,18 @@ extern "C" { #include // Profiler control variables -// Note: these "static" variables are also used in "signals-*.c" -static volatile jl_bt_element_t *bt_data_prof = NULL; -static volatile size_t bt_size_max = 0; -static volatile size_t bt_size_cur = 0; +uv_mutex_t live_tasks_lock; +uv_mutex_t bt_data_prof_lock; +volatile jl_bt_element_t *profile_bt_data_prof = NULL; +volatile size_t profile_bt_size_max = 0; +volatile size_t profile_bt_size_cur = 0; static volatile uint64_t nsecprof = 0; -static volatile int running = 0; -static const uint64_t GIGA = 1000000000ULL; +volatile int profile_running = 0; +volatile int profile_all_tasks = 0; +static const uint64_t GIGA = 1000000000ULL; // Timers to take samples at intervals JL_DLLEXPORT void jl_profile_stop_timer(void); -JL_DLLEXPORT int jl_profile_start_timer(void); +JL_DLLEXPORT int jl_profile_start_timer(uint8_t); // File-descriptor for safe logging on signal handling int jl_sig_fd; @@ -36,30 +38,30 @@ int jl_sig_fd; /////////////////////// JL_DLLEXPORT int jl_profile_init(size_t maxsize, uint64_t delay_nsec) { - bt_size_max = maxsize; + profile_bt_size_max = maxsize; nsecprof = delay_nsec; - if (bt_data_prof != NULL) - free((void*)bt_data_prof); - bt_data_prof = (jl_bt_element_t*) calloc(maxsize, sizeof(jl_bt_element_t)); - if (bt_data_prof == NULL && maxsize > 0) + if (profile_bt_data_prof != NULL) + free((void*)profile_bt_data_prof); + profile_bt_data_prof = (jl_bt_element_t*) calloc(maxsize, sizeof(jl_bt_element_t)); + if (profile_bt_data_prof == NULL && maxsize > 0) return -1; - bt_size_cur = 0; + profile_bt_size_cur = 0; return 0; } JL_DLLEXPORT uint8_t *jl_profile_get_data(void) { - return (uint8_t*) bt_data_prof; + return (uint8_t*) profile_bt_data_prof; } JL_DLLEXPORT size_t jl_profile_len_data(void) { - return bt_size_cur; + return profile_bt_size_cur; } JL_DLLEXPORT size_t jl_profile_maxlen_data(void) { - return bt_size_max; + return profile_bt_size_max; } JL_DLLEXPORT uint64_t jl_profile_delay_nsec(void) @@ -69,12 +71,12 @@ JL_DLLEXPORT uint64_t jl_profile_delay_nsec(void) JL_DLLEXPORT void jl_profile_clear_data(void) { - bt_size_cur = 0; + profile_bt_size_cur = 0; } JL_DLLEXPORT int jl_profile_is_running(void) { - return running; + return profile_running; } // Any function that acquires this lock must be either a unmanaged thread @@ -187,7 +189,102 @@ JL_DLLEXPORT int jl_profile_is_buffer_full(void) // Declare buffer full if there isn't enough room to sample even just the // thread metadata and one max-sized frame. The `+ 6` is for the two block // terminator `0`'s plus the 4 metadata entries. - return bt_size_cur + ((JL_BT_MAX_ENTRY_SIZE + 1) + 6) > bt_size_max; + return profile_bt_size_cur + ((JL_BT_MAX_ENTRY_SIZE + 1) + 6) > profile_bt_size_max; +} + +NOINLINE int failed_to_sample_task_fun(jl_bt_element_t *bt_data, size_t maxsize, int skip) JL_NOTSAFEPOINT; +NOINLINE int failed_to_stop_thread_fun(jl_bt_element_t *bt_data, size_t maxsize, int skip) JL_NOTSAFEPOINT; + +#define PROFILE_TASK_DEBUG_FORCE_SAMPLING_FAILURE (0) +#define PROFILE_TASK_DEBUG_FORCE_STOP_THREAD_FAILURE (0) + +void jl_profile_task(void) +{ + if (jl_profile_is_buffer_full()) { + // Buffer full: Delete the timer + jl_profile_stop_timer(); + return; + } + + jl_task_t *t = NULL; + int got_mutex = 0; + if (uv_mutex_trylock(&live_tasks_lock) != 0) { + goto collect_backtrace; + } + got_mutex = 1; + + arraylist_t *tasks = jl_get_all_tasks_arraylist(); + uint64_t seed = jl_rand(); + const int n_max_random_attempts = 4; + // randomly select a task that is not done + for (int i = 0; i < n_max_random_attempts; i++) { + t = (jl_task_t*)tasks->items[cong(tasks->len, UINT64_MAX, &seed)]; + assert(t == NULL || jl_is_task(t)); + if (t == NULL) { + continue; + } + int t_state = jl_atomic_load_relaxed(&t->_state); + if (t_state == JL_TASK_STATE_DONE) { + continue; + } + break; + } + arraylist_free(tasks); + free(tasks); + +collect_backtrace: + + uv_mutex_lock(&bt_data_prof_lock); + if (profile_running == 0) { + uv_mutex_unlock(&bt_data_prof_lock); + if (got_mutex) { + uv_mutex_unlock(&live_tasks_lock); + } + return; + } + + jl_record_backtrace_result_t r = {0, INT16_MAX}; + jl_bt_element_t *bt_data_prof = (jl_bt_element_t*)(profile_bt_data_prof + profile_bt_size_cur); + size_t bt_size_max = profile_bt_size_max - profile_bt_size_cur - 1; + if (t == NULL || PROFILE_TASK_DEBUG_FORCE_SAMPLING_FAILURE) { + // failed to find a task + r.bt_size = failed_to_sample_task_fun(bt_data_prof, bt_size_max, 0); + } + else { + if (!PROFILE_TASK_DEBUG_FORCE_STOP_THREAD_FAILURE) { + r = jl_record_backtrace(t, bt_data_prof, bt_size_max, 1); + } + // we failed to get a backtrace + if (r.bt_size == 0) { + r.bt_size = failed_to_stop_thread_fun(bt_data_prof, bt_size_max, 0); + } + } + + // update the profile buffer size + profile_bt_size_cur += r.bt_size; + + // store threadid but add 1 as 0 is preserved to indicate end of block + profile_bt_data_prof[profile_bt_size_cur++].uintptr = (uintptr_t)r.tid + 1; + + // store task id (never null) + profile_bt_data_prof[profile_bt_size_cur++].jlvalue = (jl_value_t*)t; + + // store cpu cycle clock + profile_bt_data_prof[profile_bt_size_cur++].uintptr = cycleclock(); + + // the thread profiler uses this block to record whether the thread is not sleeping (1) or sleeping (2) + // let's use a dummy value which is not 1 or 2 to + // indicate that we are profiling a task, and therefore, this block is not about the thread state + profile_bt_data_prof[profile_bt_size_cur++].uintptr = 3; + + // Mark the end of this block with two 0's + profile_bt_data_prof[profile_bt_size_cur++].uintptr = 0; + profile_bt_data_prof[profile_bt_size_cur++].uintptr = 0; + + uv_mutex_unlock(&bt_data_prof_lock); + if (got_mutex) { + uv_mutex_unlock(&live_tasks_lock); + } } static uint64_t jl_last_sigint_trigger = 0; diff --git a/src/signals-mach.c b/src/signals-mach.c index 6ec8f95570f17..9b5d56eaff36c 100644 --- a/src/signals-mach.c +++ b/src/signals-mach.c @@ -603,6 +603,84 @@ void jl_unlock_stackwalk(int lockret) jl_unlock_profile_mach(1, lockret); } +// assumes holding `jl_lock_profile_mach` +void jl_profile_thread_mach(int tid) +{ + // if there is no space left, return early + if (jl_profile_is_buffer_full()) { + jl_profile_stop_timer(); + return; + } + if (_dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL) + _dyld_dlopen_atfork_prepare(); + if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) + _dyld_atfork_prepare(); // briefly acquire the dlsym lock + host_thread_state_t state; + int valid_thread = jl_thread_suspend_and_get_state2(tid, &state); + unw_context_t *uc = (unw_context_t*)&state; + if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) + _dyld_atfork_parent(); // quickly release the dlsym lock + if (_dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL) + _dyld_dlopen_atfork_parent(); + if (!valid_thread) + return; + if (profile_running) { +#ifdef LLVMLIBUNWIND + /* + * Unfortunately compact unwind info is incorrectly generated for quite a number of + * libraries by quite a large number of compilers. We can fall back to DWARF unwind info + * in some cases, but in quite a number of cases (especially libraries not compiled in debug + * mode, only the compact unwind info may be available). Even more unfortunately, there is no + * way to detect such bogus compact unwind info (other than noticing the resulting segfault). + * What we do here is ugly, but necessary until the compact unwind info situation improves. + * We try to use the compact unwind info and if that results in a segfault, we retry with DWARF info. + * Note that in a small number of cases this may result in bogus stack traces, but at least the topmost + * entry will always be correct, and the number of cases in which this is an issue is rather small. + * Other than that, this implementation is not incorrect as the other thread is paused while we are profiling + * and during stack unwinding we only ever read memory, but never write it. + */ + + forceDwarf = 0; + unw_getcontext(&profiler_uc); // will resume from this point if the next lines segfault at any point + + if (forceDwarf == 0) { + // Save the backtrace + profile_bt_size_cur += rec_backtrace_ctx((jl_bt_element_t*)profile_bt_data_prof + profile_bt_size_cur, profile_bt_size_max - profile_bt_size_cur - 1, uc, NULL); + } + else if (forceDwarf == 1) { + profile_bt_size_cur += rec_backtrace_ctx_dwarf((jl_bt_element_t*)profile_bt_data_prof + profile_bt_size_cur, profile_bt_size_max - profile_bt_size_cur - 1, uc, NULL); + } + else if (forceDwarf == -1) { + jl_safe_printf("WARNING: profiler attempt to access an invalid memory location\n"); + } + + forceDwarf = -2; +#else + profile_bt_size_cur += rec_backtrace_ctx((jl_bt_element_t*)profile_bt_data_prof + profile_bt_size_cur, profile_bt_size_max - profile_bt_size_cur - 1, uc, NULL); +#endif + jl_ptls_t ptls = jl_atomic_load_relaxed(&jl_all_tls_states)[tid]; + + // store threadid but add 1 as 0 is preserved to indicate end of block + profile_bt_data_prof[profile_bt_size_cur++].uintptr = ptls->tid + 1; + + // store task id (never null) + profile_bt_data_prof[profile_bt_size_cur++].jlvalue = (jl_value_t*)jl_atomic_load_relaxed(&ptls->current_task); + + // store cpu cycle clock + profile_bt_data_prof[profile_bt_size_cur++].uintptr = cycleclock(); + + // store whether thread is sleeping (don't ever encode a state as `0` since is preserved to indicate end of block) + int state = jl_atomic_load_relaxed(&ptls->sleep_check_state) == 0 ? PROFILE_STATE_THREAD_NOT_SLEEPING : PROFILE_STATE_THREAD_SLEEPING; + profile_bt_data_prof[profile_bt_size_cur++].uintptr = state; + + // Mark the end of this block with two 0's + profile_bt_data_prof[profile_bt_size_cur++].uintptr = 0; + profile_bt_data_prof[profile_bt_size_cur++].uintptr = 0; + } + // We're done! Resume the thread. + jl_thread_resume(tid); +} + void *mach_profile_listener(void *arg) { (void)arg; @@ -620,88 +698,21 @@ void *mach_profile_listener(void *arg) // sample each thread, round-robin style in reverse order // (so that thread zero gets notified last) int keymgr_locked = jl_lock_profile_mach(0); - int nthreads = jl_atomic_load_acquire(&jl_n_threads); - int *randperm = profile_get_randperm(nthreads); - for (int idx = nthreads; idx-- > 0; ) { - // Stop the threads in the random or reverse round-robin order. - int i = randperm[idx]; - // if there is no space left, break early - if (jl_profile_is_buffer_full()) { - jl_profile_stop_timer(); - break; - } - - if (_dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL) - _dyld_dlopen_atfork_prepare(); - if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) - _dyld_atfork_prepare(); // briefly acquire the dlsym lock - host_thread_state_t state; - int valid_thread = jl_thread_suspend_and_get_state2(i, &state); - unw_context_t *uc = (unw_context_t*)&state; - if (_dyld_atfork_prepare != NULL && _dyld_atfork_parent != NULL) - _dyld_atfork_parent(); // quickly release the dlsym lock - if (_dyld_dlopen_atfork_prepare != NULL && _dyld_dlopen_atfork_parent != NULL) - _dyld_dlopen_atfork_parent(); - if (!valid_thread) - continue; - if (running) { -#ifdef LLVMLIBUNWIND - /* - * Unfortunately compact unwind info is incorrectly generated for quite a number of - * libraries by quite a large number of compilers. We can fall back to DWARF unwind info - * in some cases, but in quite a number of cases (especially libraries not compiled in debug - * mode, only the compact unwind info may be available). Even more unfortunately, there is no - * way to detect such bogus compact unwind info (other than noticing the resulting segfault). - * What we do here is ugly, but necessary until the compact unwind info situation improves. - * We try to use the compact unwind info and if that results in a segfault, we retry with DWARF info. - * Note that in a small number of cases this may result in bogus stack traces, but at least the topmost - * entry will always be correct, and the number of cases in which this is an issue is rather small. - * Other than that, this implementation is not incorrect as the other thread is paused while we are profiling - * and during stack unwinding we only ever read memory, but never write it. - */ - - forceDwarf = 0; - unw_getcontext(&profiler_uc); // will resume from this point if the next lines segfault at any point - - if (forceDwarf == 0) { - // Save the backtrace - bt_size_cur += rec_backtrace_ctx((jl_bt_element_t*)bt_data_prof + bt_size_cur, bt_size_max - bt_size_cur - 1, uc, NULL); - } - else if (forceDwarf == 1) { - bt_size_cur += rec_backtrace_ctx_dwarf((jl_bt_element_t*)bt_data_prof + bt_size_cur, bt_size_max - bt_size_cur - 1, uc, NULL); - } - else if (forceDwarf == -1) { - jl_safe_printf("WARNING: profiler attempt to access an invalid memory location\n"); - } - - forceDwarf = -2; -#else - bt_size_cur += rec_backtrace_ctx((jl_bt_element_t*)bt_data_prof + bt_size_cur, bt_size_max - bt_size_cur - 1, uc, NULL); -#endif - jl_ptls_t ptls = jl_atomic_load_relaxed(&jl_all_tls_states)[i]; - - // store threadid but add 1 as 0 is preserved to indicate end of block - bt_data_prof[bt_size_cur++].uintptr = ptls->tid + 1; - - // store task id (never null) - bt_data_prof[bt_size_cur++].jlvalue = (jl_value_t*)jl_atomic_load_relaxed(&ptls->current_task); - - // store cpu cycle clock - bt_data_prof[bt_size_cur++].uintptr = cycleclock(); - - // store whether thread is sleeping but add 1 as 0 is preserved to indicate end of block - bt_data_prof[bt_size_cur++].uintptr = jl_atomic_load_relaxed(&ptls->sleep_check_state) + 1; - - // Mark the end of this block with two 0's - bt_data_prof[bt_size_cur++].uintptr = 0; - bt_data_prof[bt_size_cur++].uintptr = 0; + if (profile_all_tasks) { + // Don't take the stackwalk lock here since it's already taken in `jl_record_backtrace` + jl_profile_task(); + } + else { + int *randperm = profile_get_randperm(nthreads); + for (int idx = nthreads; idx-- > 0; ) { + // Stop the threads in random order. + int i = randperm[idx]; + jl_profile_thread_mach(i); } - // We're done! Resume the thread. - jl_thread_resume(i); } jl_unlock_profile_mach(0, keymgr_locked); - if (running) { + if (profile_running) { jl_check_profile_autostop(); // Reset the alarm kern_return_t ret = clock_alarm(clk, TIME_RELATIVE, timerprof, profile_port); @@ -710,7 +721,8 @@ void *mach_profile_listener(void *arg) } } -JL_DLLEXPORT int jl_profile_start_timer(void) + +JL_DLLEXPORT int jl_profile_start_timer(uint8_t all_tasks) { kern_return_t ret; if (!profile_started) { @@ -739,7 +751,8 @@ JL_DLLEXPORT int jl_profile_start_timer(void) timerprof.tv_sec = nsecprof/GIGA; timerprof.tv_nsec = nsecprof%GIGA; - running = 1; + profile_running = 1; + profile_all_tasks = all_tasks; // ensure the alarm is running ret = clock_alarm(clk, TIME_RELATIVE, timerprof, profile_port); HANDLE_MACH_ERROR("clock_alarm", ret); @@ -749,5 +762,8 @@ JL_DLLEXPORT int jl_profile_start_timer(void) JL_DLLEXPORT void jl_profile_stop_timer(void) { - running = 0; + uv_mutex_lock(&bt_data_prof_lock); + profile_running = 0; + profile_all_tasks = 0; + uv_mutex_unlock(&bt_data_prof_lock); } diff --git a/src/signals-unix.c b/src/signals-unix.c index 3ebf7954dccfc..1a4071a1e79be 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -9,6 +9,10 @@ #include #include #include + +#include "julia.h" +#include "julia_internal.h" + #if defined(_OS_DARWIN_) && !defined(MAP_ANONYMOUS) #define MAP_ANONYMOUS MAP_ANON #endif @@ -562,7 +566,7 @@ int timer_graceperiod_elapsed(void) static timer_t timerprof; static struct itimerspec itsprof; -JL_DLLEXPORT int jl_profile_start_timer(void) +JL_DLLEXPORT int jl_profile_start_timer(uint8_t all_tasks) { struct sigevent sigprof; @@ -571,10 +575,12 @@ JL_DLLEXPORT int jl_profile_start_timer(void) sigprof.sigev_notify = SIGEV_SIGNAL; sigprof.sigev_signo = SIGUSR1; sigprof.sigev_value.sival_ptr = &timerprof; - // Because SIGUSR1 is multipurpose, set `running` before so that we know that the first SIGUSR1 came from the timer - running = 1; + // Because SIGUSR1 is multipurpose, set `profile_running` before so that we know that the first SIGUSR1 came from the timer + profile_running = 1; + profile_all_tasks = all_tasks; if (timer_create(CLOCK_REALTIME, &sigprof, &timerprof) == -1) { - running = 0; + profile_running = 0; + profile_all_tasks = 0; return -2; } @@ -584,7 +590,8 @@ JL_DLLEXPORT int jl_profile_start_timer(void) itsprof.it_value.tv_sec = nsecprof / GIGA; itsprof.it_value.tv_nsec = nsecprof % GIGA; if (timer_settime(timerprof, 0, &itsprof, NULL) == -1) { - running = 0; + profile_running = 0; + profile_all_tasks = 0; return -3; } return 0; @@ -592,11 +599,13 @@ JL_DLLEXPORT int jl_profile_start_timer(void) JL_DLLEXPORT void jl_profile_stop_timer(void) { - if (running) { + uv_mutex_lock(&bt_data_prof_lock); + if (profile_running) { timer_delete(timerprof); last_timer_delete_time = jl_hrtime(); - running = 0; + profile_running = 0; } + uv_mutex_unlock(&bt_data_prof_lock); } #else @@ -691,7 +700,7 @@ void trigger_profile_peek(void) jl_safe_printf("\n======================================================================================\n"); jl_safe_printf("Information request received. A stacktrace will print followed by a %.1f second profile\n", profile_peek_duration); jl_safe_printf("======================================================================================\n"); - if (bt_size_max == 0){ + if (profile_bt_size_max == 0){ // If the buffer hasn't been initialized, initialize with default size // Keep these values synchronized with Profile.default_init() if (jl_profile_init(10000000, 1000000) == -1) { @@ -699,13 +708,62 @@ void trigger_profile_peek(void) return; } } - bt_size_cur = 0; // clear profile buffer - if (jl_profile_start_timer() < 0) + profile_bt_size_cur = 0; // clear profile buffer + if (jl_profile_start_timer(0) < 0) jl_safe_printf("ERROR: Could not start profile timer\n"); else profile_autostop_time = jl_hrtime() + (profile_peek_duration * 1e9); } +// assumes holding `jl_lock_stackwalk` +void jl_profile_thread_unix(int tid, bt_context_t *signal_context) +{ + if (jl_profile_is_buffer_full()) { + // Buffer full: Delete the timer + jl_profile_stop_timer(); + return; + } + // notify thread to stop + if (!jl_thread_suspend_and_get_state(tid, 1, signal_context)) + return; + // unwinding can fail, so keep track of the current state + // and restore from the SEGV handler if anything happens. + jl_jmp_buf *old_buf = jl_get_safe_restore(); + jl_jmp_buf buf; + + jl_set_safe_restore(&buf); + if (jl_setjmp(buf, 0)) { + jl_safe_printf("WARNING: profiler attempt to access an invalid memory location\n"); + } else { + // Get backtrace data + profile_bt_size_cur += rec_backtrace_ctx((jl_bt_element_t*)profile_bt_data_prof + profile_bt_size_cur, + profile_bt_size_max - profile_bt_size_cur - 1, signal_context, NULL); + } + jl_set_safe_restore(old_buf); + + jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[tid]; + + // store threadid but add 1 as 0 is preserved to indicate end of block + profile_bt_data_prof[profile_bt_size_cur++].uintptr = ptls2->tid + 1; + + // store task id (never null) + profile_bt_data_prof[profile_bt_size_cur++].jlvalue = (jl_value_t*)jl_atomic_load_relaxed(&ptls2->current_task); + + // store cpu cycle clock + profile_bt_data_prof[profile_bt_size_cur++].uintptr = cycleclock(); + + // store whether thread is sleeping (don't ever encode a state as `0` since is preserved to indicate end of block) + int state = jl_atomic_load_relaxed(&ptls2->sleep_check_state) == 0 ? PROFILE_STATE_THREAD_NOT_SLEEPING : PROFILE_STATE_THREAD_SLEEPING; + profile_bt_data_prof[profile_bt_size_cur++].uintptr = state; + + // Mark the end of this block with two 0's + profile_bt_data_prof[profile_bt_size_cur++].uintptr = 0; + profile_bt_data_prof[profile_bt_size_cur++].uintptr = 0; + + // notify thread to resume + jl_thread_resume(tid); +} + static void *signal_listener(void *arg) { static jl_bt_element_t bt_data[JL_MAX_BT_SIZE + 1]; @@ -805,13 +863,13 @@ static void *signal_listener(void *arg) int doexit = critical; #ifdef SIGINFO if (sig == SIGINFO) { - if (running != 1) + if (profile_running != 1) trigger_profile_peek(); doexit = 0; } #else if (sig == SIGUSR1) { - if (running != 1 && timer_graceperiod_elapsed()) + if (profile_running != 1 && timer_graceperiod_elapsed()) trigger_profile_peek(); doexit = 0; } @@ -845,78 +903,46 @@ static void *signal_listener(void *arg) bt_size = 0; #if !defined(JL_DISABLE_LIBUNWIND) bt_context_t signal_context; - // sample each thread, round-robin style in reverse order - // (so that thread zero gets notified last) - if (critical || profile) { + if (critical) { int lockret = jl_lock_stackwalk(); - int *randperm; - if (profile) - randperm = profile_get_randperm(nthreads); - for (int idx = nthreads; idx-- > 0; ) { - // Stop the threads in the random or reverse round-robin order. - int i = profile ? randperm[idx] : idx; + // sample each thread, round-robin style in reverse order + // (so that thread zero gets notified last) + for (int i = nthreads; i-- > 0; ) { // notify thread to stop if (!jl_thread_suspend_and_get_state(i, 1, &signal_context)) continue; // do backtrace on thread contexts for critical signals // this part must be signal-handler safe - if (critical) { - bt_size += rec_backtrace_ctx(bt_data + bt_size, - JL_MAX_BT_SIZE / nthreads - 1, - &signal_context, NULL); - bt_data[bt_size++].uintptr = 0; - } - - // do backtrace for profiler - if (profile && running) { - if (jl_profile_is_buffer_full()) { - // Buffer full: Delete the timer - jl_profile_stop_timer(); - } - else { - // unwinding can fail, so keep track of the current state - // and restore from the SEGV handler if anything happens. - jl_jmp_buf *old_buf = jl_get_safe_restore(); - jl_jmp_buf buf; - - jl_set_safe_restore(&buf); - if (jl_setjmp(buf, 0)) { - jl_safe_printf("WARNING: profiler attempt to access an invalid memory location\n"); - } else { - // Get backtrace data - bt_size_cur += rec_backtrace_ctx((jl_bt_element_t*)bt_data_prof + bt_size_cur, - bt_size_max - bt_size_cur - 1, &signal_context, NULL); - } - jl_set_safe_restore(old_buf); - - jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[i]; - - // store threadid but add 1 as 0 is preserved to indicate end of block - bt_data_prof[bt_size_cur++].uintptr = ptls2->tid + 1; - - // store task id (never null) - bt_data_prof[bt_size_cur++].jlvalue = (jl_value_t*)jl_atomic_load_relaxed(&ptls2->current_task); - - // store cpu cycle clock - bt_data_prof[bt_size_cur++].uintptr = cycleclock(); - - // store whether thread is sleeping but add 1 as 0 is preserved to indicate end of block - bt_data_prof[bt_size_cur++].uintptr = jl_atomic_load_relaxed(&ptls2->sleep_check_state) + 1; - - // Mark the end of this block with two 0's - bt_data_prof[bt_size_cur++].uintptr = 0; - bt_data_prof[bt_size_cur++].uintptr = 0; - } - } - - // notify thread to resume + bt_size += rec_backtrace_ctx(bt_data + bt_size, + JL_MAX_BT_SIZE / nthreads - 1, + &signal_context, NULL); + bt_data[bt_size++].uintptr = 0; jl_thread_resume(i); } jl_unlock_stackwalk(lockret); } + else if (profile) { + if (profile_all_tasks) { + // Don't take the stackwalk lock here since it's already taken in `jl_record_backtrace` + jl_profile_task(); + } + else { + int lockret = jl_lock_stackwalk(); + int *randperm = profile_get_randperm(nthreads); + for (int idx = nthreads; idx-- > 0; ) { + // Stop the threads in the random order. + int i = randperm[idx]; + // do backtrace for profiler + if (profile_running) { + jl_profile_thread_unix(i, &signal_context); + } + } + jl_unlock_stackwalk(lockret); + } + } #ifndef HAVE_MACH - if (profile && running) { + if (profile_running) { jl_check_profile_autostop(); #if defined(HAVE_TIMER) timer_settime(timerprof, 0, &itsprof, NULL); diff --git a/src/signals-win.c b/src/signals-win.c index bcb3a1fd246f0..a2293d2d7a2f8 100644 --- a/src/signals-win.c +++ b/src/signals-win.c @@ -398,12 +398,16 @@ static DWORD WINAPI profile_bt( LPVOID lparam ) while (1) { DWORD timeout_ms = nsecprof / (GIGA / 1000); Sleep(timeout_ms > 0 ? timeout_ms : 1); - if (running) { + if (profile_running) { if (jl_profile_is_buffer_full()) { jl_profile_stop_timer(); // does not change the thread state SuspendThread(GetCurrentThread()); continue; } + else if (profile_all_tasks) { + // Don't take the stackwalk lock here since it's already taken in `jl_record_backtrace` + jl_profile_task(); + } else { // TODO: bring this up to parity with other OS by adding loop over tid here int lockret = jl_lock_stackwalk(); @@ -415,26 +419,27 @@ static DWORD WINAPI profile_bt( LPVOID lparam ) break; } // Get backtrace data - bt_size_cur += rec_backtrace_ctx((jl_bt_element_t*)bt_data_prof + bt_size_cur, - bt_size_max - bt_size_cur - 1, &ctxThread, NULL); + profile_bt_size_cur += rec_backtrace_ctx((jl_bt_element_t*)profile_bt_data_prof + profile_bt_size_cur, + profile_bt_size_max - profile_bt_size_cur - 1, &ctxThread, NULL); jl_ptls_t ptls = jl_atomic_load_relaxed(&jl_all_tls_states)[0]; // given only profiling hMainThread - // store threadid but add 1 as 0 is preserved to indicate end of block - bt_data_prof[bt_size_cur++].uintptr = ptls->tid + 1; + // META_OFFSET_THREADID store threadid but add 1 as 0 is preserved to indicate end of block + profile_bt_data_prof[profile_bt_size_cur++].uintptr = ptls->tid + 1; - // store task id (never null) - bt_data_prof[bt_size_cur++].jlvalue = (jl_value_t*)jl_atomic_load_relaxed(&ptls->current_task); + // META_OFFSET_TASKID store task id (never null) + profile_bt_data_prof[profile_bt_size_cur++].jlvalue = (jl_value_t*)jl_atomic_load_relaxed(&ptls->current_task); - // store cpu cycle clock - bt_data_prof[bt_size_cur++].uintptr = cycleclock(); + // META_OFFSET_CPUCYCLECLOCK store cpu cycle clock + profile_bt_data_prof[profile_bt_size_cur++].uintptr = cycleclock(); - // store whether thread is sleeping but add 1 as 0 is preserved to indicate end of block - bt_data_prof[bt_size_cur++].uintptr = jl_atomic_load_relaxed(&ptls->sleep_check_state) + 1; + // store whether thread is sleeping (don't ever encode a state as `0` since is preserved to indicate end of block) + int state = jl_atomic_load_relaxed(&ptls->sleep_check_state) == 0 ? PROFILE_STATE_THREAD_NOT_SLEEPING : PROFILE_STATE_THREAD_SLEEPING; + profile_bt_data_prof[profile_bt_size_cur++].uintptr = state; // Mark the end of this block with two 0's - bt_data_prof[bt_size_cur++].uintptr = 0; - bt_data_prof[bt_size_cur++].uintptr = 0; + profile_bt_data_prof[profile_bt_size_cur++].uintptr = 0; + profile_bt_data_prof[profile_bt_size_cur++].uintptr = 0; jl_unlock_stackwalk(lockret); jl_thread_resume(0); jl_check_profile_autostop(); @@ -449,7 +454,7 @@ static DWORD WINAPI profile_bt( LPVOID lparam ) static volatile TIMECAPS timecaps; -JL_DLLEXPORT int jl_profile_start_timer(void) +JL_DLLEXPORT int jl_profile_start_timer(uint8_t all_tasks) { if (hBtThread == NULL) { @@ -477,20 +482,24 @@ JL_DLLEXPORT int jl_profile_start_timer(void) return -2; } } - if (running == 0) { + if (profile_running == 0) { // Failure to change the timer resolution is not fatal. However, it is important to // ensure that the timeBeginPeriod/timeEndPeriod is paired. if (TIMERR_NOERROR != timeBeginPeriod(timecaps.wPeriodMin)) timecaps.wPeriodMin = 0; } - running = 1; // set `running` finally + profile_all_tasks = all_tasks; + profile_running = 1; // set `profile_running` finally return 0; } JL_DLLEXPORT void jl_profile_stop_timer(void) { - if (running && timecaps.wPeriodMin) + uv_mutex_lock(&bt_data_prof_lock); + if (profile_running && timecaps.wPeriodMin) timeEndPeriod(timecaps.wPeriodMin); - running = 0; + profile_running = 0; + profile_all_tasks = 0; + uv_mutex_unlock(&bt_data_prof_lock); } void jl_install_default_signal_handlers(void) diff --git a/src/stackwalk.c b/src/stackwalk.c index def7dd9fd6b9f..ccf73d5b5cdd7 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -7,6 +7,7 @@ #include #include "julia.h" #include "julia_internal.h" +#include "gc.h" #include "threading.h" #include "julia_assert.h" @@ -207,7 +208,7 @@ NOINLINE size_t rec_backtrace_ctx(jl_bt_element_t *bt_data, size_t maxsize, // // The first `skip` frames are omitted, in addition to omitting the frame from // `rec_backtrace` itself. -NOINLINE size_t rec_backtrace(jl_bt_element_t *bt_data, size_t maxsize, int skip) +NOINLINE size_t rec_backtrace(jl_bt_element_t *bt_data, size_t maxsize, int skip) JL_NOTSAFEPOINT { bt_context_t context; memset(&context, 0, sizeof(context)); @@ -223,6 +224,24 @@ NOINLINE size_t rec_backtrace(jl_bt_element_t *bt_data, size_t maxsize, int skip return bt_size; } +NOINLINE int failed_to_sample_task_fun(jl_bt_element_t *bt_data, size_t maxsize, int skip) JL_NOTSAFEPOINT +{ + if (maxsize < 1) { + return 0; + } + bt_data[0].uintptr = (uintptr_t) &failed_to_sample_task_fun; + return 1; +} + +NOINLINE int failed_to_stop_thread_fun(jl_bt_element_t *bt_data, size_t maxsize, int skip) JL_NOTSAFEPOINT +{ + if (maxsize < 1) { + return 0; + } + bt_data[0].uintptr = (uintptr_t) &failed_to_stop_thread_fun; + return 1; +} + static jl_value_t *array_ptr_void_type JL_ALWAYS_LEAFTYPE = NULL; // Return backtrace information as an svec of (bt1, bt2, [sp]) // @@ -870,24 +889,32 @@ _os_ptr_munge(uintptr_t ptr) extern bt_context_t *jl_to_bt_context(void *sigctx); -static void jl_rec_backtrace(jl_task_t *t) JL_NOTSAFEPOINT +JL_DLLEXPORT jl_record_backtrace_result_t jl_record_backtrace(jl_task_t *t, jl_bt_element_t *bt_data, size_t max_bt_size, int all_tasks_profiler) JL_NOTSAFEPOINT { - jl_task_t *ct = jl_current_task; - jl_ptls_t ptls = ct->ptls; - ptls->bt_size = 0; + int16_t tid = INT16_MAX; + jl_record_backtrace_result_t result = {0, tid}; + jl_task_t *ct = NULL; + jl_ptls_t ptls = NULL; + if (!all_tasks_profiler) { + ct = jl_current_task; + ptls = ct->ptls; + ptls->bt_size = 0; + tid = ptls->tid; + } if (t == ct) { - ptls->bt_size = rec_backtrace(ptls->bt_data, JL_MAX_BT_SIZE, 0); - return; + result.bt_size = rec_backtrace(bt_data, max_bt_size, 0); + result.tid = tid; + return result; } bt_context_t *context = NULL; bt_context_t c; int16_t old; - for (old = -1; !jl_atomic_cmpswap(&t->tid, &old, ptls->tid) && old != ptls->tid; old = -1) { + for (old = -1; !jl_atomic_cmpswap(&t->tid, &old, tid) && old != tid; old = -1) { int lockret = jl_lock_stackwalk(); // if this task is already running somewhere, we need to stop the thread it is running on and query its state if (!jl_thread_suspend_and_get_state(old, 0, &c)) { jl_unlock_stackwalk(lockret); - return; + return result; } jl_unlock_stackwalk(lockret); if (jl_atomic_load_relaxed(&t->tid) == old) { @@ -1018,7 +1045,7 @@ static void jl_rec_backtrace(jl_task_t *t) JL_NOTSAFEPOINT mc->pc = mc->regs[30]; context = &c; #else - #pragma message("jl_rec_backtrace not defined for ASM/SETJMP on unknown linux") + #pragma message("jl_record_backtrace not defined for ASM/SETJMP on unknown linux") (void)mc; (void)c; (void)mctx; @@ -1080,7 +1107,7 @@ static void jl_rec_backtrace(jl_task_t *t) JL_NOTSAFEPOINT mc->__pad = 0; // aka __ra_sign_state = not signed context = &c; #else - #pragma message("jl_rec_backtrace not defined for ASM/SETJMP on unknown darwin") + #pragma message("jl_record_backtrace not defined for ASM/SETJMP on unknown darwin") (void)mctx; (void)c; #endif @@ -1098,23 +1125,28 @@ static void jl_rec_backtrace(jl_task_t *t) JL_NOTSAFEPOINT mc->mc_r15 = ((long*)mctx)[7]; context = &c; #else - #pragma message("jl_rec_backtrace not defined for ASM/SETJMP on unknown system") + #pragma message("jl_record_backtrace not defined for ASM/SETJMP on unknown system") (void)c; #endif #elif defined(JL_HAVE_ASYNCIFY) - #pragma message("jl_rec_backtrace not defined for ASYNCIFY") + #pragma message("jl_record_backtrace not defined for ASYNCIFY") #elif defined(JL_HAVE_SIGALTSTACK) - #pragma message("jl_rec_backtrace not defined for SIGALTSTACK") + #pragma message("jl_record_backtrace not defined for SIGALTSTACK") #else - #pragma message("jl_rec_backtrace not defined for unknown task system") + #pragma message("jl_record_backtrace not defined for unknown task system") #endif } - if (context) - ptls->bt_size = rec_backtrace_ctx(ptls->bt_data, JL_MAX_BT_SIZE, context, t->gcstack); + size_t bt_size = 0; + if (context) { + bt_size = rec_backtrace_ctx(bt_data, max_bt_size, context, all_tasks_profiler ? NULL : t->gcstack); + } if (old == -1) jl_atomic_store_relaxed(&t->tid, old); - else if (old != ptls->tid) + else if (old != tid) jl_thread_resume(old); + result.bt_size = bt_size; + result.tid = old; + return result; } //-------------------------------------------------- @@ -1152,9 +1184,11 @@ JL_DLLEXPORT void jlbacktracet(jl_task_t *t) JL_NOTSAFEPOINT { jl_task_t *ct = jl_current_task; jl_ptls_t ptls = ct->ptls; - jl_rec_backtrace(t); - size_t i, bt_size = ptls->bt_size; + ptls->bt_size = 0; jl_bt_element_t *bt_data = ptls->bt_data; + jl_record_backtrace_result_t r = jl_record_backtrace(t, bt_data, JL_MAX_BT_SIZE, 0); + size_t bt_size = r.bt_size; + size_t i; for (i = 0; i < bt_size; i += jl_bt_entry_size(bt_data + i)) { jl_print_bt_entry_codeloc(-1, bt_data + i); } @@ -1165,7 +1199,6 @@ JL_DLLEXPORT void jl_print_backtrace(void) JL_NOTSAFEPOINT jlbacktrace(); } -extern int gc_first_tid; extern int jl_inside_heartbeat_thread(void); extern int jl_heartbeat_pause(void); extern int jl_heartbeat_resume(void); @@ -1192,7 +1225,7 @@ JL_DLLEXPORT void jl_print_task_backtraces(int show_done) JL_NOTSAFEPOINT jl_safe_printf("thread (%d) ++++ Task backtraces\n", ctid); for (size_t i = 0; i < nthreads; i++) { // skip GC threads since they don't have tasks - if (gc_first_tid <= i && i < gc_first_tid + jl_n_gcthreads) { + if (gc_is_parallel_collector_thread(i) || gc_is_concurrent_collector_thread(i)) { continue; } jl_ptls_t ptls2 = allstates[i]; diff --git a/stdlib/Profile/src/Profile.jl b/stdlib/Profile/src/Profile.jl index a0a1ecd1964ed..b8fa3682acc66 100644 --- a/stdlib/Profile/src/Profile.jl +++ b/stdlib/Profile/src/Profile.jl @@ -12,7 +12,7 @@ const nmeta = 4 # number of metadata fields per block (threadid, taskid, cpu_cyc # deprecated functions: use `getdict` instead lookup(ip::UInt) = lookup(convert(Ptr{Cvoid}, ip)) -export @profile +export @profile, @profile_walltime """ @profile @@ -31,6 +31,28 @@ macro profile(ex) end end +""" + @profile_walltime + +`@profile_walltime ` runs your expression while taking periodic backtraces of a sample of all live tasks (both running and not running). +These are appended to an internal buffer of backtraces. + +It can be configured via `Profile.init`, same as the `Profile.@profile`, and that you can't use `@profile` simultaneously with `@profile_walltime`. + +As mentioned above, since this tool sample not only running tasks, but also sleeping tasks and tasks performing IO, +it can be used to diagnose performance issues such as lock contention, IO bottlenecks, and other issues that are not visible in the CPU profile. +""" +macro profile_walltime(ex) + return quote + try + start_timer(true) + $(esc(ex)) + finally + stop_timer() + end + end +end + # An internal function called to show the report after an information request (SIGINFO or SIGUSR1). function _peek_report() iob = IOBuffer() @@ -369,9 +391,10 @@ end function has_meta(data) for i in 6:length(data) - data[i] == 0 || continue # first block end null - data[i - 1] == 0 || continue # second block end null - data[i - META_OFFSET_SLEEPSTATE] in 1:2 || continue + data[i] == 0 || continue # first block end null + data[i - 1] == 0 || continue # second block end null + data[i - META_OFFSET_SLEEPSTATE] in 1:3 || continue # 1 for not sleeping, 2 for sleeping, 3 for task profiler fake state + # See definition in `src/julia_internal.h` data[i - META_OFFSET_CPUCYCLECLOCK] != 0 || continue data[i - META_OFFSET_TASKID] != 0 || continue data[i - META_OFFSET_THREADID] != 0 || continue @@ -562,9 +585,9 @@ Julia, and examine the resulting `*.mem` files. clear_malloc_data() = ccall(:jl_clear_malloc_data, Cvoid, ()) # C wrappers -function start_timer() +function start_timer(all_tasks::Bool=false) check_init() # if the profile buffer hasn't been initialized, initialize with default size - status = ccall(:jl_profile_start_timer, Cint, ()) + status = ccall(:jl_profile_start_timer, Cint, (Bool,), all_tasks) if status < 0 error(error_codes[status]) end @@ -676,12 +699,16 @@ function parse_flat(::Type{T}, data::Vector{UInt64}, lidict::Union{LineInfoDict, startframe = length(data) skip = false nsleeping = 0 + is_task_profile = false for i in startframe:-1:1 (startframe - 1) >= i >= (startframe - (nmeta + 1)) && continue # skip metadata (its read ahead below) and extra block end NULL IP ip = data[i] if is_block_end(data, i) # read metadata - thread_sleeping = data[i - META_OFFSET_SLEEPSTATE] - 1 # subtract 1 as state is incremented to avoid being equal to 0 + thread_sleeping_state = data[i - META_OFFSET_SLEEPSTATE] - 1 # subtract 1 as state is incremented to avoid being equal to 0 + if thread_sleeping_state == 2 + is_task_profile = true + end # cpu_cycle_clock = data[i - META_OFFSET_CPUCYCLECLOCK] taskid = data[i - META_OFFSET_TASKID] threadid = data[i - META_OFFSET_THREADID] @@ -689,7 +716,7 @@ function parse_flat(::Type{T}, data::Vector{UInt64}, lidict::Union{LineInfoDict, skip = true continue end - if thread_sleeping == 1 + if thread_sleeping_state == 1 nsleeping += 1 end skip = false @@ -723,12 +750,12 @@ function parse_flat(::Type{T}, data::Vector{UInt64}, lidict::Union{LineInfoDict, end end @assert length(lilist) == length(n) == length(m) == length(lilist_idx) - return (lilist, n, m, totalshots, nsleeping) + return (lilist, n, m, totalshots, nsleeping, is_task_profile) end function flat(io::IO, data::Vector{UInt64}, lidict::Union{LineInfoDict, LineInfoFlatDict}, cols::Int, fmt::ProfileFormat, threads::Union{Int,AbstractVector{Int}}, tasks::Union{UInt,AbstractVector{UInt}}, is_subsection::Bool) - lilist, n, m, totalshots, nsleeping = parse_flat(fmt.combine ? StackFrame : UInt64, data, lidict, fmt.C, threads, tasks) + lilist, n, m, totalshots, nsleeping, is_task_profile = parse_flat(fmt.combine ? StackFrame : UInt64, data, lidict, fmt.C, threads, tasks) if false # optional: drop the "non-interpretable" ones keep = map(frame -> frame != UNKNOWN && frame.line != 0, lilist) lilist = lilist[keep] @@ -748,11 +775,15 @@ function flat(io::IO, data::Vector{UInt64}, lidict::Union{LineInfoDict, LineInfo return true end is_subsection || print_flat(io, lilist, n, m, cols, filenamemap, fmt) - Base.print(io, "Total snapshots: ", totalshots, ". Utilization: ", round(Int, util_perc), "%") + if is_task_profile + Base.print(io, "Total snapshots: ", totalshots, "\n") + else + Base.print(io, "Total snapshots: ", totalshots, ". Utilization: ", round(Int, util_perc), "%") + end if is_subsection println(io) print_flat(io, lilist, n, m, cols, filenamemap, fmt) - else + elseif !is_task_profile Base.print(io, " across all threads and tasks. Use the `groupby` kwarg to break down by thread and/or task.\n") end return false @@ -927,12 +958,16 @@ function tree!(root::StackFrameTree{T}, all::Vector{UInt64}, lidict::Union{LineI startframe = length(all) skip = false nsleeping = 0 + is_task_profile = false for i in startframe:-1:1 (startframe - 1) >= i >= (startframe - (nmeta + 1)) && continue # skip metadata (it's read ahead below) and extra block end NULL IP ip = all[i] if is_block_end(all, i) # read metadata - thread_sleeping = all[i - META_OFFSET_SLEEPSTATE] - 1 # subtract 1 as state is incremented to avoid being equal to 0 + thread_sleeping_state = all[i - META_OFFSET_SLEEPSTATE] - 1 # subtract 1 as state is incremented to avoid being equal to 0 + if thread_sleeping_state == 2 + is_task_profile = true + end # cpu_cycle_clock = all[i - META_OFFSET_CPUCYCLECLOCK] taskid = all[i - META_OFFSET_TASKID] threadid = all[i - META_OFFSET_THREADID] @@ -941,7 +976,7 @@ function tree!(root::StackFrameTree{T}, all::Vector{UInt64}, lidict::Union{LineI skip = true continue end - if thread_sleeping == 1 + if thread_sleeping_state == 1 nsleeping += 1 end skip = false @@ -1047,7 +1082,7 @@ function tree!(root::StackFrameTree{T}, all::Vector{UInt64}, lidict::Union{LineI nothing end cleanup!(root) - return root, nsleeping + return root, nsleeping, is_task_profile end function maxstats(root::StackFrameTree) @@ -1116,9 +1151,9 @@ end function tree(io::IO, data::Vector{UInt64}, lidict::Union{LineInfoFlatDict, LineInfoDict}, cols::Int, fmt::ProfileFormat, threads::Union{Int,AbstractVector{Int}}, tasks::Union{UInt,AbstractVector{UInt}}, is_subsection::Bool) if fmt.combine - root, nsleeping = tree!(StackFrameTree{StackFrame}(), data, lidict, fmt.C, fmt.recur, threads, tasks) + root, nsleeping, is_task_profile = tree!(StackFrameTree{StackFrame}(), data, lidict, fmt.C, fmt.recur, threads, tasks) else - root, nsleeping = tree!(StackFrameTree{UInt64}(), data, lidict, fmt.C, fmt.recur, threads, tasks) + root, nsleeping, is_task_profile = tree!(StackFrameTree{UInt64}(), data, lidict, fmt.C, fmt.recur, threads, tasks) end util_perc = (1 - (nsleeping / root.count)) * 100 is_subsection || print_tree(io, root, cols, fmt, is_subsection) @@ -1132,11 +1167,15 @@ function tree(io::IO, data::Vector{UInt64}, lidict::Union{LineInfoFlatDict, Line end return true end - Base.print(io, "Total snapshots: ", root.count, ". Utilization: ", round(Int, util_perc), "%") + if is_task_profile + Base.print(io, "Total snapshots: ", root.count, "\n") + else + Base.print(io, "Total snapshots: ", root.count, ". Utilization: ", round(Int, util_perc), "%") + end if is_subsection Base.println(io) print_tree(io, root, cols, fmt, is_subsection) - else + elseif !is_task_profile Base.print(io, " across all threads and tasks. Use the `groupby` kwarg to break down by thread and/or task.\n") end return false diff --git a/stdlib/Profile/test/runtests.jl b/stdlib/Profile/test/runtests.jl index cb40d80d9b756..9537791118e11 100644 --- a/stdlib/Profile/test/runtests.jl +++ b/stdlib/Profile/test/runtests.jl @@ -25,19 +25,64 @@ end end end -busywait(0, 0) # compile -@profile busywait(1, 20) +@noinline function sleeping_tasks(ch::Channel) + for _ in 1:100 + Threads.@spawn take!(ch) + end + sleep(10) +end -let r = Profile.retrieve() - mktemp() do path, io - serialize(io, r) - close(io) - open(path) do io - @test isa(deserialize(io), Tuple{Vector{UInt},Dict{UInt64,Vector{Base.StackTraces.StackFrame}}}) +function test_profile() + let r = Profile.retrieve() + mktemp() do path, io + serialize(io, r) + close(io) + open(path) do io + @test isa(deserialize(io), Tuple{Vector{UInt},Dict{UInt64,Vector{Base.StackTraces.StackFrame}}}) + end + end + end +end + +function test_has_task_profiler_sample_in_buffer() + let r = Profile.retrieve() + mktemp() do path, io + serialize(io, r) + close(io) + open(path) do io + all = deserialize(io) + data = all[1] + startframe = length(data) + for i in startframe:-1:1 + (startframe - 1) >= i >= (startframe - (Profile.nmeta + 1)) && continue # skip metadata (its read ahead below) and extra block end NULL IP + if Profile.is_block_end(data, i) + thread_sleeping_state = data[i - Profile.META_OFFSET_SLEEPSTATE] + @test thread_sleeping_state == 0x3 + end + end + end end end end +busywait(0, 0) # compile + +@profile_walltime busywait(1, 20) +test_profile() + +Profile.clear() + +ch = Channel(1) +@profile_walltime sleeping_tasks(ch) +test_profile() +close(ch) +test_has_task_profiler_sample_in_buffer() + +Profile.clear() + +@profile busywait(1, 20) +test_profile() + let iobuf = IOBuffer() Profile.print(iobuf, format=:tree, C=true) str = String(take!(iobuf)) From 8fe069c49bc13b3456726a61be835da531583f18 Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Tue, 5 Nov 2024 16:18:18 -0500 Subject: [PATCH 090/109] Fix a backport error in PR 187 (#197) --- src/jloptions.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/jloptions.c b/src/jloptions.c index 40fc3fe7f4ab5..29fd171db1437 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -315,6 +315,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) { "inline", required_argument, 0, opt_inline }, { "polly", required_argument, 0, opt_polly }, { "trace-compile", required_argument, 0, opt_trace_compile }, + { "trace-compile-timing", no_argument, 0, opt_trace_compile_timing }, { "trace-dispatch", required_argument, 0, opt_trace_dispatch }, { "math-mode", required_argument, 0, opt_math_mode }, { "handle-signals", required_argument, 0, opt_handle_signals }, From 9162ec83a83cc42c9c2ba4a6528d6d56c8feb4da Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Fri, 8 Nov 2024 14:06:58 -0500 Subject: [PATCH 091/109] Only update the world age when a new method is loaded (#196) Instead of always updating it. This should speed up loading only method specializations. --- src/staticdata.c | 12 ++++++++++-- src/staticdata_utils.c | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/staticdata.c b/src/staticdata.c index 945593034a890..fba0eb95c9ae1 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -2952,7 +2952,6 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl jl_set_gs_ctr(gs_ctr); } else { - jl_atomic_fetch_add(&jl_world_counter, 1); offset_restored = jl_read_offset(&s); offset_init_order = jl_read_offset(&s); offset_extext_methods = jl_read_offset(&s); @@ -3182,7 +3181,6 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl jl_cache_type_((jl_datatype_t*)obj); } // Perform fixups: things like updating world ages, inserting methods & specializations, etc. - size_t world = jl_atomic_load_acquire(&jl_world_counter); for (size_t i = 0; i < s.uniquing_objs.len; i++) { uintptr_t item = (uintptr_t)s.uniquing_objs.items[i]; // check whether this is a gvar index @@ -3236,6 +3234,16 @@ static void jl_restore_system_image_from_stream_(ios_t *f, jl_image_t *image, jl o->bits.in_image = 1; } arraylist_free(&cleanup_list); + size_t world = jl_atomic_load_relaxed(&jl_world_counter); + for (size_t i = 0; i < s.fixup_objs.len; i++) { + // decide if we need to allocate a world + uintptr_t item = (uintptr_t)s.fixup_objs.items[i]; + jl_value_t *obj = (jl_value_t*)(image_base + item); + if (jl_is_method(obj)) { + world = jl_atomic_fetch_add(&jl_world_counter, 1) + 1; + break; + } + } for (size_t i = 0; i < s.fixup_objs.len; i++) { uintptr_t item = (uintptr_t)s.fixup_objs.items[i]; jl_value_t *obj = (jl_value_t*)(image_base + item); diff --git a/src/staticdata_utils.c b/src/staticdata_utils.c index 2fe01d919e885..807fa2196ddf7 100644 --- a/src/staticdata_utils.c +++ b/src/staticdata_utils.c @@ -840,6 +840,10 @@ static jl_array_t *jl_verify_edges(jl_array_t *targets, size_t minworld) if (ulong_array == NULL) ulong_array = jl_apply_array_type((jl_value_t*)jl_ulong_type, 1); jl_array_t *maxvalids = jl_alloc_array_1d(ulong_array, l); + if (minworld == jl_base_module->primary_world) { + memset(jl_array_data(maxvalids), -1, l * sizeof(size_t)); + return maxvalids; + } memset(jl_array_data(maxvalids), 0, l * sizeof(size_t)); jl_value_t *loctag = NULL; jl_value_t *matches = NULL; From 5610223ddb2a6e389c7b68ad65f0737a012ecafd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Drvo=C5=A1t=C4=9Bp?= Date: Tue, 19 Nov 2024 18:13:18 +0100 Subject: [PATCH 092/109] Fix trampoline assembly for build on clang 18 on apple silicon (#54634) (#199) This avoids a: `error: non-private labels cannot appear between .cfi_startproc / .cfi_endproc pairs` error. That error was introduced in https://reviews.llvm.org/D155245#4657075 see also https://github.com/llvm/llvm-project/issues/72802 (cherry picked from commit a4e793ee31612625d9c48ebd89a53c3a5c0f6eb6) (cherry picked from commit 3f35094d298b41d57f3f3a8c5a9abd52bcf47b30) Co-authored-by: Gabriel Baraldi --- cli/trampolines/trampolines_aarch64.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/trampolines/trampolines_aarch64.S b/cli/trampolines/trampolines_aarch64.S index 2d87ae6dcdb1c..ccb9a647ac6c3 100644 --- a/cli/trampolines/trampolines_aarch64.S +++ b/cli/trampolines/trampolines_aarch64.S @@ -5,9 +5,9 @@ #define XX(name) \ .global CNAME(name) SEP \ +CNAME(name)##: SEP \ .cfi_startproc SEP \ .p2align 2 SEP \ -CNAME(name)##: SEP \ adrp x16, PAGE(CNAME(name##_addr)) SEP \ ldr x16, [x16, PAGEOFF(CNAME(name##_addr))] SEP \ br x16 SEP \ From 918a99d0c53c7444993e988ed91328d650b3620c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Drvo=C5=A1t=C4=9Bp?= Date: Thu, 21 Nov 2024 19:48:20 +0100 Subject: [PATCH 093/109] Optionally disallow defining new methods and drop backedges (#198) * Optionally disallow defining new methods and drop backedges --- src/gf.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ src/staticdata.c | 4 ++-- 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/gf.c b/src/gf.c index 559a23fdda725..58050bf95cb11 100644 --- a/src/gf.c +++ b/src/gf.c @@ -8,6 +8,7 @@ . static parameter inference . method specialization and caching, invoking type inference */ +#include #include #include #include "julia.h" @@ -24,6 +25,7 @@ extern "C" { #endif +static _Atomic(bool) allow_new_worlds = true; JL_DLLEXPORT _Atomic(size_t) jl_world_counter = 1; // uses atomic acquire/release JL_DLLEXPORT size_t jl_get_world_counter(void) JL_NOTSAFEPOINT { @@ -1718,6 +1720,8 @@ static void invalidate_backedges(void (*f)(jl_code_instance_t*), jl_method_insta // add a backedge from callee to caller JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, jl_value_t *invokesig, jl_method_instance_t *caller) { + if (!jl_atomic_load_acquire(&allow_new_worlds)) + return; JL_LOCK(&callee->def.method->writelock); if (invokesig == jl_nothing) invokesig = NULL; // julia uses `nothing` but C uses NULL (#undef) @@ -1753,6 +1757,8 @@ JL_DLLEXPORT void jl_method_instance_add_backedge(jl_method_instance_t *callee, // add a backedge from a non-existent signature to caller JL_DLLEXPORT void jl_method_table_add_backedge(jl_methtable_t *mt, jl_value_t *typ, jl_value_t *caller) { + if (!jl_atomic_load_acquire(&allow_new_worlds)) + return; JL_LOCK(&mt->writelock); if (!mt->backedges) { // lazy-init the backedges array @@ -1915,8 +1921,48 @@ static void jl_method_table_invalidate(jl_methtable_t *mt, jl_typemap_entry_t *m } } +static int erase_method_backedges(jl_typemap_entry_t *def, void *closure) +{ + jl_method_t *method = def->func.method; + jl_value_t *specializations = jl_atomic_load_relaxed(&method->specializations); + if (jl_is_svec(specializations)) { + size_t i, l = jl_svec_len(specializations); + for (i = 0; i < l; i++) { + jl_method_instance_t *mi = (jl_method_instance_t*)jl_svecref(specializations, i); + if ((jl_value_t*)mi != jl_nothing) { + mi->backedges = NULL; + } + } + } + else { + jl_method_instance_t *mi = (jl_method_instance_t*)specializations; + mi->backedges = NULL; + } + return 1; +} + +static int erase_all_backedges(jl_methtable_t *mt, void *env) +{ + // removes all method caches + // this might not be entirely safe (GC or MT), thus we only do it very early in bootstrapping + mt->backedges = NULL; + jl_typemap_visitor(jl_atomic_load_relaxed(&mt->defs), erase_method_backedges, env); + return 1; +} + +JL_DLLEXPORT void jl_disable_new_worlds(void) +{ + if (jl_generating_output()) + jl_error("Disabling Method changes is not possible when generating output."); + jl_atomic_store_release(&allow_new_worlds, false); + jl_foreach_reachable_mtable(erase_all_backedges, (void*)NULL); +} + + JL_DLLEXPORT void jl_method_table_disable(jl_methtable_t *mt, jl_method_t *method) { + if (!jl_atomic_load_acquire(&allow_new_worlds)) + jl_error("Method changes have been disabled via a call to jl_disable_new_worlds."); jl_typemap_entry_t *methodentry = do_typemap_search(mt, method); JL_LOCK(&mt->writelock); // Narrow the world age on the method to make it uncallable @@ -1986,6 +2032,8 @@ static int is_replacing(char ambig, jl_value_t *type, jl_method_t *m, jl_method_ JL_DLLEXPORT void jl_method_table_insert(jl_methtable_t *mt, jl_method_t *method, jl_tupletype_t *simpletype) { + if (!jl_atomic_load_acquire(&allow_new_worlds)) + jl_error("Method changes have been disabled via a call to jl_disable_new_worlds."); JL_TIMING(ADD_METHOD, ADD_METHOD); assert(jl_is_method(method)); assert(jl_is_mtable(mt)); diff --git a/src/staticdata.c b/src/staticdata.c index fba0eb95c9ae1..13284384e0485 100644 --- a/src/staticdata.c +++ b/src/staticdata.c @@ -3447,11 +3447,11 @@ static jl_value_t *jl_restore_package_image_from_stream(void* pkgimage_handle, i jl_restore_system_image_from_stream_(f, image, depmods, checksum, (jl_array_t**)&restored, &init_order, &extext_methods, &new_specializations, &method_roots_list, &ext_targets, &edges, &base, &ccallable_list, &cachesizes); JL_SIGATOMIC_END(); - // Insert method extensions - jl_insert_methods(extext_methods); // No special processing of `new_specializations` is required because recaching handled it // Add roots to methods jl_copy_roots(method_roots_list, jl_worklist_key((jl_array_t*)restored)); + // Insert method extensions + jl_insert_methods(extext_methods); // Handle edges size_t world = jl_atomic_load_acquire(&jl_world_counter); jl_insert_backedges((jl_array_t*)edges, (jl_array_t*)ext_targets, (jl_array_t*)new_specializations, world); // restore external backedges (needs to be last) From 9344ba8759faa604174cc7d934b54659a5cb3198 Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Thu, 5 Dec 2024 15:20:14 -0500 Subject: [PATCH 094/109] Canonicalize names of nested functions by keeping a more fine grained counter -- per (module, method name) pair (#53719) (#179) As mentioned in https://github.com/JuliaLang/julia/pull/53716, we've been noticing that `precompile` statements lists from one version of our codebase often don't apply cleanly in a slightly different version. That's because a lot of nested and anonymous function names have a global numeric suffix which is incremented every time a new name is generated, and these numeric suffixes are not very stable across codebase changes. To solve this, this PR makes the numeric suffixes a bit more fine grained: every pair of (module, top-level/outermost function name) will have its own counter, which should make nested function names a bit more stable across different versions. This PR applies @JeffBezanson's idea of making the symbol name changes directly in `current-julia-module-counter`. Here is an example: ```Julia julia> function foo(x) function bar(y) return x + y end end foo (generic function with 1 method) julia> f = foo(42) (::var"#bar#foo##0"{Int64}) (generic function with 1 method) ``` Co-authored-by: Diogo Netto <61364108+d-netto@users.noreply.github.com> --- doc/src/manual/functions.md | 4 +- src/ast.c | 44 ++++++++++++++++-- src/datatype.c | 22 +++------ src/flisp/flisp.h | 2 +- src/gf.c | 8 ---- src/julia-syntax.scm | 92 ++++++++++++++++++++++++------------- src/julia_internal.h | 29 ++++++++++++ test/show.jl | 63 +++++++++++++++++++++++++ 8 files changed, 201 insertions(+), 63 deletions(-) diff --git a/doc/src/manual/functions.md b/doc/src/manual/functions.md index 97f84f35f3eef..12534e0cc932f 100644 --- a/doc/src/manual/functions.md +++ b/doc/src/manual/functions.md @@ -292,12 +292,12 @@ syntaxes: ```jldoctest julia> x -> x^2 + 2x - 1 -#1 (generic function with 1 method) +#2 (generic function with 1 method) julia> function (x) x^2 + 2x - 1 end -#3 (generic function with 1 method) +#5 (generic function with 1 method) ``` This creates a function taking one argument `x` and returning the value of the polynomial `x^2 + diff --git a/src/ast.c b/src/ast.c index 06727b453d6a3..e291909af9a8a 100644 --- a/src/ast.c +++ b/src/ast.c @@ -7,6 +7,7 @@ #include #include #include + #ifdef _OS_WINDOWS_ #include #endif @@ -160,11 +161,46 @@ static value_t fl_defined_julia_global(fl_context_t *fl_ctx, value_t *args, uint return (b != NULL && jl_atomic_load_relaxed(&b->owner) == b) ? fl_ctx->T : fl_ctx->F; } -static value_t fl_current_module_counter(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) JL_NOTSAFEPOINT +// Used to generate a unique suffix for a given symbol (e.g. variable or type name) +// first argument contains a stack of method definitions seen so far by `closure-convert` in flisp. +// if the top of the stack is non-NIL, we use it to augment the suffix so that it becomes +// of the form $top_level_method_name##$counter, where `counter` is the smallest integer +// such that the resulting name is not already defined in the current module's bindings. +// If the top of the stack is NIL, we simply return the current module's counter. +// This ensures that precompile statements are a bit more stable across different versions +// of a codebase. see #53719 +static value_t fl_module_unique_name(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) { + argcount(fl_ctx, "julia-module-unique-name", nargs, 1); jl_ast_context_t *ctx = jl_ast_ctx(fl_ctx); - assert(ctx->module); - return fixnum(jl_module_next_counter(ctx->module)); + jl_module_t *m = ctx->module; + assert(m != NULL); + // Get the outermost function name from the `parsed_method_stack` top + char *funcname = NULL; + value_t parsed_method_stack = args[0]; + if (parsed_method_stack != fl_ctx->NIL) { + value_t bottom_stack_symbol = fl_applyn(fl_ctx, 1, symbol_value(symbol(fl_ctx, "last")), parsed_method_stack); + funcname = tosymbol(fl_ctx, bottom_stack_symbol, "julia-module-unique-name")->name; + } + size_t sz = funcname != NULL ? strlen(funcname) + 32 : 32; // 32 is enough for the suffix + char *buf = (char*)alloca(sz); + if (funcname != NULL && strchr(funcname, '#') == NULL) { + for (int i = 0; ; i++) { + snprintf(buf, sz, "%s##%d", funcname, i); + jl_sym_t *sym = jl_symbol(buf); + JL_LOCK(&m->lock); + if (jl_get_module_binding(m, sym, 0) == NULL) { // make sure this name is not already taken + jl_get_module_binding(m, sym, 1); // create the binding + JL_UNLOCK(&m->lock); + return symbol(fl_ctx, buf); + } + JL_UNLOCK(&m->lock); + } + } + else { + snprintf(buf, sz, "%d", jl_module_next_counter(m)); + } + return symbol(fl_ctx, buf); } static value_t fl_julia_current_file(fl_context_t *fl_ctx, value_t *args, uint32_t nargs) JL_NOTSAFEPOINT @@ -206,7 +242,7 @@ static jl_value_t *scm_to_julia_(fl_context_t *fl_ctx, value_t e, jl_module_t *m static const builtinspec_t julia_flisp_ast_ext[] = { { "defined-julia-global", fl_defined_julia_global }, // TODO: can we kill this safepoint - { "current-julia-module-counter", fl_current_module_counter }, + { "current-julia-module-counter", fl_module_unique_name }, { "julia-scalar?", fl_julia_scalar }, { "julia-current-file", fl_julia_current_file }, { "julia-current-line", fl_julia_current_line }, diff --git a/src/datatype.c b/src/datatype.c index 905959fb80e0a..fe8eb5642a255 100644 --- a/src/datatype.c +++ b/src/datatype.c @@ -19,23 +19,21 @@ extern "C" { // allocating TypeNames ----------------------------------------------------------- -static int is10digit(char c) JL_NOTSAFEPOINT -{ - return (c >= '0' && c <= '9'); -} - static jl_sym_t *jl_demangle_typename(jl_sym_t *s) JL_NOTSAFEPOINT { char *n = jl_symbol_name(s); if (n[0] != '#') return s; - char *end = strrchr(n, '#'); + char *end = strchr(&n[1], '#'); + // handle `#f...##...#...` + if (end != NULL && end[1] == '#') + end = strchr(&end[2], '#'); int32_t len; - if (end == n || end == n+1) + if (end == NULL || end == n+1) len = strlen(n) - 1; else len = (end-n) - 1; // extract `f` from `#f#...` - if (is10digit(n[1])) + if (isdigit(n[1]) || is_canonicalized_anonfn_typename(n)) return _jl_symbol(n, len+1); return _jl_symbol(&n[1], len); } @@ -687,14 +685,6 @@ void jl_compute_field_offsets(jl_datatype_t *st) return; } -static int is_anonfn_typename(char *name) -{ - if (name[0] != '#' || name[1] == '#') - return 0; - char *other = strrchr(name, '#'); - return other > &name[1] && is10digit(other[1]); -} - JL_DLLEXPORT jl_datatype_t *jl_new_datatype( jl_sym_t *name, jl_module_t *module, diff --git a/src/flisp/flisp.h b/src/flisp/flisp.h index b031e456cd3fe..c8412d098e4f6 100644 --- a/src/flisp/flisp.h +++ b/src/flisp/flisp.h @@ -158,7 +158,7 @@ value_t fl_cons(fl_context_t *fl_ctx, value_t a, value_t b) JL_NOTSAFEPOINT; value_t fl_list2(fl_context_t *fl_ctx, value_t a, value_t b) JL_NOTSAFEPOINT; value_t fl_listn(fl_context_t *fl_ctx, size_t n, ...) JL_NOTSAFEPOINT; value_t symbol(fl_context_t *fl_ctx, const char *str) JL_NOTSAFEPOINT; -char *symbol_name(fl_context_t *fl_ctx, value_t v); +char *symbol_name(fl_context_t *fl_ctx, value_t v) JL_NOTSAFEPOINT; int fl_is_keyword_name(const char *str, size_t len); value_t alloc_vector(fl_context_t *fl_ctx, size_t n, int init); size_t llength(value_t v); diff --git a/src/gf.c b/src/gf.c index 58050bf95cb11..c0ea4c43a58ae 100644 --- a/src/gf.c +++ b/src/gf.c @@ -1537,14 +1537,6 @@ void print_func_loc(JL_STREAM *s, jl_method_t *m) } } -static int is_anonfn_typename(char *name) -{ - if (name[0] != '#' || name[1] == '#') - return 0; - char *other = strrchr(name, '#'); - return other > &name[1] && other[1] > '0' && other[1] <= '9'; -} - static void method_overwrite(jl_typemap_entry_t *newentry, jl_method_t *oldvalue) { // method overwritten diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm index 756012b364b33..d07deacb3d6b6 100644 --- a/src/julia-syntax.scm +++ b/src/julia-syntax.scm @@ -225,6 +225,19 @@ (if lb (list lb ub) (list ub)) (if lb (list lb '(core Any)) '()))))) +(define (is-method? x) + (if (and (pair? x) (eq? (car x) 'method)) + (let ((name (cadr x))) + (if (and (pair? name) (eq? (car name) 'globalref)) + (let ((name (caddr name))) + (if (symbol? name) + #t + #f)) + (if (symbol? name) + #t + #f))) + #f)) + (define (method-expr-name m) (let ((name (cadr m))) (let ((name (if (or (length= m 2) (not (pair? name)) (not (quoted? name))) name (cadr name)))) @@ -375,7 +388,7 @@ (generator (if (expr-contains-p if-generated? body (lambda (x) (not (function-def? x)))) (let* ((gen (generated-version body)) (nongen (non-generated-version body)) - (gname (symbol (string (gensy) "#" (current-julia-module-counter)))) + (gname (symbol (string (gensy) "#" (current-julia-module-counter '())))) (gf (make-generator-function gname names anames gen))) (set! body (insert-after-meta nongen @@ -515,7 +528,7 @@ "" "#") (or und '_) "#" - (string (current-julia-module-counter))))))) + (string (current-julia-module-counter '()))))))) ;; this is a hack: nest these statements inside a call so they get closure ;; converted together, allowing all needed types to be defined before any methods. `(call (core ifelse) (false) (false) (block @@ -1249,7 +1262,7 @@ (list a))) ;; TODO: always use a specific special name like #anon# or _, then ignore ;; this as a local variable name. - (name (symbol (string "#" (current-julia-module-counter))))) + (name (symbol (string "#" (current-julia-module-counter '()))))) (expand-forms `(block (local ,name) (function @@ -3482,9 +3495,9 @@ f(x) = yt(x) (define (clear-capture-bits vinfos) (map vinfo:not-capt vinfos)) -(define (convert-lambda lam fname interp capt-sp opaq) +(define (convert-lambda lam fname interp capt-sp opaq parsed-method-stack) (let ((body (add-box-inits-to-body - lam (cl-convert (cadddr lam) fname lam (table) (table) #f interp opaq (table) (vinfo-to-table (car (lam:vinfo lam))))))) + lam (cl-convert (cadddr lam) fname lam (table) (table) #f interp opaq parsed-method-stack (table) (vinfo-to-table (car (lam:vinfo lam))))))) `(lambda ,(lam:args lam) (,(clear-capture-bits (car (lam:vinfo lam))) () @@ -3559,7 +3572,7 @@ f(x) = yt(x) ;; declared types. ;; when doing this, the original value needs to be preserved, to ;; ensure the expression `a=b` always returns exactly `b`. -(define (convert-assignment var rhs0 fname lam interp opaq globals locals) +(define (convert-assignment var rhs0 fname lam interp opaq parsed-method-stack globals locals) (cond ((symbol? var) (let* ((vi (get locals var #f)) @@ -3577,7 +3590,7 @@ f(x) = yt(x) (equal? rhs0 '(the_exception))) rhs0 (make-ssavalue))) - (rhs (convert-for-type-decl rhs1 (cl-convert vt fname lam #f #f #f interp opaq (table) locals) #t lam)) + (rhs (convert-for-type-decl rhs1 (cl-convert vt fname lam #f #f #f interp opaq parsed-method-stack (table) locals) #t lam)) (ex (cond (closed `(call (core setfield!) ,(if interp `($ ,var) @@ -3863,17 +3876,17 @@ f(x) = yt(x) (define (toplevel-preserving? e) (and (pair? e) (memq (car e) '(if elseif block trycatch tryfinally trycatchelse)))) -(define (map-cl-convert exprs fname lam namemap defined toplevel interp opaq (globals (table)) (locals (table))) +(define (map-cl-convert exprs fname lam namemap defined toplevel interp opaq parsed-method-stack (globals (table)) (locals (table))) (if toplevel (map (lambda (x) (let ((tl (lift-toplevel (cl-convert x fname lam namemap defined (and toplevel (toplevel-preserving? x)) - interp opaq globals locals)))) + interp opaq parsed-method-stack globals locals)))) (if (null? (cdr tl)) (car tl) `(block ,@(cdr tl) ,(car tl))))) exprs) - (map (lambda (x) (cl-convert x fname lam namemap defined #f interp opaq globals locals)) exprs))) + (map (lambda (x) (cl-convert x fname lam namemap defined #f interp opaq parsed-method-stack globals locals)) exprs))) (define (prepare-lambda! lam) ;; mark all non-arguments as assigned, since locals that are never assigned @@ -3882,11 +3895,17 @@ f(x) = yt(x) (list-tail (car (lam:vinfo lam)) (length (lam:args lam)))) (lambda-optimize-vars! lam)) -(define (cl-convert e fname lam namemap defined toplevel interp opaq (globals (table)) (locals (table))) +;; must start with a hash and second character must be numeric +(define (anon-function-name? str) + (and (>= (string-length str) 2) + (char=? (string.char str 0) #\#) + (char-numeric? (string.char str 1)))) + +(define (cl-convert- e fname lam namemap defined toplevel interp opaq parsed-method-stack (globals (table)) (locals (table))) (if (and (not lam) (not (and (pair? e) (memq (car e) '(lambda method macro opaque_closure))))) (if (atom? e) e - (cons (car e) (map-cl-convert (cdr e) fname lam namemap defined toplevel interp opaq globals locals))) + (cons (car e) (map-cl-convert (cdr e) fname lam namemap defined toplevel interp opaq parsed-method-stack globals locals))) (cond ((symbol? e) (define (new-undef-var name) @@ -3905,7 +3924,7 @@ f(x) = yt(x) (val (if (equal? typ '(core Any)) val `(call (core typeassert) ,val - ,(cl-convert typ fname lam namemap defined toplevel interp opaq globals locals))))) + ,(cl-convert typ fname lam namemap defined toplevel interp opaq parsed-method-stack globals locals))))) `(block ,@(if (eq? box access) '() `((= ,access ,box))) ,undefcheck @@ -3937,8 +3956,8 @@ f(x) = yt(x) e) ((=) (let ((var (cadr e)) - (rhs (cl-convert (caddr e) fname lam namemap defined toplevel interp opaq globals locals))) - (convert-assignment var rhs fname lam interp opaq globals locals))) + (rhs (cl-convert (caddr e) fname lam namemap defined toplevel interp opaq parsed-method-stack globals locals))) + (convert-assignment var rhs fname lam interp opaq parsed-method-stack globals locals))) ((local-def) ;; make new Box for local declaration of defined variable (let ((vi (get locals (cadr e) #f))) (if (and vi (vinfo:asgn vi) (vinfo:capt vi)) @@ -3993,7 +4012,7 @@ f(x) = yt(x) cvs))) `(new_opaque_closure ,(cadr e) (call (core apply_type) (core Union)) (core Any) - (opaque_closure_method (null) ,nargs ,isva ,functionloc ,(convert-lambda lam2 (car (lam:args lam2)) #f '() (symbol-to-idx-map cvs))) + (opaque_closure_method (null) ,nargs ,isva ,functionloc ,(convert-lambda lam2 (car (lam:args lam2)) #f '() (symbol-to-idx-map cvs) parsed-method-stack)) ,@var-exprs)))) ((method) (let* ((name (method-expr-name e)) @@ -4007,7 +4026,7 @@ f(x) = yt(x) (sp-inits (if (or short (not (eq? (car sig) 'block))) '() (map-cl-convert (butlast (cdr sig)) - fname lam namemap defined toplevel interp opaq globals locals))) + fname lam namemap defined toplevel interp opaq parsed-method-stack globals locals))) (sig (and sig (if (eq? (car sig) 'block) (last sig) sig)))) @@ -4034,22 +4053,22 @@ f(x) = yt(x) ;; anonymous functions with keyword args generate global ;; functions that refer to the type of a local function (rename-sig-types sig namemap) - fname lam namemap defined toplevel interp opaq globals locals) + fname lam namemap defined toplevel interp opaq parsed-method-stack globals locals) ,(let ((body (add-box-inits-to-body lam2 - (cl-convert (cadddr lam2) 'anon lam2 (table) (table) #f interp opaq (table) + (cl-convert (cadddr lam2) 'anon lam2 (table) (table) #f interp opaq parsed-method-stack (table) (vinfo-to-table (car (lam:vinfo lam2))))))) `(lambda ,(cadr lam2) (,(clear-capture-bits (car vis)) ,@(cdr vis)) ,body))))) (else - (let* ((exprs (lift-toplevel (convert-lambda lam2 '|#anon| #t '() #f))) + (let* ((exprs (lift-toplevel (convert-lambda lam2 '|#anon| #t '() #f parsed-method-stack))) (top-stmts (cdr exprs)) (newlam (compact-and-renumber (linearize (car exprs)) 'none 0))) `(toplevel-butfirst (block ,@sp-inits - (method ,name ,(cl-convert sig fname lam namemap defined toplevel interp opaq globals locals) + (method ,name ,(cl-convert sig fname lam namemap defined toplevel interp opaq parsed-method-stack globals locals) ,(julia-bq-macro newlam))) ,@top-stmts)))) @@ -4058,9 +4077,11 @@ f(x) = yt(x) (type-name (or (get namemap name #f) (and name (symbol (string (if (= (string.char (string name) 0) #\#) - "" - "#") - name "#" (current-julia-module-counter)))))) + (if (anon-function-name? (string name)) + (string "#" (current-julia-module-counter parsed-method-stack)) + name) + (string "#" name)) + "#" (current-julia-module-counter parsed-method-stack)))))) (alldefs (expr-find-all (lambda (ex) (and (length> ex 2) (eq? (car ex) 'method) (not (eq? ex e)) @@ -4152,12 +4173,12 @@ f(x) = yt(x) (append (map (lambda (gs tvar) (make-assignment gs `(call (core TypeVar) ',tvar (core Any)))) closure-param-syms closure-param-names) - `((method #f ,(cl-convert arg-defs fname lam namemap defined toplevel interp opaq globals locals) + `((method #f ,(cl-convert arg-defs fname lam namemap defined toplevel interp opaq parsed-method-stack globals locals) ,(convert-lambda lam2 (if iskw (caddr (lam:args lam2)) (car (lam:args lam2))) - #f closure-param-names #f))))))) + #f closure-param-names #f parsed-method-stack))))))) (mk-closure ;; expression to make the closure (let* ((var-exprs (map (lambda (v) (let ((cv (assq v (cadr (lam:vinfo lam))))) @@ -4191,7 +4212,7 @@ f(x) = yt(x) (begin (put! defined name #t) `(toplevel-butfirst - ,(convert-assignment name mk-closure fname lam interp opaq globals locals) + ,(convert-assignment name mk-closure fname lam interp opaq parsed-method-stack globals locals) ,@typedef ,@(map (lambda (v) `(moved-local ,v)) moved-vars) ,@sp-inits @@ -4205,14 +4226,14 @@ f(x) = yt(x) (table) (table) (null? (cadr e)) ;; only toplevel thunks have 0 args - interp opaq globals (vinfo-to-table (car (lam:vinfo e)))))) + interp opaq parsed-method-stack globals (vinfo-to-table (car (lam:vinfo e)))))) `(lambda ,(cadr e) (,(clear-capture-bits (car (lam:vinfo e))) () ,@(cddr (lam:vinfo e))) (block ,@body)))) ;; remaining `::` expressions are type assertions ((|::|) - (cl-convert `(call (core typeassert) ,@(cdr e)) fname lam namemap defined toplevel interp opaq globals locals)) + (cl-convert `(call (core typeassert) ,@(cdr e)) fname lam namemap defined toplevel interp opaq parsed-method-stack globals locals)) ;; remaining `decl` expressions are only type assertions if the ;; argument is global or a non-symbol. ((decl) @@ -4229,13 +4250,20 @@ f(x) = yt(x) (toplevel-only set_binding_type! ,(cadr e)) (call (core set_binding_type!) ,(cadr ref) (inert ,(caddr ref)) ,(caddr e)))) `(call (core typeassert) ,@(cdr e)))) - fname lam namemap defined toplevel interp opaq globals locals)))) + fname lam namemap defined toplevel interp opaq parsed-method-stack globals locals)))) ;; `with-static-parameters` expressions can be removed now; used only by analyze-vars ((with-static-parameters) - (cl-convert (cadr e) fname lam namemap defined toplevel interp opaq globals locals)) + (cl-convert (cadr e) fname lam namemap defined toplevel interp opaq parsed-method-stack globals locals)) (else (cons (car e) - (map-cl-convert (cdr e) fname lam namemap defined toplevel interp opaq globals locals)))))))) + (map-cl-convert (cdr e) fname lam namemap defined toplevel interp opaq parsed-method-stack globals locals)))))))) + +;; wrapper for `cl-convert-` +(define (cl-convert e fname lam namemap defined toplevel interp opaq (parsed-method-stack '()) (globals (table)) (locals (table))) + (if (is-method? e) + (let ((name (method-expr-name e))) + (cl-convert- e fname lam namemap defined toplevel interp opaq (cons name parsed-method-stack) globals locals)) + (cl-convert- e fname lam namemap defined toplevel interp opaq parsed-method-stack globals locals))) (define (closure-convert e) (cl-convert e #f #f (table) (table) #f #f #f)) diff --git a/src/julia_internal.h b/src/julia_internal.h index fc719c45c5753..3a66da555ea52 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -13,6 +13,8 @@ #include "support/strtod.h" #include "gc-alloc-profiler.h" #include "support/rle.h" +#include +#include #include #include #include @@ -879,6 +881,33 @@ jl_opaque_closure_t *jl_new_opaque_closure(jl_tupletype_t *argt, jl_value_t *rt_ jl_value_t *source, jl_value_t **env, size_t nenv, int do_compile); JL_DLLEXPORT int jl_is_valid_oc_argtype(jl_tupletype_t *argt, jl_method_t *source); +STATIC_INLINE int is10digit(char c) JL_NOTSAFEPOINT +{ + return (c >= '0' && c <= '9'); +} + +STATIC_INLINE int is_anonfn_typename(char *name) +{ + if (name[0] != '#' || name[1] == '#') + return 0; + char *other = strrchr(name, '#'); + return other > &name[1] && is10digit(other[1]); +} + +// Returns true for typenames of anounymous functions that have been canonicalized (i.e. +// we mangled the name of the outermost enclosing function in their name). +STATIC_INLINE int is_canonicalized_anonfn_typename(char *name) JL_NOTSAFEPOINT +{ + char *delim = strchr(&name[1], '#'); + if (delim == NULL) + return 0; + if (delim[1] != '#') + return 0; + if (!is10digit(delim[2])) + return 0; + return 1; +} + // Each tuple can exist in one of 4 Vararg states: // NONE: no vararg Tuple{Int,Float32} // INT: vararg with integer length Tuple{Int,Vararg{Float32,2}} diff --git a/test/show.jl b/test/show.jl index 9b6becbf95b1d..db4c6a1158527 100644 --- a/test/show.jl +++ b/test/show.jl @@ -748,6 +748,69 @@ end @test startswith(sprint(show, typeof(x->x), context = :module=>@__MODULE__), "var\"") +# PR 53719 +module M53719 + f = x -> x + 1 + function foo(x) + function bar(y) + function baz(z) + return x + y + z + end + return baz + end + return bar + end + function foo2(x) + function bar2(y) + return z -> x + y + z + end + return bar2 + end + lambda1 = (x)->begin + function foo(y) + return x + y + end + return foo + end + lambda2 = (x)->begin + y -> x + y + end +end + +@testset "PR 53719 function names" begin + # M53719.f should be printed as var"#[0-9]+" + @test occursin(r"var\"#[0-9]+", sprint(show, M53719.f, context = :module=>M53719)) + # M53719.foo(1) should be printed as var"#bar" + @test occursin(r"var\"#bar", sprint(show, M53719.foo(1), context = :module=>M53719)) + # M53719.foo(1)(2) should be printed as var"#baz" + @test occursin(r"var\"#baz", sprint(show, M53719.foo(1)(2), context = :module=>M53719)) + # M53719.foo2(1) should be printed as var"#bar2" + @test occursin(r"var\"#bar2", sprint(show, M53719.foo2(1), context = :module=>M53719)) + # M53719.foo2(1)(2) should be printed as var"#foo2##[0-9]+" + @test occursin(r"var\"#foo2##[0-9]+", sprint(show, M53719.foo2(1)(2), context = :module=>M53719)) + # M53719.lambda1(1) should be printed as var"#foo" + @test occursin(r"var\"#foo", sprint(show, M53719.lambda1(1), context = :module=>M53719)) + # M53719.lambda2(1) should be printed as var"#[0-9]+" + @test occursin(r"var\"#[0-9]+", sprint(show, M53719.lambda2(1), context = :module=>M53719)) +end + +@testset "PR 53719 function types" begin + # typeof(M53719.f) should be printed as var"#[0-9]+#[0-9]+" + @test occursin(r"var\"#[0-9]+#[0-9]+", sprint(show, typeof(M53719.f), context = :module=>M53719)) + #typeof(M53719.foo(1)) should be printed as var"#bar#foo##[0-9]+" + @test occursin(r"var\"#bar#foo##[0-9]+", sprint(show, typeof(M53719.foo(1)), context = :module=>M53719)) + #typeof(M53719.foo(1)(2)) should be printed as var"#baz#foo##[0-9]+" + @test occursin(r"var\"#baz#foo##[0-9]+", sprint(show, typeof(M53719.foo(1)(2)), context = :module=>M53719)) + #typeof(M53719.foo2(1)) should be printed as var"#bar2#foo2##[0-9]+" + @test occursin(r"var\"#bar2#foo2##[0-9]+", sprint(show, typeof(M53719.foo2(1)), context = :module=>M53719)) + #typeof(M53719.foo2(1)(2)) should be printed as var"#foo2##[0-9]+#foo2##[0-9]+" + @test occursin(r"var\"#foo2##[0-9]+#foo2##[0-9]+", sprint(show, typeof(M53719.foo2(1)(2)), context = :module=>M53719)) + #typeof(M53719.lambda1(1)) should be printed as var"#foo#[0-9]+" + @test occursin(r"var\"#foo#[0-9]+", sprint(show, typeof(M53719.lambda1(1)), context = :module=>M53719)) + #typeof(M53719.lambda2(1)) should be printed as var"#[0-9]+#[0-9]+" + @test occursin(r"var\"#[0-9]+#[0-9]+", sprint(show, typeof(M53719.lambda2(1)), context = :module=>M53719)) +end + #test methodshow.jl functions @test Base.inbase(Base) @test !Base.inbase(LinearAlgebra) From ce667bce9441b77c780f9b74e394784dc4cb3631 Mon Sep 17 00:00:00 2001 From: Nick Robinson Date: Mon, 9 Dec 2024 17:01:00 +0000 Subject: [PATCH 095/109] Add per-Task cpu time metric (#56320) (#194) * Add per-task metrics (#56320) Close https://github.com/JuliaLang/julia/issues/47351 (builds on top of https://github.com/JuliaLang/julia/pull/48416) Adds two per-task metrics: - running time = amount of time the task was actually running (according to our scheduler). Note: currently inclusive of GC time, but would be good to be able to separate that out (in a future PR) - wall time = amount of time between the scheduler becoming aware of this task and the task entering a terminal state (i.e. done or failed). We record running time in `wait()`, where the scheduler stops running the task as well as in `yield(t)`, `yieldto(t)` and `throwto(t)`, which bypass the scheduler. Other places where a task stops running (for `Channel`, `ReentrantLock`, `Event`, `Timer` and `Semaphore` are all implemented in terms of `wait(Condition)`, which in turn calls `wait()`. `LibuvStream` similarly calls `wait()`. This should capture everything (albeit, slightly over-counting task CPU time by including any enqueuing work done before we hit `wait()`). The various metrics counters could be a separate inlined struct if we think that's a useful abstraction, but for now i've just put them directly in `jl_task_t`. They are all atomic, except the `metrics_enabled` flag itself (which we now have to check on task start/switch/done even if metrics are not enabled) which is set on task construction and marked `const` on the julia side. In future PRs we could add more per-task metrics, e.g. compilation time, GC time, allocations, potentially a wait-time breakdown (time waiting on locks, channels, in the scheduler run queue, etc.), potentially the number of yields. Perhaps in future there could be ways to enable this on a per-thread and per-task basis. And potentially in future these same timings could be used by `@time` (e.g. writing this same timing data to a ScopedValue like in https://github.com/JuliaLang/julia/pull/55103 but only for tasks lexically scoped to inside the `@time` block). Timings are off by default but can be turned on globally via starting Julia with `--task-metrics=yes` or calling `Base.Experimental.task_metrics(true)`. Metrics are collected for all tasks created when metrics are enabled. In other words, enabling/disabling timings via `Base.Experimental.task_metrics` does not affect existing `Task`s, only new `Task`s. The other new APIs are `Base.Experimental.task_running_time_ns(::Task)` and `Base.Experimental.task_wall_time_ns(::Task)` for retrieving the new metrics. These are safe to call on any task (including the current task, or a task running on another thread). All these are in `Base.Experimental` to give us room to change up the APIs as we add more metrics in future PRs (without worrying about release timelines). cc @NHDaly @kpamnany @d-netto --------- Co-authored-by: Pete Vilter Co-authored-by: K Pamnany Co-authored-by: Nathan Daly Co-authored-by: Valentin Churavy * Address review comments --------- Co-authored-by: Pete Vilter Co-authored-by: K Pamnany Co-authored-by: Nathan Daly Co-authored-by: Valentin Churavy --- base/boot.jl | 28 ++- base/experimental.jl | 74 ++++++++ base/options.jl | 1 + base/task.jl | 53 +++++- doc/man/julia.1 | 4 + doc/src/base/multi-threading.md | 8 + doc/src/manual/command-line-interface.md | 1 + src/init.c | 4 + src/jlapi.c | 30 +++ src/jloptions.c | 38 ++-- src/jloptions.h | 1 + src/jltypes.c | 46 ++++- src/julia.h | 26 ++- src/julia_internal.h | 3 + src/task.c | 35 +++- src/threading.c | 2 + test/cmdlineargs.jl | 9 + test/core.jl | 2 + test/threads_exec.jl | 223 +++++++++++++++++++++++ 19 files changed, 551 insertions(+), 37 deletions(-) diff --git a/base/boot.jl b/base/boot.jl index 561be564d58f4..aff2a30504549 100644 --- a/base/boot.jl +++ b/base/boot.jl @@ -156,15 +156,33 @@ #end #mutable struct Task -# parent::Task +# next::Any +# queue::Any # storage::Any -# state::Symbol # donenotify::Any # result::Any -# exception::Any -# backtrace::Any -# logstate::Any +# scope::Any # code::Any +# @atomic _state::UInt8 +# sticky::UInt8 +# priority::UInt16 +# @atomic _isexception::UInt8 +# pad00::UInt8 +# pad01::UInt8 +# pad02::UInt8 +# rngState0::UInt64 +# rngState1::UInt64 +# rngState2::UInt64 +# rngState3::UInt64 +# rngState4::UInt64 +# const metrics_enabled::Bool +# pad10::UInt8 +# pad11::UInt8 +# pad12::UInt8 +# @atomic first_enqueued_at::UInt64 +# @atomic last_started_running_at::UInt64 +# @atomic running_time_ns::UInt64 +# @atomic finished_at::UInt64 #end export diff --git a/base/experimental.jl b/base/experimental.jl index cc8d368023b49..d876662ab048c 100644 --- a/base/experimental.jl +++ b/base/experimental.jl @@ -368,4 +368,78 @@ adding them to the global method table. """ :@MethodTable +### Task metrics + +""" + Base.Experimental.task_metrics(::Bool) + +Enable or disable the collection of per-task metrics. +A `Task` created when `Base.Experimental.task_metrics(true)` is in effect will have +[`Base.Experimental.task_running_time_ns`](@ref) and [`Base.Experimental.task_wall_time_ns`](@ref) +timing information available. + +!!! note + Task metrics can be enabled at start-up via the `--task-metrics=yes` command line option. +""" +function task_metrics(b::Bool) + if b + ccall(:jl_task_metrics_enable, Cvoid, ()) + else + ccall(:jl_task_metrics_disable, Cvoid, ()) + end + return nothing +end + +""" + Base.Experimental.task_running_time_ns(t::Task) -> Union{UInt64, Nothing} + +Return the total nanoseconds that the task `t` has spent running. +This metric is only updated when `t` yields or completes unless `t` is the current task, in +which it will be updated continuously. +See also [`Base.Experimental.task_wall_time_ns`](@ref). + +Returns `nothing` if task timings are not enabled. +See [`Base.Experimental.task_metrics`](@ref). + +!!! note "This metric is from the Julia scheduler" + A task may be running on an OS thread that is descheduled by the OS + scheduler, this time still counts towards the metric. + +!!! compat "Julia 1.12" + This method was added in Julia 1.12. +""" +function task_running_time_ns(t::Task=current_task()) + t.metrics_enabled || return nothing + if t == current_task() + # These metrics fields can't update while we're running. + # But since we're running we need to include the time since we last started running! + return t.running_time_ns + (time_ns() - t.last_started_running_at) + else + return t.running_time_ns + end end + +""" + Base.Experimental.task_wall_time_ns(t::Task) -> Union{UInt64, Nothing} + +Return the total nanoseconds that the task `t` was runnable. +This is the time since the task first entered the run queue until the time at which it +completed, or until the current time if the task has not yet completed. +See also [`Base.Experimental.task_running_time_ns`](@ref). + +Returns `nothing` if task timings are not enabled. +See [`Base.Experimental.task_metrics`](@ref). + +!!! compat "Julia 1.12" + This method was added in Julia 1.12. +""" +function task_wall_time_ns(t::Task=current_task()) + t.metrics_enabled || return nothing + start_at = t.first_enqueued_at + start_at == 0 && return UInt64(0) + end_at = t.finished_at + end_at == 0 && return time_ns() - start_at + return end_at - start_at +end + +end # module diff --git a/base/options.jl b/base/options.jl index a01a3f553b157..2e779c964e7fd 100644 --- a/base/options.jl +++ b/base/options.jl @@ -60,6 +60,7 @@ struct JLOptions heap_size_hint::UInt64 trace_compile_timing::Int8 safe_crash_log_file::Ptr{UInt8} + task_metrics::Int8 end # This runs early in the sysimage != is not defined yet diff --git a/base/task.jl b/base/task.jl index 137b0f7c4a3f6..2d0babbb9fd4c 100644 --- a/base/task.jl +++ b/base/task.jl @@ -810,7 +810,11 @@ function enq_work(t::Task) return t end -schedule(t::Task) = enq_work(t) +function schedule(t::Task) + # [task] created -scheduled-> wait_time + maybe_record_enqueued!(t) + enq_work(t) +end """ schedule(t::Task, [val]; error=false) @@ -857,6 +861,8 @@ function schedule(t::Task, @nospecialize(arg); error=false) t.queue === nothing || Base.error("schedule: Task not runnable") setfield!(t, :result, arg) end + # [task] created -scheduled-> wait_time + maybe_record_enqueued!(t) enq_work(t) return t end @@ -888,9 +894,15 @@ A fast, unfair-scheduling version of `schedule(t, arg); yield()` which immediately yields to `t` before calling the scheduler. """ function yield(t::Task, @nospecialize(x=nothing)) - (t._state === task_state_runnable && t.queue === nothing) || error("yield: Task not runnable") + ct = current_task() + t === ct && throw(ConcurrencyViolationError("Cannot yield to currently running task!")) + (t._state === task_state_runnable && t.queue === nothing) || throw(ConcurrencyViolationError("yield: Task not runnable")) + # [task] user_time -yield-> wait_time + record_running_time!(ct) + # [task] created -scheduled-> wait_time + maybe_record_enqueued!(t) t.result = x - enq_work(current_task()) + enq_work(ct) set_next_task(t) return try_yieldto(ensure_rescheduled) end @@ -904,6 +916,7 @@ call to `yieldto`. This is a low-level call that only switches tasks, not consid or scheduling in any way. Its use is discouraged. """ function yieldto(t::Task, @nospecialize(x=nothing)) + ct = current_task() # TODO: these are legacy behaviors; these should perhaps be a scheduler # state error instead. if t._state === task_state_done @@ -911,6 +924,10 @@ function yieldto(t::Task, @nospecialize(x=nothing)) elseif t._state === task_state_failed throw(t.result) end + # [task] user_time -yield-> wait_time + record_running_time!(ct) + # [task] created -scheduled-unfairly-> wait_time + maybe_record_enqueued!(t) t.result = x set_next_task(t) return try_yieldto(identity) @@ -924,6 +941,10 @@ function try_yieldto(undo) rethrow() end ct = current_task() + # [task] wait_time -(re)started-> user_time + if ct.metrics_enabled + @atomic :monotonic ct.last_started_running_at = time_ns() + end if ct._isexception exc = ct.result ct.result = nothing @@ -937,6 +958,11 @@ end # yield to a task, throwing an exception in it function throwto(t::Task, @nospecialize exc) + ct = current_task() + # [task] user_time -yield-> wait_time + record_running_time!(ct) + # [task] created -scheduled-unfairly-> wait_time + maybe_record_enqueued!(t) t.result = exc t._isexception = true set_next_task(t) @@ -989,6 +1015,9 @@ checktaskempty = Partr.multiq_check_empty end function wait() + ct = current_task() + # [task] user_time -yield-or-done-> wait_time + record_running_time!(ct) GC.safepoint() W = workqueue_for(Threads.threadid()) poptask(W) @@ -1003,3 +1032,21 @@ if Sys.iswindows() else pause() = ccall(:pause, Cvoid, ()) end + +# update the `running_time_ns` field of `t` to include the time since it last started running. +function record_running_time!(t::Task) + if t.metrics_enabled && !istaskdone(t) + @atomic :monotonic t.running_time_ns += time_ns() - t.last_started_running_at + end + return t +end + +# if this is the first time `t` has been added to the run queue +# (or the first time it has been unfairly yielded to without being added to the run queue) +# then set the `first_enqueued_at` field to the current time. +function maybe_record_enqueued!(t::Task) + if t.metrics_enabled && t.first_enqueued_at == 0 + @atomic :monotonic t.first_enqueued_at = time_ns() + end + return t +end diff --git a/doc/man/julia.1 b/doc/man/julia.1 index e7da6e352a96a..483b7d76ac04f 100644 --- a/doc/man/julia.1 +++ b/doc/man/julia.1 @@ -270,6 +270,10 @@ Print precompile statements for methods compiled during execution or save to a p --trace-compile-timing= If --trace-compile is enabled show how long each took to compile in ms +.TP +--task-metrics={yes|no*} +Enable the collection of per-task metrics. + .TP -image-codegen Force generate code in imaging mode diff --git a/doc/src/base/multi-threading.md b/doc/src/base/multi-threading.md index 45a60b14d541a..6758cafd9b059 100644 --- a/doc/src/base/multi-threading.md +++ b/doc/src/base/multi-threading.md @@ -71,3 +71,11 @@ These building blocks are used to create the regular synchronization objects. ```@docs Base.Threads.SpinLock ``` + +## Task metrics (Experimental) + +```@docs +Base.Experimental.task_metrics +Base.Experimental.task_running_time_ns +Base.Experimental.task_wall_time_ns +``` diff --git a/doc/src/manual/command-line-interface.md b/doc/src/manual/command-line-interface.md index d08e3fbfd2181..0c380fa2c0688 100644 --- a/doc/src/manual/command-line-interface.md +++ b/doc/src/manual/command-line-interface.md @@ -130,6 +130,7 @@ The following is a complete list of command-line switches available when launchi |`--code-coverage=tracefile.info` |Append coverage information to the LCOV tracefile (filename supports format tokens).| |`--track-allocation[={none*\|user\|all}]` |Count bytes allocated by each source line (omitting setting is equivalent to "user")| |`--track-allocation=@` |Count bytes but only in files that fall under the given file path/directory. The `@` prefix is required to select this option. A `@` with no path will track the current directory.| +|`--task-metrics={yes\|no*}` |Enable the collection of per-task metrics| |`--bug-report=KIND` |Launch a bug report session. It can be used to start a REPL, run a script, or evaluate expressions. It first tries to use BugReporting.jl installed in current environment and falls back to the latest compatible BugReporting.jl if not. For more information, see `--bug-report=help`.| |`--compile={yes*\|no\|all\|min}` |Enable or disable JIT compiler, or request exhaustive or minimal compilation| |`--output-o ` |Generate an object file (including system image data)| diff --git a/src/init.c b/src/init.c index 9a49ad60c02f4..dae5afb375916 100644 --- a/src/init.c +++ b/src/init.c @@ -851,6 +851,10 @@ JL_DLLEXPORT void julia_init(JL_IMAGE_SEARCH rel) #if defined(_COMPILER_GCC_) && __GNUC__ >= 12 #pragma GCC diagnostic ignored "-Wdangling-pointer" #endif + if (jl_options.task_metrics == JL_OPTIONS_TASK_METRICS_ON) { + // enable before creating the root task so it gets timings too. + jl_atomic_fetch_add(&jl_task_metrics_enabled, 1); + } // warning: this changes `jl_current_task`, so be careful not to call that from this function jl_task_t *ct = jl_init_root_task(ptls, stack_lo, stack_hi); #pragma GCC diagnostic pop diff --git a/src/jlapi.c b/src/jlapi.c index 0dffaac627288..670408d2260fb 100644 --- a/src/jlapi.c +++ b/src/jlapi.c @@ -509,6 +509,36 @@ JL_DLLEXPORT uint64_t jl_cumulative_recompile_time_ns(void) return jl_atomic_load_relaxed(&jl_cumulative_recompile_time); } +/** + * @brief Enable per-task timing. + */ +JL_DLLEXPORT void jl_task_metrics_enable(void) +{ + // Increment the flag to allow reentrant callers. + jl_atomic_fetch_add(&jl_task_metrics_enabled, 1); +} + +/** + * @brief Disable per-task timing. + */ +JL_DLLEXPORT void jl_task_metrics_disable(void) +{ + // Prevent decrementing the counter below zero + uint8_t enabled = jl_atomic_load_relaxed(&jl_task_metrics_enabled); + while (enabled > 0) { + if (jl_atomic_cmpswap(&jl_task_metrics_enabled, &enabled, enabled-1)) + break; + } +} + +/** + * @brief Retrieve floating-point environment constants. + * + * Populates an array with constants related to the floating-point environment, + * such as rounding modes and exception flags. + * + * @param ret An array of integers to be populated with floating-point environment constants. + */ JL_DLLEXPORT void jl_get_fenv_consts(int *ret) { ret[0] = FE_INEXACT; diff --git a/src/jloptions.c b/src/jloptions.c index 29fd171db1437..364c37cebcb6d 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -93,6 +93,7 @@ JL_DLLEXPORT void jl_init_options(void) 0, // heap-size-hint 0, // trace_compile_timing NULL, // safe_crash_log_file + 0, // task_metrics }; jl_options_initialized = 1; } @@ -206,17 +207,22 @@ static const char opts_hidden[] = " --strip-metadata Remove docstrings and source location info from system image\n" " --strip-ir Remove IR (intermediate representation) of compiled functions\n\n" - // compiler debugging (see the devdocs for tips on using these options) - " --output-unopt-bc Generate unoptimized LLVM bitcode (.bc)\n" - " --output-bc Generate LLVM bitcode (.bc)\n" - " --output-asm Generate an assembly file (.s)\n" - " --output-incremental={yes|no*}\n" - " Generate an incremental output file (rather than complete)\n" - " --trace-compile={stderr,name}\n" - " Print precompile statements for methods compiled during execution or save to a path\n" - " --trace-compile-timing If --trace-compile is enabled show how long each took to compile in ms\n" - " --image-codegen Force generate code in imaging mode\n" - " --permalloc-pkgimg={yes|no*} Copy the data section of package images into memory\n" + // compiler debugging and experimental (see the devdocs for tips on using these options) + " --experimental Enable the use of experimental (alpha) features\n" + " --output-unopt-bc Generate unoptimized LLVM bitcode (.bc)\n" + " --output-bc Generate LLVM bitcode (.bc)\n" + " --output-asm Generate an assembly file (.s)\n" + " --output-incremental={yes|no*} Generate an incremental output file (rather than\n" + " complete)\n" + " --trace-compile={stderr|name} Print precompile statements for methods compiled\n" + " during execution or save to stderr or a path. Methods that\n" + " were recompiled are printed in yellow or with a trailing\n" + " comment if color is not supported\n" + " --trace-compile-timing If --trace-compile is enabled show how long each took to\n" + " compile in ms\n" + " --task-metrics={yes|no*} Enable collection of per-task timing data.\n" + " --image-codegen Force generate code in imaging mode\n" + " --permalloc-pkgimg={yes|no*} Copy the data section of package images into memory\n" ; JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) @@ -239,6 +245,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) opt_trace_compile, opt_trace_compile_timing, opt_trace_dispatch, + opt_task_metrics, opt_math_mode, opt_worker, opt_bind_to, @@ -317,6 +324,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) { "trace-compile", required_argument, 0, opt_trace_compile }, { "trace-compile-timing", no_argument, 0, opt_trace_compile_timing }, { "trace-dispatch", required_argument, 0, opt_trace_dispatch }, + { "task-metrics", required_argument, 0, opt_task_metrics }, { "math-mode", required_argument, 0, opt_math_mode }, { "handle-signals", required_argument, 0, opt_handle_signals }, // hidden command line options @@ -873,6 +881,14 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) if (jl_options.safe_crash_log_file == NULL) jl_error("julia: failed to allocate memory for --safe-crash-log-file"); break; + case opt_task_metrics: + if (!strcmp(optarg, "no")) + jl_options.task_metrics = JL_OPTIONS_TASK_METRICS_OFF; + else if (!strcmp(optarg, "yes")) + jl_options.task_metrics = JL_OPTIONS_TASK_METRICS_ON; + else + jl_errorf("julia: invalid argument to --task-metrics={yes|no} (%s)", optarg); + break; default: jl_errorf("julia: unhandled option -- %c\n" "This is a bug, please report it.", c); diff --git a/src/jloptions.h b/src/jloptions.h index 63f639805b300..d9cf96e82f2a4 100644 --- a/src/jloptions.h +++ b/src/jloptions.h @@ -64,6 +64,7 @@ typedef struct { uint64_t heap_size_hint; int8_t trace_compile_timing; const char *safe_crash_log_file; + int8_t task_metrics; } jl_options_t; #endif diff --git a/src/jltypes.c b/src/jltypes.c index e9d843c383a9c..f67c90fba9be2 100644 --- a/src/jltypes.c +++ b/src/jltypes.c @@ -3222,7 +3222,7 @@ void jl_init_types(void) JL_GC_DISABLED NULL, jl_any_type, jl_emptysvec, - jl_perm_symsvec(16, + jl_perm_symsvec(27, "next", "queue", "storage", @@ -3230,16 +3230,27 @@ void jl_init_types(void) JL_GC_DISABLED "result", "logstate", "code", + "_state", + "sticky", + "priority", + "_isexception", + "pad00", + "pad01", + "pad02", "rngState0", "rngState1", "rngState2", "rngState3", "rngState4", - "_state", - "sticky", - "_isexception", - "priority"), - jl_svec(16, + "metrics_enabled", + "pad10", + "pad11", + "pad12", + "first_enqueued_at", + "last_started_running_at", + "running_time_ns", + "finished_at"), + jl_svec(27, jl_any_type, jl_any_type, jl_any_type, @@ -3247,20 +3258,37 @@ void jl_init_types(void) JL_GC_DISABLED jl_any_type, jl_any_type, jl_any_type, + jl_uint8_type, + jl_bool_type, + jl_uint16_type, + jl_bool_type, + jl_uint8_type, + jl_uint8_type, + jl_uint8_type, jl_uint64_type, jl_uint64_type, jl_uint64_type, jl_uint64_type, jl_uint64_type, - jl_uint8_type, jl_bool_type, - jl_bool_type, - jl_uint16_type), + jl_uint8_type, + jl_uint8_type, + jl_uint8_type, + jl_uint64_type, + jl_uint64_type, + jl_uint64_type, + jl_uint64_type), jl_emptysvec, 0, 1, 6); XX(task); jl_value_t *listt = jl_new_struct(jl_uniontype_type, jl_task_type, jl_nothing_type); jl_svecset(jl_task_type->types, 0, listt); + // Set field 20 (metrics_enabled) as const + // Set fields 8 (_state) and 24-27 (metric counters) as atomic + const static uint32_t task_constfields[1] = { 0b00000000000010000000000000000000 }; + const static uint32_t task_atomicfields[1] = { 0b00000111100000000000000010000000 }; + jl_task_type->name->constfields = task_constfields; + jl_task_type->name->atomicfields = task_atomicfields; jl_binding_type = jl_new_datatype(jl_symbol("Binding"), core, jl_any_type, jl_emptysvec, diff --git a/src/julia.h b/src/julia.h index f34bb1623eed5..3dc8552240f9e 100644 --- a/src/julia.h +++ b/src/julia.h @@ -2033,16 +2033,25 @@ typedef struct _jl_task_t { jl_value_t *result; jl_value_t *logstate; jl_function_t *start; - // 4 byte padding on 32-bit systems - // uint32_t padding0; - uint64_t rngState[JL_RNG_SIZE]; _Atomic(uint8_t) _state; uint8_t sticky; // record whether this Task can be migrated to a new thread - _Atomic(uint8_t) _isexception; // set if `result` is an exception to throw or that we exited with - // 1 byte padding - // uint8_t padding1; - // multiqueue priority uint16_t priority; + _Atomic(uint8_t) _isexception; // set if `result` is an exception to throw or that we exited with + uint8_t pad0[3]; + // === 64 bytes (cache line) + uint64_t rngState[JL_RNG_SIZE]; + // flag indicating whether or not to record timing metrics for this task + uint8_t metrics_enabled; + uint8_t pad1[3]; + // timestamp this task first entered the run queue + _Atomic(uint64_t) first_enqueued_at; + // timestamp this task was most recently scheduled to run + _Atomic(uint64_t) last_started_running_at; + // time this task has spent running; updated when it yields or finishes. + _Atomic(uint64_t) running_time_ns; + // === 64 bytes (cache line) + // timestamp this task finished (i.e. entered state DONE or FAILED). + _Atomic(uint64_t) finished_at; // hidden state: @@ -2324,6 +2333,9 @@ JL_DLLEXPORT int jl_generating_output(void) JL_NOTSAFEPOINT; #define JL_OPTIONS_USE_PKGIMAGES_YES 1 #define JL_OPTIONS_USE_PKGIMAGES_NO 0 +#define JL_OPTIONS_TASK_METRICS_OFF 0 +#define JL_OPTIONS_TASK_METRICS_ON 1 + // Version information #include // Generated file diff --git a/src/julia_internal.h b/src/julia_internal.h index 3a66da555ea52..36d25f502cd2a 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -305,6 +305,9 @@ extern JL_DLLEXPORT _Atomic(uint8_t) jl_measure_compile_time_enabled; extern JL_DLLEXPORT _Atomic(uint64_t) jl_cumulative_compile_time; extern JL_DLLEXPORT _Atomic(uint64_t) jl_cumulative_recompile_time; +// Global *atomic* integer controlling *process-wide* task timing. +extern JL_DLLEXPORT _Atomic(uint8_t) jl_task_metrics_enabled; + #define jl_return_address() ((uintptr_t)__builtin_return_address(0)) STATIC_INLINE uint32_t jl_int32hash_fast(uint32_t a) diff --git a/src/task.c b/src/task.c index 86033a81ddf41..e614d4205e937 100644 --- a/src/task.c +++ b/src/task.c @@ -295,8 +295,15 @@ void JL_NORETURN jl_finish_task(jl_task_t *t) jl_task_t *ct = jl_current_task; JL_PROBE_RT_FINISH_TASK(ct); JL_SIGATOMIC_BEGIN(); - if (jl_atomic_load_relaxed(&t->_isexception)) - jl_atomic_store_release(&t->_state, JL_TASK_STATE_FAILED); + if (ct->metrics_enabled) { + // [task] user_time -finished-> wait_time + assert(jl_atomic_load_relaxed(&ct->first_enqueued_at) != 0); + uint64_t now = jl_hrtime(); + jl_atomic_store_relaxed(&ct->finished_at, now); + jl_atomic_fetch_add_relaxed(&ct->running_time_ns, now - jl_atomic_load_relaxed(&ct->last_started_running_at)); + } + if (jl_atomic_load_relaxed(&ct->_isexception)) + jl_atomic_store_release(&ct->_state, JL_TASK_STATE_FAILED); else jl_atomic_store_release(&t->_state, JL_TASK_STATE_DONE); if (t->copy_stack) { // early free of stkbuf @@ -1084,6 +1091,11 @@ JL_DLLEXPORT jl_task_t *jl_new_task(jl_function_t *start, jl_value_t *completion t->ptls = NULL; t->world_age = ct->world_age; t->reentrant_timing = 0; + t->metrics_enabled = jl_atomic_load_relaxed(&jl_task_metrics_enabled) != 0; + jl_atomic_store_relaxed(&t->first_enqueued_at, 0); + jl_atomic_store_relaxed(&t->last_started_running_at, 0); + jl_atomic_store_relaxed(&t->running_time_ns, 0); + jl_atomic_store_relaxed(&t->finished_at, 0); jl_timing_task_init(t); #ifdef COPY_STACKS @@ -1220,6 +1232,12 @@ CFI_NORETURN #endif ct->started = 1; + if (ct->metrics_enabled) { + // [task] wait_time -started-> user_time + assert(jl_atomic_load_relaxed(&ct->first_enqueued_at) != 0); + assert(jl_atomic_load_relaxed(&ct->last_started_running_at) == 0); + jl_atomic_store_relaxed(&ct->last_started_running_at, jl_hrtime()); + } JL_PROBE_RT_START_TASK(ct); jl_timing_block_task_enter(ct, ptls, NULL); if (jl_atomic_load_relaxed(&ct->_isexception)) { @@ -1680,6 +1698,19 @@ jl_task_t *jl_init_root_task(jl_ptls_t ptls, void *stack_lo, void *stack_hi) ct->ptls = ptls; ct->world_age = 1; // OK to run Julia code on this task ct->reentrant_timing = 0; + jl_atomic_store_relaxed(&ct->running_time_ns, 0); + jl_atomic_store_relaxed(&ct->finished_at, 0); + ct->metrics_enabled = jl_atomic_load_relaxed(&jl_task_metrics_enabled) != 0; + if (ct->metrics_enabled) { + // [task] created -started-> user_time + uint64_t now = jl_hrtime(); + jl_atomic_store_relaxed(&ct->first_enqueued_at, now); + jl_atomic_store_relaxed(&ct->last_started_running_at, now); + } + else { + jl_atomic_store_relaxed(&ct->first_enqueued_at, 0); + jl_atomic_store_relaxed(&ct->last_started_running_at, 0); + } ptls->root_task = ct; jl_atomic_store_relaxed(&ptls->current_task, ct); JL_GC_PROMISE_ROOTED(ct); diff --git a/src/threading.c b/src/threading.c index d0f25de374462..5a8ae7825354f 100644 --- a/src/threading.c +++ b/src/threading.c @@ -49,6 +49,8 @@ JL_DLLEXPORT _Atomic(uint8_t) jl_measure_compile_time_enabled = 0; JL_DLLEXPORT _Atomic(uint64_t) jl_cumulative_compile_time = 0; JL_DLLEXPORT _Atomic(uint64_t) jl_cumulative_recompile_time = 0; +JL_DLLEXPORT _Atomic(uint8_t) jl_task_metrics_enabled = 0; + JL_DLLEXPORT void *jl_get_ptls_states(void) { // mostly deprecated: use current_task instead diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index 094fa8741087f..3597d99eb6d96 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -746,6 +746,15 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no` "Int(Base.JLOptions().fast_math)"`)) == JL_OPTIONS_FAST_MATH_DEFAULT end + let JL_OPTIONS_TASK_METRICS_OFF = 0, JL_OPTIONS_TASK_METRICS_ON = 1 + @test parse(Int,readchomp(`$exename -E + "Int(Base.JLOptions().task_metrics)"`)) == JL_OPTIONS_TASK_METRICS_OFF + @test parse(Int, readchomp(`$exename --task-metrics=yes -E + "Int(Base.JLOptions().task_metrics)"`)) == JL_OPTIONS_TASK_METRICS_ON + @test !parse(Bool, readchomp(`$exename -E "current_task().metrics_enabled"`)) + @test parse(Bool, readchomp(`$exename --task-metrics=yes -E "current_task().metrics_enabled"`)) + end + # --worker takes default / custom as argument (default/custom arguments # tested in test/parallel.jl) @test errors_not_signals(`$exename --worker=true`) diff --git a/test/core.jl b/test/core.jl index 0212193a0206b..0549c1eec32df 100644 --- a/test/core.jl +++ b/test/core.jl @@ -23,6 +23,7 @@ for (T, c) in ( (Core.TypeName, [:name, :module, :names, :atomicfields, :constfields, :wrapper, :mt, :hash, :n_uninitialized, :flags]), (DataType, [:name, :super, :parameters, :instance, :hash]), (TypeVar, [:name, :ub, :lb]), + (Task, [:metrics_enabled]), ) @test Set((fieldname(T, i) for i in 1:fieldcount(T) if isconst(T, i))) == Set(c) end @@ -38,6 +39,7 @@ for (T, c) in ( (Core.TypeMapLevel, [:arg1, :targ, :name1, :tname, :list, :any]), (Core.TypeName, [:cache, :linearcache]), (DataType, [:types, :layout]), + (Task, [:_state, :running_time_ns, :finished_at, :first_enqueued_at, :last_started_running_at]), ) @test Set((fieldname(T, i) for i in 1:fieldcount(T) if Base.isfieldatomic(T, i))) == Set(c) end diff --git a/test/threads_exec.jl b/test/threads_exec.jl index 9c7c524febeff..6fbad062901cf 100644 --- a/test/threads_exec.jl +++ b/test/threads_exec.jl @@ -3,6 +3,7 @@ using Test using Base.Threads using Base.Threads: SpinLock, threadpoolsize +using LinearAlgebra: peakflops # for cfunction_closure include("testenv.jl") @@ -1090,4 +1091,226 @@ end end end +@testset "Base.Experimental.task_metrics" begin + t = Task(() -> nothing) + @test_throws "const field" t.metrics_enabled = true + is_task_metrics_enabled() = fetch(Threads.@spawn current_task().metrics_enabled) + @test !is_task_metrics_enabled() + try + @testset "once" begin + Base.Experimental.task_metrics(true) + @test is_task_metrics_enabled() + Base.Experimental.task_metrics(false) + @test !is_task_metrics_enabled() + end + @testset "multiple" begin + Base.Experimental.task_metrics(true) # 1 + Base.Experimental.task_metrics(true) # 2 + Base.Experimental.task_metrics(true) # 3 + @test is_task_metrics_enabled() + Base.Experimental.task_metrics(false) # 2 + @test is_task_metrics_enabled() + Base.Experimental.task_metrics(false) # 1 + @test is_task_metrics_enabled() + @sync for i in 1:5 # 0 (not negative) + Threads.@spawn Base.Experimental.task_metrics(false) + end + @test !is_task_metrics_enabled() + Base.Experimental.task_metrics(true) # 1 + @test is_task_metrics_enabled() + end + finally + while is_task_metrics_enabled() + Base.Experimental.task_metrics(false) + end + end +end + +@testset "task time counters" begin + @testset "enabled" begin + try + Base.Experimental.task_metrics(true) + start_time = time_ns() + t = Threads.@spawn peakflops() + wait(t) + end_time = time_ns() + wall_time_delta = end_time - start_time + @test t.metrics_enabled + @test Base.Experimental.task_running_time_ns(t) > 0 + @test Base.Experimental.task_wall_time_ns(t) > 0 + @test Base.Experimental.task_wall_time_ns(t) >= Base.Experimental.task_running_time_ns(t) + @test wall_time_delta > Base.Experimental.task_wall_time_ns(t) + finally + Base.Experimental.task_metrics(false) + end + end + @testset "disabled" begin + t = Threads.@spawn peakflops() + wait(t) + @test !t.metrics_enabled + @test isnothing(Base.Experimental.task_running_time_ns(t)) + @test isnothing(Base.Experimental.task_wall_time_ns(t)) + end + @testset "task not run" begin + t1 = Task(() -> nothing) + @test !t1.metrics_enabled + @test isnothing(Base.Experimental.task_running_time_ns(t1)) + @test isnothing(Base.Experimental.task_wall_time_ns(t1)) + try + Base.Experimental.task_metrics(true) + t2 = Task(() -> nothing) + @test t2.metrics_enabled + @test Base.Experimental.task_running_time_ns(t2) == 0 + @test Base.Experimental.task_wall_time_ns(t2) == 0 + finally + Base.Experimental.task_metrics(false) + end + end + @testset "task failure" begin + try + Base.Experimental.task_metrics(true) + t = Threads.@spawn error("this task failed") + @test_throws "this task failed" wait(t) + @test Base.Experimental.task_running_time_ns(t) > 0 + @test Base.Experimental.task_wall_time_ns(t) > 0 + @test Base.Experimental.task_wall_time_ns(t) >= Base.Experimental.task_running_time_ns(t) + finally + Base.Experimental.task_metrics(false) + end + end + @testset "direct yield(t)" begin + try + Base.Experimental.task_metrics(true) + start = time_ns() + t_outer = Threads.@spawn begin + t_inner = Task(() -> peakflops()) + t_inner.sticky = false + # directly yield to `t_inner` rather calling `schedule(t_inner)` + yield(t_inner) + wait(t_inner) + @test Base.Experimental.task_running_time_ns(t_inner) > 0 + @test Base.Experimental.task_wall_time_ns(t_inner) > 0 + @test Base.Experimental.task_wall_time_ns(t_inner) >= Base.Experimental.task_running_time_ns(t_inner) + end + wait(t_outer) + delta = time_ns() - start + @test Base.Experimental.task_running_time_ns(t_outer) > 0 + @test Base.Experimental.task_wall_time_ns(t_outer) > 0 + @test Base.Experimental.task_wall_time_ns(t_outer) >= Base.Experimental.task_running_time_ns(t_outer) + @test Base.Experimental.task_wall_time_ns(t_outer) < delta + finally + Base.Experimental.task_metrics(false) + end + end + @testset "bad schedule" begin + try + Base.Experimental.task_metrics(true) + t1 = Task((x) -> 1) + schedule(t1) # MethodError + yield() + @assert istaskfailed(t1) + @test Base.Experimental.task_running_time_ns(t1) > 0 + @test Base.Experimental.task_wall_time_ns(t1) > 0 + foo(a, b) = a + b + t2 = Task(() -> (peakflops(); foo(wait()))) + schedule(t2) + yield() + @assert istaskstarted(t1) && !istaskdone(t2) + schedule(t2, 1) + yield() + @assert istaskfailed(t2) + @test Base.Experimental.task_running_time_ns(t2) > 0 + @test Base.Experimental.task_wall_time_ns(t2) > 0 + finally + Base.Experimental.task_metrics(false) + end + end + @testset "continuously update until task done" begin + try + Base.Experimental.task_metrics(true) + last_running_time = Ref(typemax(Int)) + last_wall_time = Ref(typemax(Int)) + t = Threads.@spawn begin + running_time = Base.Experimental.task_running_time_ns() + wall_time = Base.Experimental.task_wall_time_ns() + for _ in 1:5 + x = time_ns() + while time_ns() < x + 100 + end + new_running_time = Base.Experimental.task_running_time_ns() + new_wall_time = Base.Experimental.task_wall_time_ns() + @test new_running_time > running_time + @test new_wall_time > wall_time + running_time = new_running_time + wall_time = new_wall_time + end + last_running_time[] = running_time + last_wall_time[] = wall_time + end + wait(t) + final_running_time = Base.Experimental.task_running_time_ns(t) + final_wall_time = Base.Experimental.task_wall_time_ns(t) + @test last_running_time[] < final_running_time + @test last_wall_time[] < final_wall_time + # ensure many more tasks are run to make sure the counters are + # not being updated after a task is done e.g. only when a new task is found + @sync for _ in 1:Threads.nthreads() + Threads.@spawn rand() + end + @test final_running_time == Base.Experimental.task_running_time_ns(t) + @test final_wall_time == Base.Experimental.task_wall_time_ns(t) + finally + Base.Experimental.task_metrics(false) + end + end +end + +@testset "task time counters: lots of spawns" begin + using Dates + try + Base.Experimental.task_metrics(true) + # create more tasks than we have threads. + # - all tasks must have: cpu time <= wall time + # - some tasks must have: cpu time < wall time + # - summing across all tasks we must have: total cpu time <= available cpu time + n_tasks = 2 * Threads.nthreads(:default) + cpu_times = Vector{UInt64}(undef, n_tasks) + wall_times = Vector{UInt64}(undef, n_tasks) + start_time = time_ns() + @sync begin + for i in 1:n_tasks + start_time_i = time_ns() + task_i = Threads.@spawn peakflops() + Threads.@spawn begin + wait(task_i) + end_time_i = time_ns() + wall_time_delta_i = end_time_i - start_time_i + cpu_times[$i] = cpu_time_i = Base.Experimental.task_running_time_ns(task_i) + wall_times[$i] = wall_time_i = Base.Experimental.task_wall_time_ns(task_i) + # task should have recorded some cpu-time and some wall-time + @test cpu_time_i > 0 + @test wall_time_i > 0 + # task cpu-time cannot be greater than its wall-time + @test wall_time_i >= cpu_time_i + # task wall-time must be less than our manually measured wall-time + # between calling `@spawn` and returning from `wait`. + @test wall_time_delta_i > wall_time_i + end + end + end + end_time = time_ns() + wall_time_delta = (end_time - start_time) + available_cpu_time = wall_time_delta * Threads.nthreads(:default) + summed_cpu_time = sum(cpu_times) + # total CPU time from all tasks can't exceed what was actually available. + @test available_cpu_time > summed_cpu_time + # some tasks must have cpu-time less than their wall-time, because we had more tasks + # than threads. + summed_wall_time = sum(wall_times) + @test summed_wall_time > summed_cpu_time + finally + Base.Experimental.task_metrics(false) + end +end + end # main testset From e36910c652af5c101a63936d186e62bf5ee71921 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Fri, 3 Jan 2025 09:29:25 -0300 Subject: [PATCH 096/109] skip heartbeat thread from CPU profile (#201) --- src/julia_internal.h | 1 + src/signals-mach.c | 4 ++++ src/signals-unix.c | 4 ++++ src/threading.c | 2 ++ 4 files changed, 11 insertions(+) diff --git a/src/julia_internal.h b/src/julia_internal.h index 36d25f502cd2a..c747b230818e8 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -220,6 +220,7 @@ extern volatile size_t profile_bt_size_max; extern volatile size_t profile_bt_size_cur; extern volatile int profile_running; extern volatile int profile_all_tasks; +extern int heartbeat_tid; // Mostly used to ensure we skip this thread in the CPU profiler. XXX: not implemented on Windows // Ensures that we can safely read the `live_tasks`field of every TLS when profiling. // We want to avoid the case that a GC gets interleaved with `jl_profile_task` and shrinks // the `live_tasks` array while we are reading it or frees tasks that are being profiled. diff --git a/src/signals-mach.c b/src/signals-mach.c index 9b5d56eaff36c..3f9e4750df08e 100644 --- a/src/signals-mach.c +++ b/src/signals-mach.c @@ -708,6 +708,10 @@ void *mach_profile_listener(void *arg) for (int idx = nthreads; idx-- > 0; ) { // Stop the threads in random order. int i = randperm[idx]; + // skip heartbeat thread + if (i == heartbeat_tid) { + continue; + } jl_profile_thread_mach(i); } } diff --git a/src/signals-unix.c b/src/signals-unix.c index 1a4071a1e79be..f695241b3c4ad 100644 --- a/src/signals-unix.c +++ b/src/signals-unix.c @@ -933,6 +933,10 @@ static void *signal_listener(void *arg) for (int idx = nthreads; idx-- > 0; ) { // Stop the threads in the random order. int i = randperm[idx]; + // skip heartbeat thread + if (i == heartbeat_tid) { + continue; + } // do backtrace for profiler if (profile_running) { jl_profile_thread_unix(i, &signal_context); diff --git a/src/threading.c b/src/threading.c index 5a8ae7825354f..72267e37a36be 100644 --- a/src/threading.c +++ b/src/threading.c @@ -943,6 +943,7 @@ JL_DLLEXPORT int jl_alignment(size_t sz) #include volatile int heartbeat_enabled; +int heartbeat_tid; // Mostly used to ensure we skip this thread in the CPU profiler. XXX: not implemented on Windows uv_thread_t heartbeat_uvtid; uv_sem_t heartbeat_on_sem, // jl_heartbeat_enable -> thread heartbeat_off_sem; // thread -> jl_heartbeat_enable @@ -1130,6 +1131,7 @@ void jl_heartbeat_threadfun(void *arg) jl_adopt_thread(); jl_task_t *ct = jl_current_task; jl_ptls_t ptls = ct->ptls; + heartbeat_tid = ptls->tid; // Don't hold up GC, this thread doesn't participate. uint8_t gc_state = jl_gc_safe_enter(ptls); From 4fdcc11af07e9e4c5880d0654336742ed6fe5f37 Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Mon, 6 Jan 2025 07:09:34 -0500 Subject: [PATCH 097/109] ReentrantLock: wakeup a single task on unlock and add a short spin (#56814) (#200) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I propose a change in the implementation of the `ReentrantLock` to improve its overall throughput for short critical sections and fix the quadratic wake-up behavior where each unlock schedules **all** waiting tasks on the lock's wait queue. This implementation follows the same principles of the `Mutex` in the [parking_lot](https://github.com/Amanieu/parking_lot/tree/master) Rust crate which is based on the Webkit [WTF::ParkingLot](https://webkit.org/blog/6161/locking-in-webkit/) class. Only the basic working principle is implemented here, further improvements such as eventual fairness will be proposed separately. The gist of the change is that we add one extra state to the lock, essentially going from: ``` 0x0 => The lock is not locked 0x1 => The lock is locked by exactly one task. No other task is waiting for it. 0x2 => The lock is locked and some other task tried to lock but failed (conflict) ``` To: ``` ``` In the current implementation we must schedule all tasks to cause a conflict (state 0x2) because on unlock we only notify any task if the lock is in the conflict state. This behavior means that with high contention and a short critical section the tasks will be effectively spinning in the scheduler queue. With the extra state the proposed implementation has enough information to know if there are other tasks to be notified or not, which means we can always notify one task at a time while preserving the optimized path of not notifying if there are no tasks waiting. To improve throughput for short critical sections we also introduce a bounded amount of spinning before attempting to park. Not spinning on the scheduler queue greatly reduces the CPU utilization of the following example: ```julia function example() lock = ReentrantLock() @sync begin for i in 1:10000 Threads.@spawn begin @lock lock begin sleep(0.001) end end end end end @time example() ``` Current: ``` 28.890623 seconds (101.65 k allocations: 7.646 MiB, 0.25% compilation time) ``` ![image](https://github.com/user-attachments/assets/dbd6ce57-c760-4f5a-b68a-27df6a97a46e) Proposed: ``` 22.806669 seconds (101.65 k allocations: 7.814 MiB, 0.35% compilation time) ``` ![image](https://github.com/user-attachments/assets/b0254180-658d-4493-86d3-dea4c500b5ac) In a micro-benchmark where 8 threads contend for a single lock with a very short critical section we see a ~2x improvement. Current: ``` 8-element Vector{Int64}: 6258688 5373952 6651904 6389760 6586368 3899392 5177344 5505024 Total iterations: 45842432 ``` Proposed: ``` 8-element Vector{Int64}: 12320768 12976128 10354688 12845056 7503872 13598720 13860864 11993088 Total iterations: 95453184 ``` ~~In the uncontended scenario the extra bookkeeping causes a 10% throughput reduction:~~ EDIT: I reverted _trylock to the simple case to recover the uncontended throughput and now both implementations are on the same ballpark (without hurting the above numbers). In the uncontended scenario: Current: ``` Total iterations: 236748800 ``` Proposed: ``` Total iterations: 237699072 ``` Closes #56182 Co-authored-by: André Guedes --- base/lock.jl | 126 +++++++++++++++++++++++++++++++++++++++--------- test/threads.jl | 3 +- 2 files changed, 106 insertions(+), 23 deletions(-) diff --git a/base/lock.jl b/base/lock.jl index 1663a765111bb..5a3a654934a75 100644 --- a/base/lock.jl +++ b/base/lock.jl @@ -2,6 +2,14 @@ const ThreadSynchronizer = GenericCondition{Threads.SpinLock} +# This bit is set in the `havelock` of a `ReentrantLock` when that lock is locked by some task. +const LOCKED_BIT = 0b01 +# This bit is set in the `havelock` of a `ReentrantLock` just before parking a task. A task is being +# parked if it wants to lock the lock, but it is currently being held by some other task. +const PARKED_BIT = 0b10 + +const MAX_SPIN_ITERS = 40 + # Advisory reentrant lock """ ReentrantLock() @@ -36,7 +44,28 @@ mutable struct ReentrantLock <: AbstractLock # offset32 = 20, offset64 = 24 reentrancy_cnt::UInt32 # offset32 = 24, offset64 = 28 - @atomic havelock::UInt8 # 0x0 = none, 0x1 = lock, 0x2 = conflict + # + # This atomic integer holds the current state of the lock instance. Only the two lowest bits + # are used. See `LOCKED_BIT` and `PARKED_BIT` for the bitmask for these bits. + # + # # State table: + # + # PARKED_BIT | LOCKED_BIT | Description + # 0 | 0 | The lock is not locked, nor is anyone waiting for it. + # -----------+------------+------------------------------------------------------------------ + # 0 | 1 | The lock is locked by exactly one task. No other task is + # | | waiting for it. + # -----------+------------+------------------------------------------------------------------ + # 1 | 0 | The lock is not locked. One or more tasks are parked. + # -----------+------------+------------------------------------------------------------------ + # 1 | 1 | The lock is locked by exactly one task. One or more tasks are + # | | parked waiting for the lock to become available. + # | | In this state, PARKED_BIT is only ever cleared when the cond_wait lock + # | | is held (i.e. on unlock). This ensures that + # | | we never end up in a situation where there are parked tasks but + # | | PARKED_BIT is not set (which would result in those tasks + # | | potentially never getting woken up). + @atomic havelock::UInt8 # offset32 = 28, offset64 = 32 cond_wait::ThreadSynchronizer # 2 words # offset32 = 36, offset64 = 48 @@ -91,7 +120,7 @@ function islocked end # `ReentrantLock`. function islocked(rl::ReentrantLock) - return (@atomic :monotonic rl.havelock) != 0 + return (@atomic :monotonic rl.havelock) & LOCKED_BIT != 0 end """ @@ -115,7 +144,6 @@ function trylock end @inline function trylock(rl::ReentrantLock) ct = current_task() if rl.locked_by === ct - #@assert rl.havelock !== 0x00 rl.reentrancy_cnt += 0x0000_0001 return true end @@ -123,9 +151,8 @@ function trylock end end @noinline function _trylock(rl::ReentrantLock, ct::Task) GC.disable_finalizers() - if (@atomicreplace :acquire rl.havelock 0x00 => 0x01).success - #@assert rl.locked_by === nothing - #@assert rl.reentrancy_cnt === 0 + state = (@atomic :monotonic rl.havelock) & PARKED_BIT + if (@atomicreplace :acquire rl.havelock state => (state | LOCKED_BIT)).success rl.reentrancy_cnt = 0x0000_0001 @atomic :release rl.locked_by = ct return true @@ -146,23 +173,69 @@ Each `lock` must be matched by an [`unlock`](@ref). @inline function lock(rl::ReentrantLock) trylock(rl) || (@noinline function slowlock(rl::ReentrantLock) c = rl.cond_wait - lock(c.lock) - try - while true - if (@atomicreplace rl.havelock 0x01 => 0x02).old == 0x00 # :sequentially_consistent ? # now either 0x00 or 0x02 - # it was unlocked, so try to lock it ourself - _trylock(rl, current_task()) && break - else # it was locked, so now wait for the release to notify us - wait(c) + ct = current_task() + iteration = 1 + while true + state = @atomic :monotonic rl.havelock + # Grab the lock if it isn't locked, even if there is a queue on it + if state & LOCKED_BIT == 0 + GC.disable_finalizers() + result = (@atomicreplace :acquire :monotonic rl.havelock state => (state | LOCKED_BIT)) + if result.success + rl.reentrancy_cnt = 0x0000_0001 + @atomic :release rl.locked_by = ct + return end + GC.enable_finalizers() + continue end - finally - unlock(c.lock) + + if state & PARKED_BIT == 0 + # If there is no queue, try spinning a few times + if iteration <= MAX_SPIN_ITERS + Base.yield() + iteration += 1 + continue + end + + # If still not locked, try setting the parked bit + @atomicreplace :monotonic :monotonic rl.havelock state => (state | PARKED_BIT) + end + + # lock the `cond_wait` + lock(c.lock) + + # Last check before we wait to make sure `unlock` did not win the race + # to the `cond_wait` lock and cleared the parked bit + state = @atomic :acquire rl.havelock + if state != LOCKED_BIT | PARKED_BIT + unlock(c.lock) + continue + end + + # It was locked, so now wait for the unlock to notify us + wait_no_relock(c) + + # Loop back and try locking again + iteration = 1 end end)(rl) return end +function wait_no_relock(c::GenericCondition) + ct = current_task() + _wait2(c, ct) + token = unlockall(c.lock) + try + return wait() + catch + ct.queue === nothing || list_deletefirst!(ct.queue, ct) + rethrow() + end +end + + """ unlock(lock) @@ -179,18 +252,27 @@ internal counter and return immediately. rl.reentrancy_cnt = n if n == 0x0000_00000 @atomic :monotonic rl.locked_by = nothing - if (@atomicswap :release rl.havelock = 0x00) == 0x02 + result = (@atomicreplace :release :monotonic rl.havelock LOCKED_BIT => 0x00) + if result.success + return true + else (@noinline function notifywaiters(rl) cond_wait = rl.cond_wait lock(cond_wait) - try - notify(cond_wait) - finally - unlock(cond_wait) + + notify(cond_wait, all=false) + if !isempty(cond_wait.waitq) + @atomic :release rl.havelock = PARKED_BIT + else + # We may have won the race to the `cond_wait` lock as a task was about to park + # but we unlock anyway as any parking task will retry + @atomic :release rl.havelock = 0x00 end + + unlock(cond_wait) end)(rl) + return true end - return true end return false end)(rl) && GC.enable_finalizers() diff --git a/test/threads.jl b/test/threads.jl index 14fe94408a050..92e308628c9fb 100644 --- a/test/threads.jl +++ b/test/threads.jl @@ -16,7 +16,8 @@ let lk = ReentrantLock() t2 = @async (notify(c2); trylock(lk)) wait(c1) wait(c2) - @test t1.queue === lk.cond_wait.waitq + # wait for the task to park in the queue (it may be spinning) + @test timedwait(() -> t1.queue === lk.cond_wait.waitq, 1.0) == :ok @test t2.queue !== lk.cond_wait.waitq @test istaskdone(t2) @test !fetch(t2) From d0efc46d439245bb02a0c0fc43ce44569a7b42d0 Mon Sep 17 00:00:00 2001 From: Nathan Daly Date: Fri, 17 Jan 2025 12:59:23 -0700 Subject: [PATCH 098/109] Add try/catch around handle_message() to catch errors during logging. (#57004) (#204) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/JuliaLang/julia/issues/56889. Before this PR, an exception thrown while constructing the objects to log (the `msg`) would be caught and logged. However, an exception thrown while _printing_ the msg to an IO would _not_ be caught, and can abort the program. This breaks the promise that enabling verbose debug logging shouldn't introduce new crashes. After this PR, an exception thrown during handle_message is caught and logged, just like an exception during `msg` construction: ```julia julia> struct Foo end julia> Base.show(::IO, ::Foo) = error("oh no") julia> begin # Unexpectedly, the execption thrown while printing `Foo()` escapes @info Foo() # So we never reach this line! :'( println("~~~~~ ALL DONE ~~~~~~~~") end ┌ Error: Exception while generating log record in module Main at REPL[10]:3 │ exception = │ oh no │ Stacktrace: │ [1] error(s::String) │ @ Base ./error.jl:44 │ [2] show(::IOBuffer, ::Foo) │ @ Main ./REPL[9]:1 ... │ [30] repl_main │ @ ./client.jl:593 [inlined] │ [31] _start() │ @ Base ./client.jl:568 └ @ Main REPL[10]:3 ~~~~~ ALL DONE ~~~~~~~~ ``` This PR respects the change made in https://github.com/JuliaLang/julia/pull/36600 to keep the codegen as small as possible, by putting the new try/catch into a no-inlined function, so that we don't have to introduce a new try/catch in the macro-generated code body. --------- Co-authored-by: Jameson Nash --- base/logging.jl | 14 +++++++++++++- test/corelogging.jl | 13 +++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/base/logging.jl b/base/logging.jl index 96c133a239cc0..1bd5a7fbefa8b 100644 --- a/base/logging.jl +++ b/base/logging.jl @@ -398,7 +398,7 @@ function logmsg_code(_module, file, line, level, message, exs...) end line = $(log_data._line) local msg, kwargs - $(logrecord) && invokelatest($handle_message, + $(logrecord) && $handle_message_nothrow( logger, level, msg, _module, group, id, file, line; kwargs...) end @@ -409,6 +409,18 @@ function logmsg_code(_module, file, line, level, message, exs...) end end +@noinline function handle_message_nothrow(logger, level, msg, _module, group, id, file, line; kwargs...) + @nospecialize + try + @invokelatest handle_message( + logger, level, msg, _module, group, id, file, line; + kwargs...) + + catch err + @invokelatest logging_error(logger, level, _module, group, id, file, line, err, true) + end +end + function process_logmsg_exs(_orig_module, _file, _line, level, message, exs...) @nospecialize local _group, _id diff --git a/test/corelogging.jl b/test/corelogging.jl index 9626f48e4b407..d373b9d591190 100644 --- a/test/corelogging.jl +++ b/test/corelogging.jl @@ -114,6 +114,19 @@ end @test only(collect_test_logs(logmsg)[1]).kwargs[:x] === "the y" end end +@testset "Log message handle_message exception handling" begin + # Exceptions in log handling (printing) of msg are caught by default. + struct Foo end + Base.show(::IO, ::Foo) = 1 ÷ 0 + + # We cannot use `@test_logs` here, since test_logs does not actually _print_ the message + # (i.e. it does not invoke handle_message). To test exception handling during printing, + # we have to use `@test_warn` to see what was printed. + @test_warn r"Error: Exception while generating log record in module .*DivideError: integer division error"s @info Foo() + + # Exceptions in log handling (printing) of attributes are caught by default + @test_warn r"Error: Exception while generating log record in module .*DivideError: integer division error"s @info "foo" x=Foo() +end @testset "Special keywords" begin logger = TestLogger() From 25fb6f8e23ea3207b7f70119f77899e8c780246b Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Mon, 27 Jan 2025 09:40:39 -0500 Subject: [PATCH 099/109] Add `Experimental.wait_with_timeout` (#57148) (#207) --------- Co-authored-by: Jameson Nash Co-authored-by: Nick Robinson --- base/experimental.jl | 109 +++++++++++++++++++++++++++++++++++++++++++ test/channels.jl | 15 ++++++ 2 files changed, 124 insertions(+) diff --git a/base/experimental.jl b/base/experimental.jl index d876662ab048c..72518010edf59 100644 --- a/base/experimental.jl +++ b/base/experimental.jl @@ -10,6 +10,7 @@ module Experimental using Base: Threads, sync_varname +using Base: GenericCondition using Base.Meta """ @@ -442,4 +443,112 @@ function task_wall_time_ns(t::Task=current_task()) return end_at - start_at end +# wait_with_timeout +# +# A version of `wait(c::Condition)` that additionally allows the +# specification of a timeout. This is experimental as it will likely +# be dropped when a cancellation framework is added. +# +# The parallel behavior of wait_with_timeout is specified here. There +# are three concurrent entities that can interact: +# 1. Task W: the task that calls wait_with_timeout. +# 2. Task T: the task created to handle a timeout. +# 3. Task N: the task that notifies the Condition being waited on. +# +# Typical flow: +# - W enters the Condition's wait queue. +# - W creates T and stops running (calls wait()). +# - T, when scheduled, waits on a Timer. +# - Two common outcomes: +# - N notifies the Condition. +# - W starts running, closes the Timer, sets waiter_left and returns +# the notify'ed value. +# - The closed Timer throws an EOFError to T which simply ends. +# - The Timer expires. +# - T starts running and locks the Condition. +# - T confirms that waiter_left is unset and that W is still in the +# Condition's wait queue; it then removes W from the wait queue, +# sets dosched to true and unlocks the Condition. +# - If dosched is true, T schedules W with the special :timed_out +# value. +# - T ends. +# - W runs and returns :timed_out. +# +# Some possible interleavings: +# - N notifies the Condition but the Timer expires and T starts running +# before W: +# - W closing the expired Timer is benign. +# - T will find that W is no longer in the Condition's wait queue +# (which is protected by a lock) and will not schedule W. +# - N notifies the Condition; W runs and calls wait on the Condition +# again before the Timer expires: +# - W sets waiter_left before leaving. When T runs, it will find that +# waiter_left is set and will not schedule W. +# +# The lock on the Condition's wait queue and waiter_left together +# ensure proper synchronization and behavior of the tasks involved. + +""" + wait_with_timeout(c::GenericCondition; first::Bool=false, timeout::Real=0.0) + +Wait for [`notify`](@ref) on `c` and return the `val` parameter passed to `notify`. + +If the keyword `first` is set to `true`, the waiter will be put _first_ +in line to wake up on `notify`. Otherwise, `wait` has first-in-first-out (FIFO) behavior. + +If `timeout` is specified, cancel the `wait` when it expires and return +`:timed_out`. The minimum value for `timeout` is 0.001 seconds, i.e. 1 +millisecond. +""" +function wait_with_timeout(c::GenericCondition; first::Bool=false, timeout::Real=0.0) + ct = current_task() + Base._wait2(c, ct, first) + token = Base.unlockall(c.lock) + + timer::Union{Timer, Nothing} = nothing + waiter_left::Union{Threads.Atomic{Bool}, Nothing} = nothing + if timeout > 0.0 + timer = Timer(timeout) + waiter_left = Threads.Atomic{Bool}(false) + # start a task to wait on the timer + t = Task() do + try + wait(timer) + catch e + # if the timer was closed, the waiting task has been scheduled; do nothing + e isa EOFError && return + end + dosched = false + lock(c.lock) + # Confirm that the waiting task is still in the wait queue and remove it. If + # the task is not in the wait queue, it must have been notified already so we + # don't do anything here. + if !waiter_left[] && ct.queue == c.waitq + dosched = true + Base.list_deletefirst!(c.waitq, ct) + end + unlock(c.lock) + # send the waiting task a timeout + dosched && schedule(ct, :timed_out) + end + t.sticky = false + Threads._spawn_set_thrpool(t, :interactive) + schedule(t) + end + + try + res = wait() + if timer !== nothing + close(timer) + waiter_left[] = true + end + return res + catch + q = ct.queue; q === nothing || Base.list_deletefirst!(q::IntrusiveLinkedList{Task}, ct) + rethrow() + finally + Base.relockall(c.lock, token) + end +end + end # module diff --git a/test/channels.jl b/test/channels.jl index 82689e8d08d28..cb23b457b8da5 100644 --- a/test/channels.jl +++ b/test/channels.jl @@ -36,6 +36,21 @@ end @test fetch(t) == "finished" end +@testset "wait_with_timeout on Condition" begin + a = Threads.Condition() + @test @lock a Experimental.wait_with_timeout(a; timeout=0.1)==:timed_out + lock(a) + @spawn begin + @lock a notify(a) + end + @test try + Experimental.wait_with_timeout(a; timeout=2) + true + finally + unlock(a) + end +end + @testset "various constructors" begin c = Channel() @test eltype(c) == Any From 1fff8cc78d3a7ca3ad0fcfc7f9c2b6347a83790e Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Sun, 2 Feb 2025 18:47:35 -0300 Subject: [PATCH 100/109] add option to dump backtrace of stop-the-world straggler (#57045) (#208) This is still a work in progress, but it should help determine what a straggler thread was doing during the stop-the-world phase and why it failed to reach a safepoint in a timely manner. We've encountered long TTSP issues in production, and this tool should provide a valuable means to accurately diagnose them. --- base/options.jl | 1 + src/gc.c | 16 +++++++++++++++- src/jloptions.c | 12 ++++++++++++ src/jloptions.h | 1 + src/julia_internal.h | 2 ++ src/stackwalk.c | 20 ++++++++++++++++++++ test/cmdlineargs.jl | 6 ++++++ test/threads_exec.jl | 25 +++++++++++++++++++++++++ 8 files changed, 82 insertions(+), 1 deletion(-) diff --git a/base/options.jl b/base/options.jl index 2e779c964e7fd..1a52bf1a4e2ef 100644 --- a/base/options.jl +++ b/base/options.jl @@ -61,6 +61,7 @@ struct JLOptions trace_compile_timing::Int8 safe_crash_log_file::Ptr{UInt8} task_metrics::Int8 + timeout_for_safepoint_straggler_s::Int16 end # This runs early in the sysimage != is not defined yet diff --git a/src/gc.c b/src/gc.c index 12d312dea1fb2..1c8821a92befb 100644 --- a/src/gc.c +++ b/src/gc.c @@ -245,8 +245,22 @@ void jl_gc_wait_for_the_world(jl_ptls_t* gc_all_tls_states, int gc_n_threads) // We're currently also using atomic store release in mutator threads // (in jl_gc_state_set), but we may want to use signals to flush the // memory operations on those threads lazily instead. - while (!jl_atomic_load_relaxed(&ptls2->gc_state) || !jl_atomic_load_acquire(&ptls2->gc_state)) + const int64_t timeout = jl_options.timeout_for_safepoint_straggler_s * 1000000000; // convert to nanoseconds + uint64_t t0 = jl_hrtime(); + while (!jl_atomic_load_relaxed(&ptls2->gc_state) || !jl_atomic_load_acquire(&ptls2->gc_state)) { jl_cpu_pause(); // yield? + if ((jl_hrtime() - t0) > timeout) { + jl_safe_printf("===== Thread %d failed to reach safepoint after %d seconds, printing backtrace below =====\n", ptls2->tid + 1, jl_options.timeout_for_safepoint_straggler_s); + // Try to record the backtrace of the straggler using `jl_try_record_thread_backtrace` + jl_ptls_t ptls = jl_current_task->ptls; + size_t bt_size = jl_try_record_thread_backtrace(ptls2, ptls->bt_data, JL_MAX_BT_SIZE); + // Print the backtrace of the straggler + for (size_t i = 0; i < bt_size; i += jl_bt_entry_size(ptls->bt_data + i)) { + jl_print_bt_entry_codeloc(-1, ptls->bt_data + i); + } + t0 = jl_hrtime(); + } + } } } } diff --git a/src/jloptions.c b/src/jloptions.c index 364c37cebcb6d..157634bbcce4e 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -94,6 +94,7 @@ JL_DLLEXPORT void jl_init_options(void) 0, // trace_compile_timing NULL, // safe_crash_log_file 0, // task_metrics + -1, // timeout_for_safepoint_straggler_s }; jl_options_initialized = 1; } @@ -214,6 +215,8 @@ static const char opts_hidden[] = " --output-asm Generate an assembly file (.s)\n" " --output-incremental={yes|no*} Generate an incremental output file (rather than\n" " complete)\n" + " --timeout-for-safepoint-straggler If this value is set, then we will dump the backtrace for a thread\n" + " that fails to reach a safepoint within the specified time\n" " --trace-compile={stderr|name} Print precompile statements for methods compiled\n" " during execution or save to stderr or a path. Methods that\n" " were recompiled are printed in yellow or with a trailing\n" @@ -242,6 +245,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) opt_warn_scope, opt_inline, opt_polly, + opt_timeout_for_safepoint_straggler, opt_trace_compile, opt_trace_compile_timing, opt_trace_dispatch, @@ -321,6 +325,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) { "warn-scope", required_argument, 0, opt_warn_scope }, { "inline", required_argument, 0, opt_inline }, { "polly", required_argument, 0, opt_polly }, + { "timeout-for-safepoint-straggler", required_argument, 0, opt_timeout_for_safepoint_straggler }, { "trace-compile", required_argument, 0, opt_trace_compile }, { "trace-compile-timing", no_argument, 0, opt_trace_compile_timing }, { "trace-dispatch", required_argument, 0, opt_trace_dispatch }, @@ -881,6 +886,13 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) if (jl_options.safe_crash_log_file == NULL) jl_error("julia: failed to allocate memory for --safe-crash-log-file"); break; + case opt_timeout_for_safepoint_straggler: + errno = 0; + long timeout = strtol(optarg, &endptr, 10); + if (errno != 0 || optarg == endptr || timeout < 1 || timeout > INT16_MAX) + jl_errorf("julia: --timeout-for-safepoint-straggler=; seconds must be an integer between 1 and %d", INT16_MAX); + jl_options.timeout_for_safepoint_straggler_s = (int16_t)timeout; + break; case opt_task_metrics: if (!strcmp(optarg, "no")) jl_options.task_metrics = JL_OPTIONS_TASK_METRICS_OFF; diff --git a/src/jloptions.h b/src/jloptions.h index d9cf96e82f2a4..da1791a6b936c 100644 --- a/src/jloptions.h +++ b/src/jloptions.h @@ -65,6 +65,7 @@ typedef struct { int8_t trace_compile_timing; const char *safe_crash_log_file; int8_t task_metrics; + int16_t timeout_for_safepoint_straggler_s; } jl_options_t; #endif diff --git a/src/julia_internal.h b/src/julia_internal.h index c747b230818e8..12fff658cf23a 100644 --- a/src/julia_internal.h +++ b/src/julia_internal.h @@ -213,6 +213,8 @@ typedef struct { size_t bt_size; int tid; } jl_record_backtrace_result_t; +JL_DLLEXPORT JL_DLLEXPORT size_t jl_try_record_thread_backtrace(jl_ptls_t ptls2, struct _jl_bt_element_t *bt_data, + size_t max_bt_size) JL_NOTSAFEPOINT; JL_DLLEXPORT jl_record_backtrace_result_t jl_record_backtrace(jl_task_t *t, struct _jl_bt_element_t *bt_data, size_t max_bt_size, int all_tasks_profiler) JL_NOTSAFEPOINT; extern volatile struct _jl_bt_element_t *profile_bt_data_prof; diff --git a/src/stackwalk.c b/src/stackwalk.c index ccf73d5b5cdd7..d16c2640149f7 100644 --- a/src/stackwalk.c +++ b/src/stackwalk.c @@ -889,6 +889,26 @@ _os_ptr_munge(uintptr_t ptr) extern bt_context_t *jl_to_bt_context(void *sigctx); +JL_DLLEXPORT size_t jl_try_record_thread_backtrace(jl_ptls_t ptls2, jl_bt_element_t *bt_data, size_t max_bt_size) JL_NOTSAFEPOINT +{ + int16_t tid = ptls2->tid; + jl_task_t *t = NULL; + bt_context_t *context = NULL; + bt_context_t c; + int lockret = jl_lock_stackwalk(); + if (!jl_thread_suspend_and_get_state(tid, 0, &c)) { + jl_unlock_stackwalk(lockret); + return 0; + } + jl_unlock_stackwalk(lockret); + // thread is stopped, safe to read the task it was running before we stopped it + t = jl_atomic_load_relaxed(&ptls2->current_task); + context = &c; + size_t bt_size = rec_backtrace_ctx(bt_data, max_bt_size, context, ptls2->previous_task ? NULL : t->gcstack); + jl_thread_resume(tid); + return bt_size; +} + JL_DLLEXPORT jl_record_backtrace_result_t jl_record_backtrace(jl_task_t *t, jl_bt_element_t *bt_data, size_t max_bt_size, int all_tasks_profiler) JL_NOTSAFEPOINT { int16_t tid = INT16_MAX; diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index 3597d99eb6d96..4fe5ef16eb2ff 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -1126,3 +1126,9 @@ end #heap-size-hint, we reserve 250 MB for non GC memory (llvm, etc.) @test readchomp(`$(Base.julia_cmd()) --startup-file=no --heap-size-hint=500M -e "println(@ccall jl_gc_get_max_memory()::UInt64)"`) == "$((500-250)*1024*1024)" end + +@testset "--timeout-for-safepoint-straggler" begin + exename = `$(Base.julia_cmd())` + timeout = 120 + @test parse(Int,read(`$exename --timeout-for-safepoint-straggler=$timeout -E "Base.JLOptions().timeout_for_safepoint_straggler_s"`, String)) == timeout +end diff --git a/test/threads_exec.jl b/test/threads_exec.jl index 6fbad062901cf..dac0c1846cca5 100644 --- a/test/threads_exec.jl +++ b/test/threads_exec.jl @@ -1313,4 +1313,29 @@ end end end +@testset "--timeout-for-safepoint-straggler command-line flag" begin + program = " + function main() + t = Threads.@spawn begin + ccall(:uv_sleep, Cvoid, (Cuint,), 5000) + end + # Force a GC + ccall(:uv_sleep, Cvoid, (Cuint,), 1000) + GC.gc() + wait(t) + end + main() + " + tmp_output_filename = tempname() + tmp_output_file = open(tmp_output_filename, "w") + if isnothing(tmp_output_file) + error("Failed to open file $tmp_output_filename") + end + run(pipeline(`$(Base.julia_cmd()) --threads=4 --timeout-for-safepoint-straggler=1 -e $program`, stderr=tmp_output_file)) + # Check whether we printed the straggler's backtrace + @test !isempty(read(tmp_output_filename, String)) + close(tmp_output_file) + rm(tmp_output_filename) +end + end # main testset From b37edae5df399e293947630f7692b1ec09b680ba Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Tue, 4 Feb 2025 14:17:55 -0500 Subject: [PATCH 101/109] Add timing when `PRECOMPILE_TRACE_COMPILE` is set (#57251) (#209) --- base/loading.jl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/base/loading.jl b/base/loading.jl index c1972907b02bb..35cae55eb4ac2 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -2273,7 +2273,11 @@ function create_expr_cache(pkg::PkgId, input::String, output::String, output_o:: deps_eltype = sprint(show, eltype(concrete_deps); context = :module=>nothing) deps = deps_eltype * "[" * join(deps_strs, ",") * "]" - trace = isassigned(PRECOMPILE_TRACE_COMPILE) ? `--trace-compile=$(PRECOMPILE_TRACE_COMPILE[])` : `` + trace = if isassigned(PRECOMPILE_TRACE_COMPILE) + `--trace-compile=$(PRECOMPILE_TRACE_COMPILE[]) --trace-compile-timing` + else + `` + end io = open(pipeline(addenv(`$(julia_cmd(;cpu_target)::Cmd) $(opts) --startup-file=no --history-file=no --warn-overwrite=yes --color=$(have_color === nothing ? "auto" : have_color ? "yes" : "no") From 94ace4c4ba5be8ff295a9024ebd96ce08039948f Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Tue, 4 Feb 2025 17:34:21 -0300 Subject: [PATCH 102/109] introduce safepoint_waiter (#210) --- src/gc.c | 10 ++++++++++ src/jl_uv.c | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/gc.c b/src/gc.c index 1c8821a92befb..edcdcefdcaf7a 100644 --- a/src/gc.c +++ b/src/gc.c @@ -226,6 +226,14 @@ NOINLINE uintptr_t gc_get_stack_ptr(void) #define should_timeout() 0 +uv_thread_t safepoint_waiter; + +int jl_inside_waiting_for_the_world(void) +{ + uv_thread_t self = uv_thread_self(); + return uv_thread_equal(&safepoint_waiter, &self); +} + void jl_gc_wait_for_the_world(jl_ptls_t* gc_all_tls_states, int gc_n_threads) { JL_TIMING(GC, GC_Stop); @@ -234,6 +242,7 @@ void jl_gc_wait_for_the_world(jl_ptls_t* gc_all_tls_states, int gc_n_threads) TracyCZoneColor(ctx, 0x696969); #endif assert(gc_n_threads); + safepoint_waiter = uv_thread_self(); if (gc_n_threads > 1) jl_wake_libuv(); for (int i = 0; i < gc_n_threads; i++) { @@ -263,6 +272,7 @@ void jl_gc_wait_for_the_world(jl_ptls_t* gc_all_tls_states, int gc_n_threads) } } } + memset(&safepoint_waiter, 0, sizeof(safepoint_waiter)); } // malloc wrappers, aligned allocation diff --git a/src/jl_uv.c b/src/jl_uv.c index fd8718ebbea26..385edaed04bb0 100644 --- a/src/jl_uv.c +++ b/src/jl_uv.c @@ -754,6 +754,7 @@ STATIC_INLINE void write_to_safe_crash_log(char *buf) JL_NOTSAFEPOINT } extern int jl_inside_heartbeat_thread(void); +extern int jl_inside_waiting_for_the_world(void); JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...) { @@ -774,7 +775,7 @@ JL_DLLEXPORT void jl_safe_printf(const char *fmt, ...) // order is important here: we want to ensure that the threading infra // has been initialized before we start trying to print to the // safe crash log file - if (jl_sig_fd != 0 && (jl_inside_signal_handler() || jl_inside_heartbeat_thread())) { + if (jl_sig_fd != 0 && (jl_inside_signal_handler() || jl_inside_heartbeat_thread() || jl_inside_waiting_for_the_world())) { write_to_safe_crash_log(buf); } if (write(STDERR_FILENO, buf, strlen(buf)) < 0) { From 9dcccc47bfbbb217fc0e8c47966d235e3bcf1a5c Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Tue, 4 Feb 2025 15:36:00 -0500 Subject: [PATCH 103/109] Use `uv_thread_equal` to compare thread IDs (#211) And not `==`. --- src/threading.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/threading.c b/src/threading.c index 72267e37a36be..1478d233e3a38 100644 --- a/src/threading.c +++ b/src/threading.c @@ -969,7 +969,7 @@ void jl_init_heartbeat(void) int jl_inside_heartbeat_thread(void) { uv_thread_t curr_uvtid = uv_thread_self(); - return curr_uvtid == heartbeat_uvtid; + return uv_thread_equal(&curr_uvtid, &heartbeat_uvtid); } // enable/disable heartbeats From 377f91713dba05617491301d81c12ac189ca132b Mon Sep 17 00:00:00 2001 From: Babis Nikolaou Date: Mon, 10 Feb 2025 20:09:15 +0000 Subject: [PATCH 104/109] Use task stacks of size 8MB (up from 4MB) (#213) --- src/options.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/options.h b/src/options.h index 285f849eee216..71c803b67bf10 100644 --- a/src/options.h +++ b/src/options.h @@ -110,7 +110,7 @@ #if defined(_COMPILER_ASAN_ENABLED_) || defined(_COMPILER_MSAN_ENABLED_) #define JL_STACK_SIZE (64*1024*1024) #elif defined(_P64) -#define JL_STACK_SIZE (4*1024*1024) +#define JL_STACK_SIZE (8*1024*1024) #else #define JL_STACK_SIZE (2*1024*1024) #endif From 40320928e18a6a3a3cc923621c2dce4739207c63 Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Tue, 18 Feb 2025 15:25:03 -0500 Subject: [PATCH 105/109] Add exit code to `Base.compilecache` error message (#57455) (#215) Minor tweak to the error message: embed the exit code of the Julia child process that failed to compile the package. --- base/loading.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/loading.jl b/base/loading.jl index 35cae55eb4ac2..f1da2ecd41e86 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -2477,7 +2477,7 @@ function compilecache(pkg::PkgId, path::String, internal_stderr::IO = stderr, in if p.exitcode == 125 return PrecompilableError() else - error("Failed to precompile $pkg to $(repr(tmppath)).") + error("Failed to precompile $(repr("text/plain", pkg)) to $(repr(tmppath)) (exit code $(p.exitcode)).") end end From 827c19faffaf290745a51c35f1313f0f553a77eb Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Thu, 20 Feb 2025 10:15:58 -0500 Subject: [PATCH 106/109] Use `Base.process_status(p)` instead of `p.exitcode` in error message (#57460) (#217) Fixup https://github.com/JuliaLang/julia/pull/57455 --- base/loading.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/loading.jl b/base/loading.jl index f1da2ecd41e86..e90cb67937ec6 100644 --- a/base/loading.jl +++ b/base/loading.jl @@ -2477,7 +2477,7 @@ function compilecache(pkg::PkgId, path::String, internal_stderr::IO = stderr, in if p.exitcode == 125 return PrecompilableError() else - error("Failed to precompile $(repr("text/plain", pkg)) to $(repr(tmppath)) (exit code $(p.exitcode)).") + error("Failed to precompile $(repr("text/plain", pkg)) to $(repr(tmppath)) ($(Base.process_status(p))).") end end From a85728eb4242be5bb831bf08b483960a20da74eb Mon Sep 17 00:00:00 2001 From: Kiran Pamnany Date: Tue, 25 Feb 2025 10:53:20 -0500 Subject: [PATCH 107/109] Backport inference fixes (#216) * inference: avoid inferring unreachable code methods (#51317) (cherry picked from commit 0a82b71681028d6b1a49d580496f28ebc214a21e) * inference: ensure inferring reachable code methods (#57088) PR #51317 was a bit over-eager about inferring inferring unreachable code methods. Filter out the Vararg case, since that can be handled by simply removing it instead of discarding the whole call. Fixes #56628 (cherry picked from commit eb9f24c8ceb964464939775e164366939755393c) --------- Co-authored-by: Jameson Nash --- base/compiler/abstractinterpretation.jl | 59 +++++++----- base/compiler/abstractlattice.jl | 8 +- base/compiler/optimize.jl | 2 +- base/compiler/ssair/inlining.jl | 7 +- base/compiler/ssair/passes.jl | 2 +- base/compiler/tfuncs.jl | 121 +++++++++++++----------- base/compiler/typelattice.jl | 4 +- base/compiler/typeutils.jl | 24 +++-- test/compiler/inference.jl | 27 ++++++ test/compiler/inline.jl | 27 ------ 10 files changed, 158 insertions(+), 123 deletions(-) diff --git a/base/compiler/abstractinterpretation.jl b/base/compiler/abstractinterpretation.jl index ab1d8c7c570f9..a7b2953895741 100644 --- a/base/compiler/abstractinterpretation.jl +++ b/base/compiler/abstractinterpretation.jl @@ -243,6 +243,7 @@ function find_matching_methods(𝕃::AbstractLattice, for i in 1:length(split_argtypes) arg_n = split_argtypes[i]::Vector{Any} sig_n = argtypes_to_type(arg_n) + sig_n === Bottom && continue mt = ccall(:jl_method_table_for, Any, (Any,), sig_n) mt === nothing && return FailedMethodMatch("Could not identify method table for call") mt = mt::MethodTable @@ -506,7 +507,10 @@ function abstract_call_method(interp::AbstractInterpreter, return MethodCallResult(Any, false, false, nothing, Effects()) end sigtuple = unwrap_unionall(sig) - sigtuple isa DataType || return MethodCallResult(Any, false, false, nothing, Effects()) + sigtuple isa DataType || + return MethodCallResult(Any, false, false, nothing, Effects()) + all(@nospecialize(x) -> isvarargtype(x) || valid_as_lattice(x, true), sigtuple.parameters) || + return MethodCallResult(Union{}, false, false, nothing, EFFECTS_THROWS) # catch bad type intersections early if is_nospecializeinfer(method) sig = get_nospecializeinfer_sig(method, sig, sparams) @@ -1385,25 +1389,35 @@ function precise_container_type(interp::AbstractInterpreter, @nospecialize(itft) end if isa(tti, Union) utis = uniontypes(tti) - if any(@nospecialize(t) -> !isa(t, DataType) || !(t <: Tuple) || !isknownlength(t), utis) - return AbstractIterationResult(Any[Vararg{Any}], nothing, Effects()) - end - ltp = length((utis[1]::DataType).parameters) - for t in utis - if length((t::DataType).parameters) != ltp - return AbstractIterationResult(Any[Vararg{Any}], nothing) + # refine the Union to remove elements that are not valid tags for objects + filter!(@nospecialize(x) -> valid_as_lattice(x, true), utis) + if length(utis) == 0 + return AbstractIterationResult(Any[], nothing) # oops, this statement was actually unreachable + elseif length(utis) == 1 + tti = utis[1] + tti0 = rewrap_unionall(tti, tti0) + else + if any(@nospecialize(t) -> !isa(t, DataType) || !(t <: Tuple) || !isknownlength(t), utis) + return AbstractIterationResult(Any[Vararg{Any}], nothing, Effects()) end - end - result = Any[ Union{} for _ in 1:ltp ] - for t in utis - tps = (t::DataType).parameters - _all(valid_as_lattice, tps) || continue - for j in 1:ltp - result[j] = tmerge(result[j], rewrap_unionall(tps[j], tti0)) + ltp = length((utis[1]::DataType).parameters) + for t in utis + if length((t::DataType).parameters) != ltp + return AbstractIterationResult(Any[Vararg{Any}], nothing) + end + end + result = Any[ Union{} for _ in 1:ltp ] + for t in utis + tps = (t::DataType).parameters + for j in 1:ltp + @assert valid_as_lattice(tps[j], true) + result[j] = tmerge(result[j], rewrap_unionall(tps[j], tti0)) + end end + return AbstractIterationResult(result, nothing) end - return AbstractIterationResult(result, nothing) - elseif tti0 <: Tuple + end + if tti0 <: Tuple if isa(tti0, DataType) return AbstractIterationResult(Any[ p for p in tti0.parameters ], nothing) elseif !isa(tti, DataType) @@ -1667,7 +1681,7 @@ end return isa_condition(xt, ty, max_union_splitting) end @inline function isa_condition(@nospecialize(xt), @nospecialize(ty), max_union_splitting::Int) - tty_ub, isexact_tty = instanceof_tfunc(ty) + tty_ub, isexact_tty = instanceof_tfunc(ty, true) tty = widenconst(xt) if isexact_tty && !isa(tty_ub, TypeVar) tty_lb = tty_ub # TODO: this would be wrong if !isexact_tty, but instanceof_tfunc doesn't preserve this info @@ -1677,7 +1691,7 @@ end # `typeintersect` may be unable narrow down `Type`-type thentype = tty_ub end - valid_as_lattice(thentype) || (thentype = Bottom) + valid_as_lattice(thentype, true) || (thentype = Bottom) elsetype = typesubtract(tty, tty_lb, max_union_splitting) return ConditionalTypes(thentype, elsetype) end @@ -1923,7 +1937,7 @@ function abstract_invoke(interp::AbstractInterpreter, (; fargs, argtypes)::ArgIn ft′ = argtype_by_index(argtypes, 2) ft = widenconst(ft′) ft === Bottom && return CallMeta(Bottom, EFFECTS_THROWS, NoCallInfo()) - (types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, 3)) + (types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, 3), false) isexact || return CallMeta(Any, Effects(), NoCallInfo()) unwrapped = unwrap_unionall(types) if types === Bottom || !(unwrapped isa DataType) || unwrapped.name !== Tuple.name @@ -2153,6 +2167,7 @@ function abstract_call_unknown(interp::AbstractInterpreter, @nospecialize(ft), end # non-constant function, but the number of arguments is known and the `f` is not a builtin or intrinsic atype = argtypes_to_type(arginfo.argtypes) + atype === Bottom && return CallMeta(Union{}, Union{}, EFFECTS_THROWS, NoCallInfo()) # accidentally unreachable return abstract_call_gf_by_type(interp, nothing, arginfo, si, atype, sv, max_methods) end @@ -2380,7 +2395,7 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp (; rt, effects) = abstract_eval_call(interp, e, vtypes, sv) t = rt elseif ehead === :new - t, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv)) + t, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv), true) ut = unwrap_unionall(t) consistent = ALWAYS_FALSE nothrow = false @@ -2444,7 +2459,7 @@ function abstract_eval_statement_expr(interp::AbstractInterpreter, e::Expr, vtyp end effects = Effects(EFFECTS_TOTAL; consistent, nothrow) elseif ehead === :splatnew - t, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv)) + t, isexact = instanceof_tfunc(abstract_eval_value(interp, e.args[1], vtypes, sv), true) nothrow = false # TODO: More precision if length(e.args) == 2 && isconcretedispatch(t) && !ismutabletype(t) at = abstract_eval_value(interp, e.args[2], vtypes, sv) diff --git a/base/compiler/abstractlattice.jl b/base/compiler/abstractlattice.jl index 3c6c874a9a09c..42c7579698b21 100644 --- a/base/compiler/abstractlattice.jl +++ b/base/compiler/abstractlattice.jl @@ -98,8 +98,10 @@ is_valid_lattice_norec(::InferenceLattice, @nospecialize(elem)) = isa(elem, Limi """ tmeet(𝕃::AbstractLattice, a, b::Type) -Compute the lattice meet of lattice elements `a` and `b` over the lattice `𝕃`. -If `𝕃` is `JLTypeLattice`, this is equivalent to type intersection. +Compute the lattice meet of lattice elements `a` and `b` over the lattice `𝕃`, +dropping any results that will not be inhabited at runtime. +If `𝕃` is `JLTypeLattice`, this is equivalent to type intersection plus the +elimination of results that have no concrete subtypes. Note that currently `b` is restricted to being a type (interpreted as a lattice element in the `JLTypeLattice` sub-lattice of `𝕃`). """ @@ -107,7 +109,7 @@ function tmeet end function tmeet(::JLTypeLattice, @nospecialize(a::Type), @nospecialize(b::Type)) ti = typeintersect(a, b) - valid_as_lattice(ti) || return Bottom + valid_as_lattice(ti, true) || return Bottom return ti end diff --git a/base/compiler/optimize.jl b/base/compiler/optimize.jl index 7c8413ceaf9af..e6e14bbad58d6 100644 --- a/base/compiler/optimize.jl +++ b/base/compiler/optimize.jl @@ -305,7 +305,7 @@ function stmt_effect_flags(𝕃ₒ::AbstractLattice, @nospecialize(stmt), @nospe elseif head === :new_opaque_closure length(args) < 4 && return (false, false, false) typ = argextype(args[1], src) - typ, isexact = instanceof_tfunc(typ) + typ, isexact = instanceof_tfunc(typ, true) isexact || return (false, false, false) ⊑(𝕃ₒ, typ, Tuple) || return (false, false, false) rt_lb = argextype(args[2], src) diff --git a/base/compiler/ssair/inlining.jl b/base/compiler/ssair/inlining.jl index 75e63f5c6b2e4..1302d81e23427 100644 --- a/base/compiler/ssair/inlining.jl +++ b/base/compiler/ssair/inlining.jl @@ -1202,7 +1202,7 @@ function handle_invoke_call!(todo::Vector{Pair{Int,Any}}, end function invoke_signature(argtypes::Vector{Any}) - ft, argtyps = widenconst(argtypes[2]), instanceof_tfunc(widenconst(argtypes[3]))[1] + ft, argtyps = widenconst(argtypes[2]), instanceof_tfunc(widenconst(argtypes[3]), false)[1] return rewrap_unionall(Tuple{ft, unwrap_unionall(argtyps).parameters...}, argtyps) end @@ -1450,8 +1450,9 @@ function handle_call!(todo::Vector{Pair{Int,Any}}, cases = compute_inlining_cases(info, flag, sig, state) cases === nothing && return nothing cases, all_covered, joint_effects = cases - handle_cases!(todo, ir, idx, stmt, argtypes_to_type(sig.argtypes), cases, - all_covered, joint_effects) + atype = argtypes_to_type(sig.argtypes) + atype === Union{} && return nothing # accidentally actually unreachable + handle_cases!(todo, ir, idx, stmt, atype, cases, all_covered, joint_effects) end function handle_match!(cases::Vector{InliningCase}, diff --git a/base/compiler/ssair/passes.jl b/base/compiler/ssair/passes.jl index 39f1445d8c02d..8998bbbd284b5 100644 --- a/base/compiler/ssair/passes.jl +++ b/base/compiler/ssair/passes.jl @@ -1704,7 +1704,7 @@ function adce_pass!(ir::IRCode, inlining::Union{Nothing,InliningState}=nothing) else if is_known_call(stmt, typeassert, compact) && length(stmt.args) == 3 # nullify safe `typeassert` calls - ty, isexact = instanceof_tfunc(argextype(stmt.args[3], compact)) + ty, isexact = instanceof_tfunc(argextype(stmt.args[3], compact), true) if isexact && ⊑(𝕃ₒ, argextype(stmt.args[2], compact), ty) compact[idx] = nothing continue diff --git a/base/compiler/tfuncs.jl b/base/compiler/tfuncs.jl index 24b4c00250b80..b79c37ce7122c 100644 --- a/base/compiler/tfuncs.jl +++ b/base/compiler/tfuncs.jl @@ -95,9 +95,9 @@ add_tfunc(throw, 1, 1, @nospecs((𝕃::AbstractLattice, x)->Bottom), 0) # if isexact is false, the actual runtime type may (will) be a subtype of t # if isconcrete is true, the actual runtime type is definitely concrete (unreachable if not valid as a typeof) # if istype is true, the actual runtime value will definitely be a type (e.g. this is false for Union{Type{Int}, Int}) -function instanceof_tfunc(@nospecialize(t), @nospecialize(troot) = t) +function instanceof_tfunc(@nospecialize(t), astag::Bool=false, @nospecialize(troot) = t) if isa(t, Const) - if isa(t.val, Type) && valid_as_lattice(t.val) + if isa(t.val, Type) && valid_as_lattice(t.val, astag) return t.val, true, isconcretetype(t.val), true end return Bottom, true, false, false # runtime throws on non-Type @@ -110,7 +110,7 @@ function instanceof_tfunc(@nospecialize(t), @nospecialize(troot) = t) return Bottom, true, false, false # literal Bottom or non-Type elseif isType(t) tp = t.parameters[1] - valid_as_lattice(tp) || return Bottom, true, false, false # runtime unreachable / throws on non-Type + valid_as_lattice(tp, astag) || return Bottom, true, false, false # runtime unreachable / throws on non-Type if troot isa UnionAll # Free `TypeVar`s inside `Type` has violated the "diagonal" rule. # Widen them before `UnionAll` rewraping to relax concrete constraint. @@ -119,7 +119,7 @@ function instanceof_tfunc(@nospecialize(t), @nospecialize(troot) = t) return tp, !has_free_typevars(tp), isconcretetype(tp), true elseif isa(t, UnionAll) t′ = unwrap_unionall(t) - t′′, isexact, isconcrete, istype = instanceof_tfunc(t′, rewrap_unionall(t, troot)) + t′′, isexact, isconcrete, istype = instanceof_tfunc(t′, astag, rewrap_unionall(t, troot)) tr = rewrap_unionall(t′′, t) if t′′ isa DataType && t′′.name !== Tuple.name && !has_free_typevars(tr) # a real instance must be within the declared bounds of the type, @@ -134,8 +134,8 @@ function instanceof_tfunc(@nospecialize(t), @nospecialize(troot) = t) end return tr, isexact, isconcrete, istype elseif isa(t, Union) - ta, isexact_a, isconcrete_a, istype_a = instanceof_tfunc(t.a, troot) - tb, isexact_b, isconcrete_b, istype_b = instanceof_tfunc(t.b, troot) + ta, isexact_a, isconcrete_a, istype_a = instanceof_tfunc(unwraptv(t.a), astag, troot) + tb, isexact_b, isconcrete_b, istype_b = instanceof_tfunc(unwraptv(t.b), astag, troot) isconcrete = isconcrete_a && isconcrete_b istype = istype_a && istype_b # most users already handle the Union case, so here we assume that @@ -155,9 +155,9 @@ end # ---------- @nospecs bitcast_tfunc(𝕃::AbstractLattice, t, x) = bitcast_tfunc(widenlattice(𝕃), t, x) -@nospecs bitcast_tfunc(::JLTypeLattice, t, x) = instanceof_tfunc(t)[1] +@nospecs bitcast_tfunc(::JLTypeLattice, t, x) = instanceof_tfunc(t, true)[1] @nospecs conversion_tfunc(𝕃::AbstractLattice, t, x) = conversion_tfunc(widenlattice(𝕃), t, x) -@nospecs conversion_tfunc(::JLTypeLattice, t, x) = instanceof_tfunc(t)[1] +@nospecs conversion_tfunc(::JLTypeLattice, t, x) = instanceof_tfunc(t, true)[1] add_tfunc(bitcast, 2, 2, bitcast_tfunc, 1) add_tfunc(sext_int, 2, 2, conversion_tfunc, 1) @@ -275,7 +275,7 @@ add_tfunc(checked_umul_int, 2, 2, chk_tfunc, 10) # ----------- @nospecs function llvmcall_tfunc(𝕃::AbstractLattice, fptr, rt, at, a...) - return instanceof_tfunc(rt)[1] + return instanceof_tfunc(rt, true)[1] end add_tfunc(Core.Intrinsics.llvmcall, 3, INT_INF, llvmcall_tfunc, 10) @@ -445,7 +445,7 @@ function sizeof_nothrow(@nospecialize(x)) return sizeof_nothrow(rewrap_unionall(xu.a, x)) && sizeof_nothrow(rewrap_unionall(xu.b, x)) end - t, exact, isconcrete = instanceof_tfunc(x) + t, exact, isconcrete = instanceof_tfunc(x, false) if t === Bottom # x must be an instance (not a Type) or is the Bottom type object x = widenconst(x) @@ -497,7 +497,7 @@ end end # Core.sizeof operates on either a type or a value. First check which # case we're in. - t, exact = instanceof_tfunc(x) + t, exact = instanceof_tfunc(x, false) if t !== Bottom # The value corresponding to `x` at runtime could be a type. # Normalize the query to ask about that type. @@ -649,7 +649,7 @@ function pointer_eltype(@nospecialize(ptr)) unw = unwrap_unionall(a) if isa(unw, DataType) && unw.name === Ptr.body.name T = unw.parameters[1] - valid_as_lattice(T) || return Bottom + valid_as_lattice(T, true) || return Bottom return rewrap_unionall(T, a) end end @@ -681,7 +681,7 @@ end if isa(unw, DataType) && unw.name === Ptr.body.name T = unw.parameters[1] # note: we could sometimes refine this to a PartialStruct if we analyzed `op(T, T)::T` - valid_as_lattice(T) || return Bottom + valid_as_lattice(T, true) || return Bottom return rewrap_unionall(Pair{T, T}, a) end end @@ -693,7 +693,7 @@ end unw = unwrap_unionall(a) if isa(unw, DataType) && unw.name === Ptr.body.name T = unw.parameters[1] - valid_as_lattice(T) || return Bottom + valid_as_lattice(T, true) || return Bottom return rewrap_unionall(ccall(:jl_apply_cmpswap_type, Any, (Any,), T), a) end end @@ -797,7 +797,7 @@ end add_tfunc(typeof, 1, 1, typeof_tfunc, 1) @nospecs function typeassert_tfunc(𝕃::AbstractLattice, v, t) - t = instanceof_tfunc(t)[1] + t = instanceof_tfunc(t, true)[1] t === Any && return v return tmeet(𝕃, v, t) end @@ -805,7 +805,7 @@ add_tfunc(typeassert, 2, 2, typeassert_tfunc, 4) @nospecs function typeassert_nothrow(𝕃::AbstractLattice, v, t) ⊑ = Core.Compiler.:⊑(𝕃) - # ty, exact = instanceof_tfunc(t) + # ty, exact = instanceof_tfunc(t, true) # return exact && v ⊑ ty if (isType(t) && !has_free_typevars(t) && v ⊑ t.parameters[1]) || (isa(t, Const) && isa(t.val, Type) && v ⊑ t.val) @@ -815,7 +815,7 @@ add_tfunc(typeassert, 2, 2, typeassert_tfunc, 4) end @nospecs function isa_tfunc(𝕃::AbstractLattice, v, tt) - t, isexact = instanceof_tfunc(tt) + t, isexact = instanceof_tfunc(tt, true) if t === Bottom # check if t could be equivalent to typeof(Bottom), since that's valid in `isa`, but the set of `v` is empty # if `t` cannot have instances, it's also invalid on the RHS of isa @@ -855,8 +855,8 @@ add_tfunc(isa, 2, 2, isa_tfunc, 1) end @nospecs function subtype_tfunc(𝕃::AbstractLattice, a, b) - a, isexact_a = instanceof_tfunc(a) - b, isexact_b = instanceof_tfunc(b) + a, isexact_a = instanceof_tfunc(a, false) + b, isexact_b = instanceof_tfunc(b, false) if !has_free_typevars(a) && !has_free_typevars(b) if a <: b if isexact_b || a === Bottom @@ -1208,31 +1208,36 @@ end return Bottom end if nf == 1 - return rewrap_unionall(unwrapva(ftypes[1]), s00) - end - # union together types of all fields - t = Bottom - for i in 1:nf - _ft = ftypes[i] - setfield && isconst(s, i) && continue - t = tmerge(t, rewrap_unionall(unwrapva(_ft), s00)) - t === Any && break + fld = 1 + else + # union together types of all fields + t = Bottom + for i in 1:nf + _ft = unwrapva(ftypes[i]) + valid_as_lattice(_ft, true) || continue + setfield && isconst(s, i) && continue + t = tmerge(t, rewrap_unionall(_ft, s00)) + t === Any && break + end + return t end - return t + else + fld = _getfield_fieldindex(s, name) + fld === nothing && return Bottom end - fld = _getfield_fieldindex(s, name) - fld === nothing && return Bottom if s <: Tuple && fld >= nf && isvarargtype(ftypes[nf]) - return rewrap_unionall(unwrapva(ftypes[nf]), s00) - end - if fld < 1 || fld > nf - return Bottom - elseif setfield && isconst(s, fld) - return Bottom - end - R = ftypes[fld] - if isempty(s.parameters) - return R + R = unwrapva(ftypes[nf]) + else + if fld < 1 || fld > nf + return Bottom + elseif setfield && isconst(s, fld) + return Bottom + end + R = ftypes[fld] + valid_as_lattice(R, true) || return Bottom + if isempty(s.parameters) + return R + end end return rewrap_unionall(R, s00) end @@ -1367,7 +1372,7 @@ end T = _fieldtype_tfunc(𝕃, o, f, isconcretetype(o)) T === Bottom && return Bottom PT = Const(Pair) - return instanceof_tfunc(apply_type_tfunc(𝕃, PT, T, T))[1] + return instanceof_tfunc(apply_type_tfunc(𝕃, PT, T, T), true)[1] end function abstract_modifyfield!(interp::AbstractInterpreter, argtypes::Vector{Any}, si::StmtInfo, sv::AbsIntState) nargs = length(argtypes) @@ -1409,7 +1414,7 @@ end T = _fieldtype_tfunc(𝕃, o, f, isconcretetype(o)) T === Bottom && return Bottom PT = Const(ccall(:jl_apply_cmpswap_type, Any, (Any,), T) where T) - return instanceof_tfunc(apply_type_tfunc(𝕃, PT, T))[1] + return instanceof_tfunc(apply_type_tfunc(𝕃, PT, T), true)[1] end # we could use tuple_tfunc instead of widenconst, but `o` is mutable, so that is unlikely to be beneficial @@ -1441,7 +1446,7 @@ add_tfunc(replacefield!, 4, 6, replacefield!_tfunc, 3) fieldtype_nothrow(𝕃, rewrap_unionall(su.b, s0), name) end - s, exact = instanceof_tfunc(s0) + s, exact = instanceof_tfunc(s0, false) s === Bottom && return false # always return _fieldtype_nothrow(s, exact, name) end @@ -1506,7 +1511,7 @@ end fieldtype_tfunc(𝕃, rewrap_unionall(su.b, s0), name)) end - s, exact = instanceof_tfunc(s0) + s, exact = instanceof_tfunc(s0, false) s === Bottom && return Bottom return _fieldtype_tfunc(𝕃, s, name, exact) end @@ -1519,8 +1524,8 @@ end tb0 = _fieldtype_tfunc(𝕃, rewrap_unionall(u.b, s), name, exact) ta0 ⊑ tb0 && return tb0 tb0 ⊑ ta0 && return ta0 - ta, exacta, _, istypea = instanceof_tfunc(ta0) - tb, exactb, _, istypeb = instanceof_tfunc(tb0) + ta, exacta, _, istypea = instanceof_tfunc(ta0, false) + tb, exactb, _, istypeb = instanceof_tfunc(tb0, false) if exact && exacta && exactb return Const(Union{ta, tb}) end @@ -1654,7 +1659,7 @@ function apply_type_nothrow(𝕃::AbstractLattice, argtypes::Vector{Any}, @nospe return false end else - T, exact, _, istype = instanceof_tfunc(ai) + T, exact, _, istype = instanceof_tfunc(ai, false) if T === Bottom if !(u.var.lb === Union{} && u.var.ub === Any) return false @@ -1718,9 +1723,7 @@ const _tvarnames = Symbol[:_A, :_B, :_C, :_D, :_E, :_F, :_G, :_H, :_I, :_J, :_K, end end if largs == 1 # Union{T} --> T - u1 = typeintersect(widenconst(args[1]), Union{Type,TypeVar}) - valid_as_lattice(u1) || return Bottom - return u1 + return tmeet(widenconst(args[1]), Union{Type,TypeVar}) end hasnonType && return Type ty = Union{} @@ -1805,7 +1808,7 @@ const _tvarnames = Symbol[:_A, :_B, :_C, :_D, :_E, :_F, :_G, :_H, :_I, :_J, :_K, elseif !isT # if we didn't have isType to compute ub directly, try to use instanceof_tfunc to refine this guess ai_w = widenconst(ai) - ub = ai_w isa Type && ai_w <: Type ? instanceof_tfunc(ai)[1] : Any + ub = ai_w isa Type && ai_w <: Type ? instanceof_tfunc(ai, false)[1] : Any end if istuple # in the last parameter of a Tuple type, if the upper bound is Any @@ -2004,7 +2007,7 @@ function array_elmtype(@nospecialize ary) end if isa(a, DataType) T = a.parameters[1] - valid_as_lattice(T) || return Bottom + valid_as_lattice(T, true) || return Bottom return rewrap_unionall(T, a0) end end @@ -2534,7 +2537,7 @@ function intrinsic_nothrow(f::IntrinsicFunction, argtypes::Vector{Any}) return argtypes[1] ⊑ Array end if f === Intrinsics.bitcast - ty, isexact, isconcrete = instanceof_tfunc(argtypes[1]) + ty, isexact, isconcrete = instanceof_tfunc(argtypes[1], true) xty = widenconst(argtypes[2]) return isconcrete && isprimitivetype(ty) && isprimitivetype(xty) && Core.sizeof(ty) === Core.sizeof(xty) end @@ -2543,12 +2546,12 @@ function intrinsic_nothrow(f::IntrinsicFunction, argtypes::Vector{Any}) Intrinsics.sitofp, Intrinsics.fptrunc, Intrinsics.fpext) # If !isconcrete, `ty` may be Union{} at runtime even if we have # isprimitivetype(ty). - ty, isexact, isconcrete = instanceof_tfunc(argtypes[1]) + ty, isexact, isconcrete = instanceof_tfunc(argtypes[1], true) xty = widenconst(argtypes[2]) return isconcrete && isprimitivetype(ty) && isprimitivetype(xty) end if f === Intrinsics.have_fma - ty, isexact, isconcrete = instanceof_tfunc(argtypes[1]) + ty, isexact, isconcrete = instanceof_tfunc(argtypes[1], true) return isconcrete && isprimitivetype(ty) end # The remaining intrinsics are math/bits/comparison intrinsics. They work on all @@ -2686,6 +2689,10 @@ function abstract_applicable(interp::AbstractInterpreter, argtypes::Vector{Any}, isvarargtype(argtypes[2]) && return CallMeta(Bool, EFFECTS_UNKNOWN, NoCallInfo()) argtypes = argtypes[2:end] atype = argtypes_to_type(argtypes) + if atype === Union{} + rt = Union{} # accidentally unreachable code + return CallMeta(rt, EFFECTS_TOTAL, NoCallInfo()) + end matches = find_matching_methods(typeinf_lattice(interp), argtypes, atype, method_table(interp), InferenceParams(interp).max_union_splitting, max_methods) if isa(matches, FailedMethodMatch) @@ -2738,7 +2745,7 @@ function _hasmethod_tfunc(interp::AbstractInterpreter, argtypes::Vector{Any}, sv else return CallMeta(Any, Effects(), NoCallInfo()) end - (types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, typeidx)) + (types, isexact, isconcrete, istype) = instanceof_tfunc(argtype_by_index(argtypes, typeidx), false) isexact || return CallMeta(Bool, Effects(), NoCallInfo()) unwrapped = unwrap_unionall(types) if types === Bottom || !(unwrapped isa DataType) || unwrapped.name !== Tuple.name diff --git a/base/compiler/typelattice.jl b/base/compiler/typelattice.jl index 324f2b600cc44..df6022609d612 100644 --- a/base/compiler/typelattice.jl +++ b/base/compiler/typelattice.jl @@ -607,7 +607,7 @@ end if ti === widev return v end - valid_as_lattice(ti) || return Bottom + valid_as_lattice(ti, true) || return Bottom if widev <: Tuple new_fields = Vector{Any}(undef, length(v.fields)) for i = 1:length(new_fields) @@ -631,7 +631,7 @@ end return v end ti = typeintersect(widev, t) - valid_as_lattice(ti) || return Bottom + valid_as_lattice(ti, true) || return Bottom return PartialOpaque(ti, v.env, v.parent, v.source) end return tmeet(widenlattice(lattice), v, t) diff --git a/base/compiler/typeutils.jl b/base/compiler/typeutils.jl index 2ecc077228264..4d2a2c1a5015a 100644 --- a/base/compiler/typeutils.jl +++ b/base/compiler/typeutils.jl @@ -54,7 +54,12 @@ has_extended_info(@nospecialize x) = (!isa(x, Type) && !isvarargtype(x)) || isTy # certain combinations of `a` and `b` where one/both isa/are `Union`/`UnionAll` type(s)s. isnotbrokensubtype(@nospecialize(a), @nospecialize(b)) = (!iskindtype(b) || !isType(a) || hasuniquerep(a.parameters[1]) || b <: a) -argtypes_to_type(argtypes::Array{Any,1}) = Tuple{anymap(@nospecialize(a) -> isvarargtype(a) ? a : widenconst(a), argtypes)...} +function argtypes_to_type(argtypes::Array{Any,1}) + argtypes = anymap(@nospecialize(a) -> isvarargtype(a) ? a : widenconst(a), argtypes) + filter!(@nospecialize(x) -> !isvarargtype(x) || valid_as_lattice(unwrapva(x), true), argtypes) + all(@nospecialize(x) -> isvarargtype(x) || valid_as_lattice(x, true), argtypes) || return Bottom + return Tuple{argtypes...} +end function isknownlength(t::DataType) isvatuple(t) || return true @@ -95,12 +100,13 @@ end has_concrete_subtype(d::DataType) = d.flags & 0x0020 == 0x0020 # n.b. often computed only after setting the type and layout fields -# determine whether x is a valid lattice element tag +# determine whether x is a valid lattice element # For example, Type{v} is not valid if v is a value -# Accepts TypeVars also, since it assumes the user will rewrap it correctly -function valid_as_lattice(@nospecialize(x)) +# Accepts TypeVars and has_free_typevar also, since it assumes the user will rewrap it correctly +# If astag is true, then also requires that it be a possible type tag for a valid object +function valid_as_lattice(@nospecialize(x), astag::Bool=false) x === Bottom && false - x isa TypeVar && return valid_as_lattice(x.ub) + x isa TypeVar && return valid_as_lattice(x.ub, astag) x isa UnionAll && (x = unwrap_unionall(x)) if x isa Union # the Union constructor ensures this (and we'll recheck after @@ -111,6 +117,9 @@ function valid_as_lattice(@nospecialize(x)) if isType(x) p = x.parameters[1] p isa Type || p isa TypeVar || return false + elseif astag && isstructtype(x) + datatype_fieldtypes(x) # force computation of has_concrete_subtype to be updated now + return has_concrete_subtype(x) end return true end @@ -149,6 +158,7 @@ function compatible_vatuple(a::DataType, b::DataType) end # return an upper-bound on type `a` with type `b` removed +# and also any contents that are not valid type tags on any objects # such that `return <: a` && `Union{return, b} == Union{a, b}` function typesubtract(@nospecialize(a), @nospecialize(b), max_union_splitting::Int) if a <: b && isnotbrokensubtype(a, b) @@ -158,8 +168,8 @@ function typesubtract(@nospecialize(a), @nospecialize(b), max_union_splitting::I if isa(ua, Union) uua = typesubtract(rewrap_unionall(ua.a, a), b, max_union_splitting) uub = typesubtract(rewrap_unionall(ua.b, a), b, max_union_splitting) - return Union{valid_as_lattice(uua) ? uua : Union{}, - valid_as_lattice(uub) ? uub : Union{}} + return Union{valid_as_lattice(uua, true) ? uua : Union{}, + valid_as_lattice(uub, true) ? uub : Union{}} elseif a isa DataType ub = unwrap_unionall(b) if ub isa DataType diff --git a/test/compiler/inference.jl b/test/compiler/inference.jl index 223794e74fff0..605756e16e054 100644 --- a/test/compiler/inference.jl +++ b/test/compiler/inference.jl @@ -5185,3 +5185,30 @@ end let (ir, rt) = only(Base.code_ircode(issue53366, (Threads.Condition,))) Core.Compiler.verify_ir(ir) end + +# issue 51228 +global whatever_unknown_value51228 +f51228() = f51228(whatever_unknown_value51228) +f51228(x) = 1 +f51228(::Vararg{T,T}) where {T} = "2" +@test only(Base.return_types(f51228, ())) == Int + +struct A51317 + b::Tuple{1} + A1() = new() +end +struct An51317 + a::Int + b::Tuple{1} + An51317() = new() +end +@test only(Base.return_types((x,f) -> getfield(x, f), (A51317, Symbol))) === Union{} +@test only(Base.return_types((x,f) -> getfield(x, f), (An51317, Symbol))) === Int +@test only(Base.return_types(x -> getfield(x, :b), (A51317,))) === Union{} +@test only(Base.return_types(x -> getfield(x, :b), (An51317,))) === Union{} + +# issue #56628 +@test Core.Compiler.argtypes_to_type(Any[ Int, UnitRange{Int}, Vararg{Pair{Any, Union{}}} ]) === Tuple{Int, UnitRange{Int}} +@test Core.Compiler.argtypes_to_type(Any[ Int, UnitRange{Int}, Vararg{Pair{Any, Union{}}}, Float64 ]) === Tuple{Int, UnitRange{Int}, Float64} +@test Core.Compiler.argtypes_to_type(Any[ Int, UnitRange{Int}, Vararg{Pair{Any, Union{}}}, Float64, Tuple{2} ]) === Union{} +@test Base.return_types(Tuple{Tuple{Int, Vararg{Pair{Any, Union{}}}}},) do x; Returns(true)(x...); end |> only === Bool diff --git a/test/compiler/inline.jl b/test/compiler/inline.jl index 780a5424a29c2..7ab3589c725f9 100644 --- a/test/compiler/inline.jl +++ b/test/compiler/inline.jl @@ -1642,33 +1642,6 @@ function oc_capture_oc(z) end @test fully_eliminated(oc_capture_oc, (Int,)) -@eval struct OldVal{T} - x::T - (OV::Type{OldVal{T}})() where T = $(Expr(:new, :OV)) -end -with_unmatched_typeparam1(x::OldVal{i}) where {i} = i -with_unmatched_typeparam2() = [ Base.donotdelete(OldVal{i}()) for i in 1:10000 ] -function with_unmatched_typeparam3() - f(x::OldVal{i}) where {i} = i - r = 0 - for i = 1:10000 - r += f(OldVal{i}()) - end - return r -end - -@testset "Inlining with unmatched type parameters" begin - let src = code_typed1(with_unmatched_typeparam1, (Any,)) - @test !any(@nospecialize(x) -> isexpr(x, :call) && length(x.args) == 1, src.code) - end - let src = code_typed1(with_unmatched_typeparam2) - @test !any(@nospecialize(x) -> isexpr(x, :call) && length(x.args) == 1, src.code) - end - let src = code_typed1(with_unmatched_typeparam3) - @test !any(@nospecialize(x) -> isexpr(x, :call) && length(x.args) == 1, src.code) - end -end - function twice_sitofp(x::Int, y::Int) x = Base.sitofp(Float64, x) y = Base.sitofp(Float64, y) From 6a92fcebae26ad5abf045ad976beea5989db83f9 Mon Sep 17 00:00:00 2001 From: Diogo Netto <61364108+d-netto@users.noreply.github.com> Date: Sat, 1 Mar 2025 11:30:13 -0300 Subject: [PATCH 108/109] avoid overflow on functionality to print backtrace of safepoint straggler (#57579) In the line of C code: ```C const int64_t timeout = jl_options.timeout_for_safepoint_straggler_s * 1000000000; ``` `jl_options.timeout_for_safepoint_straggler_s` is an `int16_t` and `1000000000` is an `int32_t`. The result of `jl_options.timeout_for_safepoint_straggler_s * 1000000000` will be an `int32_t` which may not be large enough to hold the value of `jl_options.timeout_for_safepoint_straggler_s` after converting to nanoseconds, leading to overflow. --- src/gc.c | 2 +- test/threads_exec.jl | 26 ++++++++++++++------------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/gc.c b/src/gc.c index edcdcefdcaf7a..98ed32cd4a54a 100644 --- a/src/gc.c +++ b/src/gc.c @@ -254,7 +254,7 @@ void jl_gc_wait_for_the_world(jl_ptls_t* gc_all_tls_states, int gc_n_threads) // We're currently also using atomic store release in mutator threads // (in jl_gc_state_set), but we may want to use signals to flush the // memory operations on those threads lazily instead. - const int64_t timeout = jl_options.timeout_for_safepoint_straggler_s * 1000000000; // convert to nanoseconds + const int64_t timeout = jl_options.timeout_for_safepoint_straggler_s * 1000000000LL; // convert to nanoseconds uint64_t t0 = jl_hrtime(); while (!jl_atomic_load_relaxed(&ptls2->gc_state) || !jl_atomic_load_acquire(&ptls2->gc_state)) { jl_cpu_pause(); // yield? diff --git a/test/threads_exec.jl b/test/threads_exec.jl index dac0c1846cca5..2ed1f73972ee9 100644 --- a/test/threads_exec.jl +++ b/test/threads_exec.jl @@ -1317,25 +1317,27 @@ end program = " function main() t = Threads.@spawn begin - ccall(:uv_sleep, Cvoid, (Cuint,), 5000) + ccall(:uv_sleep, Cvoid, (Cuint,), 20_000) end # Force a GC - ccall(:uv_sleep, Cvoid, (Cuint,), 1000) + ccall(:uv_sleep, Cvoid, (Cuint,), 1_000) GC.gc() wait(t) end main() " - tmp_output_filename = tempname() - tmp_output_file = open(tmp_output_filename, "w") - if isnothing(tmp_output_file) - error("Failed to open file $tmp_output_filename") - end - run(pipeline(`$(Base.julia_cmd()) --threads=4 --timeout-for-safepoint-straggler=1 -e $program`, stderr=tmp_output_file)) - # Check whether we printed the straggler's backtrace - @test !isempty(read(tmp_output_filename, String)) - close(tmp_output_file) - rm(tmp_output_filename) + for timeout in ("1", "4", "16") + tmp_output_filename = tempname() + tmp_output_file = open(tmp_output_filename, "w") + if isnothing(tmp_output_file) + error("Failed to open file $tmp_output_filename") + end + run(pipeline(`$(Base.julia_cmd()) --threads=4 --timeout-for-safepoint-straggler=$(timeout) -e $program`, stderr=tmp_output_file)) + # Check whether we printed the straggler's backtrace + @test !isempty(read(tmp_output_filename, String)) + close(tmp_output_file) + rm(tmp_output_filename) + end end end # main testset From 590b8078231310d228ea2098bdcac5ed6ebe238a Mon Sep 17 00:00:00 2001 From: d-netto Date: Sun, 2 Mar 2025 15:18:04 -0300 Subject: [PATCH 109/109] make the default timeout 60s --- src/jloptions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jloptions.c b/src/jloptions.c index 157634bbcce4e..15a75df3e2638 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -94,7 +94,7 @@ JL_DLLEXPORT void jl_init_options(void) 0, // trace_compile_timing NULL, // safe_crash_log_file 0, // task_metrics - -1, // timeout_for_safepoint_straggler_s + 60, // timeout_for_safepoint_straggler_s }; jl_options_initialized = 1; }