Как ускорить эту проблему с помощью MPI - PullRequest
3 голосов
/ 28 января 2010

(1). Мне интересно, как я могу ускорить трудоемкие вычисления в цикле моего кода ниже, используя MPI?

 int main(int argc, char ** argv)   
 {   
 // some operations           
 f(size);           
 // some operations         
 return 0;   
 }   

 void f(int size)   
 {   
 // some operations          
 int i;           
 double * array =  new double [size];           
 for (i = 0; i < size; i++) // how can I use MPI to speed up this loop to compute all elements in the array?   
 {   
 array[i] = complicated_computation(); // time comsuming computation   
 }           
 // some operations using all elements in array           
 delete [] array;  
 }

Как показано в коде, я хочу выполнить некоторые операции до и после параллельной части с MPI, но я не знаю, как указать, где начинается и заканчивается параллельная часть.

(2) Мой текущий код использует OpenMP для ускорения вычислений.

 void f(int size)   
 {   
 // some operations           
 int i;           
 double * array =  new double [size];   
 omp_set_num_threads(_nb_threads);  
 #pragma omp parallel shared(array) private(i)  
 {
 #pragma omp for schedule(dynamic) nowait          
 for (i = 0; i < size; i++) // how can I use MPI to speed up this loop to compute all elements in the array?   
 {   
 array[i] = complicated_computation(); // time comsuming computation   
 }          
 } 
 // some operations using all elements in array           
 }

Интересно, если я перейду на использование MPI, возможно ли иметь код, написанный как для OpenMP, так и для MPI? Если это возможно, как написать код и как скомпилировать и запустить код?

(3) Наш кластер имеет три версии MPI: mvapich-1.0.1, mvapich2-1.0.3, openmpi-1.2.6. Их использование одинаково? Особенно в моем случае. Какой из них лучше для меня использовать?

Спасибо и всего наилучшего!


UPDATE:

Я хотел бы немного подробнее рассказать о своем вопросе о том, как указать начало и конец параллельной части. В следующем игрушечном коде я хочу ограничить параллельную часть внутри функции f ():

#include "mpi.h"  
#include <stdio.h>  
#include <string.h>  

void f();

int main(int argc, char **argv)  
{  
printf("%s\n", "Start running!");  
f();  
printf("%s\n", "End running!");  
return 0;  
}  


void f()  
{  
char idstr[32]; char buff[128];  
int numprocs; int myid; int i;  
MPI_Status stat;  

printf("Entering function f().\n");

MPI_Init(NULL, NULL);  
MPI_Comm_size(MPI_COMM_WORLD,&numprocs);  
MPI_Comm_rank(MPI_COMM_WORLD,&myid);  

if(myid == 0)  
{  
  printf("WE have %d processors\n", numprocs);  
  for(i=1;i<numprocs;i++)  
  {  
    sprintf(buff, "Hello %d", i);  
    MPI_Send(buff, 128, MPI_CHAR, i, 0, MPI_COMM_WORLD); }  
    for(i=1;i<numprocs;i++)  
    {  
      MPI_Recv(buff, 128, MPI_CHAR, i, 0, MPI_COMM_WORLD, &stat);  
      printf("%s\n", buff);  
    }  
}  
else  
{  
  MPI_Recv(buff, 128, MPI_CHAR, 0, 0, MPI_COMM_WORLD, &stat);  
  sprintf(idstr, " Processor %d ", myid);  
  strcat(buff, idstr);  
  strcat(buff, "reporting for duty\n");  
  MPI_Send(buff, 128, MPI_CHAR, 0, 0, MPI_COMM_WORLD);  
}  
MPI_Finalize();  

printf("Leaving function f().\n");  
}  

Однако текущий результат не ожидается. Части printf до и после параллельной части выполнялись каждым процессом, а не только основным процессом:

