DOURNAC.ORG
Français  English
Accueil
Astronomie
Sciences
Philosophie
Informatique
Cv

Informatique > Codage : Trucs et Astuces



  • 1.Langage C : syntaxe généralisée avec malloc
  • 2.Langage C : création d'un tableau 2D contigu
  • 3.Langage C : création d'un tableau 3D contigu
  • 4.Générer un flux de données pour gnuplot
  • 5.Génération rapide d'une distribution gaussienne
  • 6.Déroulage de boucles en assembleur Sparc 32 bits

1.Langage C : syntaxe généralisée avec malloc

Afin de rendre l'allocation indépendante du type de la variable pointée, on peut utiliser malloc de la manière suivante :

double ***x;
x = malloc(size_y * sizeof(*x));
for (i = 0; i < size_y; i++)
 {
  x[i] = malloc(size_x * sizeof(**x));
  for (j = 0; j < size_x; j++)
     x[i][j] = malloc(size_z * sizeof(***x));
 }

au lieu d'avoir classiquement :

double ***x;
x = malloc(size_y * sizeof(double**));
for (i = 0; i < size_y; i++)
 {
  x[i] = malloc(size_x * sizeof(double*));
  for (j = 0; j < size_x; j++)
     x[i][j] = malloc(size_z * sizeof(double));
 }

Le pattern utilisé est de la forme :

// Pattern
p = malloc(N * sizeof(*p));

// Triple pointer
double ***x;
// First allocation
x = malloc(N * sizeof(*x));
// Equivalent expressions 
x[i] = malloc(N * sizeof(*(x[i])));
x[i] = malloc(N * sizeof(**x));
// Equivalent expressions 
x[i][j] = malloc(N * sizeof(*(x[i][j])));
x[i][j] = malloc(N * sizeof(***x));

2.Création d'un tableau 2D contigu en langage C :

En langage C, les éléments sont rangés et stockés consécutivement selon les lignes ("rows" anglais). Pour créer ce tableau 2D (ici de type double), que l'on note x0, avec un nombre de lignes égal à size_x et un nombre de colonnes égal à size_y, on effectue l'allocation d'un tableau de taille size_x*size_y dont l'adresse du premier élément se situe à x0[0]. Nous affectons ensuite à chaque élément x0[j] l'adresse du bloc correspondant au début d'une ligne. Voici la portion de code :

// Declaring double pointer for 2D array
double **x0;

// Allocating array
x0 = malloc(size_x * sizeof(*x0));
x0[0] = malloc(size_x * size_y * sizeof(**x0));
// Making 2D array contiguous
for(i = 1; i < size_x; i++) 
  x0[i] = x0[0] + i * size_y;

Après ce morceau de code, le tableau x0 peut être initialisé car l'élément (i,j) sera accessible par la notation x0[i][j]. L'utilisation de tableaux 2D contigus en mémoire sert par exemple dans le développement d'applications MPI, où les vecteurs (lignes et colonnes) échangés doivent être contigus.

3.Création d'un tableau 3D contigu en langage C :

Comme dans le cas 2D ci-dessus, on va créer un tableau 3D, que l'on note x0, comportant size_x lignes, size_y colonnes et size_z pour la troisième dimension.

// Declaring pointers for arrays
double *x0_all = malloc(size_x * size_y * size_z * sizeof(*x0_all));
double *x0_alloc = x0_all;
double ***x0;

// Allocating size_x rows
x0 = malloc(size_x * sizeof(*x0));

// Loop on rows
for (i = 0; i < size_x; i++) 
{
 // Allocating size_y columns for each row
 x0[i] = malloc(size_y * sizeof(**x0)); 
 // Loop on columns
 for (j = 0; j < size_y; j++) 
 {
  // Incrementing size_z block on x0[i][j] address
  x0[i][j] = x0_alloc;
  x0_alloc += size_z;
 }
}

De la même manière que pour le cas 2D, après ce morceau de code, l'initialisation du tableau x0 peut être effectuée car l'élément (i,j,k) sera accessible par la notation x0[i][j][k]. L'utilisation de tableaux 3D contigus en mémoire sert par exemple dans le développement d'applications MPI, où l'on échange entre processus des matrices qui doivent être alignées.

4.Générer un flux de données pour gnuplot :

On peut produire en une seule ligne de commande un flux de données que l'on va transférer à gnuplot à l'aide d'un pipe. Voici comment faire pour tracer la fonction $y=\cos(x)$ avec $0 < x < 10$ :

seq 0 0.1 10 | gnuplot -p -e 'plot "-" u 1:(cos($1)) w l'

La commande "seq 0 0.1 10" génère une colonne de donnés comprises entre 0 et 10 avec un incrément de 0.1. On "pipe" ce flux dans gnuplot avec les options -e (gnuplot exécute les commandes passées en paramètres après cette option) et -p (le fenêtre du plot ne se ferme pas quand la commande est exécutée). Attention de bien respecter l'ordre des options -p -e.

