#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <string.h>
#include <math.h>
#include <omp.h>
char *help = "\n\
** Matrix_Mult_OpenMP.c ** \n\
Inmultirea matricelor in OpenMP \n\
\n\
Se compileaza: \n\
gcc Matrix_Mult_OpenMP.c -o Matrix_Mult_OpenMP -fopenmp -lgomp \n\
\n\
Se lanseaza cu parametrii n, p, mod, max_rep \n\
Implicit n = 1024, p = 1, mod = 0, max_rep = 1 \n\
\n\
./Matrix_Mult_OpenMP n p mod max_rep \n\
\n\
Parametrul mod este optional - implicit este 0: \n\
mod 0: Inmultire paralela cu partitionare pe linii \n\
mod 1: Inmultire paralela cu partitionare pe linii întretesute \n\
mod 2: Inmultire paralela cu partitionare pe coloane cu interschimb cu 1 regiune paralela \n\
mod 3: Inmultire paralela cu partitionare pe coloane cu n regiuni paralele \n\
mod 4: Inmultire paralela cu partitionare pe coloane cu 1 regiune paralela \n\
mod 5: Inmultire paralela cu partitionare pe blocuri cu 1 regiune paralela \n\
\n\
Se executa de max_rep ori si se mediaza timpul de executie dat in secunde \n\
care se afiseaza si se inscrie in fisierul Res_Matrix_Mult_OpenMP.txt \n";
int main(int argc, char *argv[])
{
int n = 1024; // Dimensiune matrice
int p = 1; // Numar thread-uri
int mod = 0; // Mod 0: partitionare pe linii
int max_rep = 1; // Numar de repetari ale executiei
float **a, *c; // Matricele de date
int i, j, k, t, f, d, rep;
char *text_mod;
struct timeval t1, t2;
float tp;
char *fn = "Res_Matrix_Mult_OpenMP.txt";
FILE *fp;
// 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)
p = atoi(argv[2]);
if (argc >= 4)
mod = atoi(argv[3]);
if (argc >= 5)
max_rep = atoi(argv[4]);
// Testare parametri
if (n < 2)
{
printf("Eroare: n < 2 \n");
exit(0);
}
if (p < 1)
{
printf("Eroare: p < 1 \n");
exit(0);
}
if (max_rep < 1)
{
printf("Eroare: max_rep < 1 \n");
exit(0);
}
// La partitionare in blocuri: p patrat perfect, n divizibil cu sqrt(p)
if (mod == 5)
{
if (sqrt(p) != (int)sqrt(p))
{
printf("Eroare: partitionare in blocuri (mod = %d) si p nu este patrat perfect\n", mod);
exit(0);
}
if (n % (int)sqrt(p) != 0)
{
printf("Eroare: partitionare in blocuri (mod = %d) si n nu este divizibil cu sqrt(p)\n", mod);
exit(0);
}
}
f = sqrt(p);
d = n / f;
// Alocarea datelor
a = (float **)malloc(sizeof(float *) * n);
c = (float *)malloc(sizeof(float) * n);
for (i = 0; i < n; i++)
{
a[i] = (float *)malloc(sizeof(float) * n);
}
// Initializare matrice a, b
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++)
{
if (p == 1)
{
// Inmultirea secventiala a doua matrice
text_mod = "Inmultire secventiala";
for (i = 0; i < n; i++)
{
c[i] = 0;
for (j = 0; j < n; j++)
c[i] += a[i][j];
}
}
// Inmultirea paralela a doua matrice
else if (mod == 0)
{
text_mod = "mod 0: Inmultire paralela cu partitionare pe linii cu 1 regiune paralela";
#pragma omp parallel num_threads(p) shared(a, c, n) private(i, j)
{
#pragma omp for
for (i = 0; i < n; i++)
{
c[i] = 0;
for (j = 0; j < n; j++)
c[i] += a[i][j];
}
}
}
}
gettimeofday(&t2, NULL);
tp = ((float)(t2.tv_sec - t1.tv_sec) + 0.000001 * (t2.tv_usec - t1.tv_usec)) / max_rep;
// Scriere timp de executie in fisier
fp = fopen(fn, "a");
if (p == 1)
fprintf(fp, "\n%f ", tp);
else
fprintf(fp, "%f ", tp);
fclose(fp);
// Afisare timp executie mediat pe max_rep teste repetate
printf("%s \n", text_mod);
printf("%d rep, n = %d, p = %d, t = %f sec\n", max_rep, n, p, tp);
// Afisare rezultate
if (n <= 16)
{
for (i = 0; i < n; i++)
{
for (j = 0; j < n; j++)
printf("%4.0f ", c[i]);
printf("\n");
}
}
return 0;
}