• Aucun résultat trouvé

Annexe D Extraits de l’application de multiplication

matricielle

N

ous proposons dans cette annexe des extraits du code C de l’application de multiplication matricielle sur des entiers de longueur arbitraire (propos´ee au chapitre 5), et cela `a des fins d’illustration des descriptions donn´ees sur le fonction-nement et l’utilisation de SKiPPER-II.

D.1 Introduction

Les deux sections qui suivent pr´esentent les extraits des principaux fichiers en langage C formant le code de l’application de multiplication matricielle sur des entiers de longueur arbi-traire.

La premi`ere section reprend le fichier contenant le codage de la repr´esentation interm´ediaire utilis´ee par SKiPPER-II pour ordonner et g´erer les squelettes de l’application.

La seconde donne un aper¸cu du contenu du fichier regroupant les fonctions de calcul de l’utilisateur et le code n´ecessaire pour faire la liaison entre celles-ci et le format attendu par SKiPPER-II ( stub-code). Le lecteur notera que dans ces fichiers, aucun appel `a une fonc-tion quelconque de communicafonc-tion de la biblioth`eque MPI n’est fait. Ce fait illustre la gesfonc-tion compl`ete par le noyau des communications entre les fonctions de calcul de l’utilisateur, et la d´echarge totale de ce dernier de toutes les tˆaches bas-niveau de programmation parall`ele.

D.2 Fichier codant la repr´esentation interm´ediaire de

l’ap-plication

Le lecteur remarquera le format des arguments des fonctions d’interface avec les fonctions de calcul. Il est con¸cu pour accepter n’importe quels type et nombre de param`etres au niveau de ces derni`eres.

Les tableaux nomm´es points d’entr´ee dans le code permettent au noyau d’appeler les fonc-tions d’interface lorsque l’application l’impose. Le fait d’utiliser un niveau d’indirection (par pointeur de fonction en C) autorise l’acc`es par le noyau `a n’importe quelle fonction de calcul du code utilisateur sans devoir ˆetre modifi´e lors d’un changement de nom ou de format d’une fonction utilisateur. Cela autorise aussi l’emploi de n’importe quel nom de fonction par l’uti-lisateur, et ne n´ecessite pas non plus de recompilation du noyau. Seul le fichier codant pour la repr´esentation interm´ediaire (et donc le fichier de liaison) n´ecessite une recompilation.

Notes :

- la mentionUNDEFINEDpour une entr´ee signifie qu’elle est sans objet,

- END OF APPindique que le squelette est le dernier de l’application,

- NO TARGETa pour rˆole d’informer le noyau que le squelette courant est le dernier

sque-lette de la hi´erarchie d’imbrication, et donc, que les r´esultats de celui-ci doivent ˆetre remont´es vers le squelette le plus englobant,

- MASTERsignifie que la fonction de calcul est en r´ealit´e un squelette imbriqu´e,

- SLAVEindique que le noyau doit utiliser la fonction utilisateur correspondant au squelette

/* DECLARATION DES FONCTIONS D’INTERFACE */ /* Prototypes des fonctions SPLIT */

int matrix_split_outter( char *, int, int **, int * ); int matrix_split_inner( char *, int, int **, int * ); /* Prototypes des fonctions PREDICATE */

int matrix_predicate( char *, int, int * ); /* Prototypes des fonctions COMPUTE */

int matrix_compute_inner( char *, int, char **, int * ); /* Prototypes des fonctions DIVIDE */

int matrix_divide( char *, int, char **, int *, int **, int * ); /* Prototypes des fonctions MERGE */

int matrix_merge_outter( char *, int, char **, int * ); int matrix_merge_inner( char *, int, char **, int * ); /* NOMBRE TOTAL DE SQUELETTES */

#define SQL_NUMBER 2

/* POINTS D’ENTREE DES FONCTIONS D’INTERFACE */ /* Fonctions COMPUTE */ int (* kd_slaves[SQL_NUMBER]) ( char * buffer_in_data , int buffer_in_size , char ** buffer_out_data, int * buffer_out_size ) = { UNDEFINED, &matrix_compute_inner }; /* Fonctions SPLIT */ int (* kd_split[SQL_NUMBER]) ( char * buffer_in_data, int buffer_in_size, int ** offsets_buffer, int * offsets_size ) = { &matrix_split_outter, &matrix_split_inner }; /* Fonctions PREDICATE */ int (* kd_predicate[SQL_NUMBER]) ( char * buffer_in_data, int buffer_in_size, int * solve ) = { UNDEFINED, &matrix_predicate };

