TP compilation,
make, archivage et appels système



1) Une matrice d’entiers peut être vue comme un tableau à deux dimentions d’entiers. On peut donc en déclarer une en langage C par int mat[100][100];


Ecrire dans un fichier f1 une fonction qui réalise la somme de deux matrices de même taille, dans un fichier f2, une fonction qui réalise le produit de deux matrices de même taille, un fichier f3 pour saisir les valeurs d’une matrice et les afficher ainsi qu’une fonction qui va générer des valeurs de manière aléatoire ; un fichier f4 qui contient le main() et qui propose un menu pour faire des sommes et des produits de matrices après des saisies.


Note : pour retrouver les algorithmes de somme et de produit de matrices, faites une recherche sur Internet ; c’est du grand classique !


Après avoir lu et compris le document http://iihm.imag.fr/blanch/howtos/GNUMake.html construisez un fichier Makefile qui va s’occuper de compiler l’ensemble des fichiers et produire l’exécutable.


Ajouter une ligne au fichier Makefile pour générer également une bibliothèque partagée regroupant les fonctions de gestion d’une matrice (fichiers f1, f2 et f3).


2) A partir de l’exemple précédent, on vous demande de compiler l’assembleur du fichier f1 et d’ajouter dans l’assembleur une primitive permettant de faire de la lecture anticipée de donnée. Faites une recherche sur Internet du mot clé prefetchw par exemple.


HINT: pour que gcc fasse du dépliage de boucle, de la lecture anticipée il faut compiler pour l'architecture Opteron de la facon suivante : gcc -S -O4 -march=opteron -funroll-loops -fprefetch-loop-arrays solution.c. Pour faire du dépliage de boucle, la taille des matrices doit être suffisamment grande !


Compiler votre nouveau code comme à l’exercice précédent. Faites varier la taille des matrices et dites si l’introduction de cette instruction permet une diminution du temps d’exécution de la somme de matrices.


3) Plus difficile. A partir de l’exécutable issu de l’exercice 1), dé-assemblez le au moyen de objdump ; insérer une instruction prefetch dans la fonction de somme ; recompilez l’assembleur et vérifiez qu’il n’y a pas de « core dump » à l’exécution.


4) On commencera par écrire une fonction et un exécutable qui prend en paramètre deux noms de fichiers contenant deux matrices d’entiers et qui en fait la somme. On écrira alors un autre fichier C qui au moyen d’une primitive exec??? lancera la somme des deux matrices et le rangement du résultat dans un troisième fichier.


5) On supposera que les matrices sont écrites dans des fichiers texte de la manière suivante :
1  23 32 45
10 20 31 21
11 7  6  89
18 6  56 78

On vous demande d’écrire un programme C qui, au moyen de l’appel a popen (+ d’autres choses bien entendu) permet de lister les valeurs sur la diagonale de la matrice (ici 1, 20, 6, 78). On supposera de plus qu’on n’a pas d’information sur la taille de la matrice qui est supposée carrée.


6) Téléchargez les sources de la « GNU Scientific Library » depuis le site http://www.gnu.org/software/gsl/ Après avoir décompressé et dé-archivé les sources, lancez une compilation (lire la documentation de l’installation qui devrait vous conduire à faire ./configure puis make). Ne faites pas make install car par défaut l’installation se fait dans des répertoires qui ne peuvent être accédés que par root et vous n’êtes pas root sur la machine.


Vous allez obtenir des librairies (fichiers lib*.o et/ou lib*.a et/ou lib*.so) qui seront stockés quelque part dans un sous répertoire du répertoire d’installation. Repérez ce(s) répertoire(s) afin de pouvoir compiler l’exemple suivant :


The following program computes the product of two matrices using the Level-3 BLAS function DGEMM, 
[ 0.11 0.12 0.13 ]  [ 1011 1012 ]   [ 367.76 368.12 ]
[ 0.21 0.22 0.23 ]  [ 1021 1022 ] = [ 674.06 674.72 ]
                    [ 1031 1032 ]


The matrices are stored in row major order, according to the C convention for arrays.

#include <stdio.h>
#include <gsl/gsl_blas.h>

int
main (void)
{
  double a[] = { 0.11, 0.12, 0.13,
                 0.21, 0.22, 0.23 };

  double b[] = { 1011, 1012,
                 1021, 1022,
                 1031, 1032 };

  double c[] = { 0.00, 0.00,
                 0.00, 0.00 };

  gsl_matrix_view A = gsl_matrix_view_array(a, 2, 3);
  gsl_matrix_view B = gsl_matrix_view_array(b, 3, 2);
  gsl_matrix_view C = gsl_matrix_view_array(c, 2, 2);

  /* Compute C = A B */

  gsl_blas_dgemm (CblasNoTrans, CblasNoTrans,
                  1.0, &A.matrix, &B.matrix,
                  0.0, &C.matrix);

  printf ("[ %g, %g\n", c[0], c[1]);
  printf ("  %g, %g ]\n", c[2], c[3]);

  return 0;  
}


Here is the output from the program,
$ ./a.out
[ 367.76, 368.12
  674.06, 674.72 ]


Le problème est de spécifier les chemins pour les fichiers include et les librairies. Modifiez donc les exemples suivants  (en ajoutant des options à la compilation comme -L et -I :


$ gcc -Wall -I/usr/local/include -c example.c

$ gcc -L/usr/local/lib example.o -lgsl -lgslcblas –lm

$ gcc example.o -lgsl -lcblas –lm

$ gcc example.o -lgsl -lcblas -latlas –lm


Note : veuillez vérifier avec la commande ldd que votre exécutable contient les librairies que vous avez installées et pas les librairies qui seraient déjà installées sur le système. Hint : pour obliger gcc à explorer d'abord un certain répertoire, utilisez l'option -Wl,-rpath,$(MY_LIB_INSTALL_PATH). Pour de plus amples informations sur les librairies partagées, lire la page ici. Il y a d'autres méthodes pour résoudre le problème comme par exemple modifier des variables d'environnement : voir ici dans ce cas. Par ailleurs, n'oubliez pas le rôle de la variable d'environnement LD_LIBRARY_PATH au moment de l'exécution du programme.


Enfin, générez des données aléatoires et faites varier la taille du problème (la taille des matrices) pour mesurer le temps d’exécution du programme. Tracez la courbe du temos d’exécution sur l’axe des Y et la taille des matrices sur l’axe des X. (On se contentera de générer des matrices carrés).


7- Téléchargez les sources de bash en version 3.2. Décompressez et installez le sous /tmp. Lancer cette version de bash et exécutez quelques exemples (par exemple ceux que vous avez développés).


Grâce à la commande nm, repérez dans l'exécutable de bash 3.2 quelques fonctions non définies dans l'exécutable (drapeau -U). Lancez également la commande ldd sur l'exécutable et donnez les librairies dynamiques liées avec l'exécutable.


8- Reprendre l'exemple du cours sur l'appel système open qui vous permettra d'écrire un programme qui écrira un fichier de 100Mo dans /tmp. Mesurez le temps de création de ce fichier. Refaites la même expérience mais en utilisant fopen et fclose. Quel est la valeur du nouveau temps mesuré ? Pourquoi ?