Skip to content
Jasmine Taylor edited this page Oct 19, 2023 · 9 revisions

It calls getAffinity once to determine which threads are generally available to all processes. By default, this is all of them but if you have isolated specific CPUs, e.g. using isolcpus=, it will detect and use these to assign critical threads to.

If you have not done this, or you want to run multiple processes like this, you can specify which threads a process can reserve. This can be set with -Daffinity.reserved=CC or whatever hex mask indicates which cpus can be used. I suggest allocating whole cores (all the threads for a core) to a process, as I suspect (but haven't tested) that this would perform best.

To allocate a thread to a CPU, it sets the thread affinity to only one CPU, assuming no other thread will be assigned to it. It can't prevent other threads or interrupts using the CPU, however you can configure the OS (with Linux definitely, and with Windows I would expect this to be possible) not to use certain CPUs, unless specifically scheduled to do so.

CPU Layout

A machine has one or more Sockets (whole chips). Many machines have only one socket, but some have two and a few have four.

Each socket can have a number of cores; between one and eight is common.

Each core can have many threads; one or two is common, but some have up to 32.

It is these logical threads which appear as individual CPUs to the operating system, and it is these that you can bind to.

How are Threads Allocated?

The library reads the CPU layout from /proc/cpuinfo (on Linux), or a cpuinfo or properties file you provide (on Windows or Linux).

Using the layout information you can declare how you want your threads laid out, relative to one another, for example:

  • SAME_CORE - on the same core.
  • SAME_SOCKET - on the same socket, but not the same core.
  • DIFFERENT_SOCKET - on a different socket.
  • DIFFERENT_CORE - any other core.
  • ANY - any available.

Like a search path, the strategies are evaluated in order, to find the next appropriate thread. The first match is taken. If ANY is not the last strategy, a warning is logged and no CPU is assigned; leaving the OS to choose.

For example,

  • SAME_SOCKET, SAME_CORE, ANY means preferably on a different core on the same socket, or the same core, or otherwise any CPU.
  • DIFFERENT_SOCKET, DIFFERENT_CORE means preferably on a different socket, or a different core, otherwise don't bind the thread and let the OS pick one.

It is assumed that CPU ids stride cores. i.e. if you have four cores, the last four CPU ids will be on different cores.
This matters because it allocates CPU ids from the last to first (not CPU 0) and you will naturally want to spread across cores if possible, only sharing cores if you have to.

CPU 0 cannot be allocated because its is assumed that the OS interrupts other processes and your threads that are not bound need to run somewhere. The minimum number of CPUs for this is 1. On Linux, CPU 0 is more likely to be used by the OS interrupts unless you change it, so it is a natural choice to leave.

This means that if you want to bind more threads than you have reservable CPUs, those threads will be left to the OS to schedule - possibly on CPU 0.

Clone this wiki locally