以编程方式查找机器上的内核数

Posted

技术标签:

【中文标题】以编程方式查找机器上的内核数【英文标题】:Programmatically find the number of cores on a machine 【发布时间】:2010-09-14 02:26:58 【问题描述】:

有没有办法以独立于平台的方式从 C/C++ 确定一台机器有多少内核?如果不存在这样的东西,那么如何确定每个平台(Windows/*nix/Mac)?

【问题讨论】:

如果您想使用它,请找出要启动的线程数,请使用 NUMBER_OF_PROCESSORS 作为主要衡量标准。我把它作为练习留给你,为什么这比使用硬件内核要好得多(如果人们会更多地使用它)。您的程序有多少内核属于环境问题! 注意std::thread::hardware_concurrency返回物理CPU核数,但Linux中的nproc只显示当前进程可以运行的CPU核数,可以用sched_setaffinity控制。我还没有找到从标准 C++ 中获取它的方法:,参见例如在 Python 中:***.com/questions/1006289/… 【参考方案1】:

C++11

#include <thread>

//may return 0 when not able to detect
const auto processor_count = std::thread::hardware_concurrency();

参考:std::thread::hardware_concurrency


在 C++11 之前的 C++ 中,没有可移植的方式。相反,您需要使用以下一种或多种方法(由适当的#ifdef 行保护):

Win32

SYSTEM_INFO sysinfo;
GetSystemInfo(&sysinfo);
int numCPU = sysinfo.dwNumberOfProcessors;

Linux、Solaris、AIX 和 Mac OS X >=10.4(即 Tiger 以后)

int numCPU = sysconf(_SC_NPROCESSORS_ONLN);

FreeBSD、MacOS X、NetBSD、OpenBSD 等

int mib[4];
int numCPU;
std::size_t len = sizeof(numCPU); 

/* set the mib for hw.ncpu */
mib[0] = CTL_HW;
mib[1] = HW_AVAILCPU;  // alternatively, try HW_NCPU;

/* get the number of CPUs from the system */
sysctl(mib, 2, &numCPU, &len, NULL, 0);

if (numCPU < 1) 

    mib[1] = HW_NCPU;
    sysctl(mib, 2, &numCPU, &len, NULL, 0);
    if (numCPU < 1)
        numCPU = 1;

HPUX

int numCPU = mpctl(MPC_GETNUMSPUS, NULL, NULL);

IRIX

int numCPU = sysconf(_SC_NPROC_ONLN);

Objective-C(Mac OS X >=10.5 或 ios

NSUInteger a = [[NSProcessInfo processInfo] processorCount];
NSUInteger b = [[NSProcessInfo processInfo] activeProcessorCount];

【讨论】:

@mcandre:留给读者作为练习。如果我正在实施,我可能会使用模板策略方法,其中策略是在预处理器指令中定义的。或者...你可以使用 boost thread::hardware_concurrency()。 作为澄清点,Win32 解决方案返回的核心总数(要求的)而不是物理 CPU 的总数。 Linux/Solaris/AIX 方式也适用于 FreeBSD,至少从 2006 年开始就有。此外,如果系统能够关闭某些 CPU,它们可能不会被计算在内。使用“_SC_NPROCESSORS_CONF”调用 sysconf 将返回配置的 CPU 总数。 有几点需要注意。 HW_NCPU 在 OS X 上已弃用。在 Windows 上,GetSystemInfo 仅在您的系统具有 32 个或更少逻辑处理器时才有用,对于具有超过 32 个逻辑处理器的系统,请使用 GetLogicalProcessorInformation @Trejkaz the documentaion 明确表示“逻辑” - 始终计算 HT 核心,“物理”一词 总是 指的是报告的核心也可以通过 BIOS/UEFI 作为核心进行仿真/虚拟化。例如,您可以使用 GetLogicalProcessorInformation 等功能区分 HT/非 HT 内核。注意:HT != 仿真或虚拟化,这是一个很大的区别,HT 是硬件优化,可以这么说【参考方案2】:

此功能是 C++11 标准的一部分。

#include <thread>

unsigned int nthreads = std::thread::hardware_concurrency();

对于较旧的编译器,您可以使用Boost.Thread 库。

#include <boost/thread.hpp>

unsigned int nthreads = boost::thread::hardware_concurrency();

在任何一种情况下,hardware_concurrency() 都会根据 CPU 内核和超线程单元的数量返回硬件能够同时执行的线程数。

【讨论】:

Seconded...本来打算使用上面的示例代码和一些预处理器宏来公开单个函数,但我已经完成了艰苦的工作。 对于 win32,它是对 GetSystemInfo 的调用。 (从 boost 版本 1.41.0 开始)这是否捕获了所有信息以确定有多少工作线程有效?是否需要同时考虑内核数量和超线程?未签名线程::hardware_concurrency() SYSTEM_INFO info=0;获取系统信息(&info);返回 info.dwNumberOfProcessors; 根据 MSDN,GetSystemInfo() 在 dwNumberOfProcessors 中返回“物理处理器”的数量,但它没有定义它的含义。 Boost 文档似乎声称它包含超线程单元。 查看***.com/questions/642348/… 了解超线程【参考方案3】:

OpenMP 在许多平台(包括 Visual Studio 2005)上受支持,它提供了一个

int omp_get_num_procs();

返回调用时可用处理器/内核数的函数。

【讨论】:

因为这是一个错误的答案。来自gcc.gnu.org/bugzilla/show_bug.cgi?id=37586“omp_get_num_procs () 将仅返回小于在线系统 CPU 数量的数字,如果使用 GOMP_CPU_AFFINITY env var,或者如果调用进程和/或线程的 CPU 亲和性仅限于 CPU 的子集”。因此,如果您之前致电 sched_setaffinity,这将不起作用。 此函数返回调用进程可用的 CPU 数量。无论如何,这不是最常见的用例吗?除了一些无用的报告目的之外,如果您无法在代码中利用它们,那么 CPU 硬件内核的实际数量与您无关。 @EvanTeran 除了这是问题的目的之外,它当然也很有用。例如,为了设置线程亲和性。比如说,我想在我的机器上运行 4 个线程绑定到最后四个 CPU 内核,而不是四个第一个内核。此外,除了 OpenMP 之外,还有其他方法可以并行化代码。我可能想自己生成 pthread。这些肯定是可用的,并且不受 OpenMP 环境变量的限制。 这会返回逻辑 CPU 的数量,而不是核心(物理 CPU)本身。【参考方案4】:

如果您有汇编语言访问权限,则可以使用 CPUID 指令来获取有关 CPU 的各种信息。它可以在操作系统之间移植,但您需要使用制造商特定的信息来确定如何查找内核数量。这是a document that describes how to do it on Intel chips,this one 的第 11 页描述了 AMD 规范。

【讨论】:

它可能已被否决,因为该问题被标记为 C++,并且此答案不适用于在非 x86 架构(ARM、PPC 等)上运行 C++ 的系统。我并不是说对答案投反对票是一个很好的理由,只是一种可能性。 此方法的一个缺陷是如果您使用 CPUID 来检测 Intel 处理器上的超线程。我在笔记本电脑上遇到了这个问题:虽然我放入机器的 CPU 支持超线程(当然,报告说它通过 CPUID 支持),但 BIOS 不支持。因此,您不应尝试仅通过读取 CPUID 来利用 HT 功能。由于您无法查询 BIOS 关于 HT 支持(我没见过),因此应该查询操作系统以获取逻辑处理器数。【参考方案5】:

(几乎)c代码中的平台无关函数

#ifdef _WIN32
#include <windows.h>
#elif MACOS
#include <sys/param.h>
#include <sys/sysctl.h>
#else
#include <unistd.h>
#endif

int getNumCores() 
#ifdef WIN32
    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);
    return sysinfo.dwNumberOfProcessors;
#elif MACOS
    int nm[2];
    size_t len = 4;
    uint32_t count;

    nm[0] = CTL_HW; nm[1] = HW_AVAILCPU;
    sysctl(nm, 2, &count, &len, NULL, 0);

    if(count < 1) 
        nm[1] = HW_NCPU;
        sysctl(nm, 2, &count, &len, NULL, 0);
        if(count < 1)  count = 1; 
    
    return count;
#else
    return sysconf(_SC_NPROCESSORS_ONLN);
#endif

【讨论】:

似乎 HW_NCPU 在 OS X 上已弃用 source @user152949 建议的替代方案是什么? (链接已损坏)【参考方案6】:

在 Linux 上,您可以读取 /proc/cpuinfo 文件并计算内核数。

【讨论】:

除了这也将超线程或其他 SMT 解决方案视为更多内核... @Arafangion:超线程不是真正的并行执行,它是一种减少上下文切换开销的技术。超线程 CPU 一次只能执行一个线程,但它可以同时存储两个线程的架构状态(寄存器值等)。性能特征与拥有两个内核有很大不同。 @Wim:这并不完全正确。具有超线程的 CPU 通常具有多个 ALU,并且每个周期可以分派多条指令。如果由于数据依赖和停顿,不是所有的 ALU 都可以由一个线程保持忙碌,那么这些 ALU 将被用于同时执行第二个硬件线程。【参考方案7】:

请注意,“核心数”可能不是一个特别有用的数字,您可能需要对其进行更多限定。您想如何计算多线程 CPU,例如 Intel HT、IBM Power5 和 Power6,以及最著名的 Sun 的 Niagara/UltraSparc T1 和 T2?或者更有趣的是,MIPS 1004k 具有两个级别的硬件线程(管理程序和用户级)......更不用说当您进入支持虚拟机管理程序的系统时会发生什么,其中硬件可能有数十个 CPU,但您的特定操作系统只看到几个。

您可以期望的最好结果是告诉您在本地操作系统分区中拥有的逻辑处理单元的数量。除非您是虚拟机管理程序,否则忘记查看真正的机器。今天这个规则的唯一例外是在 x86 领域,但非虚拟机的终结即将到来......

【讨论】:

【参考方案8】:

另一个 Windows 秘诀:使用系统范围的环境变量 NUMBER_OF_PROCESSORS

printf("%d\n", atoi(getenv("NUMBER_OF_PROCESSORS")));

【讨论】:

【参考方案9】:

您可能无法以独立于平台的方式获得它。 Windows 你得到处理器的数量。

Win32 System Information

【讨论】:

小心:超线程处理器说有两个。所以你还需要看看处理器是否支持超线程。【参考方案10】:

Windows(x64 和 Win32)和 C++11

共享单个处理器内核的逻辑处理器组的数量。(使用GetLogicalProcessorInformationEx,也请参见GetLogicalProcessorInformation)

size_t NumberOfPhysicalCores() noexcept 

    DWORD length = 0;
    const BOOL result_first = GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, &length);
    assert(GetLastError() == ERROR_INSUFFICIENT_BUFFER);

    std::unique_ptr< uint8_t[] > buffer(new uint8_t[length]);
    const PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX info = 
            reinterpret_cast< PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX >(buffer.get());

    const BOOL result_second = GetLogicalProcessorInformationEx(RelationProcessorCore, info, &length);
    assert(result_second != FALSE);

    size_t nb_physical_cores = 0;
    size_t offset = 0;
    do 
        const PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX current_info =
            reinterpret_cast< PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX >(buffer.get() + offset);
        offset += current_info->Size;
        ++nb_physical_cores;
     while (offset < length);
        
    return nb_physical_cores;

