From 69454b3ab3280201b6bc1fa9f9f7d80de9bb2381 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Tue, 18 Feb 2025 11:18:54 -0300 Subject: [PATCH 1/8] If the user explicitly asked for 1 thread don't add an interactive one. This basically makes the assumption that if the user asked for 1 thread they really want their program to not have threads --- src/threading.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/threading.c b/src/threading.c index 690c5fafb5792..621bd70ae4d97 100644 --- a/src/threading.c +++ b/src/threading.c @@ -716,7 +716,10 @@ void jl_init_threading(void) nthreads = jl_options.nthreads_per_pool[0]; if (nthreads < 0) nthreads = jl_effective_threads(); - nthreadsi = (jl_options.nthreadpools == 1) ? 0 : jl_options.nthreads_per_pool[1]; + if (nthreads == 1) // User asked for 1 thread so lets assume they dont want an interactive thread + nthreadsi = 0; + else + nthreadsi = (jl_options.nthreadpools == 1) ? 0 : jl_options.nthreads_per_pool[1]; } else if ((cp = getenv(NUM_THREADS_NAME))) { // ENV[NUM_THREADS_NAME] specified if (!strncmp(cp, "auto", 4)) { @@ -729,6 +732,8 @@ void jl_init_threading(void) if (errno != 0 || endptr == cp || nthreads <= 0) nthreads = 1; cp = endptr; + if (nthreads == 1) // User asked for 1 thread so lets assume they dont want an interactive thread + nthreadsi = 0; } if (*cp == ',') { cp++; From 5a7e7c3224c920a8e92d2c259fc80dee06b31df9 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Tue, 18 Feb 2025 11:45:16 -0300 Subject: [PATCH 2/8] Add change to the docs --- doc/src/manual/multi-threading.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/src/manual/multi-threading.md b/doc/src/manual/multi-threading.md index ec470f867cc47..9e06bb7638e02 100644 --- a/doc/src/manual/multi-threading.md +++ b/doc/src/manual/multi-threading.md @@ -37,6 +37,7 @@ each threadpool. !!! compat "Julia 1.12" Starting by default with 1 interactive thread, as well as the 1 worker thread, was made as such in Julia 1.12 + If the number of threads is set to 1 by either doing `-t1` or `JULIA_NUM_THREADS=1` an interactive thread will not be spawned. Lets start Julia with 4 threads: From d9d4befb4208cfa35a9826143909e758acc8ea52 Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Wed, 19 Feb 2025 10:21:38 -0300 Subject: [PATCH 3/8] Also add note to threadpool section of docs --- doc/src/manual/multi-threading.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/src/manual/multi-threading.md b/doc/src/manual/multi-threading.md index 9e06bb7638e02..2c730813fd62e 100644 --- a/doc/src/manual/multi-threading.md +++ b/doc/src/manual/multi-threading.md @@ -145,6 +145,8 @@ julia> nthreads(:interactive) julia> nthreads() 3 ``` +!!! note + Explicitly asking for 1 thread by doing `-t1` or `JULIA_NUM_THREADS=1` does not add an interactive thread. !!! note The zero-argument version of `nthreads` returns the number of threads From a7b037b725963e2a146113ea99e848e9c1a456fc Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Wed, 19 Feb 2025 11:48:43 -0300 Subject: [PATCH 4/8] Change HISTORY --- HISTORY.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index 6f29331fa2ff5..539408a77c7bc 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -32,9 +32,10 @@ Language changes * Julia now defaults to 1 "interactive" thread, in addition to the 1 default "worker" thread. i.e. `-t1,1`. This means in default configuration the main task and repl (when in interactive mode), which both run on thread 1, now run within the `interactive` threadpool. The libuv IO loop also runs on thread 1, - helping efficient utilization of the worker threadpool used by `Threads.@spawn`. Pass `0` to disable the - interactive thread i.e. `-t1,0` or `JULIA_NUM_THREADS=1,0`, or `-tauto,0` etc. The zero is explicitly - required to disable it, `-t2` will set the equivalent of `-t2,1` ([#57087]). + helping efficient utilization of the worker threadpool used by `Threads.@spawn`. Asking for specifically 1 thread + (`-t1`/`JULIA_NUM_THREADS=1`) or passing `0` will disable the interactive thread i.e. `-t1,0` or `JULIA_NUM_THREADS=1,0` + , or `-tauto,0` etc. Asking for more than 1 thread will enable the interactive thread so + `-t2` will set the equivalent of `-t2,1` ([#57087]). * When a method is replaced with an exactly equivalent one, the old method is not deleted. Instead, the new method takes priority and becomes more specific than the old method. Thus if the new method is deleted later, the old method will resume operating. This can be useful in mocking frameworks (as in SparseArrays, From 3fe02a41d02d1235c9ad010420e034144f02295f Mon Sep 17 00:00:00 2001 From: Gabriel Baraldi Date: Wed, 19 Feb 2025 14:09:47 -0300 Subject: [PATCH 5/8] Change logic slightly --- src/jloptions.c | 3 +++ src/threading.c | 5 +---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/jloptions.c b/src/jloptions.c index ac515bea19845..10c9461e7219d 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -660,6 +660,9 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) if (nthreadsi == 0) jl_options.nthreadpools = 1; } + } else if (nthreads == 1) { // User asked for 1 thread so don't add an interactive one + jl_options.nthreadpools = 1; + nthreadsi = 0; } jl_options.nthreads = nthreads + nthreadsi; } diff --git a/src/threading.c b/src/threading.c index 621bd70ae4d97..d3b38604f3e09 100644 --- a/src/threading.c +++ b/src/threading.c @@ -716,10 +716,7 @@ void jl_init_threading(void) nthreads = jl_options.nthreads_per_pool[0]; if (nthreads < 0) nthreads = jl_effective_threads(); - if (nthreads == 1) // User asked for 1 thread so lets assume they dont want an interactive thread - nthreadsi = 0; - else - nthreadsi = (jl_options.nthreadpools == 1) ? 0 : jl_options.nthreads_per_pool[1]; + nthreadsi = (jl_options.nthreadpools == 1) ? 0 : jl_options.nthreads_per_pool[1]; } else if ((cp = getenv(NUM_THREADS_NAME))) { // ENV[NUM_THREADS_NAME] specified if (!strncmp(cp, "auto", 4)) { From 612afb16a5de59a2df34b74b625174e36c5e4d3c Mon Sep 17 00:00:00 2001 From: gbaraldi Date: Tue, 6 May 2025 14:02:24 -0300 Subject: [PATCH 6/8] Fix whitespace + add tests --- src/jloptions.c | 2 +- test/cmdlineargs.jl | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/jloptions.c b/src/jloptions.c index 91f62d62a5458..be223c98661a2 100644 --- a/src/jloptions.c +++ b/src/jloptions.c @@ -662,7 +662,7 @@ JL_DLLEXPORT void jl_parse_opts(int *argcp, char ***argvp) if (nthreadsi == 0) jl_options.nthreadpools = 1; } - } else if (nthreads == 1) { // User asked for 1 thread so don't add an interactive one + } else if (nthreads == 1) { // User asked for 1 thread so don't add an interactive one jl_options.nthreadpools = 1; nthreadsi = 0; } diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index 7934d9c60d54d..d0c873db134b1 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -351,6 +351,7 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no` # -t, --threads code = "print(Threads.threadpoolsize())" + code2 = "print(Threads.maxthreadid())" cpu_threads = ccall(:jl_effective_threads, Int32, ()) @test string(cpu_threads) == read(`$exename --threads auto -e $code`, String) == @@ -361,6 +362,11 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no` withenv("JULIA_NUM_THREADS" => nt) do @test read(`$exename --threads=2 -e $code`, String) == read(`$exename -t 2 -e $code`, String) == "2" + if nt === nothing + @test read(`$exename $code2`, String) == "2" #default + interactive + elseif nt == "1" + @test read(`$exename $code2`, String) == "1" #if user asks for 1 give 1 + end end end # We want to test oversubscription, but on manycore machines, this can From 609924c9b4fd199a91362180ec6d12f9ffdeeaca Mon Sep 17 00:00:00 2001 From: gbaraldi Date: Tue, 6 May 2025 14:41:43 -0300 Subject: [PATCH 7/8] Fix doctest --- doc/src/manual/multi-threading.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/manual/multi-threading.md b/doc/src/manual/multi-threading.md index 2c730813fd62e..401169e9c2132 100644 --- a/doc/src/manual/multi-threading.md +++ b/doc/src/manual/multi-threading.md @@ -8,7 +8,7 @@ of Julia multi-threading features. By default, Julia starts up with 2 threads of execution; 1 worker thread and 1 interactive thread. This can be verified by using the command [`Threads.nthreads()`](@ref): -```jldoctest +```julia julia> Threads.nthreads(:default) 1 julia> Threads.nthreads(:interactive) From e2ca02a14173bd1c398a5783b275f6598f05bb8c Mon Sep 17 00:00:00 2001 From: gbaraldi Date: Wed, 7 May 2025 12:45:57 -0300 Subject: [PATCH 8/8] Fix cmdlineargs test --- test/cmdlineargs.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/cmdlineargs.jl b/test/cmdlineargs.jl index d0c873db134b1..991911122ffdc 100644 --- a/test/cmdlineargs.jl +++ b/test/cmdlineargs.jl @@ -363,9 +363,9 @@ let exename = `$(Base.julia_cmd()) --startup-file=no --color=no` @test read(`$exename --threads=2 -e $code`, String) == read(`$exename -t 2 -e $code`, String) == "2" if nt === nothing - @test read(`$exename $code2`, String) == "2" #default + interactive + @test read(`$exename -e $code2`, String) == "2" #default + interactive elseif nt == "1" - @test read(`$exename $code2`, String) == "1" #if user asks for 1 give 1 + @test read(`$exename -e $code2`, String) == "1" #if user asks for 1 give 1 end end end