77

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 < 64; i++)
 {
  if (CPU_ISSET(i, &cs))
   count++;
  else
   break;
 }
 return count;
}

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

Treviño
  • 2,999
  • 3
  • 28
  • 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
  • 1
    @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

9 Answers9

93
#include <unistd.h>
long number_of_processors = sysconf(_SC_NPROCESSORS_ONLN);
selbie
  • 100,020
  • 15
  • 103
  • 173
chrisaycock
  • 36,470
  • 14
  • 88
  • 125
48
#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
  • 223,805
  • 18
  • 296
  • 547
  • 4
    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
21

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
  • 170,088
  • 45
  • 397
  • 571
Vikram.exe
  • 4,565
  • 3
  • 29
  • 40
  • 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
12

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,794
  • 4
  • 19
  • 29
RCL
  • 426
  • 4
  • 6
12

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
  • 208,859
  • 35
  • 376
  • 711
  • 14
    +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
  • 13
    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
7

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;
}
Damien Zammit
  • 71
  • 1
  • 1
  • 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. – 15 Volts 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. – 15 Volts Dec 21 '20 at 07:42
  • 1
    @S.Goswami: That's exactly what this code is intended to do; let you know how many threads you could start to max out the number of cores in the affinity mask your process started with. That's useful for some scenarios. – Peter Cordes Jul 28 '22 at 22:20
6

Personally for recent Intel cpus (not x86 in general, just Intel) I use the EAX=0Bh cpuid leaf. See Wikipedia for some details on what info you get about the cores in the current socket aka package. On a multi-socket system, this might be half or a quarter of the system-wide number of physical / logical cores. Intel has a whitepaper on enumerating CPUs with details on what to check in case of multi-socket systems. This code doesn't do that, it just checks one sub-leaf (ECX=1).

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
Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Zibri
  • 9,096
  • 3
  • 52
  • 44
  • 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
  • 1
    Note that even if the physical CPU has e.g. 4 cores and 8 threads, your current `cgroup` or task affinity may limit your process only to 2 cores/2 threads. Why do you need to know the number of cores or threads? – Mikko Rantalainen Jul 26 '22 at 20:58
  • In a VM, this may still report the geometry of the actual hardware you're running on, not the number of virtual CPUs in the guest your VM is running on. That may be interesting to know, but for most purposes isn't what you want. (A VM *can* virtualize the CPUID results if it wants to feed a VM numbers appropriate for the guest, but I think some might not.) – Peter Cordes Jul 28 '22 at 22:24
  • Also, on a multi-socket system, I think this just reports the cores in the current package (socket), so it might be half or a quarter of the true number of physical / logical cores. https://en.wikipedia.org/wiki/CPUID#EAX=4_and_EAX=Bh:_Intel_thread/core_and_cache_topology uses the term "package". – Peter Cordes Jul 28 '22 at 22:26
2

On Linux (Ubuntu):

#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <sched.h>
int GetCPUCount()
{
 cpu_set_t cs;
 sched_getaffinity(0, sizeof(cs), &cs);
 return CPU_COUNT_S(sizeof(cs), &cs);
}

(Assuming the current process has the default CPU affinity.)

Petr Vepřek
  • 1,547
  • 2
  • 24
  • 35
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
  • 12,528
  • 4
  • 33
  • 46