使用CPUID检测CPU规格,可靠的解决方案?
使用CPUID检测CPU规格,可靠的解决方案?
我正在尝试使用__cpuid()
来收集关于我的CPU的信息。虽然在我的电脑上可以正确获取信息,但是当我在同事的电脑上运行程序时,它却将Intel Core2 Quad Q6600检测为超线程,尽管根据Intel官网的规格说明它并不支持超线程。
__cpuid()
还错误地检测出了"逻辑核心"的数量,如下所示:
Programmatically detect number of physical processors/cores or if hyper-threading is active on Windows, Mac and Linux。在这个链接中,它声称Intel Xeon E5520有16个逻辑核心和8个物理核心。
我在自己的电脑上尝试运行了那个链接中的代码,我的电脑是Intel i7 2600K,得到的数字与Xeon的相同。
那么,__cpuid()
到底可靠吗?根据我的经验,它似乎并不可靠。我是否犯了一些非常基本的错误?
使用CPUID检测CPU规格,可靠的解决方案是什么?
问题的原因是处理器上的[x2]APIC id几乎肯定存在空隙,这意味着某些APIC id的值不与任何逻辑处理器映射。您应该使用cpuid的0xB叶子找出。您可以查看参考Intel代码和算法(https://software.intel.com/en-us/articles/intel-64-architecture-processor-topology-enumeration/)的步骤,但它归结为使用EAX=0xB,ECX=0调用并在EBX中获取每个核心的逻辑处理器(线程)数量,然后再次使用EAX=0xB,ECX=1调用cpuid,并在EBX中获取每个处理器包的逻辑处理器数量。
使用叶子0x1的旧方法无法解决APIC id空缺的问题。遗憾的是,这仍然是MSDN Visual C++ 2013参考页面上给出的示例代码,并且对于2010年及以后生产的处理器来说是不正确的,正如您使用来自MSDN或其他地方的类似错误代码发现的那样。我最近在维基百科的cpuid页面上更新了自己努力理解这个问题后的信息,现在在“Intel线程/核心和缓存拓扑”部分中有一个解决该问题的示例,包括如何确定实际使用和“死”的APIC id的哪些位。
鉴于Microsoft在其__cpuid()页面上提供的代码示例,这基本上是与“Logical CPU count return 16 instead of 4”(https://stackoverflow.com/questions/24088837)这个问题根源相同,因为它源于对Intel规格的同样解释错误。对于MSDN表现不佳的解释,他们提供的代码在2010年左右之前工作得很好;正如您在这个旧视频/文章中所看到的,Intel以前也提供了类似的方法:https://software.intel.com/en-us/articles/hyper-threading-technology-and-multi-core-processor-detection 如果您查看__cpuid的各个版本的MSDN页面,他们的代码示例自2008年以来基本保持不变...
至于单个超线程检测位,这是一个较长的故事,我已经在https://stackoverflow.com/questions/10436013 中回答过了。简而言之,这个相当古老的位告诉您处理器包是否支持多个逻辑处理器,无论是通过超线程还是多核技术。因此,该位的名称有些误导性。
另外,我建议将您的问题标题更改为“使用CPUID检测CPU拓扑,可靠的解决方案?”因为我是偶然发现您的问题的。我在谷歌上搜索Sandy Bridge cpuid转储时找到了您的问题。
CPUID可以信任,只需要正确使用它。在这种情况下,正确枚举拓扑结构是关键。获取到的16个逻辑处理器是因为该字段表示CPU能够支持的最大逻辑处理器数量,而不是实际存在的数量。获取到的核心数实际上是逻辑处理器的数量。
这个主题中的代码非常基础,只是作为一个起点。在我的系统(i7 2720QM)上,我也记录到了无效的数据。但是使用我自己的代码来检查拓扑结构,按照Intel CPUID映射,我得到了正确的结果。
解决方法:
使用自己的代码来检查拓扑结构,按照Intel CPUID映射,获取正确的结果。
代码示例:
// 自己的代码来检查拓扑结构
// 按照Intel CPUID映射,获取正确的结果