如何通过 MPI 加速这个问题

Posted

技术标签:

【中文标题】如何通过 MPI 加速这个问题【英文标题】:How to speed up this problem by MPI 【发布时间】:2011-01-10 12:47:29 【问题描述】:

(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。 它们的用法一样吗?特别是在我的情况下。 哪一个最适合我使用?

感谢和问候!


更新:

我想多解释一下关于如何指定并行部分的开始和结束的问题。在下面的玩具代码中,我想限制函数 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()。

除了这个,我仍然希望有人能回答我的其他问题。谢谢!

【问题讨论】:

我看不出这与您之前的问题有任何实际区别:***.com/questions/2152422/from-openmp-to-mpi/…。您可以像我在回答中向您展示的那样拆分数组。并行部分以 MPI_Init 开始,以 MPI_Finilize 结束,因此您可以在这些调用之前和/或之后进行任何串行计算。 谢谢你,3lectrologos!我刚刚对我的问题添加了一些更新,以表明并行部分以 MPI_Init 开头并以 MPI_Finilize 结尾似乎不正确。 【参考方案1】:

快速编辑(因为我不知道如何离开 cmets,或者我还不允许离开 cmets)—— 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】:

MPI_Init(参数为 &argc 和 &argv。这是 MPI 实现的要求)必须是 MAIN 的第一个执行语句。而且 Finalize 必须是最后执行的语句。

main() 将在 MPI 环境中的每个节点上启动。节点数、node_id、主节点地址等参数可以通过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;  
  

【讨论】:

【参考方案3】:

如果数组中的所有值都是独立的,那么它应该是可并行化的。将数组拆分为大小大致相等的块,将每个块分配给一个节点,然后将结果重新编译在一起。

【讨论】:

谢谢凯尔!你能为我的案例提供示例代码吗?我想在使用 MPI 的并行部分之前和之后做一些操作,特别是在数组上,但我不知道如何指定并行部分的开始和结束位置。我还为我的问题添加了更多内容。【参考方案4】:

从 OpenMP 迁移到集群的最简单方法是英特尔的“Cluster OpenMP”。

对于 MPI,您需要完全重写工作调度。

【讨论】:

以上是关于如何通过 MPI 加速这个问题的主要内容,如果未能解决你的问题,请参考以下文章

新技能:通过代码缓存加速 Node.js 的启动

使用 MPI for Python 并行化遗传算法

线性方程组的求解方法的选择和加速

线性方程组的求解方法的选择和加速

记录加速度计数据并分享

使用 C++ 加速 Python