#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <pthread.h>
#include <sys/time.h>
char* help = "\n\
** Matrix_Mult_Pthread.c ** \n\
Inmultirea matricelor in Pthread \n\
\n\
Se compileaza: \n\
gcc Matrix_Mult_Pthread.c -o Matrix_Mult_Pthread -lpthread -lm \n\
\n\
Se lanseaza cu parametrii n, p, mod, max_rep \n\
Implicit n = 1024, p = 1, mod = 0, max_rep = 1 \n\
Pentru inmulțirea cu partitionare in blocuri p trebuie sa fie patrat perfect si n divizibil cu sqrt(p) \n\
\n\
./Matrix_Mult_Pthread 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 dupa 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 in blocuri cu 1 regiune paralela, p patrat perfect, n divizibil cu sqrt(p) \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_Pthread.txt \n";
void *Matrix_Mult_line(void *);
int n = 1024; // Dimensiune matrice
int p = 2; // Numar thread-uri
int mod = 0; // Mod 0: partitionare pe linii
int max_rep = 1; // Numar de repetari ale executiei
float **a, *b, *c; // Matricele partajate
typedef struct _group{ // Structura pentru parametrii functiei thread in part cu n reg. paralele (coloane sau blocuri)
int line; // linii
int col; // coloane
} group;
group *groups; // Variabila partajata - parametri thread-uri in partit cu n regiuni paralele sau al doilea nivel
pthread_t *ids2; // Variabila partajata - identificatori thread-uri al doilea nivel de partitionare
int main(int argc, char *argv[]){ // Thread-ul principal Thm
int i, j, k, q, rep;
char* text_mod;
int* params; // Parametri thread-uri in partit cu 1 regiune paralela sau primul nivel part
pthread_t *ids; // Identificatori thread-uri primul nivel de partitionare
struct timeval t1, t2;
float tp;
char *fn = "Res_Matrix_Mult_Pthread.txt";
FILE *fp;
// Citire parametri
if (argc >= 2 && strcmp(argv[1],"-help") == 0) {
printf("%s\n",help);
exit(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);
}
}
// Alocarea datelor
a = (float**)malloc(sizeof(float*)*n);
b = (float*)malloc(sizeof(float)*n);
c = (float*)malloc(sizeof(float)*n);
for (i = 0; i < n; i++){
a[i] = (float*)malloc(sizeof(float)*n);
}
params = (int*)malloc(sizeof(int)*p);
groups = (group*)malloc(sizeof(group)*p);
ids = (pthread_t*)malloc(sizeof(pthread_t)*p);
// Initializarea matricelor de intrare a, b
for (i = 0; i < n; i++){
b[i] = 1;
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] * b[j];
}
}
}
// Imnultirea paralela a doua matrice
else if (mod == 0) {
text_mod = "mod 0: Inmultire paralela cu partitionare pe linii cu 1 regiune paralela";
for (q = 0; q < p; q++) {
params[q] = q;
pthread_create(&ids[q],0,Matrix_Mult_line,(void*)¶ms[q]);
}
for (q = 0; q < p; q++)
pthread_join (ids[q],0);
}
else {
printf("Eroare: mod %d - inexistent\n", mod);
exit (0);
}
} // end for (rep)
gettimeofday(&t2, NULL);
tp = (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++){
printf("%4.0f ", c[i]);
}
printf("\n");
}
return 0;
}
//
// Functii thread
//
// Mod 0 - Inmultire paralela cu partitionare pe linii
void *Matrix_Mult_line(void *param) {
int i, j, k, first, last;
int q = *(int*)param;
int s = (int) n/p;
int kp = n%p;
if (kp == 0) { // n divizibil cu p
first = q*s;
last = first + s;
}
else if (q < kp) { // primele kp partitii au dimensiunea s+1
first = q*(s+1);
last = first + s+1;
}
else { // ultimele (p-kp) partitii au dimensiunea s
first = q*s + kp;
last = first + s;
}
for (i=first; i<last; i++){
c[i] = 0;
for (j = 0; j<n; j++){
c[i] += a[i][j] * b[j];
}
}
return 0;
}