请注意,NumberOfPhysicalCores 的实现远非微不足道(即“使用 GetLogicalProcessorInformationGetLogicalProcessorInformationEx”)。相反,如果您阅读 MSDN 上的文档(显式存在于 GetLogicalProcessorInformation 并隐式存在于 GetLogicalProcessorInformationEx),则相当微妙。

逻辑处理器的数量。(使用GetSystemInfo)

size_t NumberOfSystemCores() noexcept 
    SYSTEM_INFO system_info;
    ZeroMemory(&system_info, sizeof(system_info));
    
    GetSystemInfo(&system_info);
    
    return static_cast< size_t >(system_info.dwNumberOfProcessors);

请注意,这两种方法都可以轻松转换为 C/C++98/C++03。

【讨论】:

@KeyWeeUsr 感谢 Windows 编程远非简单和合乎逻辑。同时,我使用了稍微更新的C++17 version,根据静态分析器PVS-Studio 对一些size_t 演员表的看法,这也更正确。 (虽然,msvc++ 在 W4 并没有抱怨。)【参考方案11】:

有关 OS X 的更多信息:sysconf(_SC_NPROCESSORS_ONLN) 仅适用于 >= 10.5 的版本,而不是 10.4。

另一种选择是HW_AVAILCPU/sysctl() BSD 代码,该代码适用于 >= 10.2 的版本。

