2012-11-24 12 views
6

Sto provando a creare una versione parallela del problema "Somma progressione armonica" usando MPI e opemMP insieme. Ma l'output è diverso l'un l'altro processo.Sommario della progressione armonica C++ MPI e OpenMP

Qualcuno potrebbe aiutarmi a finire questo problema?

programma parallelo: (MPI e OpenMP)

#include <stdio.h> 
#include <stdlib.h> 
#include <iostream> 
#include <sstream> 
#include <time.h> 
#include <omp.h> 
#include <mpi.h> 

#define d 10 //Numbers of Digits (Example: 5 => 0,xxxxx) 
#define n 1000 //Value of N (Example: 5 => 1/1 + 1/2 + 1/3 + 1/4 + 1/5) 

using namespace std; 

double t_ini, t_fim, t_tot; 

int getProcessId(){ 
    int rank; 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
    return rank; 
} 

int numberProcess(){ 
    int numProc; 
    MPI_Comm_size(MPI_COMM_WORLD, &numProc); 
    return numProc; 
} 

void reduce(long unsigned int digits1 []) 
{ 
    long unsigned int digits2[d + 11]; 
    int i = 0; 
    for(i = 0; i < d + 11; i++) digits2[i] = 0; 

    MPI_Allreduce(digits1, digits2,(d+11),MPI_INT,MPI_SUM,MPI_COMM_WORLD); 

    for(i = 0; i < d + 11; i++) digits1[i] = digits2[i]; 

} 

void slave(long unsigned int *digits) 
{ 
    int idP = getProcessId(), numP = numberProcess(); 

    int i; 
    long unsigned int digit; 
    long unsigned int remainder; 

    #pragma omp parallel for private(i, remainder, digit) 
    for (i = idP+1; i <= n; i+=numP){ 
     remainder = 1; 
     for (digit = 0; digit < d + 11 && remainder; ++digit) { 
      long unsigned int div = remainder/i; 
      long unsigned int mod = remainder % i; 
      #pragma omp atomic 
      digits[digit] += div; 
      remainder = mod * 10; 
     } 
    } 
} 

void HPS(char* output) { 
    long unsigned int digits[d + 11]; 

    for (int digit = 0; digit < d + 11; ++digit) 
     digits[digit] = 0; 

    reduce(digits); 
    slave(digits); 

    for (int i = d + 11 - 1; i > 0; --i) { 
     digits[i - 1] += digits[i]/10; 
     digits[i] %= 10; 
    } 

    if (digits[d + 1] >= 5) ++digits[d]; 


    for (int i = d; i > 0; --i) { 
     digits[i - 1] += digits[i]/10; 
     digits[i] %= 10; 
    } 
    stringstream stringstreamA; 
    stringstreamA << digits[0] << ","; 


    for (int i = 1; i <= d; ++i) stringstreamA << digits[i]; 

    string stringA = stringstreamA.str(); 
    stringA.copy(output, stringA.size()); 
} 

int main(int argc, char **argv) { 
    MPI_Init(&argc,&argv); 

    t_ini = clock(); 

    //Parallel MPI com OpenMP Method 
    cout << "Parallel MPI com OpenMP Method: " << endl; 
    char output[d + 10]; 
    HPS(output); 

    t_fim = clock(); 
    t_tot = t_fim-t_ini; 

    cout << "Parallel MPI with OpenMP Method: " << (t_tot/1000) << endl; 
    cout << output << endl; 

    MPI_Finalize(); 

    system("PAUSE"); 
    return 0; 
} 

Esempi:

ingresso:

#define d 10 
#define n 1000 

uscita:

7,4854708606 

ingresso:

#define d 12 
#define n 7 

uscita:

2,592857142857 

risposta

4

Hai un errore che re:

void HPS(char* output) { 
    ... 
    reduce(digits); 
    slave(digits); 

    ... 
} 

Si dovrebbe prima calcolare e non eseguire la riduzione non il contrario. Passa a:

void HPS(char* output) { 
    ... 

    slave(digits); 
    reduce(digits); 
    ... 
} 

Dal momento che si desidera utilizzare MPI + OpenMP, si può anche lasciare questo:

for (i = idP+1; i <= n; i+=numP) 

di essere divario tra i processi. E il divario ciclo all'interno tra i fili:

#pragma omp parallel for private(remainder) 
for (digit = 0; digit < d + 11 && remainder; ++digit) 

avendo così qualcosa di simile:

for (i = idP+1; i <= n; i+=numP){ 
     remainder = 1; 
     #pragma omp parallel for private(i, remainder, digit) 
     for (digit = 0; digit < d + 11 && remainder; ++digit) { 
      long unsigned int div = remainder/i; 
      long unsigned int mod = remainder % i; 
      #pragma omp atomic 
      digits[digit] += div; 
      remainder = mod * 10; 
     } 
    } 

È anche possibile, se si preferisce (è simile a quello che hai fatto), dividere il numero di lavoro del ciclo esterno attraverso tutta l'operazione parallela (thread/processo), in questo modo:

int idT = omp_get_thread_num();  // Get the thread id 
int numT = omp_get_num_threads(); // Get the number of threads. 
int numParallelTask = numT * numP; // Number of parallel task 
int start = (idP+1) + (idT*numParallelTask); // The first position here each thread will work 

#pragma omp parallel 
{ 

for (i = start; i <= n; i+=numParallelTask) 

... 
} 

si noti che non sto dicendo questo vi darà le migliori prestazioni, ma è un inizio. Dopo aver ottenuto il corretto funzionamento dell'algoritmo in MPI + OpenMP, è possibile procedere con approcci più sofisticati.