Fast-Math

 Trucs et astuces techniques  Commentaires fermés sur Fast-Math
Fév 272010
 

Il existe des options de compilation pour gcc permettant d’accélérer les calculs.
Par contre, attention il est posible d’avoir des erreurs d’arrondi non négligeables et donc un comportement erratique.
NE JAMAIS faire de tests d’égalité entre des float ou des doubles si cette option de compilation est activée.

gcc -mmmx -msse -msse2 -msse3 --ffast-math

Calculs trigonometriques rapides

 Trucs et astuces techniques  Commentaires fermés sur Calculs trigonometriques rapides
Fév 262010
 

Apres avoir lu quelques tutos sur comment optimiser les calculs trigonométriques, j’ai voulu me faire une librairie trigo rapide basée sur une table et là : surprise !

sur un PC récent

matablesin[(int)(angle/deuxpi*tailletable)]

est presque 2 fois plus lent que

sin(angle);

L’explication est toute simple : Les processeurs modernes ont tout le hardware necessaire pour calculer sin et cos, et même les deux en même temps. (instructions assembleur spécialisées)

Remarque : La taille de la table a une influence car il est probable qu’elle soit accédée a peu près alléatoirement. Dans ces conditions les mécaniques de cache et de préchargement de pages ne peuvent pas fonctionner et la lecture en RAM prends finalement plus de temps que de demander le calcul au processeur.

Ce genre de technique reste cependant applicable au calcul de asin et acos qui ne sont pas (encore) accélérés materiellement.

Netstat et ses options sympa

 Trucs et astuces techniques  Commentaires fermés sur Netstat et ses options sympa
Fév 092010
 

Pour avoir des statistiques réseau sous linux, vous connaissez certainement netstat

Certaines combinaisons d’options sont plus faciles à retenir avec des moyens mnemotechniques
Parmis les options intéressantes :

netstat -lapute

ou encore

netstat -pantalon

Ce sont évidemment des options composées, pour plus d’infos RTFM.

Monitoring CPU temps réel

 Trucs et astuces techniques  Commentaires fermés sur Monitoring CPU temps réel
Fév 082010
 

voici un petit bout de code C qui mesure l’activité CPU d’une machine et envoie les statistiques à une machine de monitoring

#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#define BUFSIZE 1024


enum { CURRENT , OLD , DIFF , PERCENT , TABSIZE };
enum { USR, NICE, SYSTEM , IDLE , IOWAIT , IRQ , SOFTIRQ , TOTAL , NBCOLS };
enum { ERROR, OK };

unsigned long long int table[NBCOLS][TABSIZE];

void setcolor(int f, int b) { printf("%c[0;%d;%dm",27,30+f,40+b); }
void setfcolor(int f) { printf("%c[%d;%dm", 27, f/8, 30+(f%8) ); }
void setbcolor(int b) { printf("%c[%d;%dm", 27, b/8, 40+(b%8) ); }
void setdefault(void) { printf("%c[m",27); }
char thishostname[BUFSIZE];



int s;
struct sockaddr_in srvAddr;
struct hostent *h;

void recuphostname(void)
{	FILE * f;
	f=fopen("/etc/hostname" ,"r");
	fgets(thishostname , BUFSIZE-1 , f);
	if ( thishostname[strlen(thishostname)-1] == '\n') thishostname[strlen(thishostname)-1] ='\0';
	fclose(f);
}

int recup(void)
{   FILE * f;
    char cpuline[BUFSIZE];
    unsigned int i;
    
    f=fopen("/proc/stat" ,"r");
    if (!f) return ERROR;    
    fgets(cpuline , BUFSIZE-1 , f);
    fclose(f);

    for ( i=0 ; cpuline[i] != ' ' && i<BUFSIZE ; i++ ); i++; 
    sscanf(cpuline+i, "%llu", &( table[USR][CURRENT] )        );
    for ( i++ ; cpuline[i] != ' ' && i<BUFSIZE ; i++ ); i++; 
    sscanf(cpuline+i, "%llu", &( table[NICE][CURRENT] )       );
    for ( i++ ; cpuline[i] != ' ' && i<BUFSIZE ; i++ ); i++; 
    sscanf(cpuline+i, "%llu", &( table[SYSTEM][CURRENT] )     );
    for ( i++ ; cpuline[i] != ' ' && i<BUFSIZE ; i++ ); i++; 
    sscanf(cpuline+i, "%llu", &( table[IDLE][CURRENT] )       );
    for ( i++ ; cpuline[i] != ' ' && i<BUFSIZE ; i++ ); i++; 
    sscanf(cpuline+i, "%llu", &( table[IOWAIT][CURRENT] )     );
    for ( i++ ; cpuline[i] != ' ' && i<BUFSIZE ; i++ ); i++; 
    sscanf(cpuline+i, "%llu", &( table[IRQ][CURRENT] )        );
    for ( i++ ; cpuline[i] != ' ' && i<BUFSIZE ; i++ ); i++; 
    sscanf(cpuline+i, "%llu", &( table[SOFTIRQ][CURRENT] )    );
    return OK;
}


