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

有没有一种方法可以以平台无关的方式确定一台机器有多少个C/ c++内核?如果不存在这样的东西,如何确定每个平台(Windows/*nix/Mac)?

252087 次浏览

Windows Server 2003及以后版本允许您利用GetLogicalProcessorInformation函数

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

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

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

Win32系统信息

这个功能是c++ 11标准的一部分。

#include <thread>


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

对于较旧的编译器,您可以使用提振。线程库。

#include <boost/thread.hpp>


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

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

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

sysconf(_SC_NPROCESSORS_CONF)

sysconf(_SC_NPROCESSORS_ONLN)

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

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

c++ 11

#include <thread>


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

参考:# EYZ0


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

  • < h3 > Win32
    SYSTEM_INFO sysinfo;
    GetSystemInfo(&sysinfo);
    int numCPU = sysinfo.dwNumberOfProcessors;
    
  • Linux, Solaris, AIX and Mac OS X >=10.4 (i.e. Tiger onwards)

    int numCPU = sysconf(_SC_NPROCESSORS_ONLN);
    
  • FreeBSD, MacOS X, NetBSD, OpenBSD, etc.

    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 or iOS)

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

请注意,“核数”可能不是一个特别有用的数字,您可能需要对它进行更严格的限定。如何计算Intel HT、IBM Power5和Power6等多线程cpu,以及最著名的Sun的Niagara/UltraSparc T1和T2?或者更有趣的是,MIPS 1004k具有两个级别的硬件线程(管理器级和用户级)……更不用说当您迁移到支持管理程序的系统时,硬件可能有几十个cpu,但您的特定操作系统只看到几个。

最好的情况是告诉您在本地OS分区中拥有的逻辑处理单元的数量。除非您是管理程序,否则不要考虑看到真正的机器。今天这个规则唯一的例外是在x86领域,但非虚拟机的末日很快就会到来……

OpenMP在许多平台上都是受支持的(包括Visual Studio 2005)

int omp_get_num_procs();

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

还有一个Windows秘方:使用系统范围的环境变量NUMBER_OF_PROCESSORS:

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

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

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

如果你是一个Cocoa程序员,不要被这是Carbon这个事实吓到。你只需要将Carbon框架添加到你的Xcode项目中,MPProcessors()就可以使用了。

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

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

grep processor /proc/cpuinfo | wc -l

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

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

更多关于OS X: sysconf(_SC_NPROCESSORS_ONLN)只有>= 10.5版本可用,而不是10.4。

另一种替代方法是HW_AVAILCPU/sysctl() BSD代码,在>= 10.2版本中可用。

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

使用# EYZ0:

#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

Win32:

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

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的实现在我看来远非微不足道(即“使用GetLogicalProcessorInformation或# eyz2”)。相反,如果阅读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。

#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的实现。