71

Is there an API to get the number of CPUs available in Linux? I mean, without using /proc/cpuinfo or any other sys-node file...

I've found this implementation using sched.h:

int GetCPUCount()
{
 cpu_set_t cs;
 CPU_ZERO(&cs);
 sched_getaffinity(0, sizeof(cs), &cs);

 int count = 0;
 for (int i = 0; i < 8; i++)
 {
  if (CPU_ISSET(i, &cs))
   count++;
 }
 return count;
}

But, isn't there anything more higher level using common libraries?

Treviño
  • 2,497
  • 2
  • 26
  • 23
  • 25
    Why are people so afraid to use /proc? Every Linux box i've seen in the past 15 years has it, it's always up to date with what the kernel knows, and the format of the existing stuff in it doesn't change much. – cHao Jan 03 '11 at 16:58
  • 1
    I think it's great that you're trying to learn different ways of doing things, but are you trying to reinvent the wheel? – David Weiser Jan 03 '11 at 17:09
  • For gnulib systems this *does* work by looking at /proc, but if you really want an easy one liner and don't have major performance/security considerations, you can just ``(system("exit `nproc`") >> 8)`` ...even busybox has an internal nproc so this should be fine on just about any linux (for instance, my router firmware...). The shift is required because `sh` exit codes embed a trailing null byte to be string processing friendly. – l.k May 05 '19 at 09:01
  • 1
    Also see https://stackoverflow.com/questions/150355/programmatically-find-the-number-of-cores-on-a-machine – Jay Sullivan Feb 01 '20 at 15:53
  • 4
    /proc isn't portable – Edd Barrett Jun 02 '21 at 11:07
  • @cHao Because /proc ignores cgroups, which may lead to "oversubscription" if the process is running more threads than are granted to it in the cpuset cgroup. – phzx_munki Feb 14 '22 at 21:28

8 Answers8

91
#include <unistd.h>
long number_of_processors = sysconf(_SC_NPROCESSORS_ONLN);
selbie
  • 91,215
  • 14
  • 97
  • 163
chrisaycock
  • 34,416
  • 14
  • 83
  • 119
45
#include <stdio.h>
#include <sys/sysinfo.h>

int main(int argc, char *argv[])
{
    printf("This system has %d processors configured and "
        "%d processors available.\n",
        get_nprocs_conf(), get_nprocs());
    return 0;
}

https://linux.die.net/man/3/get_nprocs

Basile Starynkevitch
  • 216,767
  • 17
  • 275
  • 509
  • 1
    This answer does not give the same result as the snippet given in the question. If a process is bound to a subset of the CPUs on the machine using `taskset`, then the method using `sched_getaffinity()` gives the number of allocated CPUs, while `get_nprocs()` gives the total number of CPUs that the machine has available. This is bad if you're using this to decide on a number of threads, since if only a single core is allocated on a many-core machine then the process will thrash. – Ed Bennett Sep 01 '21 at 09:59
20

This code (drawn from here) should work on both windows and *NIX platforms.

#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#else
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>


int main() {
  long nprocs = -1;
  long nprocs_max = -1;
#ifdef _WIN32
#ifndef _SC_NPROCESSORS_ONLN
SYSTEM_INFO info;
GetSystemInfo(&info);
#define sysconf(a) info.dwNumberOfProcessors
#define _SC_NPROCESSORS_ONLN
#endif
#endif
#ifdef _SC_NPROCESSORS_ONLN
  nprocs = sysconf(_SC_NPROCESSORS_ONLN);
  if (nprocs < 1)
  {
    fprintf(stderr, "Could not determine number of CPUs online:\n%s\n", 
strerror (errno));
    exit (EXIT_FAILURE);
  }
  nprocs_max = sysconf(_SC_NPROCESSORS_CONF);
  if (nprocs_max < 1)
  {
    fprintf(stderr, "Could not determine number of CPUs configured:\n%s\n", 
strerror (errno));
    exit (EXIT_FAILURE);
  }
  printf ("%ld of %ld processors online\n",nprocs, nprocs_max);
  exit (EXIT_SUCCESS);
#else
  fprintf(stderr, "Could not determine number of CPUs");
  exit (EXIT_FAILURE);
#endif
}
Brad Larson
  • 169,393
  • 45
  • 393
  • 567