void affiche(void)
{   printf("USR=%03lu ",     table[USR][PERCENT]);
    printf("NICE=%03lu ",    table[NICE][PERCENT]);
    printf("SYSTEM=%03lu ",  table[SYSTEM][PERCENT]);
    printf("IDLE=%03lu ",    table[IDLE][PERCENT]);
    printf("IOWAIT=%03lu ",  table[IOWAIT][PERCENT]);
    printf("IRQ=%03lu ",     table[IRQ][PERCENT]);
    printf("SOFTIRQ=%03lu\n", table[SOFTIRQ][PERCENT]);
}

void affiche2(void)
{   int i;
    int cpt=0;

    printf("[");   
    //setfcolor(0);
    setfcolor(2);
    for ( i=0 ; i < table[USR][PERCENT] ; i++ ) { putc('U',stdout); cpt++; }
    setfcolor(1);
    for ( i=0 ; i < table[SYSTEM][PERCENT] ; i++ ) { putc('S',stdout); cpt++; }
    setfcolor(4);
    for ( i=0 ; i < table[IOWAIT][PERCENT] ; i++ ) { putc('W',stdout); cpt++; }
    setfcolor(6);
    for ( i=0 ; i < table[IRQ][PERCENT]+table[SOFTIRQ][PERCENT] ; i++ ) { putc('I',stdout); cpt++; }
    setdefault();
    for ( i=cpt ; i < 100 ; i++ ) putc(' ',stdout);
    printf("] CHARGE CPU : %4lu%% \n", 100 - table[IDLE][PERCENT] );

   
}

void affichenet(void)
{   char outbuffer[2000];

    sprintf(outbuffer , "%s|",thishostname);
    sprintf(outbuffer+strlen(outbuffer) , "%lu|",     table[USR][PERCENT]);
    sprintf(outbuffer+strlen(outbuffer) , "%lu|",    table[NICE][PERCENT]);
    sprintf(outbuffer+strlen(outbuffer) , "%lu|",  table[SYSTEM][PERCENT]);
    sprintf(outbuffer+strlen(outbuffer) , "%lu|",    table[IDLE][PERCENT]);
    sprintf(outbuffer+strlen(outbuffer) , "%lu|",  table[IOWAIT][PERCENT]);
    sprintf(outbuffer+strlen(outbuffer) , "%lu|",     table[IRQ][PERCENT]);
    sprintf(outbuffer+strlen(outbuffer) , "%lu\n", table[SOFTIRQ][PERCENT]);

    printf("%s", outbuffer);

    sendto(s, outbuffer, strlen(outbuffer)+1, 0, (struct sockaddr *) &srvAddr, sizeof(srvAddr));

}

void submain(void)
{       
    unsigned int i=0;
   
    
    if ( ! recup() ) return;
    
    for ( i=USR ; i<TOTAL ; i++)
    {       if (table[i][CURRENT]<table[i][OLD]) return;
    }

    table[TOTAL][CURRENT] = 0;
    for ( i=USR ; i<TOTAL ; i++ ) 
        table[TOTAL][CURRENT] += table[i][CURRENT];           /*genere le total       */
    for ( i=USR ; i<=TOTAL ; i++) 
        table[i][DIFF] = table[i][CURRENT] - table[i][OLD];   /*genere différences */

    if ( table[TOTAL][DIFF] == 0 ) return;
    for ( i=USR ; i<=TOTAL ; i++) 
        table[i][PERCENT] = ( table[i][DIFF] * 100 ) / table[TOTAL][DIFF];    /*calcul pourcentages */

    //affiche2();
    affichenet();
    
    for ( i=USR ; i<=TOTAL ; i++ ) 
        table[i][OLD]=table[i][CURRENT];     /*archive les anciennes valeur pour la prochaine mesure */
    
}


int main(void)
{       
    unsigned int i=0;
    unsigned int j=0;
    struct timespec ts;
    ts.tv_sec=0;
    ts.tv_nsec=100000000;
   
     
    for ( i=USR ; i<=TOTAL ; i++) for (j=CURRENT ; j<NBCOLS ; j++ ) table[i][j]=0;
    
    recuphostname();

    srvAddr.sin_family = AF_INET;
    srvAddr.sin_port = htons(31857);
    srvAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
    

    s=socket(AF_INET,SOCK_DGRAM,0);
    if ( s<0 ) return 1;

    while (1)
    {   nanosleep(&ts, NULL);
        submain();
    }
     return 0;
}

Emulation vs Paravirtualisation

 Trucs et astuces techniques  Commentaires fermés sur Emulation vs Paravirtualisation
Fév 082010
 

Dans le monde de la virtualisation, il y a 2 grandes familles :

  • L’émulation
  • La paravirtualisation

L’émulation consiste a emuler logiciellement le matériel sur lequel le systeme d’exploitation est censé fonctionner.
Dans le cas d’une emulation totale,on émule jusqu’au fonctionnement du processeur. C’est le cas dans les emulateurs d’autres architectures comme par exemple un emulateur de console nintendo NES ou Sega MegaDrive sur PC.
Les ressources CPU necessaires pour réaliser ce type d’emulation sont enormes par rapport à la puissance des machines émulées.

