【高性能计算】MPI

学习来源

MPI编程入门详解
LINUX系统安装MPI

MPI安装

打开官网下载源代码
在这里插入图片描述
在这里插入图片描述
然后将这个mpich-4.0.2.tar.gz上传到服务器(一般服务器上是可以直接下载的,但是我用的是百度的aistudio,不支持apt-get,只能手工下载了)

解压它
tar -xzvf ./mpich-4.0.2.tar.gz -C  /home/aistudio/external-libraries/mpich3
进入解压缩文件夹
cd ./mpich3/mpich-4.0.2
配置(这个过程很漫长)
 ./configure --prefix=/home/aistudio/external-libraries/mpich3
 编译
 make
 安装
 make install

添加mpi的bin文件:一般是

vim ~/.bashrc
末尾添加
export PATH=/home/mpich3/bin:$PATH
保存文件后,刷新
source ~/.bashrc

但我是在aistudio下操作的,貌似官网就说了怎么添加环境变量,我就大胆尝试了一下

%env PATH=/home/aistudio/external-libraries/mpich3/bin:$PATH

没想到输完之后,mpi命令能用了,但是原来的linux指令都不能用了,后来我又改回去了,没想到改回来之后mpi的命令还是能用,这波搞不懂了,不知道有没有懂的兄弟提点一下。

%env PATH=/bin:/usr/bin:$PATH

demo

编译:mpic++ main.cpp -o main
执行:mpiexec -np 4 ./main

#include <stdio.h>
#include <string.h>
#include "mpi.h"
void main(int argc, char* argv[])
{
    int numprocs, myid, source;
    MPI_Status status;
    char message[100];
    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
    if (myid != 0) {  //非0号进程发送消息
        strcpy(message, "Hello World!");
        MPI_Send(message, strlen(message) + 1, MPI_CHAR, 0, 99,
            MPI_COMM_WORLD);
    }
    else {   // myid == 0,即0号进程接收消息
        for (source = 1; source < numprocs; source++) {
            MPI_Recv(message, 100, MPI_CHAR, source, 99,
                MPI_COMM_WORLD, &status);
            printf("接收到第%d号进程发送的消息:%s\n", source, message);
        }
    }
    MPI_Finalize();
} 

在这里插入图片描述

实验

实验内容:分别使用不同矩阵规模、不同的进程数、不同的线程数进行矩阵乘法实验。
实验结果:分别展示了不同矩阵规模下加速比与进程数的关系(如图1所示,线程数设置为1)、不同矩阵规模下加速比与线程数的关系(如图2所示,进程数设置为8)。
在这里插入图片描述
在这里插入图片描述
实验分析
(1)我们可以发现,随着进程数的增加,加速比不是线性增长的,反而在某几个较小的进程数上,可以得到较大的加速比,说明进程的创建是有很大开销的,如果这个开销被多个进程带来的并行计算能力抵消,则加速效果显著,反之,若增加的计算能力没有抵消这部分开销,加速效果反而不佳,也就是说合理的使用MPI技术,能够得到一个较为不错的效果。
(2)在一定的进程数下,增加线程数,加速比呈现上升趋势,说明线程的开销并没有进程那么大,合理的增加线程数,可以带来较大的增益,也就是说MPI与OpenMP的结合可以得到更好的效果。

c++源代码mpic++ main.cpp -o main && mpiexec -np 8 ./main

#include <stdio.h>
#include <string.h>
#include <chrono>
#include "mpi.h"

using namespace std;
using namespace std::chrono;

const int N=1024; //矩阵的维度
const int ThreadNumber=32; //线程数
int a[N*N],b[N*N],c[N*N],buffer[N*N],ans[N*N];