/* Fonctions DIVIDE */ int (* kd_divide[SQL_NUMBER]) ( char * buffer_in_data , int buffer_in_size , char ** buffer_out_data, int * buffer_out_size, int ** offsets_buffer , int * offsets_size ) = { UNDEFINED, &matrix_divide }; /* Fonctions MERGE */ int (* kd_merge[SQL_NUMBER]) ( char * buffer_slave_recv_data, int buffer_slave_recv_size, char ** buffer_out_data , int * buffer_out_size ) = { &matrix_merge_outter, &matrix_merge_inner };

/* DESCRIPTEUR DE LA STRUCTURE DE L’APPLICATION */ Jump kd_jump[SQL_NUMBER] =

{

{END_OF_APP, MASTER, 1 }, {NO_TARGET , SLAVE , UNDEFINED } };

D.3 Fonctions de calcul de l’utilisateur, et code de liaison

#define MATRIX_SIZE 25

#define MATRIX_A_ROW_SIZE MATRIX_SIZE #define MATRIX_A_COLUMN_SIZE MATRIX_SIZE

#define MATRIX_B_ROW_SIZE MATRIX_A_COLUMN_SIZE #define MATRIX_B_COLUMN_SIZE MATRIX_SIZE

#define ALI_SIZE 50

char matrix_a[MATRIX_A_ROW_SIZE][MATRIX_A_COLUMN_SIZE][ALI_SIZE]; char matrix_b[MATRIX_B_ROW_SIZE][MATRIX_B_COLUMN_SIZE][ALI_SIZE]; char matrix_r[MATRIX_A_ROW_SIZE][MATRIX_B_COLUMN_SIZE][ALI_SIZE]; char ali[ALI_SIZE];

/* FONCTIONS DE CALCUL DE L’UTILISATEUR */ int addc( char pos, char carry, char * result ) {

int d; char rt;

for( d=pos; d<ALI_SIZE; d++ ) { rt = result[d]; result[d] = (rt+carry) % 10; carry = (rt+carry) / 10; } }

int add( char carry, char * ali1, char * ali2, char * result ) {

int d, a;

memcpy( result, ali1, ALI_SIZE ); addc( 0, carry, result );

for( d=0; d<ALI_SIZE; d++ ) {

addc( d, ali2[d], result ); }

}

int multd( char digit, char * ali, char * result ) { int a, d, r; char carry = 0; for( d=0; d<ALI_SIZE; d++ ) { r = digit*ali[d]; result[d] = (r+carry) % 10; carry = (r+carry) / 10; } }

int mult( char * ali1, char * ali2, char * result ) {

int a, d;

char local_ali1[ALI_SIZE], local_ali2[ALI_SIZE*2]; char * buffer1;

for( a=0; a<ALI_SIZE; a++) {

local_ali2[a] = 0; }

buffer1 = local_ali2+ALI_SIZE; memcpy( buffer1, ali2, ALI_SIZE); for( d=0; d<ALI_SIZE; d++ ) {

multd( ali1[d], buffer1, local_ali1 ); add( 0, result , local_ali1, result ); buffer1--;

} }

