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.
Calculs trigonometriques rapides
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
est presque 2 fois plus lent que
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
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
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
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
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ï
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)
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