From 479cab2e3e870aecc1ca0fd7125c08f3409f2307 Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 27 May 2024 10:52:42 +0200 Subject: [PATCH] julia_gc: fix detection of already canned root task We already scan some stack during as part of the `GapRootScanner` callback, which usually will be the stack of the active task of the main thread. As an optimization, we want to avoid scanning that task's thread a second time in `GapTaskScanner`. We used to do that by checking in the latter whether the task about to be scanned is the current task. But that is wrong: the task may be different for all kinds of reasons, most notably if there are multiple GC threads active. So instead, just record the task we scanned in `GapRootScanner` (this is safe to write as there is single thread involved at this point) and then compare against that in `GapTaskScanner` (which may be called concurrently from multiple threads). --- src/julia_gc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/julia_gc.c b/src/julia_gc.c index ace1ce6f21..08cfe8383c 100644 --- a/src/julia_gc.c +++ b/src/julia_gc.c @@ -184,6 +184,8 @@ static jl_datatype_t * DatatypeGapObj; static jl_datatype_t * DatatypeSmallBag; static jl_datatype_t * DatatypeLargeBag; +static jl_task_t * ScannedRootTask; + static size_t MaxPoolObjSize; static int FullGC; static UInt StartTime, TotalTime; @@ -565,6 +567,8 @@ static void GapRootScanner(int full) jl_ptls_t ptls = jl_get_ptls_states(); jl_task_t * task = (jl_task_t *)jl_get_current_task(); + ScannedRootTask = task; + // We figure out the end of the stack from the current task. While // `stack_bottom` is passed to InitBags(), we cannot use that if // current_task != root_task. @@ -615,9 +619,8 @@ static void GapRootScanner(int full) // Julia callback static void GapTaskScanner(jl_task_t * task, int root_task) { - // If it is the current task, it has been scanned by GapRootScanner() - // already. - if (task == (jl_task_t *)jl_get_current_task()) + // If this task has been scanned by GapRootScanner() already, skip it + if (task == ScannedRootTask) return; int rescan = 1; @@ -689,6 +692,7 @@ static void PreGCHook(int full) // Julia callback static void PostGCHook(int full) { + ScannedRootTask = 0; TotalTime += SyTime() - StartTime; #ifdef COLLECT_MARK_CACHE_STATS /* printf("\n>>>Attempts: %ld\nHit rate: %lf\nCollision rate: %lf\n",