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


464

有没有一种方法可以以平台无关的方式确定C / C ++中一台计算机有多少个内核?如果不存在这样的问题,那么如何在每个平台上确定它(Windows / * nix / Mac)?


4
如果要使用它来查找要启动的线程数,请使用NUMBER_OF_PROCESSORS作为主要指标。我将其作为练习来向您介绍为什么这样做会比使用硬件内核更好(如果人们会更多地使用它)。属于您的程序的内核有多少是环境问题!
Lothar

请注意,它std::thread::hardware_concurrency返回物理CPU核心的数量,但是nproc在Linux中仅显示当前进程可以运行的CPU核心的数量,可以使用进行控制sched_setaffinity。我还没有找到一种方式来获得从不是标准的C ++ :,例如见在Python:stackoverflow.com/questions/1006289/...
西罗桑蒂利郝海东冠状病六四事件法轮功

Answers:


706

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;
    }
  • 惠普

    int numCPU = mpctl(MPC_GETNUMSPUS, NULL, NULL);
  • 虹膜

    int numCPU = sysconf(_SC_NPROC_ONLN);
  • Objective-C(Mac OS X> = 10.5或iOS)

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

5
@mcandre:留给读者练习。如果要实现,则可能会使用模板策略方法,该策略在预处理器指令中定义。或者...您可以使用boost thread :: hardware_concurrency()。
paxos1977

3
为了澄清起见,Win32解决方案返回的是内核总数(要求的总数),而不是物理CPU的总数。
艾瑞克(Eric)

1
Linux / Solaris / AIX方式也可以在FreeBSD上使用,并且至少从2006年开始使用。此外,如果系统能够关闭某些CPU,它们可能会重新联机,这可能不算在内。使用“ _SC_NPROCESSORS_CONF”调用sysconf将返回已配置的CPU总数。
克里斯S

3
有几件事要注意。HW_NCPU在OS X上已弃用。在Windows GetSystemInfo上,仅当您的系统具有32个或更少的逻辑处理器时才有用,适用于具有32个以上的逻辑处理器GetLogicalProcessorInformation的系统。

1
@Trejkaz 文档清楚地指出“逻辑”-一直在计算HT内核,“物理” 一词始终指BIOS / UEFI报告的内核,因为内核也可以被仿真/虚拟化。例如,您可以使用诸如GetLogicalProcessorInformation之类的功能来区分HT /非HT内核。注意:HT!=仿真或虚拟化,那是一个很大的不同,HT是一种硬件优化,可以这么说
specializt

202

此功能是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内核和超线程单元的数量返回硬件能够同时执行的线程数。


1
其次...将使用上面的示例代码和一些预处理器宏公开一个功能,但是辛苦了。
jkp

对于win32,它是对GetSystemInfo的调用。(从boost 1.41.0版本开始)是否捕获所有信息以确定多少个工作线程有效?是否需要同时考虑内核数量和超线程?未签名的线程:: hardware_concurrency(){SYSTEM_INFO info = {0}; GetSystemInfo(&info); 返回info.dwNumberOfProcessors; }
Jive Dadson

根据MSDN,GetSystemInfo()在dwNumberOfProcessors中返回“物理处理器”的数量,但未定义其含义。Boost文档似乎声称它包含超线程单元。
Ferruccio 2010年


57

许多平台(包括Visual Studio 2005)都支持OpenMP,并且它提供了

int omp_get_num_procs();

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


因为这是一个错误的答案。在gcc.gnu.org/bugzilla/show_bug.cgi?id=37586中,如果使用了GOMP_CPU_AFFINITY env var,或者调用进程和/或线程具有“ CPU相似性仅限于CPU的子集”。因此,如果您较早致电,例如,sched_setaffinity这将无法工作。
2013年

7
此函数返回可用于调用进程的CPU数量。无论如何,这不是最常见的用例吗?出于某些无用的报告目的,CPU硬件内核的实际数量与您无关,如果您无法在代码中利用它们的话。
macbirdie

@EvanTeran除了这是问题的目的这一事实外,它当然也很有用。例如,出于设置线程亲和力的目的。假设,我想运行绑定到计算机上最后四个CPU内核的4个线程,而不是最初的四个内核。除OpenMP外,还有其他并行化代码的方法。我可能想自己生成pthread。这些肯定可用,不受OpenMP环境变量的限制。
angainor

