#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/time.h>
char* help = "\n\
** Reduction_Pthread.c ** \n\
Adunarea vectorilor in Pthread \n\
\n\
Se compileaza: \n\
gcc Reduction_Pthread.c -o Reduction_Pthread -lpthread \n\
\n\
Se lanseaza cu parametrii n, p, max_rep (implicit n = 1024, p = 1, max_rep = 1) \n\
\n\
./Reduction_Pthread n p max_rep \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_Reduction_Pthread.txt \n";
int n = 1024; // Variabila partajata dimensiune matrice
int p = 1; // Variabila partajata numar thread-uri
float *a, *b; // Vectorul partajat
double sum;
pthread_mutex_t mutex;
void * Reduction(void *param);
int main(int argc, char *argv[]){
int i, q, rep;
int max_rep = 1; // Numar maxim de repetari ale executiei
int* params; // Parametri thread-uri
pthread_t *ids; // Identificatori thread-uri
struct timeval t1, t2;
float tp;
char *fn = "Res_Reduction_Pthread.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) max_rep = atoi(argv[3]);
// 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);
}
// Alocarea datelor
a = (float*)malloc(sizeof(float)*n);
b= (float*)malloc(sizeof(float)*n);
params = (int*)malloc(sizeof(int)*p);
ids = (pthread_t*)malloc(sizeof(pthread_t)*p);
pthread_mutex_init(&mutex,0); // Initializare mutex
// Initializarea vectorului de intrare
if (n <= 16)
for (i = 0; i < n; i++) {
a[i] = 1;
b[i]=1;
}
else
for (i = 0; i < n; i++) a[i] = rand()/(float)RAND_MAX;
gettimeofday(&t1, NULL);
for (rep = 0; rep < max_rep; rep++)
{
sum = 0.0;
if (p == 1) {
// Reducerea secventiala
for (i = 0; i < n; i++)
sum += a[i]*b[i];
}
else {
// Reducerea paralela
for (q = 0; q < p; q++) { // creare thread-uri de lucru
params[q] = q;
pthread_create(&ids[q],0,Reduction,(void*)¶ms[q]);
}
for (q = 0; q < p; q++)
pthread_join (ids[q],0);
}
} // end for (rep)
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
printf("%d rep, sum = %f, n = %d, p = %d, t = %f sec\n", max_rep, sum, n, p, tp);
return 0;
}
//
// Functie thread
//
void *Reduction (void *param) {
double psum = 0;
int i, first, last;
int q = *(int*)param;
int s = (int) n/p;
int k = n%p;
if (k == 0) { // n divizibil cu p
first = q*s;
last = first + s;
}
else if (q < k) { // primele k partitii au dimensiunea s+1
first = q*(s+1);
last = first + s+1;
}
else { // ultimele (p-k) partitii au dimensiunea s
first = q*s + k;
last = first + s;
}
// Etapa 1 - reducerea partiala (in partitie)
for(i = first; i < last; i++)
psum += a[i]*b[i];
// Etapa 2: - reducere globala folosind un mutex
pthread_mutex_lock(&mutex);
sum += psum;
pthread_mutex_unlock(&mutex);
return 0;
}