There’s something really quite subtle about how the
nproc utility from GNU coreutils works. If you look at the man page, it’s even the very first sentence:
Print the number of processing units available to the current process, which may be less than the number of online processors.
So, what does that actually mean? Well, just because the computer some code is running on has a certain number of CPUs (and here I mean “number of hardware threads”) doesn’t necessarily mean that you can spawn a process that uses that many. What’s a simple example? Containers! Did you know that when you invoke
docker to run a container, you can easily limit how much CPU the container can use? In this case, we’re looking at the
--cpuset-cpus parameter, as the
--cpus one works differently.
$ nproc 8 $ docker run --cpuset-cpus=0-1 --rm=true -it amazonlinux:2 bash-4.2# nproc 2 bash-4.2# exit $ docker run --cpuset-cpus=0-2 --rm=true -it amazonlinux:2 bash-4.2# nproc 3
As you can see,
nproc here gets the right bit of information, so if you’re wanting to do a calculation such as “Please use up to the maximum available CPUs” as a parameter to the configuration of a piece of software (such as how many threads to run), you get the right number.
But what if you use some of the other common methods?
$ /usr/bin/lscpu -p | grep -c "^[0-9]" 8 $ grep -c 'processor' /proc/cpuinfo 8 $ docker run --cpuset-cpus=0-1 --rm=true -it amazonlinux:2 bash-4.2# yum install -y /usr/bin/lscpu ...... bash-4.2# /usr/bin/lscpu -p | grep -c "^[0-9]" 8 bash-4.2# grep -c 'processor' /proc/cpuinfo 8 bash-4.2# nproc 2
In this case, if you base your number of threads off grepping
lscpu you take another dependency (on the
util-linux package), which isn’t needed. You also get the wrong answer, as you do by grepping
/proc/cpuinfo. So, what this will end up doing is just increase the number of context switches, possibly also adding a performance degradation. It’s not just in
docker containers where this could be an issue of course, you can use the same mechanism that
docker uses anywhere you want to control resources of a process.
Another subtle thing to watch out for is differences in
/proc/cpuinfo content depending on CPU architecture. You may not think it’s an issue today, but who wants to needlessly debug something?
tl;dr: for determining “how many processes to run”: use
nproc, don’t grep
Thanks Stewart. Once again, I learned something interesting. Is there a library function that avoids shelling out to coreutils?
Good to know.
I would like to know how `nproc` works internally though, but I could check the code anyway.
@Brad: It seams that `nproc` does not simply call a single function. But it seams hand-able enough to extract the functions into a library.