Dans le cas ou on émule une architecture identique à l’architecture hote, il est possible de prendre pas mal de racourcis en faisant executer directement la majorité du code par le CPU. seules les instructions privilégiées comme pour l’accès au matériel devront être émulées. Cette technique consiste essentiellement à intercepter tous les appels bas niveau et à y répondre comme le ferait les matériel « émulé »
Cette technique est par exemple utilisée dans le logiciel VMware.
Les microprocesseurs récents intègrent des optimisations spécifiques permettant de réaliser ces opérations d’émulation avec un niveau de performances nettement supérieur à ce qui était possible auparavent.

Enfin Il existe une technique dite de paravirtualisation qui est à mon avis la meilleure car elle permet des performances proches de celles obtennues avec une machine physique. Cette technique consiste à employer un « hyperviseur » qui implémente toutes les routines d’accès bas niveau et auquel les systemes d’exploitation hébergés feront directement référence. Le problème de cette technique est que les systemes d’exploitation en question doivent être modifiés pour tenir compte qu’ils fonctionnent dans un environnement virtuel.

Actuellement, une des meilleurs solutions de paravirtualisation est Xen.
malheureusement, Windows n’est pas conçu pour fonctionner avec Xen. Il n’est possible de paravirtualiser windows qu’en employant l’hyperviseur microsoft HyperV.

Disques virtuels avec LVM pour machines XEN

 Trucs et astuces techniques  Commentaires fermés sur Disques virtuels avec LVM pour machines XEN
Fév 082010
 

Lors de la création de machines virtuelles XEN, (on parle de machines paravirtualisées et non émulées) On peut utiliser des volumes logiques pour créer les disques virtuels de cette machine. Il faut absolument éviter d’utiliser LVM à l’intérieur du domU car la couche lvm de dom0 reconnaitra les PV du domU comme un nouveau VG de dom0.

Le systeme *peut* fonctionner comme ça mais il y a quand même de gros risques de confusion ou cafouillages en particulier si on tente de manipuler les volumes en question à partir de dom0.

donc : une manipe à éviter.

Les tours de hanoï

 Trucs et astuces techniques  Commentaires fermés sur Les tours de hanoï
Fév 022010
 

Ce petit bout de code C illustre la résolution du problème des
tours de hanoï par l’utilisation de fonctions récursives.

#include <stdio.h>
#include <time.h>


//variables globales
const int nb=16;
int colonne[3][100];

//prototypes
int autre(int c1, int c2);//renvoie l'autre colonne (on lui en donne 2 elle renvoie la troisième)
void affiche(void);//Affiche l'état des 3 colonnes
void deplace1(int s, int d);//Déplace un jeton d'une colonne à une autre
void deplacen(int n, int s, int d);//Déplace n jeton(s) d'une colonne à une autre

int main(void)
{  int cpt, col ;
   for (cpt=0; cpt<100 ; cpt++)
      for (col=0 ; col<3 ; col++)
         colonne[col][cpt]=0;
   for (cpt=0; cpt<nb ; cpt++)
      colonne[0][cpt]=nb-cpt;
   affiche();
   deplacen(nb,0,2);
}

void deplacen(int n, int s, int d)
{  if ( n == 1 ) { deplace1(s,d); return; }
   deplacen(n-1,s,autre(s,d));
   deplace1(s,d);
   deplacen(n-1,autre(s,d),d);
}

void deplace1(int s, int d)
{  int cpts=0, cptd=0;
   while (colonne[s][cpts]) cpts++ ; 
   while (colonne[d][cptd]) cptd++ ; 
   colonne[d][cptd]=colonne[s][cpts-1] ; 
   colonne[s][cpts-1] = 0 ;
   affiche();
}

int autre(int c1, int c2)
{  switch (c1)
   {  case 0 :  if ( c2 == 1 ) return 2 ; else return 1 ;
      case 1 :  if ( c2 == 0 ) return 2 ; else return 0 ;
      case 2 :  if ( c2 == 0 ) return 1 ; else return 0 ;
   }
}

void affiche(void)
{  int cpt, col;
   static int etape=0;
   printf("etape %09u\n",etape++);
   for (col=0 ; col<3 ; col++)
   {  printf("Colonne %c > ",'A'+col);
      cpt=0 ; while ( colonne[col][cpt] ) printf("%02u ", colonne[col][cpt++]) ; 
      printf("\n");
   }
   printf("\n");
   usleep(1000);
}

Programmation openGL sous Debian (Lenny)

 Trucs et astuces techniques  Commentaires fermés sur Programmation openGL sous Debian (Lenny)
Fév 012010
 

Les paquets nécessaires pour compiler une application opengl minimale sont :

apt-get install --assume-yes libxi-dev libxi6
apt-get install --assume-yes libxmu6 libxmu-dev
apt-get install --assume-yes freeglut3-dev freeglut3 libglut3 libglut3-dev glutg3 glutg3-dev
apt-get install --assume-yes libgl1-mesa-dev libglib2.0-dev libglu1-mesa-dev libglut3 libglut3-dev