$ mpirun -np 3 ex2  
Start running!  
Entering function f().  
Start running!  
Entering function f().  
Start running!  
Entering function f().  
WE have 3 processors  
Hello 1 Processor 1 reporting for duty  

Hello 2 Processor 2 reporting for duty  

Leaving function f().  
End running!  
Leaving function f().  
End running!  
Leaving function f().  
End running!  

Так что мне кажется, что параллельная часть не ограничена между MPI_Init () и MPI_Finalize ().

Помимо этого, я все еще надеюсь, что кто-нибудь ответит на мои другие вопросы. Спасибо!

Ответы [ 4 ]

6 голосов
/ 18 февраля 2010

Быстрое редактирование (потому что я либо не могу понять, как оставлять комментарии, либо мне пока не разрешено оставлять комментарии) - 3lectrologos неверно относится к параллельной части программ MPI. Вы не можете выполнять последовательную работу до MPI_Init и после MPI_Finalize и ожидать, что он на самом деле будет последовательным - он все равно будет выполняться всеми потоками MPI.

Я думаю, что часть проблемы в том, что «параллельная часть» программы MPI - это вся программа . MPI начнет выполнять ту же программу (вашу основную функцию) на каждом узле, который вы укажете, примерно в одно и то же время. Вызов MPI_Init просто устанавливает определенные параметры для программы, чтобы она могла правильно использовать вызовы MPI.

Правильный «шаблон» (в псевдокоде) для того, что я думаю, вы хотите сделать:

int main(int argc, char *argv[]) {
    MPI_Init(&argc, &argv);  
    MPI_Comm_size(MPI_COMM_WORLD,&numprocs);  
    MPI_Comm_rank(MPI_COMM_WORLD,&myid);

    if (myid == 0) { // Do the serial part on a single MPI thread
        printf("Performing serial computation on cpu %d\n", myid);
        PreParallelWork();
    }

    ParallelWork();  // Every MPI thread will run the parallel work

    if (myid == 0) { // Do the final serial part on a single MPI thread
        printf("Performing the final serial computation on cpu %d\n", myid);
        PostParallelWork();
    }

    MPI_Finalize();  
    return 0;  
}  
2 голосов
/ 07 февраля 2010

MPI_Init (с аргументами & argc и & argv. Это требование реализаций MPI) должен быть действительно первым выполненным оператором MAIN. И Finalize должен быть последним выполненным оператором.

main () будет запускаться на каждом узле в среде MPI. Такие параметры, как количество узлов, идентификатор_узла и адрес главного узла, могут передаваться через argc и argv.

Это рамки:

#include "mpi.h"  
#include <stdio.h>  
#include <string.h>  

void f();

int numprocs; int myid; 

int main(int argc, char **argv)  
{  

MPI_Init(&argc, &argv);  
MPI_Comm_size(MPI_COMM_WORLD,&numprocs);  
MPI_Comm_rank(MPI_COMM_WORLD,&myid);  

if(myid == 0)  
{  /* main process. user interaction is ONLY HERE */

    printf("%s\n", "Start running!");  

    MPI_Send ... requests with job
    /*may be call f in main too*/
    MPU_Reqv ... results..
    printf("%s\n", "End running!");  
}
else
{

  /* Slaves. Do sit here and wait a job from main process */
  MPI_Recv(.input..);  
  /* dispatch input by parsing it 
    (if there can be different types of work)
    or just do the work */    
  f(..)
  MPI_Send(.results..);  
}

MPI_Finalize();  

return 0;  
}  
1 голос
/ 07 февраля 2010

Самым простым переходом к форме кластера OpenMP может быть «Cluster OpenMP» от intel.

Для MPI нужно полностью переписать диспетчеризацию работы.

1 голос
/ 28 января 2010

Если все значения в массиве независимы, то он должен быть тривиально распараллеливаемым. Разбейте массив на куски примерно одинакового размера, передайте каждый кусочек узлу, а затем скомпилируйте результаты обратно.

...