OpenMPI并行环境的模拟
OpenMPI是MPI的一个开源实现,MPI是Message Passing Interface(消息传递接口)的缩写,是一个得到广泛支持的并行标准库。本文讲述用几台虚拟机来搭建一个OpenMPI并行计算环境的过程。
测试环境
并行集群的结点数一般是2的n次方,这里先使用4台虚拟机来搭建(后期可以扩展),第一个结点兼做控制结点。系统均使用slackware64 14.0,软件都是完全安装,只启用ssh服务,保证一个纯粹的平台。
机器网络配置如下:
域名 | IP地址 |
---|---|
slk-op1.example.org | 192.168.176.81/24 |
slk-op2.example.org | 192.168.176.82/24 |
slk-op3.example.org | 192.168.176.83/24 |
slk-op4.example.org | 192.168.176.84/24 |
初始安装
集群规模很小,故暂不采用NFS等网络集中管理方案,下面这些操作在每台机器上都要做。
安装OpenMPI
这里使用SlackBuilds.org提供的脚本来编译OpenMPI,以生成二进制安装包,这样就只需在一台机器上编译,其他机器可以获得生成的安装包,直接安装。
解开脚本:
tar xzvf openmpi.tar.gz
将OpenMPI的源代码包放在脚本目录下,进行编译打包:
cd openmpi/ cp ~/downloads/openmpi-1.4.2.tar.bz2 . ./openmpi.SlackBuild
安装(生成的安装包在/tmp下):
cd /tmp installpkg openmpi-1.4.2-x86_64-1_SBo.tgz
其他机器获得openmpi-1.4.2-x86_64-1_SBo.tgz后,执行installpkg安装即可。
添加用户
我们新建一个普通账户openmpi,而不是直接用root:
useradd -m -s /bin/bash openmpi
配置域名解析
由于网络规模很小,故暂不采用集中的DNS域名解析机制,直接编辑/etc/hosts文件,添加其余所有节点的IP信息。
比如slk-op1的内容如下:
127.0.0.1 localhost 192.168.176.81 slk-op1.example.org slk-op1 192.168.176.82 slk-op2.example.org slk-op2 192.168.176.83 slk-op3.example.org slk-op3 192.168.176.84 slk-op4.example.org slk-op4
集群配置
接下来的操作只在控制结点,即slk-op1上进行。
ssh登录配置
配置ssh,让控制结点(slk-op1)能采用无密码的方式ssh登录到其他结点。
首先生成一对密钥:
ssh-keygen
接下来把密钥中的公钥附加到要登录节点的.ssh/authorized_keys文件里,通过ssh-copy-id命令完成:
ssh-copy-id slk-op2 ssh-copy-id slk-op3 ssh-copy-id slk-op4
进行一次登录测试,确保可以无交互的登录:
ssh slk-op2 ssh slk-op3 ssh slk-op4
hostfile配置文件
要在集群的多个结点上运行任务,需要一个包含各结点信息的配置文件,运行时通过命令行参数-hostfile指定。文件内容很简单,每个结点一行:
slk-op1 slk-op2 slk-op3 slk-op4
如果想让某个结点运行不止一个process,可用slots属性指定(缺省为1),如:
slk-op1 slots=1 slk-op2 slots=2 slk-op3 slots=3 slk-op4 slots=4
集群测试
初始测试
配置完毕,先运行hostname程序来验证集群是否能正常工作。hostname是一个显示或设置系统主机名的命令,根据执行结果可以判断程序是否真的在多个结点上运行:
openmpi@slk-op1:~$ mpirun -hostfile hostfile hostname slk-op1 slk-op3 slk-op3 slk-op3 slk-op2 slk-op2 slk-op4 slk-op4 slk-op4 slk-op4
接下来我们编译一个样例C代码hello_c.c(在OpenMPI源代码包的examples目录下):
mpicc hello_c.c -o hello_c
编译生成的目标程序必须存在于每个参与运算的结点上。由于没有使用NFS等集中的管理方案,需要手工拷贝到其余结点上:
scp hello_c slk-op2: scp hello_c slk-op3: scp hello_c slk-op4:
现在可以运行了:
openmpi@slk-op1:~$ mpirun -hostfile hostfile -np 8 hello_c Hello, world, I am 0 of 8 Hello, world, I am 5 of 8 Hello, world, I am 3 of 8 Hello, world, I am 4 of 8 Hello, world, I am 2 of 8 Hello, world, I am 1 of 8 Hello, world, I am 7 of 8 Hello, world, I am 6 of 8
Makefile
当程序越来越多时,每次都敲命令编译是很繁琐的事,可以用Make来管理。下面是一个Makefile样例:
MPICC := mpicc LDLIBS := TARGETS := hello_c all: $(TARGETS) hello_c: hello_c.o .PHONY: all clean %: %.o $(MPICC) -o $@ $^ $(LDLIBS) echo "cp $@ to slk-op2:"; \ scp $@ slk-op2:; \ echo "cp $@ to slk-op3:"; \ scp $@ slk-op3:; \ echo "cp $@ to slk-op4:"; \ scp $@ slk-op4: %.o: %.c $(MPICC) -Wall -g -c $< clean: rm -rf $(TARGETS) *.o
编译的同时也完成了复制程序到其他结点的工作。
当结点数增多时,可以用for循环代替目前的逐条拷贝的方法。当然,那时,也许应该考虑集中的网络管理方案了。