API

Index

References - Pinning

ThreadPinning.pinthreadsFunction
pinthreads(cpuids[; nthreads, force=true, warn=first_pin_attempt(), threadpool=:default])

Pin the first min(length(cpuids), nthreads) Julia threads to an explicit or implicit list of CPU IDs. The latter can be specified in three ways:

  1. explicitly (e.g. 0:3 or [0,12,4]),
  2. by passing one of several predefined symbols (e.g. :cores or :sockets),
  3. by providing a logical specification via helper functions (e.g. node and socket).

See below for more information.

If force=false the pinthreads call will only pin threads if this is the first attempt to pin threads with ThreadPinning.jl. Otherwise it will be a no-op. This may be particularly useful for packages that merely want to specify a "default pinning".

The option warn toggles general warnings, such as unwanted interference with BLAS thread settings.

The keyword argument threadpool can be used to indicate the pool of threads to be pinned. Supported values are :default, :interactive, or :all. (Requires Julia >= 1.9.)

1) Explicit

Simply provide an AbstractVector{<:Integer} of CPU IDs. The latter are expected to be the "physical" ids, i.e. as provided by lscpu, and thus start at zero!

2) Predefined Symbols

  • :cputhreads or :compact: successively pin to all available CPU-threads.
  • :cores: spread threads across all available cores, only use hyperthreads if necessary.
  • :sockets: spread threads across sockets (round-robin), only use hyperthreads if necessary. Set compact=true to get compact pinning within each socket.
  • :numa: spread threads across NUMA/memory domains (round-robin), only use hyperthreads if necessary. Set compact=true to get compact pinning within each NUMA/memory domain.
  • :random: pin threads randomly to CPU-threads
  • :current: pin threads to the CPU-threads they are currently running on
  • :firstn: pin threads to CPU-threads in "physical" order (as specified by lscpu).
  • :affinitymask: pin threads to different CPU-threads in accordance with their affinity mask (must be the same for all of them). By default, hyperthreads_last=true.

3) Logical Specification

The functions node, socket, numa, and core can be used to to specify CPU IDs of/within a certain domain. Moreover, the functions sockets and numas can be used to express a round-robin scatter policy between sockets or NUMA domains, respectively.

Examples (domains):

  • pinthreads(socket(1, 1:3)) # pin to the first 3 cores in the first socket
  • pinthreads(socket(1, 1:3; compact=true)) # pin to the first 3 CPU-threads in the first socket
  • pinthreads(numa(2, [2,4,6])) # pin to the second, the fourth, and the sixth cores in the second NUMA/memory domain
  • pinthreads(node(ncores():-1:1)) # pin threads to cores in reversing order (starting at the end of the node)
  • pinthreads(sockets()) # scatter threads between sockets, cores before hyperthreads

Different domains can be concatenated by providing them in a vector or as separate arguments to pinthreads.

Examples (concatenation):

  • pinthreads([socket(1, 1:3), numa(2, 4:6)])
  • pinthreads(socket(1, 1:3), numa(2, 4:6))
source
ThreadPinning.unpinthreadMethod
unpinthread(threadid)

Unpins the given Julia thread by setting the affinity mask to all unity. Afterwards, the OS is free to move the Julia thread from one CPU thread to another.

source
ThreadPinning.unpinthreadsMethod

Unpins all Julia threads by setting the affinity mask of all threads to all unity. Afterwards, the OS is free to move any Julia thread from one CPU thread to another.

source
ThreadPinning.with_pinthreadsMethod
with_pinthreads(f, args; threadpool, soft, kwargs...)

Runs the function f with the specified pinning and restores the previous thread affinities afterwards. Typically to be used in combination with do-syntax.

By default (soft=false), before the thread affinities are restored, the Julia threads will be pinned to the CPU-threads they were running on previously.

Example

julia> getcpuids()
4-element Vector{Int64}:
  7
 75
 63
  4

julia> with_pinthreads(:cores) do
           getcpuids()
       end
4-element Vector{Int64}:
 0
 1
 2
 3