Vikram.exe
  • 4,485
  • 3
  • 28
  • 39
  • I got this code a long time back from some one (don't remember the name). – Vikram.exe Jan 03 '11 at 18:10
  • 2
    I'm not sure posting this code snippet really answers the OP's question, although they might reverse-engineer some useful info out of it. – MarkR Jan 04 '11 at 06:47
  • 2
    I agree with MarkR. chrisaycock provides a succinct answer. – poindexter Jul 05 '12 at 17:41
  • 1
    You should use the `#error` preprocessor directive if `_SC_NPROCESSORS_ONLN` is not defined. This is a compile-time failure, not a run-time failure. – Guido Flohr Feb 03 '19 at 11:43
11

sched_affinity() version you mention in the beginning is still better than /proc/cpuinfo and/or _SC_NPROCESSORS_ONLN since it only counts CPUs available for a given process (some may be disabled by sched_setaffinity() invoked by an outside process). The only change would be using CPU_COUNT() instead of doing CPU_ISSET in a loop.

krsteeve
  • 1,797
  • 4
  • 19
  • 29
RCL
  • 406
  • 4
  • 6
11

Using /proc/cpuinfo is the cleanest and most portable solution. In case the open fails, you could simply assume 1 cpu or 2 cpus. Code that depends on knowing the number of cpus for a purpose other than micro-optimizing (e.g. choosing the ideal number of threads to run) is almost surely doing something dumb.

The _SC_NPROCESSORS_ONLN solution depends on a non-standard (glibc-specific) sysconf extension, which is a much bigger dependency than /proc (all Linux systems have /proc, but some have non-glibc libcs or older versions of glibc that lack _SC_NPROCESSORS_ONLN).

R.. GitHub STOP HELPING ICE
  • 201,833
  • 32
  • 354
  • 689
  • 12
    +1 The OP seemed adamant about hanging himself, so I just gave him the rope. – chrisaycock Jan 03 '11 at 17:19
  • 3
    I think Ulrich Drepper gave him the rope. I really don't understand the motivation for adding non-standard things like this when there's an existing, much cleaner and much more portable way to do the same thing. (If you write `_SC_NPROCESSORS_ONLN` in your program, it will fail to compile if the constant is missing, but the other ways just fail at runtime (failed `open`, etc.) and any sane code would handle the failure condition.) – R.. GitHub STOP HELPING ICE Jan 03 '11 at 17:24
  • 12
    In what way is /proc/cpuinfo portable? This is a Linux-specific interface (some other systems emulate it, for example, FreeBSD with the linprocfs filesystem mounted in /proc). the sysconfig _SC_NPROCESSORS_ONLN for example, is supported by FreeBSD. – MarkR Jan 04 '11 at 06:50
  • 5
    It's portable in that it doesn't prevent your program from running on systems where it's not available, and on systems where `/proc` doesn't have a special meaning, a simple text file with the right information could be stored by the administrator in `/proc/cpuinfo`. – R.. GitHub STOP HELPING ICE Jan 04 '11 at 13:37
  • 6
    Parsing a file in order to get low level information is completely primitive (and hard to maintain if the file format changes or vary across implementations). – ebasconp May 21 '15 at 15:11
  • @oopscene: Getting, or IMO even _caring_ about, low level information is primitive, by definition. Once you do care, though, getting it from text files allows for abstractions that syscalls and such simply can't match. Like the one mentioned in the comment right above yours. – cHao Aug 25 '15 at 23:14
  • 3
    @cHao: This is untrue. Caring about the number of CPUs (and moreso, the number of hyperthreaded cores) is only "primitive" insofar as it is a basic piece of information that is needed for most non-trivial modern programs (yes, it is not 1980 any more). While other operating systems are arguably poor at getting this information programatically (e.g. 35 lines of code with a loop and several memory allocations under Windows) the LInux approach "parse a text file" is simply ridiculous. Even more so as they can't even agree on whether /proc or /sys is the correct thing. – Damon Jan 16 '17 at 15:33
  • @Damon: It's "primitive" in that it relies directly on what hardware you're running. Firstly, no, you don't need that information in the vast majority of cases. While it can occasionally be used to optimize the number of waiting threads or whatever, a program that breaks because it doesn't know how many cores are available is already quite broken. But secondly, the Linux approach doesn't even require Linux. And i've yet to see a Linux machine where /proc/cpuinfo is unavailable. – cHao Jan 16 '17 at 18:06
6

Personally for recent intel cpus I use this:

int main()
{
unsigned int eax=11,ebx=0,ecx=1,edx=0;

asm volatile("cpuid"
        : "=a" (eax),
          "=b" (ebx),
          "=c" (ecx),
          "=d" (edx)
        : "0" (eax), "2" (ecx)
        : );
            
printf("Cores: %d\nThreads: %d\nActual thread: %d\n",eax,ebx,edx);
}

Output:

Cores: 4
Threads: 8
Actual thread: 1

Or, more concisely:

#include <stdio.h>

int main()
{
unsigned int ncores=0,nthreads=0,ht=0;

asm volatile("cpuid": "=a" (ncores), "=b" (nthreads) : "a" (0xb), "c" (0x1) : );

ht=(ncores!=nthreads);

printf("Cores: %d\nThreads: %d\nHyperThreading: %s\n",ncores,nthreads,ht?"Yes":"No");

return 0;
}

Output:

Cores: 4
Threads: 8
HyperThreading: Yes
Zibri
  • 8,006
  • 3
  • 47
  • 40
  • In the first example, `edx` says 4 (I don't have hyperthreading turned on, but I don't get 1.) Is it possible that you made a small mistake here? – Alexis Wilke Apr 18 '19 at 19:20
  • I think that the only drawback here is that some of the CPUs may not be available to you for one reason or another. The `CPUID` instruction is likely to ignore that OS feature. That being said, I've yet to come across such a system! – Alexis Wilke Apr 18 '19 at 19:27
  • Also this is specific to Intel processors https://en.wikipedia.org/wiki/CPUID#EAX=4_and_EAX=Bh:_Intel_thread/core_and_cache_topology – Alexis Wilke Apr 18 '19 at 22:57
  • @AlexisWilke I stated that in the **first line** of my answer. Did you miss that or you love to state the obvious? ;) – Zibri Dec 01 '19 at 09:48
  • what is the difference between threads, actual threads and hyperthreading in a nutshell in terms of allocating threads to cores for say a summation or matrix multiplication? – mLstudent33 Dec 29 '19 at 22:06
  • With the posted code in this answer running on my machine, I got 4 cores, 6 threads, hyperthread YES. But with the library [cpuinfo](https://github.com/pytorch/cpuinfo) installed and called from my cpp file, there is 6 cores and 6 processors. I don't understand why got different number of cores. – ChrisZZ Jan 31 '22 at 13:51
3

None of the answers that involve sysconf(...) or get_nprocs() are correct for honouring the number of processors restricted to a task by cpu affinity.

You need something like this to get the number of processors available to a task:

#define _GNU_SOURCE
#include <sched.h>
#include <stdio.h>

int nprocs()
{
  cpu_set_t cs;
  CPU_ZERO(&cs);
  sched_getaffinity(0, sizeof(cs), &cs);
  return CPU_COUNT(&cs);
}

int main()
{
  printf("procs=%d\n", nprocs());
  return 0;
}
  • Would this still be correct if the process has called cpu_setaffinity to restrict the number of affine CPUs? – user1637056 Aug 10 '20 at 23:43
  • For the test, I have a bash script `while : ; do echo 0 > /sys/devices/system/cpu/cpu3/online && sleep 0.5 && echo 1 > /sys/devices/system/cpu/cpu3/online ; sleep 0.5 ; echo Hey! ; done` ; it switches off and on cpu3 really fast. `sysconf(_SC_NPROCESSORS_ONLN)` fails to show the correct CPU when put inside a while loop, but if I put that in a `watch -n 0.1 ./a.out` (terrible choice), then it shows the core counts correctly. Same thing with getconf, it restarts every time in watch, and shows correct info. Your script also shows the correct values. – S.Goswami Dec 20 '20 at 21:18
  • But the caveat being if I use `task -c 0 ./a.out`, it gives me `procs=1` instead of 4, in other words it just counts the CPU assigned to the process. – S.Goswami Dec 21 '20 at 07:42
0

Another method scanning cpu* directories under sys file system:

#include<stdio.h>
#include <dirent.h>
#include <errno.h>
#define LINUX_SYS_CPU_DIRECTORY "/sys/devices/system/cpu"

int main() {
   int cpu_count = 0;
   DIR *sys_cpu_dir = opendir(LINUX_SYS_CPU_DIRECTORY);
   if (sys_cpu_dir == NULL) {
       int err = errno;
       printf("Cannot open %s directory, error (%d).\n", LINUX_SYS_CPU_DIRECTORY, strerror(err));
       return -1;
   }
   const struct dirent *cpu_dir;
   while((cpu_dir = readdir(sys_cpu_dir)) != NULL) {
       if (fnmatch("cpu[0-9]*", cpu_dir->d_name, 0) != 0)
       {
          /* Skip the file which does not represent a CPU */
          continue;
       }
       cpu_count++;
   }
   printf("CPU count: %d\n", cpu_count);
   return 0;
}
Sunil Bojanapally
  • 11,964
  • 4
  • 34
  • 43