Autre solution avec la fonction "awk" - Représentation de la fonction $y=x^{2}$ :

seq 0 0.1 10 | awk '{printf("%3f\t%3f\n", \$1, \$1^2)}' | gnuplot -p -e 'plot "-" u 1:2 w l'

Pour remplacer les virgules par des points avec les flottants dans les versions de Bash "non Anglo-saxonnes", ne pas oublier de faire : export LC_NUMERIC=en_US

5.Génération rapide d'une distribution gaussienne :

Voici un moyen rapide de générer une distribution de Gauss. Pour cela, nous utilisons le module random de python :

for ((i=1;i<=10000;i++)); do python -c "import random; print \
min(10,max(0,random.gauss(5,1)))"; done | \
gnuplot -p -e "set terminal png size 550,384 font 'Helvetica,9'; \
set tics font 'Helvetica,8'; set output 'gaussian.png'; \
set style data histograms; set style histogram cluster gap 1; \
set style fill solid border 3; set boxwidth 0.1; binwidth=0.1; \
bin(x,width)=width*floor(x/width) + width/2.0; set xrange[0:10]; \
plot '-' using (bin(\$1, binwidth)):(1) smooth frequency with boxes \
title '{Gaussian distribution}'"

Voici ci-dessous la distribution obtenue avec $\mu=5$ et $\sigma=1$ :


Figure 1 : Exemple d'une distribution de Gauss(5,1) avec 10000 tirages dans un intervalle [0,10]

Si l'on veut sauvegarder les valeurs de l'histogramme dans un fichier, on doit faire :

set table 'hist.dat'; \
plot '-' using (bin(\$1, binwidth)):(1) smooth frequency with boxes; \
unset table;"

6.Déroulage de boucles en assembleur Sparc 32 bits :

Le déroulage de boucles ("unrolling loops" en anglais) est une technique d'optimisation de code qui consiste à dupliquer le corps d'une boucle afin de limiter la répétition de l'instruction de saut. Voici ci-dessous un exemple de code qui met en évidence le gain obtenu sur le runtime pour une simple boucle. Pour cela, nous incluons le code assembleur dans un source C, ce qui permet d'utiliser la fonction gettimeofday() pour mesurer le temps d'exécution passé dans cette boucle :

Tout d'abord, le code C dans lequel nous incluons du code assembleur, sans déroulage de boucles ni autres optimisations (fichier loop-without-unroll.c) :

#include <stdio.h>
#include <sys/time.h>
#include <unistd.h>

int main ()
{
  // Init sum
  int sum = 0;
  // Number of iterations
  int n = 100000000;

  struct timeval tv1, tv2;
  long int diff;

  // Start time
  gettimeofday (&tv1, NULL);

  // Loop with Sparc assembly into C source
  asm volatile ("clr %%g1\n\t"
                "clr %%g2\n\t"
                "mov %1, %%g1\n" // %1 = input parameter
                "loop:\n\t"
                "add %%g2, 1, %%g2\n\t"
                "subcc %%g1, 1, %%g1\n\t"
                "bne loop\n\t"
                "nop\n\t"
                "mov %%g2, %0\n" // %0 = output parameter
                : "=r" (sum)     // output
                : "r" (n)        // input
                : "g1", "g2");   // clobbers

  // End time
  gettimeofday (&tv2, NULL);

  // Compute runtime for loop
  diff = (tv2.tv_sec - tv1.tv_sec) * 1000000L + (tv2.tv_usec - tv1.tv_usec);

  // Print results
  printf ("Elapsed time = %d usec\n", diff);
  printf ("Sum = %ld\n", sum);

  return 0;

}

Remarques sur l'inclusion pour gcc de code assembleur Sparc dans un source C :

  • Doubler le symbole "%" devant chaque nom de registre
  • "%0" correspond au paramètre de sortie
  • "%1" correspond au paramètre d'entrée ("%2" au deuxième, "%3" au troisième, etc ...)
  • La syntaxe, pour faire le lien entre les variables du source C et les registres, est la suivante :

    : "=r" (sum)
    : "r" (n)
    : "g1", "g2"

    où la première ligne correspond au paramètre de sortie ("sum"), la deuxième au paramètre d'entrée ("n") et la dernière aux registres "clobbered", c'est-à-dire les registres qui seront modifiés durant l'exécution du code assembleur (ici les registres "%g1" et "%g2").






ps : contribuez comme moi au projet Cosmology@Home dont le but est d'affiner le modèle décrivant le mieux notre Univers.

    Accueil | Astronomie | Sciences | Philosophie | Informatique | Cv    
- dournac.org © 2003 by fab -

Haut de Page