2009-05-12 7 views
6

Mon application fonctionnant sous Mac OS X qui doit récupérer des détails sur la machine sur laquelle elle s'exécute pour générer des rapports sur les informations système. L'un des éléments dont j'ai besoin est des détails sur le (s) processeur (s) installé (s) dans l'ordinateur.Récupérez par programme les détails du processeur à partir de Mac OS X

Mon code fonctionne actuellement, mais est loin d'être une solution idéale, en fait je la considère comme une mauvaise solution, mais je n'ai pas eu de chance d'en trouver une meilleure.

Les informations que je déclare actuellement et après une mise en forme ressemble à:

Processeur: Intel Core 2 Duo 2,1 GHz, Famille 6 Modèle 23 Stepping 6

Toutes les informations que je reçois est via des utilitaires de ligne de commande appelés depuis un popen(). La partie lisible de la description du processeur provient de la sortie de la commande "system_profiler" et les valeurs Family, Model et Stepping sont extraites de la commande "sysctl".

Ces utilitaires de ligne de commande doivent obtenir des informations de quelque part. Je me demande s'il y a une interface programmatique disponible pour obtenir cette même information?


connexes:

+0

Si quelqu'un a la réponse, il devrait probablement être ajouté au lien "lié" ... – dmckee

Répondre

5

sysctl(3) est probablement un bon endroit pour commencer. Vous voulez probablement les éléments définis par les sélecteurs CTL_HW.

+0

Je me souviens d'avoir regardé la méthode sysctl() avec le sélecteur CTL_HW que vous mentionnez, mais il ne semble pas fournir les valeurs entières Family, Model et Stepping que j'obtiens maintenant et je pense qu'il ne fournit qu'un type de description x86 très générique du processeur. Le sysctlbyname() pourrait avoir plus de chance cependant. Je ne suis pas sûr si j'ai déjà regardé de près. Je vais enquêter et signaler mes conclusions. Merci! – brader24

+0

Vous pouvez utiliser syscctlnametomib pour extraire les nombres pour la famille, le modèle et le pas, que vous pouvez utiliser pour sysctl. C'est environ 3x plus rapide que sysctlbyname. –

7

Vous devez consulter les API IOKit. L'application IORegistryExplorer (qui fait partie de l'installation standard de devtools) vous aidera à trouver ce que vous cherchez. Par exemple, sur mon MacBook Pro, dans IORegistryExplorer, je sélectionne 'IODeviceTree' dans le menu déroulant en haut à gauche de la fenêtre, et je vois deux processeurs dans l'arborescence ci-dessous. La sélection de l'un me reçoit les informations suivantes:

IORegistryExplorer screenshot http://blog.alanquatermain.net/images/IORegistryExplorer-CPUs.png

« bus-fréquence » et « fréquence d'horloge » et « base de temps-fréquence » sont wrapper tous les entiers 32 bits dans les objets de données, et doivent donc être byte-troqué à interpréter ici (little-endian mots machine i386) et travailler aux valeurs suivantes:

  • bus fréquence: 1064000000 Hz => 1,064 GHz
  • horloge de fréquence: 2530000000 Hz = > 2,53 GHz
  • fréquence base de temps: 1000000000 HZ => 1,0 GHz

Si vous lisez ces via IOKit cependant, vous récupérerez un CFDataRef, et peut tout simplement copier les octets dans votre propre uint32_t comme ceci:

uint32_t bus_frequency = 0; 
CFDataGetBytes(theData, (UInt8 *) &bus_frequency, sizeof(uint32_t)); 

Ensuite, vous pouvez obtenir des informations sur le processeur en utilisant l'appel NXArchInfo() obtenu en incluant <mach-o/arch.h>. Cela renverra une structure contenant des codes de type et de sous-type de cpu ainsi que des noms et des descriptions de chaînes de caractères.Si cela n'inclut pas d'identifiant pas à pas, la seule façon de penser à cela (de haut en bas) est via l'instruction CPUID. Créer un .s et .h, et mettre dans le code suivant:

fichier .s:

#ifdef __i386__ || __x86_64__ 

.macro ENTRY 
    .text 
    .private_extern $0 
    .align 4, 0x90 
$0: 
.endmacro 

// __private_extern__ unsigned long GetCPUSteppingID(void) 
ENTRY _GetCPUSteppingID 
    push  %ebp    // store existing frame pointer 
    mov   %esp,%ebp   // make a new frame pointer from stack pointer 
#if __x86_64__ 
    push  %rbx 
#endif 
    push  %ebx    // we save %ebx because the cpuid instruction 
            // will overwrite it, and it's expected 
            // to be unchanged in the caller after 
            // calling another function 
    movl  $1,%eax    // fetch cpu info 
    cpuid       // stepping-id is in low 4 bits of %edx now 
    and   $0x0000000f,%edx // clear out everything we don't want 
#if __x86_64__ 
    mov   %edx,%rax   // %rax is 64-bit arch result register 
#else 
    mov   %edx,%eax   // %eax is 32-bit arch result register 
#endif 
    pop   %ebx    // restore saved value of %ebx 
#if __x86_64__ 
    pop   %rbx    // restore saved value of %rbx 
#endif 
    leave       // restores prior stack frame from %ebp 
    ret        // returns to caller 

#endif // __i386__ || __x86_64__ 

.h:

#ifndef __GET_STEPPING_ID__ 
#define __GET_STEPPING_ID__ 

/* unsigned long is register-sized on both 32-bit and 64-bit OS X */ 
__private_extern__ unsigned long GetSteppingID(void); 

#endif /* __GET_STEPPING_ID__ */ 

S'il vous plaît noter que je ne suis pas certain à propos du bit x86_64 ci-dessus; en théorie, ce que j'ai tapé ici assurera que le même code compile pour 64 bits, et retournera une valeur de 64 bits dans ce cas. Il va également sauvegarder/restaurer le registre% rbx, la version 64 bits du registre% ebx. Théoriquement qui couvrira toutes les bases.

0

Si vous souhaitez spécifiquement des informations sur le processeur, utilisez l'instruction cpuid (dans C asus cpuid). Il donne toutes les informations possibles sur un CPU, y compris sa famille, son modèle, son entreprise, son nombre de cœurs, etc. Toutes les API utilisent principalement cette instruction pour récupérer les informations du CPU. Vous pouvez obtenir des informations détaillées sur CPUID sur le web, y compris des exemples de code et des tutoriels.

6

Utilisez sysctlbyname plutôt que sysctl, par ex.

#include <stdio.h> 
#include <stdint.h> 
#include <sys/types.h> 
#include <sys/sysctl.h> 

uint64_t get_cpu_freq(void) 
{ 
    uint64_t freq = 0; 
    size_t size = sizeof(freq); 

    if (sysctlbyname("hw.cpufrequency", &freq, &size, NULL, 0) < 0) 
    { 
     perror("sysctl"); 
    } 
    return freq; 
} 

Vous pouvez obtenir une liste des noms qui peuvent être transmis à systctlbyname en regardant la sortie de sysctl -a de la ligne de commande.

Questions connexes