/ 中存储网

在Ubuntu环境下用MPICH和Intel Fortran进行并行计算的方法

2015-10-10 10:39:37 来源:中存储网

以下是最近Y某在用mpi进行某程序并行运算时所做的设置的一些总结,由于intel fortran(在intel cpu上)的效率,所以想要配置intel fortran 实现并行,放在这里记录备用吧……

至于什么是mpi,自己看有关介绍。
主节点master node 就是控制其他节点进行运算的计算机,大家这里起名为node0。
从节点slave node 嗯,就是进行计算的节点,起名为node1 ~ noden

1. 设置网络文件系统NFS(Network File System/Need for Speed),这是进行并行计算的基础,所有的节点必须能够读写同一个网络路径才可以进行同步计算。需要注意的是,一旦你只是在一台电脑上运行这一程序(比如你有多个处理器或者多核),你可以跳过这一步直接进行第二步……

首先要安装NFS server
sudo apt-get install nfs-kernel-server
设置一下共享
首先在主节点(master node)建立一个共享文件夹,或者也可以自己指定一个……
sudo mkdir /sharing
设置共享
sudo cat /mirror *(rw,sync) >> /etc/exports
之后就可以运行nfs服务端
sudo /etc/init.d/nfs-kernel-server start

要进行运算,在每一个从节点(slave node)中都需要设置映射主节点的目录……
首先加入主节点的ip
sudo cat  xxx:xxx:xxx:xxx node0 >> /etc/hosts  #不会有人把xxx输进去吧…
在从节点里面进行映射……
sudo mkdir /sharing
sudo mount node0:/sharing /sharing

2. 接下来要设置ssh(secure shell),防止每次你运行mpi程序都要输n遍密码(有多少个线程就多少次……),一旦你的系统安全要求不那么高,也可以选择使用rsh(其实我只是懒得设置rsh)

首先你要装上它……
sudo apt-get install ssh
之后在主节点上生成DSA key,注意在运行的时候把密码留空
ssh­-keygen ­-t dsa
把密钥加入到受信任密钥中:
cd  ~/.ssh
cat id_dsa.pub >> authorized_keys
就可以了,之后可以试着用ssh username@machinename 来连接。另外,所有的节点必须有一个同样的用户(如mpiusr),以便主节点通过ssh(远程登录)的方式与其他节点进行通信,并控制其他节点进行运算。

3. 之后要做的是装interl fortran,请参看这里……顺便,现在的Intel fortran for linux 改名成了Intel? Fortran Composer XE 2011 for Linux and Mac OS X,诡异的名字……

4. 然后(终于)要安装mpi了:
首先,实际上能够使用的mpi版本有很多,可以在Ubuntu上面安装的主要有openmpi,mpich,和mpich2,总体来说,这些版本大同小异,并且……其实尽管有的版本叫做open,有的没有,它们都是开源软件……我这里安装的是mpich2,其他的版本跟这个的设置差不多。另外,其实intel有自己的mpi,还有个什么parallel studio什么的,并且效率很高,不过那个是要收费……买不起

对于基于debian发行版的用户来说,很简单:
sudo apt-get install mpich2 #注意这里是安装了mpich2 而非mpich

或者,一旦想要更新的版本,也可以选择去其官方网站上下载源码安装:

http://www.mcs.anl.gov/research/projects/mpich2/

大概一顿configure 和一顿sudo make install 就可以了……

一点点设置:
首先要在家目录下~/ 建立一个mpd.host文件,这样主机才能知道有多少台机器可以供它驱使,比如包含如下的内容:
localhost
node1
node2

noden

之后建立一个conf文件用于设置口令,比如:
cat secretword=lalala >>  ~/.mpd.conf
之后确保只有你自己能读:
chmod 600 ~/.mpd.conf

之后就大功告成!可以尝试着使用mpdboot -n N #(N=你有的节点数)启动后台程序。
可以使用mpitrace来查看有那些节点被使用了……

编译示例:
正常编译就没有问题,一旦是用Ubuntu自动安装的mpich2的话,include的那些库应该是在:
/usr/include/mpich2/
一般只需要包含mpi.h,对于fortran来说,会是mpif.h。一般动态链接只要在连接的时候加上 -lmpi 的参数就可以了。

你应该很容易在网上找到一些并行计算的示例程序代码,比如无数的计算pi的程序……
这里有一个,注意你要把fortran的格式加上……

