在大规模节点间的并行时,由于节点间通讯的量是成平方项增长的,所以带宽很快就会显得不够。所以一种思路增加程序效率线性的方法是用MPI/OPENMP混合编写并行部分。这一部分其实在了解了MPI和OPENMP以后相对容易解决点。大致思路是每个节点分配1-2个MPI进程后,每个MPI进程执行多个OPENMP线程。OPENMP部分由于不需要进程间通信,直接通过内存共享方式交换信息,不走网络带宽,所以可以显著减少程序所需通讯的信息。
Fortran:
Program hello
use mpi
use omp_lib
Implicit None
Integer :: myid,numprocs,rc,ierr
Integer :: i,j,k,tid
Call MPI_INIT(ierr)
Call MPI_COMM_RANK(MPI_COMM_WORLD,myid,ierr)
Call MPI_COMM_SIZE(MPI_COMM_WORLD,numprocs,ierr)
!$OMP Parallel private(tid)
tid=OMP_GET_THREAD_NUM()
write(*,*) 'hello from',tid,'of process',myid
!$OMP END PARALLEL
Call MPI_FINALIZE(rc)
Stop
End Program hello
C++:
# include <cstdlib>
# include <iostream>
# include <ctime>
# include "mpi.h"
# include "omp.h"
using namespace std;
int main ( int argc, char *argv[] );
//****************************************************************************80
int main ( int argc, char *argv[] )
{
int myid;
int nprocs;
int this_thread;
MPI::Init();
myid=MPI::COMM_WORLD.Get_rank();
nprocs=MPI::COMM_WORLD.Get_size();
#pragma omp parallel private(this_thread)
{
this_thread=omp_get_thread_num();
cout <<this_thread<<" thread from "<<myid<<" is ok\n";
}
MPI::Finalize();
return 0;
}
这里值得要注意的是,似乎直接用mpif90/mpicxx编译的库会报错,所以需要用
icc -openmp hello.cpp -o hello -DMPICH_IGNORE_CXX_SEEK -L/Path/to/mpi/lib/ -lmpi_mt -lmpiic -I/path/to/mpi/include
其中-DMPICH_IGNORE_CXX_SEEK为防止MPI2协议中一个重复定义问题所使用的选项,为了保证线程安全,必须使用mpi_mt库
对于intel的mpirun,必须在mpirun后加上-env I_MPI_PIN_DOMAIN omp使得每个mpi进程会启动openmp线程。
通过export OMP_NUM_THREADS来控制每个MPI产生多少线程。