int main(int argc, char* argv[])
{
    int rank, numprocs, line;
    // MPI 初始化
    MPI_Init(NULL, NULL);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); //当前进程的索引
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs);  // 进程个数
    line = N / numprocs;  // 从进程分到 a 矩阵的行数
    for (int i = 0; i < N*N; i++) //矩阵初始化
        a[i] = b[i] = i;
    if(rank==0) //主进程
    {
        auto start = system_clock::now();
        for (int i = 1; i < numprocs; i++)
        {
            //把b矩阵发给每个从进程
            MPI_Send(b, N * N, MPI_INT, i, 0, MPI_COMM_WORLD);
            //把a矩阵的对应行发给每个从线程
            MPI_Send(a + (i - 1) * line * N, N * line, MPI_INT, i, 1,MPI_COMM_WORLD);
        }
        for (int k = 1; k < numprocs; k++)
        {
            MPI_Recv(ans, line * N, MPI_INT, k, 3, MPI_COMM_WORLD,MPI_STATUS_IGNORE);
            for (int i = 0; i < line; i++)
            {
                for (int j = 0; j < N; j++)
                {
                    c[((k - 1) * line + i) * N + j] = ans[i * N + j];
                } 
            } 
        }
        auto end = system_clock::now();
        auto duration = duration_cast<microseconds>(end - start);
        auto paraller_compute_time=double(duration.count()) * microseconds::period::num / microseconds::period::den;

        start = system_clock::now();
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                int temp = 0;
                for (int k = 0; k < N; k++) {
                    temp += a[i*N+k] * b[i*N+k];
                }
                c[i*N+j] = temp;
            }
        }
        end = system_clock::now();
        duration = duration_cast<microseconds>(end - start);
        auto serial_compute_time=double(duration.count()) * microseconds::period::num / microseconds::period::den;
        printf("加速比:%.1lf \n",serial_compute_time/paraller_compute_time);
    }
    else{
        MPI_Recv(b, N * N, MPI_INT, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
        MPI_Recv(buffer, N * line, MPI_INT, 0, 1, MPI_COMM_WORLD,MPI_STATUS_IGNORE);
        #pragma omp parallel for num_threads(ThreadNumber)
        for (int i = 0; i < line; i++)
        {
            for (int j = 0; j < N; j++)
            {
                int temp = 0;
                for (int k = 0; k < N; k++)
                    temp += buffer[i * N + k] * b[k * N + j];
                ans[i * N + j] = temp;
            }
        }
        MPI_Send(ans, line * N, MPI_INT, 0, 3, MPI_COMM_WORLD);
    }
    MPI_Finalize();
    return 0;
} 

python绘图代码

import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
import matplotlib

# aistudio上设置plt中文正常显示
matplotlib.rcParams['font.sans-serif'] = ['FZSongYi-Z13S'] # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False # 正确显示连字符

# 参数设置
process_nums=[4,8,16,32] # 进程数
thread_nums=[4,8,16,32] # 进程数
matrix_scales=[64,128,256,512,1024] # 矩阵规模
# problem1_dic[i]表示某一个矩阵规模下的 各个进程数对应的加速比 实验数据
problem1_dic=[
    [2.7,2.1,0.8,0.4],
    [2.8,3.7,3.3,0.9],
    [4.6,5.7,0.5,1.1],
    [1.7,1.2,1.1,0.8],
    [1.0,0.7,0.5,0.7]
]
# problem2_dic[i]表示某一个矩阵规模、8个进程下 各个线程数对应的加速比 实验数据
problem2_dic=[
    [1.3,1.7,1.6,1.4],
    [3.9,3.8,4.0,4.2],
    [4.6,5.2,5.0,5.8],
    [1.3,1.4,1.3,1.3],
    [0.6,0.8,0.9,1.7]
]

# 第一张图
x=process_nums
fig=plt.figure()
axes=fig.add_axes([0.1,0.1,0.8,0.8])
axes.set_title("不同矩阵规模下加速比与进程数的关系")
colors=["green","black","blue","cyan","magenta","red"]
labels=[str(matrix_scale)+" * "+str(matrix_scale) for matrix_scale in matrix_scales]

for idx in range(len(matrix_scales)):
    y=problem1_dic[idx]
    axes.plot(x,y,c=colors[idx],label=labels[idx])
axes.axis([4,32,0,6])
axes.xaxis.set_major_locator(MultipleLocator(4))
axes.set_xlabel("进程数")
axes.set_ylabel("加速比")
axes.legend()
fig.savefig("3.1.png",dpi=300)

# 第二张图
x=thread_nums
fig=plt.figure()
axes=fig.add_axes([0.1,0.1,0.8,0.8])
axes.set_title("不同矩阵规模下加速比与线程数的关系")
colors=["green","black","blue","cyan","magenta","red"]
labels=[str(matrix_scale)+" * "+str(matrix_scale) for matrix_scale in matrix_scales]

for idx in range(len(matrix_scales)):
    y=problem2_dic[idx]
    axes.plot(x,y,c=colors[idx],label=labels[idx])
axes.axis([4,32,0,6])
axes.xaxis.set_major_locator(MultipleLocator(4))
axes.set_xlabel("线程数")
axes.set_ylabel("加速比")
axes.legend()

fig.savefig("3.2.png",dpi=300)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值