【讨论】:

【参考方案12】:

与 C++ 无关,但在 Linux 上我通常这样做:

grep processor /proc/cpuinfo | wc -l

非常适合 bash/perl/python/ruby 等脚本语言。

【讨论】:

对于python:import multiprocessingprint multiprocessing.cpu_count() 已经很久了,但是grep-c 标志来统计条目! 已经很久了,但是我的树莓派在它的 cpuinfo 中有model name : ARMv6-compatible processor rev 7 (v6l),所以可能有人会使用grep -c ^processor /proc/cpuinfo【参考方案13】:

Windows Server 2003 及更高版本允许您利用 GetLogicalProcessorInformation 函数

http://msdn.microsoft.com/en-us/library/ms683194.aspx

【讨论】:

【参考方案14】:

hwloc (http://www.open-mpi.org/projects/hwloc/) 值得一看。虽然需要将另一个库集成到您的代码中,但它可以提供有关您的处理器的所有信息(内核数量、拓扑等)

【讨论】:

【参考方案15】:

据我所知,在 linux 上最好的编程方式是使用

sysconf(_SC_NPROCESSORS_CONF)

sysconf(_SC_NPROCESSORS_ONLN)

这些不是标准的,但在我的 Linux 手册页中。

【讨论】:

【参考方案16】:

在 Linux 上,使用 _SC_NPROCESSORS_ONLN 可能不安全,因为它不是 POSIX 标准的一部分,sysconf 手册也说明了这一点。所以_SC_NPROCESSORS_ONLN 有可能不存在:

 These values also exist, but may not be standard.

     [...]     

     - _SC_NPROCESSORS_CONF
              The number of processors configured.   
     - _SC_NPROCESSORS_ONLN
              The number of processors currently online (available).

一种简单的方法是读取/proc/stat/proc/cpuinfo 并计算它们:

#include<unistd.h>
#include<stdio.h>

int main(void)

char str[256];
int procCount = -1; // to offset for the first entry
FILE *fp;

if( (fp = fopen("/proc/stat", "r")) )

  while(fgets(str, sizeof str, fp))
  if( !memcmp(str, "cpu", 3) ) procCount++;


if ( procCount == -1) 
 
printf("Unable to get proc count. Defaulting to 2");
procCount=2;


printf("Proc Count:%d\n", procCount);
return 0;

使用/proc/cpuinfo

#include<unistd.h>
#include<stdio.h>

int main(void)

char str[256];
int procCount = 0;
FILE *fp;

if( (fp = fopen("/proc/cpuinfo", "r")) )

  while(fgets(str, sizeof str, fp))
  if( !memcmp(str, "processor", 9) ) procCount++;


if ( !procCount ) 
 
printf("Unable to get proc count. Defaulting to 2");
procCount=2;


printf("Proc Count:%d\n", procCount);
return 0;


在 shell 中使用 grep 的相同方法:

grep -c ^processor /proc/cpuinfo

或者

grep -c ^cpu /proc/stat # subtract 1 from the result

【讨论】:

【参考方案17】:

OS X 替代方案:根据文档,前面描述的基于 [[NSProcessInfo processInfo] processorCount] 的解决方案仅在 OS X 10.5.0 上可用。对于早期版本的 OS X,请使用 Carbon 函数 MPProcessors()。

如果您是 Cocoa 程序员,请不要被 Carbon 所吓倒。您只需要将 Carbon 框架添加到您的 Xcode 项目中,即可使用 MPProcessors()。

【讨论】:

【参考方案18】:

对于 Win32:

当 GetSystemInfo() 获取 逻辑 处理器的数量时,使用 GetLogicalProcessorInformationEx() 获取物理处理器的数量。

【讨论】:

【参考方案19】:
#include <stdint.h>

#if defined(__APPLE__) || defined(__FreeBSD__)
#include <sys/sysctl.h>

uint32_t num_physical_cores(void)

    uint32_t num_cores      = 0;
    size_t num_cores_len    = sizeof(num_cores);

    sysctlbyname("hw.physicalcpu", &num_cores, &num_cores_len, 0, 0);

    return num_cores;

#elif defined(__linux__)
#include <unistd.h>
#include <stdio.h>
uint32_t num_physical_cores(void)

    uint32_t lcores = 0, tsibs = 0;

    char buff[32];
    char path[64];

    for (lcores = 0;;lcores++) 
        FILE *cpu;

        snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%u/topology/thread_siblings_list", lcores);

        cpu = fopen(path, "r");
        if (!cpu) break;

        while (fscanf(cpu, "%[0-9]", buff)) 
            tsibs++;
            if (fgetc(cpu) != ',') break;
        

        fclose(cpu);
    

    return lcores / (tsibs / lcores);

#else
#error Unrecognized operating system
#endif

这应该返回系统上的物理内核数。这与大多数答案提供的逻辑核心数量不同。如果您希望确定一个不执行阻塞 I/O 并且不休眠的线程池的大小,那么您需要使用物理内核的数量,而不是逻辑(超线程)内核的数量。

此答案仅提供 Linux 和 BSD 的实现。

【讨论】:

【参考方案20】:

您也可以在 .net 中使用 WMI,但您需要依赖正在运行的 wmi 服务 等等。有时它在本地工作,但当相同的代码在服务器上运行时会失败。 我认为这是一个命名空间问题,与您正在阅读其值的“名称”有关。

【讨论】:

以上是关于以编程方式查找机器上的内核数的主要内容,如果未能解决你的问题,请参考以下文章

使用 .Net Core 在 linux 机器上查找内核数失败并出现错误(未终止的引用字符串)

以编程方式检测物理内核的数量

如何查找 Google COLAB GPU 中的内核数?

使用命令提示符查找每个 CPU 的 CPU 数和内核数

Linux内核模块编程问题

Linux内核模块编程问题