【问题标题】:How to get the number of CPUs in Linux using C?如何使用 C 获取 Linux 中的 CPU 数量?
【发布时间】:2011-06-02 22:51:13
【问题描述】:

是否有 API 可以获取 Linux 中可用的 CPU 数量? 我的意思是,不使用 /proc/cpuinfo 或任何其他 sys-node 文件...

我使用 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;
}

但是,使用通用库没有更高层次的东西吗?

【问题讨论】:

  • 为什么人们如此害怕使用 /proc?我在过去 15 年中看到的每一个 Linux 机器都有它,它总是与内核所知道的内容保持同步,并且其中现有内容的格式没有太大变化。
  • 我认为您尝试学习不同的做事方式很好,但您是否想重新发明轮子?
  • 对于 gnulib 系统,这确实通过查看 /proc 来工作,但如果你真的想要一个简单的单行并且没有主要的性能/安全考虑,你可以(system("exit `nproc`") &gt;&gt; 8) ...甚至busybox都有一个内部nproc,所以这在任何Linux上都应该没问题(例如,我的路由器固件......)。由于sh 退出代码嵌入了一个尾随空字节,以便字符串处理友好,因此需要进行移位。
  • /proc 不可移植

标签: c linux multithreading cpu processor


【解决方案1】:
#include <unistd.h>
long number_of_processors = sysconf(_SC_NPROCESSORS_ONLN);

【讨论】:

  • 不错的解决方案,但似乎是 POSIX 的 Linux 扩展:pubs.opengroup.org/onlinepubs/9699919799/functions/sysconf.html
  • 这给出了在线核心数。如果我让任何核心离线,它不会在这里返回
  • @iDebD_gh - 如果我没记错的话,那是_SC_NPROCESSORS_CONF 提供的。
  • @iDebD_gh 离线核心是什么意思?
【解决方案2】:
#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

【讨论】:

  • 这个答案给出的结果与问题中给出的 sn-p 不同。如果使用taskset 将进程绑定到机器上的CPU 子集,则使用sched_getaffinity() 的方法给出分配的CPU 数量,而get_nprocs() 给出机器可用的CPU 总数。如果你用它来决定线程的数量,这很糟糕,因为如果在多核机器上只分配一个核,那么进程就会崩溃。
【解决方案3】:

这段代码(取自here)应该可以在windows和*NIX平台上运行。

#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
}

【讨论】:

  • 我很久以前从某个人那里得到了这段代码(不记得名字了)。
  • 我不确定发布此代码 sn-p 是否真的回答了 OP 的问题,尽管他们可能会从中逆向工程出一些有用的信息。
  • 我同意 MarkR。 chrisaycock 提供了一个简洁的答案。
  • 如果未定义 _SC_NPROCESSORS_ONLN,则应使用 #error 预处理器指令。这是编译时失败,而不是运行时失败。
【解决方案4】:

使用/proc/cpuinfo 是最简洁、最便携的解决方案。如果打开失败,您可以简单地假设 1 cpu 或 2 cpu。出于微优化以外的目的(例如选择要运行的理想线程数)而依赖于知道 cpu 数量的代码几乎肯定是在做一些愚蠢的事情。

_SC_NPROCESSORS_ONLN 解决方案依赖于非标准(glibc 特定)sysconf 扩展,它比 /proc 更大的依赖(所有 Linux 系统都有 /proc,但有些有非 glibc libcs或缺少 _SC_NPROCESSORS_ONLN 的旧版本 glibc)。

【讨论】:

  • +1 OP 似乎坚持要上吊,所以我就给了他绳子。
  • 我认为 Ulrich Drepper 给了他绳索。当有一种现有的、更清洁、更便携的方式来做同样的事情时,我真的不明白添加这样的非标准内容的动机。 (如果你在程序中写_SC_NPROCESSORS_ONLN,如果常量丢失,它将无法编译,但其他方式只会在运行时失败(失败open,等等)并且任何理智的代码都会处理失败情况。)
  • /proc/cpuinfo 以何种方式可移植?这是一个特定于 Linux 的接口(一些其他系统模拟它,例如,带有安装在 /proc 中的 linprocfs 文件系统的 FreeBSD)。例如,sysconfig _SC_NPROCESSORS_ONLN 由 FreeBSD 支持。
  • 它是可移植的,因为它不会阻止你的程序在它不可用的系统上运行,以及在/proc没有特殊含义的系统上运行,一个简单的文本文件管理员可以将信息存储在/proc/cpuinfo
  • 解析文件以获取低级信息是完全原始的(如果文件格式发生变化或因实现而异,则难以维护)。
【解决方案5】:

您在开头提到的sched_affinity() 版本仍然优于/proc/cpuinfo 和/或_SC_NPROCESSORS_ONLN,因为它只计算给定进程可用的CPU(有些可能被外部进程调用的sched_setaffinity() 禁用) .唯一的变化是使用CPU_COUNT(),而不是循环使用CPU_ISSET

【讨论】:

    【解决方案6】:

    个人最近的英特尔CPU我用这个:

    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);
    }
    

    输出:

    Cores: 4
    Threads: 8
    Actual thread: 1
    

    或者,更简洁:

    #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;
    }
    

    输出:

    Cores: 4
    Threads: 8
    HyperThreading: Yes
    

    【讨论】:

    • 在第一个示例中,edx 说 4(我没有打开超线程,但我没有得到 1。)您可能在这里犯了一个小错误吗?跨度>
    • 我认为这里唯一的缺点是某些 CPU 可能由于某种原因对您不可用。 CPUID 指令可能会忽略该操作系统功能。话虽如此,我还没有遇到过这样的系统!
    • @AlexisWilke 我在回答的第一行中说过。您是否错过了这一点,或者您喜欢陈述显而易见的事情? ;)
    • 简而言之,线程、实际线程和超线程在将线程分配给核心以进行求和或矩阵乘法方面有什么区别?
    【解决方案7】:

    涉及sysconf(...)get_nprocs() 的答案均不适用于遵守受CPU 亲和力限制的任务的处理器数量。

    你需要这样的东西来获得一个任务可用的处理器数量:

    #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;
    }
    

    【讨论】:

    • 如果进程调用了 cpu_setaffinity 来限制仿射 CPU 的数量,这仍然正确吗?
    • 为了测试,我有一个bash脚本while : ; do echo 0 &gt; /sys/devices/system/cpu/cpu3/online &amp;&amp; sleep 0.5 &amp;&amp; echo 1 &gt; /sys/devices/system/cpu/cpu3/online ; sleep 0.5 ; echo Hey! ; done;它非常快地关闭和打开 cpu3。 sysconf(_SC_NPROCESSORS_ONLN) 放入 while 循环时无法显示正确的 CPU,但如果我将其放入 watch -n 0.1 ./a.out(糟糕的选择),那么它会正确显示核心计数。与 getconf 相同,它每次在 watch 中都会重新启动,并显示正确的信息。您的脚本还显示了正确的值。
    • 但需要注意的是,如果我使用task -c 0 ./a.out,它会给我procs=1而不是4,换句话说,它只计算分配给进程的CPU。
    【解决方案8】:

    另一种扫描sys文件系统下cpu*目录的方法:

    #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;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-03-02
      • 1970-01-01
      • 1970-01-01
      • 2011-07-13
      • 2010-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-13
      相关资源
      最近更新 更多