Skip to content

Commit 065aeb6

Browse files
carstenbauervchuravyDilumAluthge
authored
Add jl_getaffinity and jl_setaffinity (#53402)
This PR adds two functions `jl_getaffinity` and `jl_setaffinity` to the runtime, which are slim wrappers around `uv_thread_getaffinity` and `uv_thread_setaffinity` and can be used to set the affinity of Julia threads. This will * simplify thread pinning (ThreadPinning.jl currently pins threads by spawning tasks that run the necessary ccalls) and * enable users to also pin GC threads (or, more generally, all Julia threads). **Example:** ```julia bauerc@n2lcn0146 julia git:(cb/affinity) ➜ ./julia -q --startup-file=no --threads 2,3 --gcthreads 4,1 julia> cpumasksize = @CCall uv_cpumask_size()::Cint 1024 julia> mask = zeros(Cchar, cpumasksize); julia> jl_getaffinity(tid, mask, cpumasksize) = ccall(:jl_getaffinity, Int32, (Int16, Ptr{Cchar}, Int32), tid, mask, cpumasksize) jl_getaffinity (generic function with 1 method) julia> jl_getaffinity(1, mask, cpumasksize) 0 julia> print(mask[1:Sys.CPU_THREADS]) Int8[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] julia> mask[1] = 0; julia> jl_setaffinity(tid, mask, cpumasksize) = ccall(:jl_setaffinity, Int32, (Int16, Ptr{Cchar}, Int32), tid, mask, cpumasksize) jl_setaffinity (generic function with 1 method) julia> jl_setaffinity(1, mask, cpumasksize) 0 julia> fill!(mask, 0); julia> jl_getaffinity(1, mask, cpumasksize) 0 julia> print(mask[1:Sys.CPU_THREADS]) Int8[0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] ``` (cc @vchuravy, @gbaraldi) Would be great to get this into 1.11 (despite feature freeze) because otherwise we won't be able to pin GC threads until 1.12 (likely not until the end of the year). Closes #53073 --------- Co-authored-by: Valentin Churavy <[email protected]> Co-authored-by: Dilum Aluthge <[email protected]>
1 parent b54dce2 commit 065aeb6

File tree

4 files changed

+63
-0
lines changed

4 files changed

+63
-0
lines changed

src/jl_exported_funcs.inc

+2
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@
194194
XX(jl_generating_output) \
195195
XX(jl_generic_function_def) \
196196
XX(jl_gensym) \
197+
XX(jl_getaffinity) \
197198
XX(jl_getallocationgranularity) \
198199
XX(jl_getnameinfo) \
199200
XX(jl_getpagesize) \
@@ -406,6 +407,7 @@
406407
XX(jl_safepoint_suspend_thread) \
407408
XX(jl_safepoint_resume_thread) \
408409
XX(jl_SC_CLK_TCK) \
410+
XX(jl_setaffinity) \
409411
XX(jl_set_ARGS) \
410412
XX(jl_set_const) \
411413
XX(jl_set_errno) \

src/julia_threads.h

+3
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,9 @@ JL_DLLEXPORT int8_t jl_gc_is_in_finalizer(void) JL_NOTSAFEPOINT;
373373

374374
JL_DLLEXPORT void jl_wakeup_thread(int16_t tid);
375375

376+
JL_DLLEXPORT int jl_getaffinity(int16_t tid, char *mask, int cpumasksize);
377+
JL_DLLEXPORT int jl_setaffinity(int16_t tid, char *mask, int cpumasksize);
378+
376379
#ifdef __cplusplus
377380
}
378381
#endif

src/threading.c

+46
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,52 @@ JL_DLLEXPORT int jl_alignment(size_t sz)
984984
return jl_gc_alignment(sz);
985985
}
986986

987+
// Return values:
988+
// 0 == success
989+
// 1 == invalid thread id provided
990+
// 2 == ptls2 was NULL
991+
// <0 == uv_thread_getaffinity exit code
992+
JL_DLLEXPORT int jl_getaffinity(int16_t tid, char *mask, int cpumasksize) {
993+
int nthreads = jl_atomic_load_acquire(&jl_n_threads);
994+
if (tid < 0 || tid >= nthreads)
995+
return 1;
996+
997+
// TODO: use correct lock. system_id is only legal if the thread is alive.
998+
jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[tid];
999+
if (ptls2 == NULL)
1000+
return 2;
1001+
uv_thread_t uvtid = ptls2->system_id;
1002+
1003+
int ret_uv = uv_thread_getaffinity(&uvtid, mask, cpumasksize);
1004+
if (ret_uv != 0)
1005+
return ret_uv;
1006+
1007+
return 0; // success
1008+
}
1009+
1010+
// Return values:
1011+
// 0 == success
1012+
// 1 == invalid thread id provided
1013+
// 2 == ptls2 was NULL
1014+
// <0 == uv_thread_getaffinity exit code
1015+
JL_DLLEXPORT int jl_setaffinity(int16_t tid, char *mask, int cpumasksize) {
1016+
int nthreads = jl_atomic_load_acquire(&jl_n_threads);
1017+
if (tid < 0 || tid >= nthreads)
1018+
return 1;
1019+
1020+
// TODO: use correct lock. system_id is only legal if the thread is alive.
1021+
jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[tid];
1022+
if (ptls2 == NULL)
1023+
return 2;
1024+
uv_thread_t uvtid = ptls2->system_id;
1025+
1026+
int ret_uv = uv_thread_setaffinity(&uvtid, mask, NULL, cpumasksize);
1027+
if (ret_uv != 0)
1028+
return ret_uv;
1029+
1030+
return 0; // success
1031+
}
1032+
9871033
#ifdef __cplusplus
9881034
}
9891035
#endif

test/threads.jl

+12
Original file line numberDiff line numberDiff line change
@@ -354,3 +354,15 @@ end
354354
@test istaskfailed(t)
355355
end
356356
end
357+
358+
@testset "jl_*affinity" begin
359+
cpumasksize = @ccall uv_cpumask_size()::Cint
360+
if !Sys.iswindows() && cpumasksize > 0 # otherwise affinities are not supported on the platform (UV_ENOTSUP)
361+
mask = zeros(Cchar, cpumasksize);
362+
jl_getaffinity = (tid, mask, cpumasksize) -> ccall(:jl_getaffinity, Int32, (Int16, Ptr{Cchar}, Int32), tid, mask, cpumasksize)
363+
jl_setaffinity = (tid, mask, cpumasksize) -> ccall(:jl_setaffinity, Int32, (Int16, Ptr{Cchar}, Int32), tid, mask, cpumasksize)
364+
@test jl_getaffinity(1, mask, cpumasksize) == 0
365+
fill!(mask, 1)
366+
@test jl_setaffinity(1, mask, cpumasksize) == 0
367+
end
368+
end

0 commit comments

Comments
 (0)