Clavier PC et Mac : aïe !

Comme je l’ai décrit dans mon dernier article (Mac mini « Late 2012 » – Intel Core i5 et OS X Mountain Lion), j’ai rencontré quelques difficultés avec les touches de mon clavier PC et leurs correspondances sous OS X.

L’outil « Visualiseur de clavier » m’a sauvé la vie !

Voici plusieurs captures d’écran du visualiseur en fonction des touches pressées sur mon clavier PC (les touches grisées correspondent aux touches de modification Ctrl, Alt ou Maj).

Par défaut :
Par défaut

Avec Ctrl :
Avec Ctrl

Avec Alt :
Avec Alt

Avec Maj :
Avec Maj

Avec Ctrl + Maj :
Avec Ctrl + Maj

Avec Ctrl + Alt :
Avec Ctrl + Alt

Avec Alt + Maj :
Avec Alt + Maj

La question est : combien de temps vais-je tenir avant de craquer pour un vrai clavier Mac ?

:?

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.