In today’s world of multi-CPUs, a fundamental question arises as on which of the multiple CPUs does the various tasks (processes and threads) in Linux run / execute? Is it all on one, or distributed over all? If distributed over all, how is the distribution decided? Can the tasks dynamically change the CPU? and so on.
The default behaviour is that the various tasks are distributed over all the enabled* CPUs. And, the Linux scheduler decides which task gets to run on which CPU in a way which yields an optimal performance. This association of a task with a CPU is called CPU affinity of the task. In general, a task (once started) is not switched dynamically from one CPU to another unless and otherwise demanded by some overall performance specific situations. This tendency to keep a task associated with a particular CPU is termed as natural CPU affinity. Though Linux scheduler supports natural CPU affinity, it is not a 100% guarantee that a particular task will always be associated, only with one particular CPU. In fact, Linux scheduler intentionally by default keeps a weak affinity of a task to a particular CPU. In general, that is good only. But what if it is required to have a 100% guaranteed fixed affinity due to some constraints? Is it possible to run a specific task always on a specific CPU, or among some specific CPUs, or at least exclude some CPUs? And the answer is yes – using the command taskset, which is part of the Linux utilities.
As understood above, by default, all tasks are free to run on all enabled CPUs, and that is specified by a CPU bitmask corresponding to all CPUs. Say, there are 4 CPUs on a system. Then, the all CPU bitmask would be hexadecimal “f”.
Number of CPUs on a system can be checked as follows:
$ grep "^processor" /proc/cpuinfo | wc -l
Current CPU affinity bitmask of a specific process, say the init / systemd (pid 1) can be obtained as follows:
$ taskset -p 1
Current CPU affinity bitmask for the current shell can be checked as follows:
$ taskset -p $$
But out of the list of CPUs, specified by the bitmask, how do one know, on which CPU is the specific task currently running on? For that, one may run “top” with the corresponding pid and add the “Last used CPU” column to “top” after pressing “f” key. For the current shell, it may be run as:
$ top -p $$
And then, press “f”. Go to “Last used CPU” by pressing down arrow. Select it by pressing “Space” bar. Come back by pressing “Esc”. Now, the last column in “top” labelled by “P”, tells the processor number, the corresponding task is running on. Without the “-p” option to “top”, it would show for all the top actively running processes. And one may observe the switching of the various tasks between various CPUs.
Now let’s fix one of the tasks to a particular CPU, say for the web browser task. Note down its pid using “ps ax”. Say it is <pid>. And then, run the “top” for this <pid> and with its CPU details as mentioned above. Observe its current CPU change frequently, or even if it is fixed on say 0th CPU. To fix / change its CPU to say 1st, give the following command on an another shell:
$ taskset -p 0x2 <pid>
Observe the CPU in the “top” getting fixed to 1. That’s all.
In fact, if fixing of the CPU is desired for a command to be run from a shell, it can be done while starting the command itself. As an example:
$ taskset 0x3 ls -l
would run the “ls” command between CPUs 0 & 1. For more details, checkout:
$ man taskset
*NB that CPU 0 is always enabled. And for others, they are enabled if /sys/bus/cpu/devices/cpu<cpu_no>/online is set to 1.