2009-11-03 17 views
20

Je voudrais savoir si quelqu'un ici a de bons exemples d'une implémentation CPUID C++ qui peut être référencée à partir de l'un des langages .net gérés.Implémentations CPUID en C++

De même, si ce n'est pas le cas, devrais-je être conscient de certaines différences de mise en œuvre entre X86 et X64?

Je voudrais utiliser CPUID pour obtenir des informations sur la machine sur laquelle mon logiciel fonctionne (crashreporting etc ...) et je veux que tout soit aussi largement compatible que possible.

Principale raison que je demande est parce que je suis un noob totale en ce qui concerne l'écriture ce qui sera probablement toutes les instructions de la machine que j'ai des connaissances de base sur les registres CPU et ainsi de suite ...

Avant que les gens commencent à me dire à Google: J'ai trouvé quelques exemples en ligne, mais ils n'étaient généralement pas destinés à permettre l'interaction à partir du code managé et aucun des exemples ne visait X86 et X64. La plupart des exemples semblaient être spécifiques à X86.

Répondre

38

Accès aux informations CPUID première est en fait très simple, voici une classe C++ pour ce qui fonctionne sous Windows, Linux et Mac OS X:

#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 

Pour utiliser juste instancier une instance de la classe, chargez le CPUID instruction qui vous intéresse et examinez les registres. Par exemple:

#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; 
} 

Cette page Wikipédia indique comment utiliser CPUID: http://en.wikipedia.org/wiki/CPUID

EDIT: Ajouté #include <intrin.h> pour Windows, par commentaires.

+4

Grande réponse. Juste une note: vous devez inclure le '#include ' sur Windows pour utiliser la fonction __cpuid(). –

+1

C'est une mésaventure extrêmement mineure, et une solution facile, mais vous avez également oublié de #include '; 3 – Gurgadurgen

+0

@Gurgadurgen' '' '' 'est inclus par' '' '' 'sur la plupart des systèmes, mais ok, Je vais l'ajouter. – jcoffland

1

Peut-être pas exactement ce que vous recherchez, mais Intel a un good article and sample code pour l'énumération des architectures de plate-forme Intel 64 bits (processeur, cache, etc.) qui semble également couvrir les processeurs 32 bits x86.

+0

J'ai vu celui-ci déjà , il y en a d'autres sur intel.com ainsi que sur MSDN. Mais en particulier pour celui que vous avez référencé: pour la vie de moi, je ne serais pas capable de comprendre comment compiler correctement dans une DLL native que je pourrais appeler à partir de mon code C# ... Je suis occupé à essayer d'apprendre toutes choses programmation au-delà des environnements gérés, mais les courbes d'apprentissage sont raides :) – Kris

+2

IA64 est en fait Itanium, alors que cet article fait référence à "Intel 64" qui est plus communément appelé x86_64. – kdt

+1

Intel 64 est un correspondant de AMD64, pas IA64 qui est Itanium –

6

Voir this MSDN article about __cpuid.

Un exemple complet compile avec Visual Studio 2005 ou mieux. Pour Visual Studio 6, vous pouvez utiliser cette place du compilateur instrinsic __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 
    } 
} 

pour Visual Studio 2005, vous pouvez utiliser cette place du compilateur instrinsic __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 
    } 
} 
+3

La définition de '__cpuid' et' __cpuidex' vous-même entraîne un comportement indéfini car les identifiants sont réservés. – rightfold