Skip to content

Commit

Permalink
Fix JULIA_EXCLUSIVE setting affinity on non-worker threads
Browse files Browse the repository at this point in the history
With JULIA_EXCLUSIVE=1, we would try to give both worker and interactive threads
an exclusive CPU, causing --threads=auto to produce a "Too many threads
requested" error.

Fixes JuliaLang#50702.
  • Loading branch information
xal-0 committed Jan 24, 2025
1 parent b70761f commit 8bb6b8f
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 12 deletions.
24 changes: 14 additions & 10 deletions src/threading.c
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,9 @@ void jl_start_threads(void)
{
int nthreads = jl_atomic_load_relaxed(&jl_n_threads);
int ngcthreads = jl_n_gcthreads;
int nthreadsi = jl_n_threads_per_pool[0];
int nmutator_threads = nthreads - ngcthreads;

int cpumasksize = uv_cpumask_size();
char *cp;
int i, exclusive;
Expand All @@ -812,32 +815,33 @@ void jl_start_threads(void)
// according to a 'compact' policy
// non-exclusive: no affinity settings; let the kernel move threads about
if (exclusive) {
if (nthreads > jl_cpu_threads()) {
if (nmutator_threads - nthreadsi > jl_cpu_threads()) {
jl_printf(JL_STDERR, "ERROR: Too many threads requested for %s option.\n", MACHINE_EXCLUSIVE_NAME);
exit(1);
}
memset(mask, 0, cpumasksize);
mask[0] = 1;
uvtid = uv_thread_self();
uv_thread_setaffinity(&uvtid, mask, NULL, cpumasksize);
mask[0] = 0;

if (nthreadsi == 0) {
mask[0] = 1;
uvtid = uv_thread_self();
uv_thread_setaffinity(&uvtid, mask, NULL, cpumasksize);
mask[0] = 0;
}
}

// create threads
uv_barrier_init(&thread_init_done, nthreads);

// GC/System threads need to be after the worker threads.
int nmutator_threads = nthreads - ngcthreads;

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;
uv_thread_create(&uvtid, jl_threadfun, t);
if (exclusive) {
mask[i] = 1;
if (exclusive && i > nthreadsi) {
mask[i - nthreadsi] = 1;
uv_thread_setaffinity(&uvtid, mask, NULL, cpumasksize);
mask[i] = 0;
mask[i - nthreadsi] = 0;
}
uv_thread_detach(&uvtid);
}
Expand Down
6 changes: 4 additions & 2 deletions test/threads.jl
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,11 @@ if AFFINITY_SUPPORTED
end
end

function get_nthreads(options = ``; cpus = nothing)
function get_nthreads(options = ``; cpus = nothing, exclusive = false)
cmd = `$(Base.julia_cmd()) --startup-file=no $(options)`
cmd = `$cmd -e "print(Threads.threadpoolsize())"`
cmd = addenv(cmd, "JULIA_EXCLUSIVE" => "0", "JULIA_NUM_THREADS" => "auto")
cmd = addenv(cmd, "JULIA_EXCLUSIVE" => exclusive ? "1" : "0",
"JULIA_NUM_THREADS" => "auto")
if cpus !== nothing
cmd = setcpuaffinity(cmd, cpus)
end
Expand All @@ -138,6 +139,7 @@ end
allowed_cpus = findall(uv_thread_getaffinity())
if length(allowed_cpus) 2
@test get_nthreads() 2
@test get_nthreads(exclusive = true) 2
@test get_nthreads(cpus = allowed_cpus[1:1]) == 1
@test get_nthreads(cpus = allowed_cpus[2:2]) == 1
@test get_nthreads(cpus = allowed_cpus[1:2]) == 2
Expand Down

0 comments on commit 8bb6b8f

Please sign in to comment.