利用MPI多节点分布式并行计算PI实验报告
环境配置:
一、配置步骤:
1. 环境配置
1.1 hosts配置
修改节点对应主机名
hostnamectl --static set-hostname
配置/etc/hosts文件,添加以下内容
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.8.5 node1
192.168.8.6 node2
192.168.8.7 node3
192.168.8.8 node4
1.2 配置SSH免密登陆
(在node1节点上执行)
ssh-keygen -t rsa
ssh-copy-id root@node1
ssh-copy-id root@node2
ssh-copy-id root@node3
ssh-copy-id root@ node4
验证各节点ssh是否能免密登陆
1.3 关闭SELINUX和防火墙
(所有节点执行)
sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config
systemctl stop firewalld
systemctl disable firewalld
systemctl status firewalld
reboot
1.4 配置时间同步
(所有节点执行)
yum -y install ntp ntpdate
cd /etc && mv ntp.conf ntp.conf.bak
(在node1节点执行)
vi /etc/ntp.conf添加以下内容:
restrict 127.0.0.1
restrict ::1
restrict 192.168.8.0 mask 255.255.255.0
server 127.127.1.0
fudge 127.127.1.0 stratum 8
重启ntp服务
systemctl start ntpd
systemctl enable ntpd
(其余节点执行)
vi /etc/ntp.conf添加以下内容:
server 192.168.8.5
同步node1时间
ntpdate node1
写入硬件时钟
hwclock -w
1.5配置NFS
使用node1作为NFS服务器,node2~node4作为客户端, 安装完NFS后只需要在node1修改代码就行了
在node1上执行(服务端)
安装NFS
yum -y install nfs-utils
启动rpc服务
systemctl start rpcbind
查看是否安装成功
rpm -qa nfs-utils
编辑/etc/exports ,添加以下内容
/data/MPI 192.168.8.0/24(rw,async, no_root_squash)
启动nfs服务
systemctl start nfs
在node2~node4上执行(客户端)
安装NFS(客户端上不需要启动nfs服务,只是为了使用showmount工具)
yum -y install nfs-utils
启动rpc服务
systemctl start rpcbind
使用showmount命令查看nfs服务器共享信息
showmount -e 192.168.8.5
挂载共享目录
mount -t nfs 192.168.8.5:/data/MPI /data/MPI
查看共享目录
ls /data/MPI
1.6 配置MPI环境
安装GCC、C++、fortran编译器
yum install -y gcc gcc-c++ gcc-gfortran
下载MPI安装包并解压
tar xzvf mpich-3.3.2.tar.gz
进入到mpich-3.3.2目录下
cd mpich-3.3.2
configure配置编译环境,选择一个安装路径
./configure --prefix=/etc/mpich-3.3.2
编译安装
make
make install
创建文件/etc/profile.d/user.sh,包含以下内容:
export PATH=$PATH:/etc/mpich-3.3.2/bin
export MANPATH=$MANPATH:/etc/mpich-3.3.2/share/man
执行以下命令,使两个文件生效:
source /etc/profile.d/user.sh
在/etc/profile文件中添加库共享路径,执行vi /etc/profile,然后在其中加入一行
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
使该配置文件生效
source /etc/profile
授权,在每个节点/etc目录下创建hosts.equiv文件,包含以下内容:
node1 root
node2 root
node3 root
node4 root
配置分布式运行程序节点,在每个节点创建hosts文件。包含以下内容:
格式如下
机器名:该机器可执行的进程数
2. 编写代码
用MPI编程实现PI的计算
算法描述:通过MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD)广播给本通信环境中的所有进程,各个进程计算自己的mypi = h * sum; 通过 MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);由进程 0 进行归约,把每个进程计算出来的 mypi 进行相加(MPI_SUM),赋给pi 。
#include "mpi.h"
#include <stdio.h>
#include <math.h>
double f(double a)
{
return (4.0/(1.0 + a*a));
}
int main(int argc, char *argv[])
{
int done = 0, n, myid, numprocs, i;
double PI25DT = 3.141592653589793238462643;
double mypi, pi, h, sum, x;
double startwtime = 0.0, endwtime;
int namelen;
char processor_name[MPI_MAX_PROCESSOR_NAME];
MPI_Init(&argc, &argv); //mpi的初始化
MPI_Comm_size(MPI_COMM_WORLD, &numprocs); //获取线程数
MPI_Comm_rank(MPI_COMM_WORLD, &myid); //获取线程id值
MPI_Get_processor_name(processor_name, &namelen); //获取处理器名称
fprintf(stderr, "Process %d on %s\n", myid, processor_name);
n = 0;
while(!done)
{
if(myid == 0)
{
if(n == 0)
n = 100;
else
n = 0;
startwtime = MPI_Wtime();
}
MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD); //进行广播传送消息
if(n == 0)
done = 1;
else
{
h = 1.0/(double)n;
sum = 0.0;
for(i=myid+1; i<=n; i+=numprocs) //各线程计算自己的面积
{
x = h * ((double)i - 0.5);
sum += f(x);
}
mypi = h * sum;
MPI_Reduce(&mypi, &pi, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);//归约
if(myid == 0)
{
printf("pi is approximately %.16f,Error is %.16f\n",pi, fabs(pi-PI25DT));
endwtime = MPI_Wtime();
printf("wall clock time = %f\n", endwtime-startwtime);
}
}
}
MPI_Finalize(); //mpi结束
return 0;
}
3.运行测试
在node1运行执行,MPI会把进程交给其他机器执行
编译测试
mpicc mpipi.c -o mpipi
运行测试
mpirun -n 9 -f ./hosts ./mpipi
实验结果
结果分析
- 取进程为9时,分析n 分别使用100、1000、10000对PI精度及误差的影响,结果如下图所示:由结果可知,随着分割数越大,计算得到的结果越精确,误差越小。
- 在误差较小的条件下,即n取为10000时,分析并行进程的个数对计算速度的影响,结果如下图所示:由结果可知,计算速度受到并行进程个数的影响,且随着进程数的增多,运行时间增大,运行速度越慢。
- 从以上实验数据可以看出,并不是进程开的越多运算时间越短,因为集群计算机是基于VMware虚拟机的单核cpu计算机,所以在进程数为1时,效果是最佳的,进程数过多的话,因为一个cpu的一个核同一时间最多只有一个进程在运行,同一时间最多有一个进程同时运行,所以超过两个进程会发生进程的切换,进程切换会消耗额外的时间。