利用MPI多节点分布式并行计算PI实验报告

环境配置:

云服务器部署pi节点 云服务器运行pi节点_云服务器部署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文件。包含以下内容:

格式如下

机器名:该机器可执行的进程数

云服务器部署pi节点 云服务器运行pi节点_#include_02

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

实验结果

云服务器部署pi节点 云服务器运行pi节点_分布式计算_03


结果分析

  1. 取进程为9时,分析n 分别使用100、1000、10000对PI精度及误差的影响,结果如下图所示:由结果可知,随着分割数越大,计算得到的结果越精确,误差越小。
  2. 云服务器部署pi节点 云服务器运行pi节点_云服务器部署pi节点_04

  3. 在误差较小的条件下,即n取为10000时,分析并行进程的个数对计算速度的影响,结果如下图所示:由结果可知,计算速度受到并行进程个数的影响,且随着进程数的增多,运行时间增大,运行速度越慢。
  4. 云服务器部署pi节点 云服务器运行pi节点_云服务器部署pi节点_05

  5. 从以上实验数据可以看出,并不是进程开的越多运算时间越短,因为集群计算机是基于VMware虚拟机的单核cpu计算机,所以在进程数为1时,效果是最佳的,进程数过多的话,因为一个cpu的一个核同一时间最多只有一个进程在运行,同一时间最多有一个进程同时运行,所以超过两个进程会发生进程的切换,进程切换会消耗额外的时间。