Sunday, January 28, 2024

[SOLVED] Without writing any code, is there a command to retrieve the number of available cores in the affinity for the current shell?

Issue

Assuming Linux, and assuming the current shell was started possibly restricted with taskset, I can write some code to get the current process affinity as

#include <vector>
#include <pthread.h>
#include <stdio.h>

int getNumberOfAvailableCores() {
    pthread_t self = pthread_self();
    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    int res = ::pthread_getaffinity_np(self, sizeof(cpuset), &cpuset);
    int num_cores = 0;
    if ( res!=0 ) return -1;
    for (int j = 0; j < CPU_SETSIZE; j++) {
        if (CPU_ISSET(j, &cpuset)) ++num_cores;
    }
    return num_cores;
}


int main() {
    int num_cores = getNumberOfAvailableCores();
    printf( "%d\n", num_cores );
    return 0;
}

https://godbolt.org/z/TxT67WWT6

But on machines where I do not even a compiler installed, is there any way to guess the number of available cores?

getconf _NPROCESSORS_ONLN will return the number of processors online, but will not take in consideration the number of cores isolated. Same for grepping /proc/cpuinfo or lscpu.

I looked into /proc/self but would not find a clean way to do it.


Solution

You want the command nproc:

nproc - print the number of processing units available

Example where the affinity mask contains 3 processors:

$ taskset --cpu-list 0,2,4 bash
$ nproc
3

My old answer may be useful in case nproc isn't available for some reason:

The taskset command is used to set or retrieve the CPU affinity of a running process given its pid

And the -p option for taskset says:

  • Operate on an existing PID and do not launch a new task.

So, you get a hex number with the affinity mask for your process. Example:

$ taskset -p $$
pid 1643922's current affinity mask: fff

Now, you want to do a (count the number of 1s in the binary representation of the number).

The idea is then to convert the number into its binary form and then count the number of 1s. Here's a one-liner:

taskset -p $$ | \
tr '[[:lower:]]' '[[:upper:]]' | \
sed -E 's/.*:\s*/ibase=16;obase=2;/' | bc | tr -d '0\n' | wc -c
  • tr '[[:lower:]]' '[[:upper:]]' - converts the output from taskset into uppercase (because bc needs uppercase hexadecimal numbers).
  • sed -E 's/.*:\s*/ibase=16;obase=2;/' - remove the textual output from taskset and replace it with instructions for bc. ibase is the base of the input number (16 = hex) and obase is the base we want for the output (2 = binary).
    • At this point we'll have ibase=16;obase=2;FFF
  • bc - Reads ibase=16;obase=2;FFF and prints FFF as 111111111111
  • tr -d '0\n' - Deletes all zeroes and the newline from the output from bc
  • wc -c - count all characters.

In my case, where the affinity mask is fff, the output is 12.


Testing: I here start a subshell with 3 processors available and then use the oneliner above from within that shell to figure this out:

$ taskset --cpu-list 0,2,4 bash
$ taskset -p $$ | \
> tr '[[:lower:]]' '[[:upper:]]' | \
> sed -E 's/.*:\s*/ibase=16;obase=2;/' | bc | tr -d '0\n' | wc -c
3


Answered By - Ted Lyngmo
Answer Checked By - Cary Denson (WPSolving Admin)