int innerprod( char vect1[MATRIX_A_COLUMN_SIZE][ALI_SIZE], char vect2[MATRIX_A_COLUMN_SIZE][ALI_SIZE], char * result ) { int v, a; char local_ali[ALI_SIZE]; for( v=0; v<MATRIX_A_COLUMN_SIZE; v++ ) {

for( a=0; a<ALI_SIZE; a++) {

local_ali[a] = 0; }

mult( vect1[v], vect2[v], local_ali ); add( 0, result, local_ali, result ); }

/* FONCTIONS D’INTERFACE AVEC LES FONCTIONS DE CALCUL */

/* Fonction initiale, permettant par exemple l’acquisition des donnees */ int app_begin( char ** buffer_out_data, int * buffer_out_size )

{ int data_size; int r1, c2, v, a; char * buffer; data_size = MATRIX_A_ROW_SIZE*MATRIX_B_COLUMN_SIZE * ((MATRIX_A_COLUMN_SIZE+MATRIX_B_ROW_SIZE)*ALI_SIZE+2); *buffer_out_size = data_size;

*buffer_out_data = (char *) malloc( *buffer_out_size ); buffer = *buffer_out_data;

for( r1=0; r1<MATRIX_A_ROW_SIZE; r1++ ) {

for( c2=0; c2<MATRIX_B_COLUMN_SIZE; c2++ ) {

*buffer = (char) r1; buffer++; *buffer = (char) c2; buffer++;

for( v=0; v<MATRIX_A_COLUMN_SIZE; v++ ) {

for( a=0; a<ALI_SIZE/2; a++ ) buffer[v*ALI_SIZE+a] = rand() % 10; for( a=ALI_SIZE/2; a<ALI_SIZE; a++ ) buffer[v*ALI_SIZE+a] = 0;

}

buffer += MATRIX_A_COLUMN_SIZE*ALI_SIZE; for( v=0; v<MATRIX_B_ROW_SIZE; v++ ) {

for( a=0; a<ALI_SIZE/2; a++ ) buffer[v*ALI_SIZE+a] = rand() % 10; for( a=ALI_SIZE/2; a<ALI_SIZE; a++ ) buffer[v*ALI_SIZE+a] = 0;

} buffer += MATRIX_A_COLUMN_SIZE*ALI_SIZE; } } puts("BEGIN"); fflush( stdout ); return NO_ERROR; }

/* Fonction terminale de l’application, permettant la restitution des resultats */ int app_end( char * buffer_in_data, int buffer_in_size )

{ int r, c, a; for( r=0; r<MATRIX_A_ROW_SIZE; r++ ) { for( c=0; c<MATRIX_B_COLUMN_SIZE; c++ ) {

for( a=0; a<ALI_SIZE; a++ ) {

printf( "%u", matrix_r[r][c][a] ); } printf( " " ); } printf( "\n" ); } puts("END"); fflush( stdout ); return NO_ERROR; }

int matrix_split_outter( char * buffer_in_data, int buffer_in_size, int ** offsets_buffer, int * offsets_size ) { int i; *offsets_size = MATRIX_A_ROW_SIZE +1; *offsets_buffer

= (int *) malloc( *offsets_size *sizeof( int ) ); for( i=0; i<*offsets_size; i++ )

{

(*offsets_buffer)[i] = i*(MATRIX_A_COLUMN_SIZE*2*ALI_SIZE +2)*MATRIX_B_COLUMN_SIZE; }

return NO_ERROR; }

int matrix_merge_outter( char * buffer_in_data, int buffer_in_size, char ** buffer_out_data, int * buffer_out_size ) {

static int call = 0; char * buffer;

*buffer_out_size += MATRIX_B_COLUMN_SIZE*(ALI_SIZE+2); *buffer_out_data

= (char *) realloc( *buffer_out_data,

*buffer_out_size *sizeof( char ) );

for( buffer=buffer_in_data; buffer<buffer_in_data+buffer_in_size; buffer+=ALI_SIZE+2 ) {

memcpy( &(matrix_r[*buffer][*(buffer+1)]), buffer+2, ALI_SIZE ); }

call++;

return NO_ERROR; }

int matrix_compute_inner( char * buffer_in_data, int buffer_in_size, char ** buffer_out_data, int * buffer_out_size ) { int c; char (*vect1)[MATRIX_A_COLUMN_SIZE][ALI_SIZE]; char (*vect2)[MATRIX_A_COLUMN_SIZE][ALI_SIZE]; *buffer_out_size = ALI_SIZE+2;

*buffer_out_data = (char *) malloc( *buffer_out_size ); (*buffer_out_data)[0] = *buffer_in_data;

(*buffer_out_data)[1] = *(buffer_in_data+1);

for( c=2; c<*buffer_out_size; c++ ) (*buffer_out_data)[c] = 0; vect1 = buffer_in_data+2;

vect2 = buffer_in_data+2+(MATRIX_A_COLUMN_SIZE*ALI_SIZE); /* Appel effectif de la fonction de calcul de l’utilisateur */ innerprod( *vect1, *vect2, (*buffer_out_data)+2 );

return NO_ERROR; }

int matrix_split_inner( char * buffer_in_data, int buffer_in_size, int ** offsets_buffer, int * offsets_size ) { int i; *offsets_size = MATRIX_B_COLUMN_SIZE +1; *offsets_buffer

= (int *) malloc( *offsets_size *sizeof( int ) ); for( i=0; i<*offsets_size; i++ )

{

(*offsets_buffer)[i] = i*(MATRIX_A_COLUMN_SIZE*2*ALI_SIZE +2); }

return NO_ERROR; }

int matrix_merge_inner( char * buffer_in_data, int buffer_in_size, char ** buffer_out_data, int * buffer_out_size ) {

static int call = 0;

if (!call) {

*buffer_out_size = buffer_in_size*MATRIX_B_COLUMN_SIZE;

*buffer_out_data = (char *) malloc( *buffer_out_size *sizeof( char ) ); }

memcpy( (*buffer_out_data)+(buffer_in_size*call), buffer_in_data, buffer_in_size ); call++;

return NO_ERROR; }

int matrix_predicate( char * buffer_in_data, int buffer_in_size, int * solve ) {

/* Donnees pretes a etre traitees */ *solve = YES_;

return NO_ERROR; }

int matrix_divide( char * buffer_in_data, int buffer_in_size, char ** buffer_out_data, int * buffer_out_size, int ** offsets_buffer, int * offsets_size ) { /* Sans objet */ return NO_ERROR; }

Annexe E