c**********************************************************************
c   pi.f – compute pi by integrating f(x) = 4/(1 + x**2)
c
c  (C) 2001 by Argonne National Laboratory.
c      See COPYRIGHT in top-level directory.
c
c   Each node:
c    1) receives the number of rectangles used in the approximation.
c    2) calculates the areas of it’s rectangles.
c    3) Synchronizes for a global summation.
c   Node 0 prints the result.
c
c  Variables:
c
c    pi  the calculated result
c    n   number of points of integration.
c    x           midpoint of each rectangle’s interval
c    f           function to integrate
c    sum,pi      area of rectangles
c    tmp         temporary scratch space for global summation
c    i           do loop index
c****************************************************************************
program main

include ‘mpif.h’

double precision  PI25DT
parameter        (PI25DT = 3.141592653589793238462643d0)

double precision  mypi, pi, h, sum, x, f, a
integer n, myid, numprocs, i, rc
c                                 function to integrate
f(a) = 4.d0 / (1.d0 + a*a)

call MPI_INIT( ierr )
call MPI_COMM_RANK( MPI_COMM_WORLD, myid, ierr )
call MPI_COMM_SIZE( MPI_COMM_WORLD, numprocs, ierr )
print *, “Process “, myid, ” of “, numprocs, ” is (still) alive”

sizetype   = 1
sumtype    = 2

10   if ( myid .eq. 0 ) then
write(6,98)
98      format(‘Enter the number of intervals: (0 quits)’)
read(5,99) n
99      format(i10)
endif

call MPI_BCAST(n,1,MPI_INTEGER,0,MPI_COMM_WORLD,ierr)

c                                 check for quit signal
if ( n .le. 0 ) goto 30

c                                 calculate the interval size
h = 1.0d0/n

sum  = 0.0d0
do 20 i = myid+1, n, numprocs
x = h * (dble(i) – 0.5d0)
sum = sum + f(x)
20   continue
mypi = h * sum

c                                 collect all the partial sums
call MPI_REDUCE(mypi,pi,1,MPI_DOUBLE_PRECISION,MPI_SUM,0,
$     MPI_COMM_WORLD,ierr)

c                                 node 0 prints the answer.
if (myid .eq. 0) then
write(6, 97) pi, abs(pi – PI25DT)
97      format(‘  pi is approximately: ‘, F18.16,
+          ‘  Error is: ‘, F18.16)
endif

goto 10

30   call MPI_FINALIZE(rc)
stop
end

首先你要把程序弄到共享文件夹中(要不然别的节点无法读取),或者也可以只把可执行文件弄过去:
sudo cp pi.f  /sharing
cd /sharing
其实使用ifort 和使用 gfortran没有什么本质的区别,大概直接运行mpif77 或者 mpif77 -fc=yourfc 就可以了
一旦使用gfortran,需要在mpi的编译命令上加上参数:
mpif77 -fc=gfortran
一旦使用ifort,需要在mpi的编译命令上加上参数:
mpif77 -fc=ifort
编译大家的示例程序:
mpif77 -fc=ifort pi.f -o calpi
之后执行:
mpiexec -n N ./calpi
其中N 为你的节点数。一旦你只是在一台电脑上运行(比如你有多处理器或多核处理器),可以使用:
mpiexec.gforker -n N ./calpi
其中N为你的处理器数/核数
一旦正常的话,程序首先会显示有几个节点在工作,之后会让你输入一个数字(积分数,大概就是把积分离散成累加的数字,数字越大,计算pi越准(大概吧),当然算得也越慢)之后就开始计算了,之后会输出pi的值和误差。

Troubleshooting:
“The only problem with troubleshooting is that sometimes trouble shoots back.”(笑)

装mpi进行并行计算很麻烦,并且很有可能会有各种各样的问题,很常见的就是segment error之类的……比如报错:

forrtl: severe (174): SIGSEGV, segmentation fault occurred

大概有一万种原因可以造成这个结果,大抵就是内存越界(比如程序尝试去访问某一段不属于它的内存)然而一旦你单机运行你的程序没有问题,只是在mpi下报错的话,很有可能是因为linux用户的stack限制造成的,尝试运行:
ulimit -s
ubuntu默认的stack 大小应该是8192 (Kb),一旦你在计算一个很大的数组,可以尝试将它修改成无限大……
ulimit -s unlimited
可以在每次终端启动的时候设置这个值:
sudo cat ulimit -s unlimited >> /etc/bash.bashrc

或者,也有可能遇到:

p4_error: alloc_p4_msg: Message size exceeds P4s maximum message size: 344530944

这个错误一般也是因为cpu之间传递的数据量过大,超出了默认的共享内存(P4_GLOBMEMSIZE)大小,对于这个问题,可以通过增加 P4_GLOBMEMSIZE 的大小来解决。对于bash终端而言,可以:
sudo cat export P4_GLOBMEMSIZE=1073741824 >> /etc/bash.bashrc
这样每次运行终端都会设置这个值(现在是1GiB)