几乎可以肯定,处理器上的 [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 中获取每个内核的逻辑处理器(线程)数,然后使用 EAX=0xB, ECX=1 再次调用 cpuid 并在 EBX 中获取每个处理器包的逻辑处理器数。
使用叶子 0x1 的旧方法无法解决 APIC id 差距。唉,这仍然是 MSDN Visual C++ 2013 参考页面 ( http://msdn.microsoft.com/en-us/library/hskdteyh.aspx ) 上给出的示例代码,它对于 2010 年及之后制造的处理器是不正确的,因为您发现是使用 MSDN 中的代码还是其他地方的类似错误代码。cpuid 上的 Wikipedia 页面,我最近在努力理解这个问题后进行了更新,现在在“英特尔线程/核心和缓存拓扑”部分中有一个已解决的示例,用于枚举具有 APIC id 间隙的处理器上的拓扑,附加详细信息,包括如何确定 APIC id 的哪些位实际使用以及哪些是“死的”。
鉴于 Microsoft 当前在其 __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 年以来基本保持不变......
至于单个超线程检测位,这是一个更长的故事,我已经回答了为什么超线程在没有它的处理器上被报告为支持?. 简而言之,这个相当遗留的位会告诉您处理器包是否支持多个逻辑处理器,无论是通过超线程还是多核技术。因此,该位的名称颇具误导性。
另外,我建议您将问题的标题更改为“使用 CPUID 检测 CPU拓扑,可靠的解决方案吗?” 因为我完全偶然发现了你的问题。当我发现你的问题时,我正在谷歌上搜索 Sandy Bridge cpuid 转储。