From Zero to Hero:MPICH2,OPENMPI函数使用——高性能计算
MPI环境安装、配置SSH免密登录
一、安装MPI
1、安装MPI库
sudo yum install mpich mpich-devel
2、 配置环境变量
编辑~/.bashrc
文件,在文件末尾添加如下两行:
在普通用户模式下输入vim ~/bashrc
export PATH=$PATH:/usr/lib64/mpich/bin
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/lib64/mpich/lib
然后:
source ~/.bashrc
3、 测试MPI环境
mpirun -np 2 hostname
如果输出了两个主机名,则MPI环境配置成功。
二、安装openmp环境
1、 安装GCC/G++
CentOS中安装GCC可以使用yum命令:
sudo yum install gcc
sudo yum install gcc-c++
2、配置环境变量:
编辑~/.bashrc
文件,在文件末尾添加如下一行:
export OMP_NUM_THREADS=4
其中4可以根据实际需要修改。
3、测试OpenMP环境
新建一个文件test.c,写入以下代码:
#include <stdio.h>
#include <omp.h>
int main() {
#pragma omp parallel
{
int tid = omp_get_thread_num();
printf("Hello, world! This is thread %d\n", tid);
}
return 0;
}
在终端输入以下命令编译并运行程序:
gcc -fopenmp test.c -o test
./test
三、配置ssh免密登录
修改映射
vim /etc/hosts
node1:192.168.79.133
node2:192.168.79.134
添加:
192.168.79.133 node1
192.168.79.134 node2
生成公钥、私钥
ssh-keygen -t rsa
配置ssh
在node01机器上输入命令
ssh-copy-id -i Node1
然后输入对应密码,再输入
ssh-copy-id -i Node2
node02同理
四、多节点程序
编辑hostfile文件,确认每个机器发起进程的上限
node1:2
node2:3
(1)多节点单程序
如果执行中用到的-n number,number中的前2个会在node1中执行,接下来的会在node2中执行
mpirun -f hostfile -n 10 ./mpi
(2)多节点多程序
mpi的前10个rank执行hello程序,接下来的20个rank执行world程序
mpirun -f hostfile -n 10 ./hello : -n 20 ./world
注意事项:
上述执行方式中,在node1和node2中必须有相同路径、相同名称的可执行文件,否则程序会报错,找不到文件。
可能会提示需要安装ssh-askpass,按照提示安装即可
最好都加上具体路径 “./mpi”的形式,直接使用“mpi”可能会报错,报错如下图
bcast广播函数使用
代码文件:test5.c
#include "mpi.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv)
{
int rank,size,i;
int *arr = NULL;
int len = 6;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
arr = (int*)malloc(len*sizeof(int));
memset(arr, 0, sizeof(int)*len);
if(rank == 0)
{
for(i = 0; i < len; i++)
arr[i] = i + 1;
}
MPI_Bcast(arr, len, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Barrier(MPI_COMM_WORLD);
if(rank != 0)
{
printf("In process %d...\n", rank);
for(i = 0; i < len; i++)
printf("arr[%d]=%d\t", i, arr[i]);
}
free(arr);
MPI_Finalize();
return 0;
}
1)在语义上,可以认为MPI_Bcast是一个“多次发送”的过程,这是没有错误的,但在语法上,不可以将MPI_Bcast等同为多个MPI_Send语句,因此,在MPI程序中,就不能用MPI_Recv去和MPI_Bcast相匹配。
2)MPI_Bcast是组操作,在每一个进程中都必须有相应的MPI_Bcast语句,而不是MPI_Recv语句。
3)由上面的程序,可以看出MPI_Bcast函数处于所有进程的执行流程中。且对于所有进程来说,广播进程(0进程)和其他进程之间的发送/接收缓冲区名字是一致的,如本程序中都是arr,看过的其他程序中也仍然存在这种一致性,这也许是MPI中对MPI_Bcast的一种约定俗成?
带着3)中的疑问,我们不妨将程序test5.c中对数组arr分配内存的部分放到主进程(0进程)中,即:
if(rank == 0)
{
arr = (int*)malloc(len*sizeof(int));
memset(arr, 0, sizeof(int)*len);
for(i = 0; i < len; i++)
arr[i] = i + 1;
}
然后编译,运行程序,启动两个进程,然后输出的运行结果为:
====================================================================================
= BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES
= EXIT CODE: 11
= CLEANING UP REMAINING PROCESSES
= YOU CAN IGNORE THE BELOW CLEANUP MESSAGES
=====================================================================================
APPLICATION TERMINATED WITH THE EXIT STRING: Segmentation fault (signal 11)
程序运行错误,错误字串为:Segmentation fault
(根据经验,这是引用了未分配的内存所造成的)
因为,将对数组arr内存分配的代码放到主进程(0进程)中后,从进程将无法对arr分配内存,而又要执行MPI_Bcast函数接收主进程发送过来的数据而引用未分配的内存空间,所以产生Segmentation fault错误