Archives du mot-clé cpuid

Identification de processeur sous MATLAB (3/3)

Pour clôturer cette série de billets (lire les billets 1/3 et 2/3), je vais vous présenter rapidement une dernière méthode pour obtenir les caractéristiques du processeur (CPU) de votre machine.

Les méthodes présentées jusqu’à présent étaient soient incomplètes (voire incorrectes), soient différentes selon le système d’exploitation. Afin de corriger ces problèmes, nous allons utiliser une méthode très proche du CPU. Pour ce faire nous allons utiliser le langage assembleur et l’opcode CPUID.

Pour l’utiliser sous MATLAB, il est nécessaire de l’inclure dans un fichier MEX. Je vous propose donc deux versions écrites en C selon que vous utilisez les compilateurs Microsoft Visual C++ ou GNU gcc.

Voici le code pour gcc :

#include "mex.h"
#include <string.h>

void cpuid(int b[4], int a) {
   
    __asm( "cpuid"
            : "=a" (b[0]), "=b" (b[1]), "=c" (b[2]), "=d" (b[3])
            : "a"  (a));
           
}

void mexFunction( int nlhs, mxArray *plhs[],
        int nrhs, const mxArray *prhs[] ) {
   
    int CPUInfo[4] = {-1};
    char CPUString[0x20];
    const mwSize dims[2] = {1,5};
   
    cpuid(CPUInfo, 0);
   
    memset(CPUString, 0, sizeof(CPUString));
    *((int*)CPUString) = CPUInfo[1];
    *((int*)(CPUString+4)) = CPUInfo[3];
    *((int*)(CPUString+8)) = CPUInfo[2];    
   
    plhs[0] = mxCreateCellArray(2, dims);
   
    mxSetCell(plhs[0], 4, mxCreateString(CPUString));
   
    cpuid(CPUInfo, 1);
   
    mxSetCell(plhs[0], 0, mxCreateDoubleScalar((double)((CPUInfo[0] >> 8) & 0xf)));
    mxSetCell(plhs[0], 1, mxCreateDoubleScalar((double)((CPUInfo[0] >> 16) & 0xf)));
    mxSetCell(plhs[0], 2, mxCreateDoubleScalar((double)((CPUInfo[0] >> 4) & 0xf)));
    mxSetCell(plhs[0], 3, mxCreateDoubleScalar((double)(CPUInfo[0] & 0xf)));
   
}

et le « même » pour Visual C++ :

#include "mex.h"
#include <string.h>
#include <intrin.h>

void mexFunction( int nlhs, mxArray *plhs[],
        int nrhs, const mxArray *prhs[] ) {
   
    int CPUInfo[4] = {-1};
    char CPUString[0x20];
    const mwSize dims[2] = {1,5};
   
    __cpuid(CPUInfo, 0);
   
    memset(CPUString, 0, sizeof(CPUString));
    *((int*)CPUString) = CPUInfo[1];
    *((int*)(CPUString+4)) = CPUInfo[3];
    *((int*)(CPUString+8)) = CPUInfo[2];    
   
    plhs[0] = mxCreateCellArray(2, dims);
   
    mxSetCell(plhs[0], 4, mxCreateString(CPUString));
   
    __cpuid(CPUInfo, 1);
   
    mxSetCell(plhs[0], 0, mxCreateDoubleScalar((double)((CPUInfo[0] >> 8) & 0xf)));
    mxSetCell(plhs[0], 1, mxCreateDoubleScalar((double)((CPUInfo[0] >> 16) & 0xf)));
    mxSetCell(plhs[0], 2, mxCreateDoubleScalar((double)((CPUInfo[0] >> 4) & 0xf)));
    mxSetCell(plhs[0], 3, mxCreateDoubleScalar((double)(CPUInfo[0] & 0xf)));
   
}

A compiler comme ceci sous MATLAB :

mex getcpuinfosmx.c

Vous pourrez ensuite l’utiliser sous MATLAB comme ceci :

data = getcpuinfosmx;

fprintf('Family %d Extended Model %d Model %d Stepping %d, %s\n', ...
    data{1},data{2},data{3},data{4},strtrim(data{5}));

Ce qui renvoie bien les bonnes valeurs sur ma machine comme nous l’avons vu dans le billet précédent :

