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 popcount (count the number of 1
s 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 1
s. 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 fromtaskset
into uppercase (becausebc
needs uppercase hexadecimal numbers).sed -E 's/.*:\s*/ibase=16;obase=2;/'
- remove the textual output fromtaskset
and replace it with instructions forbc
.ibase
is the base of the input number (16 = hex) andobase
is the base we want for the output (2 = binary).- At this point we'll have
ibase=16;obase=2;FFF
- At this point we'll have
bc
- Readsibase=16;obase=2;FFF
and printsFFF
as111111111111
tr -d '0\n'
- Deletes all zeroes and the newline from the output frombc
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)