Skip to content

CPU resource management#

HyperQueue allows you to select how many CPU cores will be allocated for each task.

Note

In this text, we use the term CPU for a resource that is provided by the operating system (e.g. what you get from /proc/cpuinfo). In this meaning, it is usually a core of a physical CPU. In the text related to NUMA we use the term socket to refer to physical CPUs.

Requesting more CPUs#

By default, each task requires a single CPU of the worker's node. This can be changed by the flag --cpus.

For example, to submit a job with a task that requires 8 CPUs:

$ hq submit --cpus=8 <program_name> <args...>

This ensures that HyperQueue will exclusively reserve 8 CPUs for this task when it is started. This task would thus never be scheduled on a worker that has less than 8 CPUs.

Note that this reservation exists on a logical level only. To ensure more direct mapping to physical cores, see pinning below.

Requesting all CPUs#

You can also use the value all for the --cpus flag to ensure that the task will request all available CPUs of the worker where it is executed. This will make sure that there will not be any other tasks executing on the same worker at the same time.

$ hq submit --cpus=all <program_name> <args...>

Pinning#

By default, HQ internally allocates CPUs on a logical level. In other words, HQ ensures that the sum of requests of concurrently running tasks does not exceed the number of CPUs of the worker, but process assignment to cores is left to the system scheduler, which may move processes across CPUs as it wants.

If this is not desired, especially in the case of NUMA, processes could be pinned, either manually or automatically.

Automatic pinning#

HyperQueue can pin threads using two ways: with taskset or by setting OpenMP environment variables. You can use the --pin flag to choose between these two modes.

$ hq submit --pin taskset --cpus=8 <your-program> <args>

will cause HyperQueue to execute your program like this:

taskset -c "<allocated-cores>" <your-program> <args>`

$ hq submit --pin omp --cpus=8 <your-program> <args>

will cause HyperQueue to execute your program like this:

OMP_PROC_BIND=close OMP_PLACES="{<allocated-cores>}" <your-program> <args>

If any automatic pinning mode is enabled, the environment variable HQ_PIN will be set.

Manual pinning#

If you want to gain full control over core pinning, you may pin the process by yourself.

The assigned CPUs are stored in the environment variable HQ_CPUS as a comma-delimited list of CPU IDs. You can use utilities such as taskset or numactl and pass them HQ_CPUS to pin a process to these CPUs.

Warning

If you manually pin your processes, do not also use the --pin flag of the submit command. It may have some unwanted interferences.

Below you can find an example of a script file that pins the executed process manually using taskset and numactl:

#!/bin/bash

taskset -c $HQ_CPUS <your-program> <args...>
#!/bin/bash

numactl -C $HQ_CPUS <your-program> <args...>

If you submit this script with hq submit --cpus=4 script.sh, it will pin your program to 4 CPUs allocated by HQ.

NUMA allocation policy#

HQ currently offers the following allocation strategies for CPUs allocation. It can be specified with the --cpus flag in the form "<#cpus> <policy>".

  • Compact (compact) - Tries to allocate cores on as few sockets as possible, based on the currently available cores of a worker.

    $ hq submit --cpus="8 compact" ...
    
  • Strict Compact (compact!) - Always allocates cores on as few sockets as possible for a target node. The task will not be executed until the requirement could be fully fulfilled. For example, if your worker has 4 cores per socket, and you ask for 4 CPUs, it will always be executed on a single socket. If you ask for 8 CPUs, it will always be executed on two sockets.

    $ hq submit --cpus="8 compact!" ...
    

    Tip

    You might encounter a problem in your shell when you try to specify the strict compact policy, because the definition contains an exclamation mark (!). In that case, try to wrap the policy in single quotes, like this:

    $ hq submit --cpus='8 compact!' ...
    
  • Scatter (scatter) - Allocate cores across as many sockets possible, based on the currently available cores of a worker. If your worker has 4 sockets with 8 cores per socket, and you ask for 8 CPUs, then HQ will try to run the process with 2 CPUs on each socket, if possible given the currently available worker cores.

    $ hq submit --cpus="8 scatter" ...
    

The default policy is the compact policy, i.e. --cpus=<X> is equivalent to --cpus="<X> compact".

Note

Specifying policy has effect only if you have more than one socket (physical CPUs). In case of a single socket, policies are indistinguishable.

CPU requests and task arrays#

Resource requests are applied to each task of job. For example, if you submit the following:

$ hq submit --cpus=2 --array=1-10

it will create 10 tasks where each task needs two CPUs.

CPU configuration#

Each worker will automatically detect the number of CPUs available. On Linux systems, it will also detect the partitioning into sockets (NUMA configuration). In most cases, it should work out of the box. If you want to see how will a HQ worker see your CPU configuration without actually starting the worker, you can use the hq worker hwdetect command, which will print the detected CPU configuration.

Manual specification of CPU configuration#

If the automatic detection fails for some reason, or you want to manually configure the CPU configuration, you can use the --cpus flag when starting a worker. Below there are some examples of configuration that you can specify:

  • Worker with 8 CPUs and a single socket.

    $ hq worker start --cpus=8
    

  • Worker with 2 sockets with 12 cores per socket.

    $ hq worker start --cpus=2x12
    

  • Automatically detect CPUs, but ignore HyperThreading. It will detect only the first virtual core of each physical core.

    $ hq worker start --cpus="no-ht"
    

  • Manually specify that the worker should use the following core ids and how they are organized into sockets. In this example, two sockets are defined, one with 3 cores and one with 2 cores.

    $ hq worker start --cpus=[[2, 3, 4], [10, 14]]
    

Several environment variables related to CPU management will be passed to tasks executed by HyperQueue:

  • HQ_CPUS - Comma-separated list of numeric core IDs assigned to the task.
  • HQ_PIN - It is set to taskset or omp (depending on the used pinning mode) if the task was pinned.
  • NUM_OMP_THREADS - Set to the number of cores assigned for task. (For compatibility with OpenMP).

Last update: August 9, 2022
Created: November 7, 2021
Back to top