#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <string.h>
#include <math.h>
#include <mpi.h>
char* help = "\n\
** Matrix_Mult_MPI.c ** \n\
Algoritm MPI de inmultire a doua matrice \n\
\n\
Se compileaza: \n\
mpicc Matrix_Mult_MPI.c -o Matrix_Mult_MPI \n\
\n\
Se lanseaza cu parametrii n, p max_rep (n divizibil cu p) \n\
Implicit n = 1024, p = 1, max_rep = 1 \n\
mpirun -np p Matrix_Mult_MPI n max_rep \n\
\n\
Executie in mai multe noduri specificate in fisierul hosts:\n\
mpirun -hostfile hosts -np p Matrix_Mult_MPI n \n\
\n\
Fisierul hosts contine numele nodurilor (hostname) si numarul de procesoare (slots): \n\
hpc slots=1 \n\
compute-0-1 slots=1 \n\
compute-0-2 slots=1 \n\
compute-0-3 slots=1 \n";
int main(int argc, char *argv[]) {
int n = 1024; // Dim matrice
int p = 1; // Nr procese MPI
int max_rep = 1; // Numar de repetari executie
int root = 0;
int rank; // rangul procesului (q)
int i, j, k, s, rep;
struct timeval t1, t2;
float tp;
FILE * fp;
char* fn = "Res_Matrix_Mult_MPI.txt";
// Citire parametri
if (argc >= 2 && strcmp(argv[1],"-help") == 0) {
printf("%s\n",help);
return 0;
}
if (argc >= 2) n = atoi(argv[1]);
if (argc >= 3) max_rep = atoi(argv[2]);
// Testare parametri
if (n < 2){
printf("Eroare: n < 2 \n");
exit(0);
}
if (max_rep < 1){
printf("Eroare: max_rep < 1 \n");
MPI_Finalize();
exit(0);
}
//
MPI_Init (&argc,&argv);
MPI_Comm_rank (MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &p);
// Test n divizibil cu p
if ( n % p != 0) {
if (rank == root) printf("Eroare: n = %d nu este divizibil cu p = % d\n",n, p);
MPI_Finalize();
exit(0);
}
s = n / p;
// Alocarea matricelor
float **a = (float**)malloc(sizeof(float*)*n);
float *c = (float*)malloc(sizeof(float*)*n);
float *ma = (float*)malloc(sizeof(float)*n*n);
for (i = 0; i < n; i++){
a[i] = ma; ma += n;
}
// Initializare matrice a, b
if (rank == root){
for (i = 0; i < n; i++)
for (j = 0; j < n; j++) {
a[i][j] = 1;
}
gettimeofday(&t1, NULL);
}
for (rep = 0; rep < max_rep; rep++){
//
// Inmultire secventiala daca p = 1
//
if (p == 1){
for (i = 0; i < n; i++) {
c[i] = 0;
for (j = 0; j < n; j++){
c[i] += a[i][j] ;
}
}
}
//
// Inmultire paralela (p > 1)
else {
// Transmitere matrice a, b
if (rank == root && root == 0)
MPI_Scatter(a[0], s*n, MPI_FLOAT, MPI_IN_PLACE, s*n, MPI_FLOAT, root, MPI_COMM_WORLD);
else MPI_Scatter(a[0], s*n, MPI_FLOAT, a[0], s*n, MPI_FLOAT, root, MPI_COMM_WORLD);
// Inmultire submatrice de s linii in fiecare proces
for (i = 0; i < s; i++) {
c[i] = 0;
for (j = 0; j < n; j++){
c[i] += a[i][j] ;
}
// Colectare rezultate
if (rank == root && root == 0)
MPI_Gather(MPI_IN_PLACE, s, MPI_FLOAT, c, s, MPI_FLOAT, root, MPI_COMM_WORLD);
else MPI_Gather(c, s, MPI_FLOAT, c, s, MPI_FLOAT, root, MPI_COMM_WORLD);
} // end else
} // end rep
// Scriere si afisare rezultate
if (rank == root) {
gettimeofday(&t2, NULL);
tp = ((float)(t2.tv_sec - t1.tv_sec) + 0.000001*(t2.tv_usec - t1.tv_usec))/max_rep;
fp = fopen(fn, "a");
if (p == 1) fprintf(fp, "\n%f ",tp);
else fprintf(fp, "%f ",tp);
fclose(fp);
printf("%d rep, n = %d, p = %d, t = %f sec\n", max_rep, n, p, tp);
if (n <= 16)
{
for (i = 0; i < n; i++) {
printf("%4.0f ", c[i]);
}
}
}
MPI_Finalize();
return 0;
}
}