Skip to content

Commit 6b4b5ef

Browse files
carstenbauerKristofferC
authored and
KristofferC
committed
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]> (cherry picked from commit 065aeb6)
1 parent 4bc3d07 commit 6b4b5ef

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) \
@@ -407,6 +408,7 @@
407408
XX(jl_safepoint_suspend_thread) \
408409
XX(jl_safepoint_resume_thread) \
409410
XX(jl_SC_CLK_TCK) \
411+
XX(jl_setaffinity) \
410412
XX(jl_set_ARGS) \
411413
XX(jl_set_const) \
412414
XX(jl_set_errno) \

src/julia_threads.h

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

364364
JL_DLLEXPORT void jl_wakeup_thread(int16_t tid);
365365

366+
JL_DLLEXPORT int jl_getaffinity(int16_t tid, char *mask, int cpumasksize);
367+
JL_DLLEXPORT int jl_setaffinity(int16_t tid, char *mask, int cpumasksize);
368+
366369
#ifdef __cplusplus
367370
}
368371
#endif

src/threading.c

+46
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,52 @@ JL_DLLEXPORT int jl_alignment(size_t sz)
960960
return jl_gc_alignment(sz);
961961
}
962962

963+
// Return values:
964+
// 0 == success
965+
// 1 == invalid thread id provided
966+
// 2 == ptls2 was NULL
967+
// <0 == uv_thread_getaffinity exit code
968+
JL_DLLEXPORT int jl_getaffinity(int16_t tid, char *mask, int cpumasksize) {
969+
int nthreads = jl_atomic_load_acquire(&jl_n_threads);
970+
if (tid < 0 || tid >= nthreads)
971+
return 1;
972+
973+
// TODO: use correct lock. system_id is only legal if the thread is alive.
974+
jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[tid];
975+
if (ptls2 == NULL)
976+
return 2;
977+
uv_thread_t uvtid = ptls2->system_id;
978+
979+
int ret_uv = uv_thread_getaffinity(&uvtid, mask, cpumasksize);
980+
if (ret_uv != 0)
981+
return ret_uv;
982+
983+
return 0; // success
984+
}
985+
986+
// Return values:
987+
// 0 == success
988+
// 1 == invalid thread id provided
989+
// 2 == ptls2 was NULL
990+
// <0 == uv_thread_getaffinity exit code
991+
JL_DLLEXPORT int jl_setaffinity(int16_t tid, char *mask, int cpumasksize) {
992+
int nthreads = jl_atomic_load_acquire(&jl_n_threads);
993+
if (tid < 0 || tid >= nthreads)
994+
return 1;
995+
996+
// TODO: use correct lock. system_id is only legal if the thread is alive.
997+
jl_ptls_t ptls2 = jl_atomic_load_relaxed(&jl_all_tls_states)[tid];
998+
if (ptls2 == NULL)
999+
return 2;
1000+
uv_thread_t uvtid = ptls2->system_id;
1001+
1002+
int ret_uv = uv_thread_setaffinity(&uvtid, mask, NULL, cpumasksize);
1003+
if (ret_uv != 0)
1004+
return ret_uv;
1005+
1006+
return 0; // success
1007+
}
1008+
9631009
#ifdef __cplusplus
9641010
}
9651011
#endif

test/threads.jl

+12
Original file line numberDiff line numberDiff line change
@@ -341,3 +341,15 @@ end
341341
@testset "Base.Threads docstrings" begin
342342
@test isempty(Docs.undocumented_names(Threads))
343343
end
344+
345+
@testset "jl_*affinity" begin
346+
cpumasksize = @ccall uv_cpumask_size()::Cint
347+
if !Sys.iswindows() && cpumasksize > 0 # otherwise affinities are not supported on the platform (UV_ENOTSUP)
348+
mask = zeros(Cchar, cpumasksize);
349+
jl_getaffinity = (tid, mask, cpumasksize) -> ccall(:jl_getaffinity, Int32, (Int16, Ptr{Cchar}, Int32), tid, mask, cpumasksize)
350+
jl_setaffinity = (tid, mask, cpumasksize) -> ccall(:jl_setaffinity, Int32, (Int16, Ptr{Cchar}, Int32), tid, mask, cpumasksize)
351+
@test jl_getaffinity(1, mask, cpumasksize) == 0
352+
fill!(mask, 1)
353+
@test jl_setaffinity(1, mask, cpumasksize) == 0
354+
end
355+
end

0 commit comments

Comments
 (0)