系统相关
首页 > 系统相关> > c – 以编程方式检测多个物理处理器/核心,或者在Windows,Mac和Linux上是否激活超线程

c – 以编程方式检测多个物理处理器/核心,或者在Windows,Mac和Linux上是否激活超线程

作者:互联网

我有一个多线程的c应用程序,可以在Windows,Mac和一些Linux风格上运行.

简而言之:为了使它以最高效率运行,我必须能够为每个物理处理器/核心实例化一个线程.创建比物理处理器/内核更多的线程会大大降低程序的性能.我已经可以在所有这三个平台上正确检测逻辑处理器/核心的数量.为了能够正确检测物理处理器/内核的数量,我必须检测是否支持超级交叉和活动.

因此,我的问题是,是否有办法检测是否支持和启用超线程?如果是这样,究竟如何.

解决方法:

编辑:由于英特尔正在进行的讨论,这已不再是100%正确.

我理解这个问题的方式是,您正在询问如何检测CPU核心数与CPU线程数,这与检测系统中的逻辑和物理核心数不同. CPU核心通常不被操作系统视为物理核心,除非它们有自己的封装或裸片.因此,操作系统将报告Core 2 Duo具有1个物理CPU和2个逻辑CPU,并且具有超线程的Intel P4将以完全相同的方式报告,即使2个超线程与2个CPU核心非常相同不同的表现明智.

我一直在努力解决这个问题,直到我将下面的解决方案拼凑在一起,我认为这对AMD和Intel处理器都有效.据我所知,我可能错了,AMD还没有CPU线程,但他们提供了一种检测它们的方法,我认为这些方法可以用于未来可能拥有CPU线程的AMD处理器.

简而言之,这里是使用CPUID指令的步骤:

>使用CPUID功能0检测CPU供应商
>从CPUID功能1检查CPU功能EDX中的HTT位28
>从CPUID函数1获取EBX [23:16]的逻辑核心数
>获取实际的非线程CPU核心数

>如果供应商==’GenuineIntel’,这是来自CPUID功能4的1加EAX [31:26]
>如果供应商==’AuthenticAMD’,这是来自CPUID函数0x80000008的1加ECX [7:0]

听起来很难,但这是一个希望平台独立的C程序,可以解决这个问题:

#include <iostream>
#include <string>

using namespace std;


void cpuID(unsigned i, unsigned regs[4]) {
#ifdef _WIN32
  __cpuid((int *)regs, (int)i);

#else
  asm volatile
    ("cpuid" : "=a" (regs[0]), "=b" (regs[1]), "=c" (regs[2]), "=d" (regs[3])
     : "a" (i), "c" (0));
  // ECX is set to zero for CPUID function 4
#endif
}


int main(int argc, char *argv[]) {
  unsigned regs[4];

  // Get vendor
  char vendor[12];
  cpuID(0, regs);
  ((unsigned *)vendor)[0] = regs[1]; // EBX
  ((unsigned *)vendor)[1] = regs[3]; // EDX
  ((unsigned *)vendor)[2] = regs[2]; // ECX
  string cpuVendor = string(vendor, 12);

  // Get CPU features
  cpuID(1, regs);
  unsigned cpuFeatures = regs[3]; // EDX

  // Logical core count per CPU
  cpuID(1, regs);
  unsigned logical = (regs[1] >> 16) & 0xff; // EBX[23:16]
  cout << " logical cpus: " << logical << endl;
  unsigned cores = logical;

  if (cpuVendor == "GenuineIntel") {
    // Get DCP cache info
    cpuID(4, regs);
    cores = ((regs[0] >> 26) & 0x3f) + 1; // EAX[31:26] + 1

  } else if (cpuVendor == "AuthenticAMD") {
    // Get NC: Number of CPU cores - 1
    cpuID(0x80000008, regs);
    cores = ((unsigned)(regs[2] & 0xff)) + 1; // ECX[7:0] + 1
  }

  cout << "    cpu cores: " << cores << endl;

  // Detect hyper-threads  
  bool hyperThreads = cpuFeatures & (1 << 28) && cores < logical;

  cout << "hyper-threads: " << (hyperThreads ? "true" : "false") << endl;

  return 0;
}

我还没有在Windows或OSX上测试过这个,但它应该可以工作,因为CPUID指令在i686机器上有效.显然,这对PowerPC不起作用,但它们也没有超线程.

以下是几台不同Intel机器的输出:

Intel(R)Core(TM)2 Duo CPU T7500 @ 2.20GHz:

 logical cpus: 2
    cpu cores: 2
hyper-threads: false

英特尔(R)酷睿(TM)2四核CPU Q8400 @ 2.66GHz:

 logical cpus: 4
    cpu cores: 4
hyper-threads: false

英特尔(R)Xeon(R)CPU E5520 @ 2.27GHz(带有x2物理CPU封装):

 logical cpus: 16
    cpu cores: 8
hyper-threads: true

英特尔(R)奔腾(R)4 CPU 3.00GHz:

 logical cpus: 2
    cpu cores: 1
hyper-threads: true

标签:hyperthreading,c,assembly,macos,windows
来源: https://codeday.me/bug/20190916/1807690.html