我正试图用__cpuid()
收集有关我的CPU的信息。尽管它在我的电脑上运行得很好,但当我在同事的电脑上执行程序时,它检测到英特尔Core2 Quad Q6600是超线程的,尽管根据英特尔自己网站上的规范,它不是。
__cpuid()
还检测到错误数量的"逻辑核",如下所示:以编程方式检测物理处理器/内核的数量,或者在Windows、Mac和Linux上是否激活了超线程。它声称英特尔至强E5520有16个逻辑内核和8个物理内核。
我试着在我自己的电脑上运行该线程中的代码,一台英特尔i7 2600K给了我与至强相同的数字。
那么__cpuid()
究竟有多可靠呢?根据我自己的经验,它似乎并不那么可靠。我有什么根本性的错误吗?
处理器上的[x2]APIC ID几乎肯定存在缺口,这意味着APIC ID的某些值没有映射到任何逻辑处理器。您应该使用cpuid的0xB叶来查找。您可以查看参考英特尔代码和算法(https://software.intel.com/en-us/articles/intel-64-architecture-processor-topology-enumeration/)对于这些步骤,但它可以归结为调用EAX=0xB,ECX=0,并在EBX中获得每个核心的逻辑处理器(线程)数量,然后再次调用cpuid,调用EAX=0xB,ECU=1,并在EB中获得每个处理器包的逻辑处理器数量。
使用叶0x1的旧方法无法解释APIC id间隙。遗憾的是,这是MSDN Visual C++2013参考页上仍然提供的示例代码(http://msdn.microsoft.com/en-us/library/hskdteyh.aspx),并且对于2010年及以后生产的处理器来说,这是不正确的,因为您发现是使用MSDN中的代码还是其他地方类似的不正确代码。在努力理解这个问题后,我最近更新了关于cpuid的维基百科页面,现在在"英特尔线程/核心和缓存拓扑"一节中有一个示例,用于枚举具有APIC id间隙的处理器上的拓扑,并提供了更多详细信息,包括如何确定APIC id的哪些位实际使用,哪些位"已失效"。
考虑到微软目前在其__cpuid()页面上提供的代码示例,这与逻辑CPU计数返回16而不是4基本上是相同的问题,因为它源于英特尔规格的相同解释错误。作为MSDN糟糕表现的一个解释,他们提供的代码在2010年左右之前运行良好;在x2APIC推出之前,英特尔曾提供过类似的方法,如您在这段旧视频/文章中所见:https://software.intel.com/en-us/articles/hyper-threading-technology-and-multi-core-processor-detection如果您查看__cpuid上MSDN页面的各个版本,它们的代码示例自2008年以来基本保持不变…
至于单个超线程检测位,这是一个更长的故事,我已经在《为什么没有超线程的处理器支持超线程?》中回答了这个问题?。简言之,这个相当传统的比特告诉你,如果处理器包支持多个逻辑处理器,无论是通过hyphethreading还是多核技术。因此,比特的名称相当具有误导性。
此外,我建议将您问题的标题更改为"使用CPUID检测CPU拓扑,可靠的解决方案?",因为我完全是偶然发现您的问题的。当我发现你的问题时,我正在谷歌上搜索SandyBridge的cpuid转储。
CPUID是可以信任的,您只需要正确使用它。在这种情况下,这意味着正确地枚举拓扑。您得到了16个逻辑处理器,因为它得到的字段表示它可以支持的最大值,而不是实际支持的数量。为核心检索的值实际上是逻辑计数。
主题中的代码非常基本,作为一个起点,在我的系统(i7 2720QM)上,我也记录了无效数据,但使用我自己的代码,根据Intel CPUID映射检查拓扑,我得到了正确的结果。