Family 6 Extended Model 2 Model 10 Stepping 7, GenuineIntel

On peut ensuite appliquer la méthodologie décrite dans les précédents billets pour retrouver le CPU dans les fiches constructeurs.

Dans le même esprit, voici un autre code pour récupérer la désignation commerciale du CPU.

Avec gcc :

#include "mex.h"
#include <string.h>

void cpuid(int b[4], int a) {
   
    __asm( "cpuid"
            : "=a" (b[0]), "=b" (b[1]), "=c" (b[2]), "=d" (b[3])
            : "a"  (a));
           
}

void mexFunction( int nlhs, mxArray *plhs[],
        int nrhs, const mxArray *prhs[] ) {
   
    int CPUInfo[4] = {-1};
    char CPUBrandString[0x40];
   
    cpuid(CPUInfo, 0x80000000);
    memset(CPUBrandString, 0, sizeof(CPUBrandString));
   
    cpuid(CPUInfo, 0x80000002);
    memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
   
    cpuid(CPUInfo, 0x80000003);
    memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
   
    cpuid(CPUInfo, 0x80000004);
    memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
   
    plhs[0] = mxCreateString(CPUBrandString);
   
}

Sous Visual C++ :

#include "mex.h"
#include <string.h>
#include <intrin.h>

void mexFunction( int nlhs, mxArray *plhs[],
        int nrhs, const mxArray *prhs[] ) {
   
    int CPUInfo[4] = {-1};
    char CPUBrandString[0x40];
   
    __cpuid(CPUInfo, 0x80000000);
    memset(CPUBrandString, 0, sizeof(CPUBrandString));
   
    __cpuid(CPUInfo, 0x80000002);
    memcpy(CPUBrandString, CPUInfo, sizeof(CPUInfo));
   
    __cpuid(CPUInfo, 0x80000003);
    memcpy(CPUBrandString + 16, CPUInfo, sizeof(CPUInfo));
   
    __cpuid(CPUInfo, 0x80000004);
    memcpy(CPUBrandString + 32, CPUInfo, sizeof(CPUInfo));
   
    plhs[0] = mxCreateString(CPUBrandString);
   
}

Une fois compilé, ce code me renvoi bien la bonne désignation du CPU de ma machine :

cpuname = getcpubrandstringmx

cpuname =

       Intel(R) Core(TM) i5-2430M CPU @ 2.40GHz

Voila, vous avez maintenant la possibilité d’identifier le CPU de votre machine sous MATLAB grâce à plusieurs méthodes.

Vous trouverez les fichiers MEX compilés (Windows, Linux et Mac) de getcpubrandstring ici.

Vous trouverez les fichiers sources C-MEX utilisés dans cet article ici.

Si vous voulez aller plus loin dans l’exploration des caractéristiques du CPU de votre machine, voici quelques liens utiles :

PS : les solutions proposées dans ce billet supposent que le CPU de votre machine connait les instructions CPUID (ce qui est le cas pour les processeurs Intel et AMD les plus couramment utilisés).

Identification de processeur sous MATLAB (2/3)

Dans mon précédent billet, je vous ai montré qu’il ne fallait pas faire confiance à la fonction feature(‘GetCPU’) pour obtenir les caractéristiques du processeur (CPU) de votre machine.

Il existe une méthode plus robuste dépendante du système d’exploitation

Avec Windows, il est possible d’utiliser la fonction getenv dans MATLAB comme ceci :

getenv('PROCESSOR_IDENTIFIER')

ans =

Intel64 Family 6 Model 42 Stepping 7, GenuineIntel

Avec Linux, il suffit de traiter les données contenues dans /proc/cpuinfo avec MATLAB comme ceci :

[status,data{1}] = system('grep -m 1 "vendor_id" /proc/cpuinfo | cut -d: -f2');
[status,data{2}] = system('grep -m 1 "cpu family" /proc/cpuinfo | cut -d: -f2');
[status,data{3}] = system('grep -m 1 "model" /proc/cpuinfo | cut -d: -f2');
[status,data{4}] = system('grep -m 1 "stepping" /proc/cpuinfo | cut -d: -f2');

Avec Mac OS X, il faut exploiter les retours de la commande sysctl machdep.cpu :

