【问题标题】:CPUID implementations in C++C++ 中的 CPUID 实现
【发布时间】:2010-12-12 13:44:42
【问题描述】:

我想知道这里是否有人有一些 C++ CPUID 实现的好例子,可以从任何托管的 .net 语言中引用。

另外,如果不是这样,我应该注意 X86 和 X64 之间的某些实现差异吗?

我想使用 CPUID 来获取运行我的软件的机器上的信息(崩溃报告等...),并且我想保持一切尽可能广泛兼容。

我问的主要原因是,虽然我对 CPU 寄存器等有基本的了解,但在编写可能都是机器指令时,我是一个完全的菜鸟……

在人们开始告诉我 Google 之前:我在网上找到了一些示例,但通常它们并不意味着允许来自托管代码的交互,而且这些示例都不是针对 X86 和 X64 的。大多数示例似乎是特定于 X86 的。

【问题讨论】:

    标签: c++ assembly x86-64 cpu cpuid


    【解决方案1】:

    可能不是您正在寻找的,但英特尔有一个good article and sample code 用于枚举英特尔 64 位平台架构(处理器、缓存等),它似乎也涵盖了 32 位 x86 处理器。

    【讨论】:

    • 我已经看过这个了,在 intel.com 和 MSDN 上还有更多。但特别是对于您引用的那个:对于我的一生,我无法弄清楚如何将它正确编译成一些我可以从我的 C# 代码中调用的本机 dll ......我正忙着学习所有东西超出托管环境的编程,但学习曲线陡峭:)
    • IA64 实际上是 Itanium,而那篇文章指的是“Intel 64”,通常称为 x86_64。
    • Intel 64 对应 AMD64,而不是 IA64,它是 Itanium
    【解决方案2】:

    访问原始 CPUID 信息实际上非常简单,这里有一个适用于 Windows、Linux 和 OSX 的 C++ 类:

    #ifndef CPUID_H
    #define CPUID_H
    
    #ifdef _WIN32
    #include <limits.h>
    #include <intrin.h>
    typedef unsigned __int32  uint32_t;
    
    #else
    #include <stdint.h>
    #endif
    
    class CPUID {
      uint32_t regs[4];
    
    public:
      explicit CPUID(unsigned i) {
    #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
      }
    
      const uint32_t &EAX() const {return regs[0];}
      const uint32_t &EBX() const {return regs[1];}
      const uint32_t &ECX() const {return regs[2];}
      const uint32_t &EDX() const {return regs[3];}
    };
    
    #endif // CPUID_H
    

    要使用它,只需实例化一个类的实例,加载您感兴趣的 CPUID 指令并检查寄存器。例如:

    #include "CPUID.h"
    
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int main(int argc, char *argv[]) {
      CPUID cpuID(0); // Get CPU vendor
    
      string vendor;
      vendor += string((const char *)&cpuID.EBX(), 4);
      vendor += string((const char *)&cpuID.EDX(), 4);
      vendor += string((const char *)&cpuID.ECX(), 4);
    
      cout << "CPU vendor = " << vendor << endl;
    
      return 0;
    }
    

    这个维基百科页面告诉你如何使用 CPUID:http://en.wikipedia.org/wiki/CPUID

    编辑:为 Windows 添加了#include &lt;intrin.h&gt;,每个 cmets。

    【讨论】:

    • 很好的答案。请注意:您需要在 Windows 上包含 #include &lt;intrin.h&gt; 才能使用 __cpuid() 函数。
    • 这是一个非常小的事故,而且很容易解决,但你也忘了#include &lt;string&gt; ;3
    • @Gurgadurgen &lt;string&gt; 在大多数系统上都包含在 &lt;iostream&gt; 中,但是好的,我会添加它。
    • @jcoffland 显然不是 Visual C++ 2013。使用 ostream 运算符时出现错误,不包括
    • 用gcc可以用__get_cpuid,不用自己写
    【解决方案3】:

    this MSDN article about __cpuid

    有一个使用 Visual Studio 2005 或更高版本编译的综合示例。对于 Visual Studio 6,您可以使用它来代替编译器固有的 __cpuid:

    void __cpuid(int CPUInfo[4], int InfoType)
    {
     __asm 
      {
         mov    esi, CPUInfo
         mov    eax, InfoType
         xor    ecx, ecx  
         cpuid  
         mov    dword ptr [esi +  0], eax
         mov    dword ptr [esi +  4], ebx  
         mov    dword ptr [esi +  8], ecx  
         mov    dword ptr [esi + 12], edx  
      }
    }
    

    对于 Visual Studio 2005,您可以使用它来代替编译器固有的 __cpuidex:

    void __cpuidex(int CPUInfo[4], int InfoType, int ECXValue)
    {
     __asm 
      {
         mov    esi, CPUInfo
         mov    eax, InfoType
         mov    ecx, ECXValue
         cpuid  
         mov    dword ptr [esi +  0], eax
         mov    dword ptr [esi +  4], ebx  
         mov    dword ptr [esi +  8], ecx  
         mov    dword ptr [esi + 12], edx  
      }
    }
    

    【讨论】:

    • 自己定义 __cpuid__cpuidex 会导致未定义的行为,因为标识符被保留。
    猜你喜欢
    • 2011-03-14
    • 2012-03-21
    • 2012-10-24
    • 1970-01-01
    • 2014-04-28
    • 2011-02-24
    • 1970-01-01
    • 2013-01-09
    • 2011-04-04
    相关资源
    最近更新 更多