julia> getcpuids()
4-element Vector{Int64}:
  7
 75
 63
  4
source
ThreadPinning.pinthreads_mpiMethod
pinthreads_mpi(symbol, rank, nranks; nthreads_per_rank, compact, kwargs...)

Pin MPI ranks, that is, their respective Julia thread(s), to (subsets of) domains (e.g. sockets or memory domains). Specifically, when calling this function on all MPI ranks, the latter will be distributed in a round-robin fashion among the specified domains such that their Julia threads are pinned to non-overlapping ranges of CPU-threads within the domain.

Valid options for symbol are :sockets and :numa.

If compact=false (default), physical cores are occupied before hyperthreads. Otherwise, CPU-cores - with potentially multiple CPU-threads - are filled up one after another (compact pinning).

The keyword argument nthreads_per_rank (default Threads.nthreads()) can be used to pin only a subset of the available Julia threads per MPI rank.

Note: As per usual for MPI, rank starts at zero.

Example:

using ThreadPinning
using MPI
comm = MPI.COMM_WORLD
nranks = MPI.Comm_size(comm)
rank = MPI.Comm_rank(comm)
pinthreads_mpi(:sockets, rank, nranks)
source
ThreadPinning.setaffinityMethod
setaffinity(cpuids::AbstractVector{<:Integer})

Set the affinity of the calling Julia thread to the given CPU-threads.

Example:

  • setaffinity(socket(1)) # set the affinity to the first socket
  • setaffinity(numa(2)) # set the affinity to the second NUMA domain
  • setaffinity(socket(1, 1:3)) # set the affinity to the first three cores in the first NUMA domain
  • setaffinity([1,3,5]) # set the affinity to the CPU-threads with the IDs 1, 3, and 5.
source
ThreadPinning.setaffinityMethod
setaffinity(
    threadid::Integer,
    cpuids::AbstractVector{<:Integer};
    kwargs...
)

Set the affinity of a specific Julia thread to the given CPU-threads.

source

References - Querying

ThreadPinning.coreFunction
core(i)
core(i, idcs; shuffle, kwargs...)

Represents the CPU ID domain of core i (logical index, starts at 1). Uses compact ordering by default. Set shuffle=true to randomize.

Optional second argument: Logical indices to select a subset of the domain.

To be used as input argument for pinthreads. What it actually returns is an implementation detail!

source
ThreadPinning.cpuids_allMethod

Returns a Vector{Int} which lists all valid CPUIDs. There is no guarantee about the order except that it is the same as in lscpu.

source
ThreadPinning.cpuids_per_nodeMethod
cpuids_per_node(; compact)

Returns a Vector{Int} which indicates the CPUIDs associated with the available node. Physical cores come first. Set compact=true to get compact ordering.

source
ThreadPinning.cpuids_per_numaMethod
cpuids_per_numa(; compact)

Returns a Vector{Vector{Int}} which indicates the CPUIDs associated with the available NUMA domains. Within each memory domain, physical cores come first. Set compact=true to get compact ordering instead.

source
ThreadPinning.cpuids_per_socketMethod
cpuids_per_socket(; compact)

Returns a Vector{Vector{Int}} which indicates the CPUIDs associated with the available CPU sockets. Within each socket, physical cores come first. Set compact=true to get compact ordering instead.

source
ThreadPinning.getcpuidMethod
getcpuid(threadid)

Returns the ID of the CPU thread on which the given Julia thread (threadid) is currently running.

source
ThreadPinning.getcpuidMethod

Returns the ID of the CPU thread on which the calling thread is currently running.

See sched_getcpu for more information.

source
ThreadPinning.getcpuidsMethod

Returns the IDs of the CPU-threads on which the Julia threads are currently running.

See getcpuid for more information.

source
ThreadPinning.getnumanodeMethod
getnumanode(threadid)

Returns the ID (starting at zero) of the NUMA node corresponding to the CPU thread on which the given Julia thread (threadid) is currently running.

source
ThreadPinning.getnumanodeMethod

