Archives pour la catégorie MEX

Compilation de fichiers MEX sur Mac OS X

D’après le site de MathWorks, pour compiler des fichiers MEX avec les versions récentes de MATLAB sur Mac OS X, il suffit d’installer XCode (à partir du site Apple Developer ou à partir de l’Apple Store).

Par contre, une fois sous MATLAB, à la première compilation d’un fichier MEX, on reçoit un message d’erreur assez déroutant :

gcc-4.2: command not found

Après une brève recherche sur le support de MathWorks, on arrive sur la page suivante : Can I use Xcode 4.2 to 4.6 as my C or C++ compiler in MATLAB?

Il faut donc commencer par aller dans le menu « XCode > Preferences > Downloads » de XCode et installer, si ce n’est déjà fait, le composant « Command Line Tools» (la suite de compilateurs Gcc).

Après l’application du patch fourni par MathWorks, la compilation de fichiers MEX est opérationnelle 8-)

Note : il est sans doute possible de se passer de l’encombrant XCode en ne téléchargeant que le composant « Command Line Tools » directement sur le site Apple Developer – Open Source. Par contre, je ne sais pas si le patch fourni par MathWorks fonctionne sans XCode. Il y aura peut être des problèmes de chemins non disponibles. A tester…

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).