Linux allows one to specify the logical cores on which a given process is allowed to run. The reason for referring to logical instead of physical cores is due to the fact that each thread of execution of a physical core capable of simultaneous multithreading is presented to the operational system as an independent processing unit. Therefore, a physical core with two threads of execution is seen by the operational system as two (logical) cores, meaning processes can be scheduled to run on on a single logical core or on an arbitrary combination of them.
In Linux terminology, a CPU is the smallest hardware unit capable of executing a thread, so the term CPU will be used below as a synonym for logical core whenever the context permits.
The set of CPUs on which a process is allowed to run is called its processor affinity. One tool which controls the processor affinity of processes on Linux is taskset.
Using taskset, one can run a given command on a single CPU or on a specified set of CPUs; a user with sufficient privileges can also use taskset to change the CPU affinity of a running process. To understand how taskset works, open a terminal and get the PID of some running process in your system (e.g. your web browser):
pidof firefox
Assuming you have a single instance of firefox running in your system, you should get a single PID. Now you can use taskset to retrieve the sets of CPUs on which every thread created by the firefox process is currently allowed to run:
taskset -a -p -c <pid>
The output of the command above should be similar to this (you might see many more threads than shown below):
pid 14367's current affinity list: 0-3
pid 14388's current affinity list: 0-3
pid 14389's current affinity list: 0-3
pid 14390's current affinity list: 0-3
pid 14391's current affinity list: 0-3
pid 14392's current affinity list: 0-3
In my case, the PID of firefox is 14367. All other processes shown above are actually threads belonging to the original firefox process (14367). Given that my laptop's CPU package has four logical cores (two physical cores with Hyper-Threading), the list 0-3 means the process is allowed to run on every logical core available. You can find the total number of logical cores on your device by running lscpu; if your processor suports simultaneous multithreading (SMT), the value of "thread(s) per core" will be larger than 1.
By default, a process is allowed to run on every CPU. To change the allowed set of CPUs for all threads of an already running process, do as shown below:
taskset -a -p -c <cpu-list> <pid>
If you omit -a, only the CPU affinity of the thread whose PID is <pid> will be changed (for processes which have a single thread, using -a or not yields the same result). If you only wish to change the CPU affinity of a single thread of a process, all you have to do then is to omit -a and specify the thread's PID directly. Above, <cpu-list> can be specified with commas, ranges or combinations of both: 1,3-5,7 is equivalent to 1,3,4,5,7.
You need to have administrative privileges to change the CPU affinity of a running process (technically, a program needs only the CAP_SYS_NICE capability to change CPU affinities of other processes, but this is outside the scope of this post).
To start a process and specify its CPU affinity right away (as well as the CPU affinity of all threads created by this process) , use:
taskset -c <cpu-list> <command>
CPU affinity bitmasks
Since, in some applications, using bitmasks might be more convenient than using lists, taskset also takes bitmasks as input (with the least significant bit representing the first logical core). If you wish to specify CPU affinities using bitmasks, just omit the -c option on the commands above and specify the desired CPUs in hexadecimal notation (omitting -c also means outputs will be shown as bitmasks instead of lists). As an example:
taskset -a -p 0x6 <pid>
sets the CPU affinity of all threads of a process whose PID is <pid> to 1,2 (0x6 is 110 in binary representation).
Linux kernel threads
You can visualize the CPU affinities of all threads from all processes running in the system with the following command:
for pid in $(ps -eLf | awk '{print $2}'); do taskset -a -c -p $pid; done
It is very likely that the threads which are not allowed to run in all logical cores of your system (excluding those whose CPU affinities you have set yourself) are kernel threads. To verify that, use the list of PIDs on the output of the command above and look at the output of the following ps command for some process which is not allowed to run on all CPUs:
ps -up <pid>
If the process name (which appears under the column COMMAND) is shown inside square brackets (e.g. [kdmflush]), it is a kernel thread.
Comments
No comments posted yet.