Returns the ID (starting at zero) of the NUMA node corresponding to the CPU thread on which the calling thread is currently running.

source
ThreadPinning.getnumanodesMethod

Returns the ID (starting at zero) of the NUMA nodes corresponding to the CPU threads on which the Julia threads are currently running.

source
ThreadPinning.ishyperthreadMethod
ishyperthread(cpuid)

Check whether the given CPU-thread is a hyperthread (i.e. the second CPU-thread associated with a CPU-core).

source
ThreadPinning.ispinnedFunction

Returns true if the thread is pinned, i.e. if it has an affinity mask that comprises a single CPU-thread.

source
ThreadPinning.nodeFunction
node()
node(idcs; shuffle, kwargs...)

Represents the CPU ID domain of the entire node/system. By default, cores will be used first and hyperthreads will only be used if necessary. Provide compact=true to get compact ordering instead. Set shuffle=true to randomize. Set shuffle=true to randomize.

Optional first argument: Logical indices to select a subset of the domain.

To be used as input argument for pinthreads. What it actually returns is an implementation detail!

source
ThreadPinning.numaFunction
numa(i)
numa(i, idcs; shuffle, kwargs...)

Represents the CPU ID domain of NUMA/memory domain i (logical index, starts at 1). By default, cores will be used first and hyperthreads will only be used if necessary. Provide compact=true to get compact ordering instead. Set shuffle=true to randomize.

Optional second argument: Logical indices to select a subset of the domain.

To be used as input argument for pinthreads. What it actually returns is an implementation detail!

source
ThreadPinning.numasFunction
numas()
numas(idcs; shuffle, kwargs...)

Represents the CPU IDs of the system as obtained by a round-robin scattering between NUMA/memory domain. By default, within each memory domain, cores will be used first and hyperthreads will only be used if necessary. Provide compact=true to get compact ordering within each memory domain. Set shuffle=true to randomize.

Optional first argument: Logical indices to select a subset of the domain.

To be used as input argument for pinthreads. What it actually returns is an implementation detail!

source
ThreadPinning.socketFunction
socket(i)
socket(i, idcs; shuffle, kwargs...)

Represents the CPU ID domain of socket i (logical index, starts at 1). By default, cores will be used first and hyperthreads will only be used if necessary. Provide compact=true to get compact ordering instead. Set shuffle=true to randomize.

Optional second argument: Logical indices to select a subset of the domain.

To be used as input argument for pinthreads. What it actually returns is an implementation detail!

source
ThreadPinning.socketsFunction
sockets()
sockets(idcs; shuffle, kwargs...)

Represents the CPU IDs of the system as obtained by a round-robin scattering between sockets. By default, within each socket, cores will be used first and hyperthreads will only be used if necessary. Provide compact=true to get compact ordering within each socket. Set shuffle=true to randomize.

Optional first argument: Logical indices to select a subset of the domain.

To be used as input argument for pinthreads. What it actually returns is an implementation detail!

source
ThreadPinning.threadinfoFunction
threadinfo()
threadinfo(
    io;
    blas,
    hints,
    color,
    masks,
    groupby,
    threadpool,
    slurm,
    kwargs...
)

Print information about Julia threads, e.g. on which CPU-threads (i.e. cores if hyperthreading is disabled) they are running.

Keyword arguments:

  • color (default: true): Toggle between colored and black-and-white output.
  • blocksize (default: 32): Wrap to a new line after blocksize many CPU-threads.
  • hyperthreading (default: true): If true, we (try to) highlight CPU-threads associated with hyperthreading in the color=true output.
  • blas (default: false): Show information about BLAS threads as well.
  • slurm (default: false): Only show the part of the system that is covered by the active SLURM session.
  • hints (default: false): Give some hints about how to improve the threading related settings.
  • groupby (default: :sockets): Options are :sockets, :numa, :cores, or :none.
  • masks (default: false): Show the affinity masks of all Julia threads.
  • threadpool (default: :default): Only consider Julia threads in the given thread pool. Supported values are :default, :interactive, and :all. Only works for Julia >= 1.9.
source