2
这将返回逻辑CPU的数量,而不是核心(物理CPU)的数量。
MichaelKonečný16年

37

如果您具有汇编语言访问权限,则可以使用CPUID指令来获取有关CPU的各种信息。它在操作系统之间是可移植的,尽管您需要使用制造商特定的信息来确定如何找到内核数。下面是描述如何做到这一点英特尔芯片的文档,以及第11页这一个介绍AMD规范。


4
它可能被否决了,因为该问题被标记为C ++,并且此答案不适用于在非x86体系结构(ARM,PPC等)上运行C ++的系统。我并不是说这是降低答案的充分理由,只是一种可能。
Ferruccio

3
这种方法的一个陷阱是,如果您使用CPUID来检测Intel处理器上的超线程。我在笔记本电脑上遇到了这个问题:虽然我放入计算机的CPU支持HyperThreading(当然,它报告说是通过CPUID完成的),但BIOS不支持。因此,您不应仅从读取的CPUID中尝试利用HT功能。由于您无法向BIOS查询有关HT支持的信息(我从未见过),因此应查询OS以获取逻辑处理器数。
Chuck R

32

(几乎)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

16

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


除此之外,还将超线程或其他SMT解决方案视为更多核心...
jakobengblom2

13
@Arafangion:超线程不是真正的并行执行,它是一种减少上下文切换开销的技术。一个超线程的cpu一次只能执行一个线程,但是可以同时存储两个线程的体系结构状态(寄存器值等)。性能特征与具有两个核心的情况有很大不同。
Wim Coenen

7
@Wim:那是不完全正确的。具有超线程的CPU通常具有多个ALU,并且每个周期可以调度多个指令。如果由于数据依赖性和停顿而导致一个线程无法使所有ALU保持繁忙,那么这些ALU将用于同时执行第二个硬件线程。
Ben Voigt

11

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

最好的办法是告诉您本地OS分区中逻辑处理单元的数量。除非您是虚拟机监控程序,否则不要再看真实的机器了。今天,此规则的唯一例外是在x86领域,但是非虚拟机的终结日趋迅速。


7

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

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

7

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

Win32系统信息


1
认真:超线程处理器说有两个。因此,您还需要查看处理器是否具有超线程能力。
马丁·约克

6

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

请注意,NumberOfPhysicalCoresIMHO 的实现远非琐碎(即“ use 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。


1
谢谢!我之所以要这样做,是因为GetLogicalProcessorInformation无法使用我使用的各种缓冲区大小。不止满意!^^
KeyWeeUsr

@KeyWeeUsr谢谢Windows编程有点琐碎和逻辑化。同时,我使用稍微更新的C ++ 17版本,根据静态分析器PVS-Studio对于某些size_t转换,它也更正确。(尽管msvc ++在W4上没有抱怨。)
Matthias,

5

有关OS X的更多信息:sysconf(_SC_NPROCESSORS_ONLN)仅在> = 10.5,而不是10.4上可用。

另一种选择是HW_AVAILCPU/sysctl()BSD代码,该代码在版本> = 10.2上可用。



4

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

grep processor /proc/cpuinfo | wc -l

适用于bash / perl / python / ruby​​等脚本语言。


4
对于python:import multiprocessing print multiprocessing.cpu_count()
initzero 2011年

3
已经很长时间了,但是grep-c标记来计数条目!
Lapshin Dmitry

3

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


3

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

sysconf(_SC_NPROCESSORS_CONF)

要么

sysconf(_SC_NPROCESSORS_ONLN)

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


3

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

在外壳中使用grep的相同方法:

grep -c ^processor /proc/cpuinfo

要么

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

2

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

如果您是Cocoa程序员,请不要害怕这是Carbon。您只需要向Xcode项目添加Carbon框架,即可使用MPProcessors()。



-2

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


-3

在Linux中,您可以检出dmesg并过滤ACPI初始化CPU的行,例如:

dmesg | grep 'ACPI: Processor'

其他可能性是使用dmidecode过滤掉处理器信息。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.