超线程是英特尔对同时多线程 (SMT)的实现。当前的 AMD 处理器没有实现 SMT(Bulldozer 微架构系列有其他 AMD 称为基于集群的多线程,但 Zen 微架构应该有 SMT)。OpenMP 没有内置支持来检测 SMT。
如果您想要一个通用功能来检测超线程,您需要支持不同代的处理器,并确保处理器是 Intel 处理器而不是 AMD。最好为此使用库。
但是您可以使用 OpenMP 创建一个适用于许多现代 Intel 处理器的函数,正如我在此处描述的那样。
以下代码将计算现代英特尔处理器上的物理内核数量(它在我尝试过的每个英特尔处理器上都有效)。您必须绑定线程才能使其正常工作。使用 GCC,您可以使用
,export OMP_PROC_BIND=true
否则您可以使用代码绑定(这就是我所做的)。
请注意,我不确定此方法对 VirtualBox 是否可靠。使用 VirtualBox 在 4 核/8 逻辑处理器 CPU 上,windows 作为主机,Linux 作为猜测,将 VM 的内核数设置为 4,此代码报告 2 个内核,/proc/cpuinfo 显示其中两个内核实际上是逻辑处理器。
#include <stdio.h>
//cpuid function defined in instrset_detect.cpp by Agner Fog (2014 GNU General Public License)
//http://www.agner.org/optimize/vectorclass.zip
// Define interface to cpuid instruction.
// input: eax = functionnumber, ecx = 0
// output: eax = output[0], ebx = output[1], ecx = output[2], edx = output[3]
static inline void cpuid (int output[4], int functionnumber) {
#if defined (_MSC_VER) || defined (__INTEL_COMPILER) // Microsoft or Intel compiler, intrin.h included
__cpuidex(output, functionnumber, 0); // intrinsic function for CPUID
#elif defined(__GNUC__) || defined(__clang__) // use inline assembly, Gnu/AT&T syntax
int a, b, c, d;
__asm("cpuid" : "=a"(a),"=b"(b),"=c"(c),"=d"(d) : "a"(functionnumber),"c"(0) : );
output[0] = a;
output[1] = b;
output[2] = c;
output[3] = d;
#else // unknown platform. try inline assembly with masm/intel syntax
__asm {
mov eax, functionnumber
xor ecx, ecx
cpuid;
mov esi, output
mov [esi], eax
mov [esi+4], ebx
mov [esi+8], ecx
mov [esi+12], edx
}
#endif
}
int getNumCores(void) {
//Assuming an Intel processor with CPUID leaf 11
int cores = 0;
#pragma omp parallel reduction(+:cores)
{
int regs[4];
cpuid(regs,11);
if(!(regs[3]&1)) cores++;
}
return cores;
}
int main(void) {
printf("cores %d\n", getNumCores());
}