基于MPICH的并行程序设计
下面用一个简单的例子,给出在Linux平台上开发MPI并行程序的一个基本框架,以便对基于MPICH的并行程序有一个感性认识。基于MPICH的并行程序可以用C或者Fortran开发,此处给出的例子是用C语言编写的。
/*====================*
* mpi_hello.c - Demo program of MPICH. *
*====================*/
#include
#include “mpi.h”
int main(int argc, char **argv)
{
int myrank, nprocs, namelen;
char processor_name[MPI_MAX
_PROCESSOR_NAME];
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_
WORLD, &nprocs);
MPI_Comm_rank(MPI_COMM
_WORLD, &myrank);
MPI_Get_processor_name(processor_name, &namelen);
printf(“Hello World! I’m rank %d of %d on %s\n”, myrank,
nprocs, processor_name);
MPI_Finalize();
return 0;
}
为了保证编译的正确性,程序的首部必须包含MPI的头文件mpi.h。该文件给出了MPI所有调用接口的说明,并对所有用到的常量进行了定义。MPI_MAX_PROCESSOR_NAME就是该文件中定义的一个常量,是某一MPI具体实现(此处即为MPICH)中允许的主机名的最大长度。
在调用任何MPI函数之前,必须先调用MPI_Init()进行相应的初始化工作。当所有MPI函数调用都完成之后,还必须调用MPI_Finalize()进行相应的清理工作。命令行参数通过MPI_Init()函数传递给MPI,以便为各个并行执行的程序建立起正确的运行环境。
接下去的几个MPI函数用来获得并行计算环境的一些基本信息。上面的示例程序只是简单地输出了这些信息,但通常情况下这些信息将被用来进行问题的自动分解,或者用于建立各并行机间的通信。MPI_Comm_size()函数可以得到参与并行计算的进程个数;MPI_Comm_rank()函数可以得到当前正在运行的进程的标识;而MPI_Get_processor_name()函数则能够获得当前进程所在主机的名称。
基于MPI的并行程序可能有很多种编译方法,大多数MPI实现都提供了一个易于使用的脚本来完成编译,这些脚本能够为编译器设置合适的参数,帮助编译器找到MPI头文件所在的目录,并能够连接上所需的库文件,从而保证编译过程的正确性。MPICH和LAM都提供了一个名为mpicc的脚本来完成并行程序的编译。例如,要编译上述的示例程序,只需执行下面的命令即可:
$ mpicc -o mpi_hello mpi_hello.c
在并行环境中的多台计算机上同时执行该程序,要将编译好的程序复制到不同的机器上,并且可执行程序必须放 $ mpirun -np 6 mpi_hello
在MPICH中,mpirun是MPI程序的启动脚本,它简化了并行进程的启动过程,尽可能屏蔽了底层的实现细节,从而为用户提供了一个通用的MPI并行机。在用mpirun命令执行并行程序时,参数-np指明了需要并行运行的进程个数。mpirun首先在本地结点上启动一个进程,然后根据/usr/local/share/machines.LINUX文件中所列出的主机,为每个主机启动一个进程。若进程数比可用的并行节点数多,则多余的进程将重新按照上述规则进行 Hello World! I′m rank 0 of 6 on node1
Hello World! I′m rank 1 of 6 on node2
Hello World! I′m rank 5 of 6 on node3
Hello World! I′m rank 3 of 6 on node1
Hello World! I′m rank 2 of 6 on node2
Hello World! I′m rank 4 of 6 on node3
基于PVM的并行程序设计
在用PVM进行并行程序设计时,程序员首先要将被求解的问题分解成独立的程序,然后用C或者Fortran实现每个程序,最后再通过PVM提供的虚拟机在整个并行计算环境中运行。下面用一个简单的例子,给出在Linux平台上开发PVM并行程序的一个基本框架。
/*===================*
* pvm_hello.c - Demo
program of PVM.*
*==================*/
#include
#include “pvm3.h”
int main(int argc, char** argv)
{
int i, mytid, dtid, info, nhost, narch;
struct pvmhostinfo* hostp;
mytid = pvm_mytid();
dtid = pvm_tidtohost(mytid);
info = pvm_config(&nhost, &narch, &hostp);
for (i = 0; i < nhost && hostp[i].hi_tid != dtid; i++)
;
printf(“Hello World! My task id is t%x on %s with %d hosts.\n”,
mytid, hostp[i].hi_name, nhost);
pvm_exit();
return 0;
}
上述示例程序给出了启动和终止一个PVM程序的基本步骤:首先在程序首部包含PVM的头文件pvm.h。然后调用pvm_mytid()函数获得当前运行进程的任务标识符,调用pvm_tidtohost()函数获得与任务标识符对应的主机标识符。若想获得当前进程所在虚拟机的相关信息(如主机总数和平台种类等),则可以通过调用函数pvm_config()来实现。最后,当所有的PVM函数都执行完后,调用pvm_exit()函数来结束整个并行计算过程。
PVM没有提供一个单独的脚本来完成编译过程,要编译上述示例程序,需要手工执行以下命令:
$ gcc -o pvm_hello -I/usr/local/src/pvm3/include/ \
> -L/usr/local/src/pvm3/lib/LINUX/ pvm_hello.c -lpvm3
同MPICH一样,用PVM编写的程序要想能够在多台主机上并行运行,首先要将编译好的可执行文件复制到不同的机器上。PVM要求用户运行的可执行文件都应该位于Home目录下的pvm3/bin/LINUX下。例如,要想在node1上以gary账户启动上述示例程序,同时要求node2和node3能够并行执行该程序,则应先将可执行文件pvm_hello复制到node1、node2和node3机器上的/home/gary/pvm3/bin/LINUX目录下,然后在node1上执行如下命令:
$ cd ~/pvm3/bin/LINUX
$ pvm
pvm> add node2 node3
pvm> spawn -6 -> pvm_hello
pvm> halt
PVM专门提供了一个Shell来对并行执行的任务进行管理和调度。上述程序中add命令用来添加一个新的并行节点机;spawn命令用来启动一个并行程序,参数“-6”指明了并行执行的进程个数,参数“->”指示将输出信息显示在屏幕上;halt命令则用来终止整个并行计算虚拟机。
上述示例程序的一次执行结果如下所示:
[1:t40002] Hello World! My task id is t40002 on node1 with 3 hosts.
[1:t40002] EOF
[1:t40003] Hello World! My task id is t40003 on node1 with 3 hosts.
[1:t40003] EOF
[1:tc0002] Hello World! My task id is tc0002 on node3 with 3 hosts.
[1:t80001] Hello World! My task id is t80001 on node2 with 3 hosts.
[1:t80001] EOF
[1:tc0001] Hello World! My task id is tc0001 on node3 with 3 hosts.
[1:tc0001] EOF
[1:tc0002] EOF
[1:t80002] Hello World! My task id is t80002 on node2 with 3 hosts.
[1:t80002] EOF
[1] finished
并行计算使用多台计算机或者具有多个处理器的计算机来求解问题,从而为求解大规模复杂问题提供了可能。作为一个优秀的操作系统,Linux特别适合用来组建并行计算平台。
下面用一个简单的例子,给出在Linux平台上开发MPI并行程序的一个基本框架,以便对基于MPICH的并行程序有一个感性认识。基于MPICH的并行程序可以用C或者Fortran开发,此处给出的例子是用C语言编写的。
/*====================*
* mpi_hello.c - Demo program of MPICH. *
*====================*/
#include
#include “mpi.h”
int main(int argc, char **argv)
{
int myrank, nprocs, namelen;
char processor_name[MPI_MAX
_PROCESSOR_NAME];
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_
WORLD, &nprocs);
MPI_Comm_rank(MPI_COMM
_WORLD, &myrank);
MPI_Get_processor_name(processor_name, &namelen);
printf(“Hello World! I’m rank %d of %d on %s\n”, myrank,
nprocs, processor_name);
MPI_Finalize();
return 0;
}
为了保证编译的正确性,程序的首部必须包含MPI的头文件mpi.h。该文件给出了MPI所有调用接口的说明,并对所有用到的常量进行了定义。MPI_MAX_PROCESSOR_NAME就是该文件中定义的一个常量,是某一MPI具体实现(此处即为MPICH)中允许的主机名的最大长度。
在调用任何MPI函数之前,必须先调用MPI_Init()进行相应的初始化工作。当所有MPI函数调用都完成之后,还必须调用MPI_Finalize()进行相应的清理工作。命令行参数通过MPI_Init()函数传递给MPI,以便为各个并行执行的程序建立起正确的运行环境。
接下去的几个MPI函数用来获得并行计算环境的一些基本信息。上面的示例程序只是简单地输出了这些信息,但通常情况下这些信息将被用来进行问题的自动分解,或者用于建立各并行机间的通信。MPI_Comm_size()函数可以得到参与并行计算的进程个数;MPI_Comm_rank()函数可以得到当前正在运行的进程的标识;而MPI_Get_processor_name()函数则能够获得当前进程所在主机的名称。
基于MPI的并行程序可能有很多种编译方法,大多数MPI实现都提供了一个易于使用的脚本来完成编译,这些脚本能够为编译器设置合适的参数,帮助编译器找到MPI头文件所在的目录,并能够连接上所需的库文件,从而保证编译过程的正确性。MPICH和LAM都提供了一个名为mpicc的脚本来完成并行程序的编译。例如,要编译上述的示例程序,只需执行下面的命令即可:
$ mpicc -o mpi_hello mpi_hello.c
在并行环境中的多台计算机上同时执行该程序,要将编译好的程序复制到不同的机器上,并且可执行程序必须放 $ mpirun -np 6 mpi_hello
在MPICH中,mpirun是MPI程序的启动脚本,它简化了并行进程的启动过程,尽可能屏蔽了底层的实现细节,从而为用户提供了一个通用的MPI并行机。在用mpirun命令执行并行程序时,参数-np指明了需要并行运行的进程个数。mpirun首先在本地结点上启动一个进程,然后根据/usr/local/share/machines.LINUX文件中所列出的主机,为每个主机启动一个进程。若进程数比可用的并行节点数多,则多余的进程将重新按照上述规则进行 Hello World! I′m rank 0 of 6 on node1
Hello World! I′m rank 1 of 6 on node2
Hello World! I′m rank 5 of 6 on node3
Hello World! I′m rank 3 of 6 on node1
Hello World! I′m rank 2 of 6 on node2
Hello World! I′m rank 4 of 6 on node3
基于PVM的并行程序设计
在用PVM进行并行程序设计时,程序员首先要将被求解的问题分解成独立的程序,然后用C或者Fortran实现每个程序,最后再通过PVM提供的虚拟机在整个并行计算环境中运行。下面用一个简单的例子,给出在Linux平台上开发PVM并行程序的一个基本框架。
/*===================*
* pvm_hello.c - Demo
program of PVM.*
*==================*/
#include
#include “pvm3.h”
int main(int argc, char** argv)
{
int i, mytid, dtid, info, nhost, narch;
struct pvmhostinfo* hostp;
mytid = pvm_mytid();
dtid = pvm_tidtohost(mytid);
info = pvm_config(&nhost, &narch, &hostp);
for (i = 0; i < nhost && hostp[i].hi_tid != dtid; i++)
;
printf(“Hello World! My task id is t%x on %s with %d hosts.\n”,
mytid, hostp[i].hi_name, nhost);
pvm_exit();
return 0;
}
上述示例程序给出了启动和终止一个PVM程序的基本步骤:首先在程序首部包含PVM的头文件pvm.h。然后调用pvm_mytid()函数获得当前运行进程的任务标识符,调用pvm_tidtohost()函数获得与任务标识符对应的主机标识符。若想获得当前进程所在虚拟机的相关信息(如主机总数和平台种类等),则可以通过调用函数pvm_config()来实现。最后,当所有的PVM函数都执行完后,调用pvm_exit()函数来结束整个并行计算过程。
PVM没有提供一个单独的脚本来完成编译过程,要编译上述示例程序,需要手工执行以下命令:
$ gcc -o pvm_hello -I/usr/local/src/pvm3/include/ \
> -L/usr/local/src/pvm3/lib/LINUX/ pvm_hello.c -lpvm3
同MPICH一样,用PVM编写的程序要想能够在多台主机上并行运行,首先要将编译好的可执行文件复制到不同的机器上。PVM要求用户运行的可执行文件都应该位于Home目录下的pvm3/bin/LINUX下。例如,要想在node1上以gary账户启动上述示例程序,同时要求node2和node3能够并行执行该程序,则应先将可执行文件pvm_hello复制到node1、node2和node3机器上的/home/gary/pvm3/bin/LINUX目录下,然后在node1上执行如下命令:
$ cd ~/pvm3/bin/LINUX
$ pvm
pvm> add node2 node3
pvm> spawn -6 -> pvm_hello
pvm> halt
PVM专门提供了一个Shell来对并行执行的任务进行管理和调度。上述程序中add命令用来添加一个新的并行节点机;spawn命令用来启动一个并行程序,参数“-6”指明了并行执行的进程个数,参数“->”指示将输出信息显示在屏幕上;halt命令则用来终止整个并行计算虚拟机。
上述示例程序的一次执行结果如下所示:
[1:t40002] Hello World! My task id is t40002 on node1 with 3 hosts.
[1:t40002] EOF
[1:t40003] Hello World! My task id is t40003 on node1 with 3 hosts.
[1:t40003] EOF
[1:tc0002] Hello World! My task id is tc0002 on node3 with 3 hosts.
[1:t80001] Hello World! My task id is t80001 on node2 with 3 hosts.
[1:t80001] EOF
[1:tc0001] Hello World! My task id is tc0001 on node3 with 3 hosts.
[1:tc0001] EOF
[1:tc0002] EOF
[1:t80002] Hello World! My task id is t80002 on node2 with 3 hosts.
[1:t80002] EOF
[1] finished
并行计算使用多台计算机或者具有多个处理器的计算机来求解问题,从而为求解大规模复杂问题提供了可能。作为一个优秀的操作系统,Linux特别适合用来组建并行计算平台。