如何在运行时检测正在使用的CPU?

5

如何在运行时检测使用的 CPU?C++ 代码需要区分 AMD/Intel 架构。使用 gcc 4.2。

6个回答

13
cpuid指令与EAX=0一起使用时,将按顺序在EBXEDXECX中返回一个12个字符的供应商字符串。

对于英特尔(Intel),此字符串为“GenuineIntel”。对于AMD,则为“AuthenticAMD”。其他创建x86芯片的公司也有自己的字符串。 Wikipedia页面列出了许多(全部?)的字符串,以及检索详细信息的示例ASM列表。

您只需要检查ECX是否与最后四个字符匹配。您不能使用前四个字母,因为一些Transmeta CPU也以“Genuine”开头。

  • 对于英特尔,这是0x6c65746e
  • 对于AMD,这是0x444d4163

如果将这些字节转换为字符,则它们看起来是反向的。这只是x86的小端设计产生的结果。如果将寄存器复制到内存并将其作为字符串查看,则可以正常工作。

示例代码:

bool IsIntel() // returns true on an Intel processor, false on anything else
{
  int id_str; // The first four characters of the vendor ID string

  __asm__ ("cpuid":\    // run the cpuid instruction with...
  "=c" (id_str) :       // id_str set to the value of EBX after cpuid runs...
  "a" (0) :             // and EAX set to 0 to run the proper cpuid function.
  "eax", "ebx", "edx"); // cpuid clobbers EAX, ECX, and EDX, in addition to EBX.

  if(id_str==0x6c65746e) // letn. little endian clobbering of GenuineI[ntel]
    return true;
  else
    return false;
}

编辑:还有一件事 - 只需更改if中的魔术数字,就可以轻松将此代码更改为IsAMD函数、IsVIA函数、IsTransmeta函数等。

EDIT: One other thing - this can easily be changed into an IsAMD function, IsVIA function, IsTransmeta function, etc. just by changing the magic number in the if.

你甚至可以使用内联汇编编写一个函数 int Last4(),返回最后四个字符作为整数,然后很容易地创建 bool IsIntel() { return Last4() == 0x6c65746e; }bool IsAMD() { return Last4() == 0x444d4163; }。这还避免了代码重复,并减少了所需的内联汇编总量。 - Chris Lutz

11

如果您使用Linux(或在Cygwin下运行的Windows),您可以通过读取特殊文件/proc/cpuinfo并查找以vendor_id开头的行来确定。 如果字符串为GenuineIntel,则表示您正在运行Intel芯片。 如果是AuthenticAMD,则表示您正在运行AMD芯片。

void get_vendor_id(char *vendor_id)  // must be at least 13 bytes
{
    FILE *cpuinfo = fopen("/proc/cpuinfo", "r");
    if(cpuinfo == NULL)
        ;  // handle error
    char line[256];
    while(fgets(line, 256, cpuinfo))
    {
        if(strncmp(line, "vendor_id", 9) == 0)
        {
            char *colon = strchr(line, ':');
            if(colon == NULL || colon[1] == 0)
                ;  // handle error
            strncpy(vendor_id, 12, colon + 2);
            fclose(cpuinfo);
            return;
        }
    }

    // if we got here, handle error
    fclose(cpuinfo);
}

如果您知道您正在运行x86架构,一个不太便携的方法是使用CPUID指令:

void get_vendor_id(char *vendor_id)  // must be at least 13 bytes
{
    // GCC inline assembler
    __asm__ __volatile__
        ("movl $0, %%eax\n\t"
         "cpuid\n\t"
         "movl %%ebx, %0\n\t"
         "movl %%edx, %1\n\t"
         "movl %%ecx, %2\n\t"
         : "=m"(vendor_id), "=m"(vendor_id + 4), "=m"(vendor_id + 8)  // outputs
         : // no inputs
         : "%eax", "%ebx", "%edx", "%ecx", "memory");  // clobbered registers
    vendor_id[12] = 0;
}

int main(void)
{
    char vendor_id[13];
    get_vendor_id(vendor_id);

    if(strcmp(vendor_id, "GenuineIntel") == 0)
        ; // it's Intel
    else if(strcmp(vendor_id, "AuthenticAMD") == 0)
        ; // it's AMD
    else
        ; // other
    return 0;
}

/proc/cpuinfo 是全局可读的,那你为什么认为你无法访问它呢? - phihag
该程序将在使用DJGPP的DOS上运行。因此无法访问/proc/cpuinfo。 - vivekian2
读取/proc/cpuinfo 就像是使用重型武器一样。我的意思是,实际上只有几行汇编代码,那么读取/proc/cpuinfo 的意义何在呢? - Tamas Czinege
这是MPlayer使用的CPU检测代码:http://svn.mplayerhq.hu/mplayer/trunk/cpudetect.c?view=markup,还可以查看cpudetect.h中使用的定义。 - Johannes Schaub - litb
如果你正在运行DOS,那么很可能是嵌入式系统。你怎么可能不知道呢?你的PCB设计将规定使用Intel、AMD或其他供应商的芯片。 - MSalters
显示剩余3条评论

2

1

你可能根本不应该去检查。相反,检查CPU是否支持你需要的功能,例如SSE3。两个英特尔芯片之间的差异可能比AMD和英特尔芯片之间的差异要大。


0

0
你必须在Makefile中定义arch=uname -p 2>&1,然后使用#ifdef i386和# endif来处理不同的架构。

1
这会检测它被编译的机器,而不是它正在运行的机器。 - Adam Rosenfield
真的。我误解了答案。 - Jorge Niedbalski R.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接