[status,data{1}] = system('sysctl machdep.cpu | grep cpu.vendor | cut -d: -f2');
[status,data{2}] = system('sysctl machdep.cpu | grep cpu.family | cut -d: -f2');
[status,data{3}] = system('sysctl machdep.cpu | grep cpu.model | cut -d: -f2');
[status,data{4}] = system('sysctl machdep.cpu | grep cpu.stepping | cut -d: -f2');

Ce qui donne par exemple :

fprintf('Family %s Model %s Stepping %s, %s\n',strtrim(data{2}),strtrim(data{3}),strtrim(data{4}),strtrim(data{1}));

Family 6 Model 42 Stepping 7, GenuineIntel

Pour rappel, la valeur de Model était 10 dans le précédent billet et cela posait problème pour déterminer avec exactitude le CPU.

Ici, il faut convertir 42 en binaire, soit 00101010. Il faut ensuite séparer les bits en deux paquets comme ceci : 0010 et 1010. La première valeur correspond à l’Extended Model qui si on se reporte au tableau Intel nous permet bien de cibler : « 2nd Generation Intel core Processor Family Mobile (Sandy Bridge) ». Ce qui correspond bien à la famille de mon CPU.

Note : avec Mac OS X, on peut directement récupérer l’Extended Model en passant cpu.extmodel à grep.

Pour identifier le CPU avec précision dans sa famille, il faut identifier plusieurs paramètres comme la fréquence, les mémoire caches… Ce qui peut s’avérer assez fastidieux.

Il nous faudrait une solution plus rapide qui donnerait la désignation commerciale du CPU en une seule ligne.

Avec Windows :

[status,cpuname] = system('for /f "tokens=2 delims==" %A in (''wmic cpu get name /value'') do @(echo %A)');

Avec Linux :

[status,cpuname] = system('grep -m 1 "model name" /proc/cpuinfo | cut -d: -f2');

Avec Mac OS X :

[status,cpuname] = system('sysctl machdep.cpu | grep brand_string | cut -d: -f2');

Ce qui donne par exemple :

cpuname =

Intel(R) Core(TM) i5-2430M CPU @ 2.40GHz

C’est beaucoup mieux :)

Dans le prochain billet, je vous montrerai comment demander directement ces informations au CPU lui-même à l’aide de l’opcode CPUID. Cette dernière solution sera portable et fonctionnera donc quelque soit le système d’exploitation.

Identification de processeur sous MATLAB (1/3)

Vous pouvez identifier le modèle du processeur (CPU) installé sur votre machine avec MATLAB à l’aide de la fonction non documentée feature.

Sur mon portable, voici ce que cela donne :

feature('GetCPU')

ans =

x86 Family 6 Model 10 Stepping 7, GenuineIntel

La dernière donnée nous donne le nom du fabricant. Les deux plus courants sont « GenuineIntel » pour Intel et « AuthenticAMD » pour AMD.

Il suffit alors de se référer à une liste donnée par le fabricant du CPU. Dans mon cas, il s’agit d’Intel et la fiche est disponible à cette adresse : Intel® Processor Identification and the CPUID Instruction (voir CPUID Specification pour les processeurs AMD)

Je me reporte donc à la table 5-4 « Intel486 and Subsequent Processeor Signatures » (p23) et je cherche les valeurs 6 (Family) et 10 (Model) converties en binaire (soit respectivement 0110 et 1010) dans les deux colonnes « Family Code » et « Model No. »

J’obtiens trois résultats possibles : « Pentium III Xeon processor » ou « Intel Core i7 processor or Intel Xeon processor » ou encore « 2nd Generation Intel core Processor Family Mobile (Sandy Bridge) ».

La dernière est la bonne puisque mon portable est équipé d’un Intel Core i5-2430M

Il manque en fait une information non retournée par la fonction feature. Il s’agit de la valeur de l’Extended Model.

On trouve en effet 0000 pour les « Pentium III Xeon », « 0001 » pour les « Intel Core i7″ et 0010 pour les « Intel Core Mobile de 2ème génération ».

Essayez sur votre machine et dites-moi si vous pouvez identifier à coup sûr votre CPU avec feature(‘GetCPU’) !

Dans un prochain billet, je vous montrerai comment identifier sans erreur votre CPU. Vous saurez également comment obtenir directement son intitulé commercial comme « Intel Core i5-2430M » dans mon cas.