以下是最近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)