刚刚跟实验室的一个博士生师兄联系上了,研究生入学前本来漫无目的的乱学过程终于稍微找到点方向。虽然还没决定以后具体要做体系结构方向的哪一块内容,至少先走一步学一步吧。
师兄是主要做并行程序优化的,估计老师也是看我以前编程方面还可以才给我推荐的这个方向。
下一阶段开始学习并行编程:mpi和openmp
先从mpi开始吧。
一些资料
一个MPI的教程站:http://mpitutorial.com/
因为是托管在Github上的,顺手fork过来了:http://mpi.jcf94.com/MPICH,一个MPI的实现机制,包括编译器和运行器等:http://www.mpich.org/
以及MPICH的各个版本资源
MPICH在Windows下的安装
MPICH官网上提供了整个MPICH2的源码,一般是需要下过来然后在本地进行完整编译,这个等下次移到Ubuntu下面的时候再看一下编译的全过程吧。现在先找现成的安装包用着先。
最新的版本大概出到了3.x,不过已经编译好了的Windows安装文件似乎最高只到1.4.1。下之,然后安装。
安装过程中要求输入一串smpd的底层密码,这个应该是在整个MPICH系统中用来传递消息的一个服务。
装好之后,安装目录里面有用的几个exe有:
mpiexec.exe MPI运行器
smpd.exe
wmpiconfig.exe 图形界面下的MPICH配置查看器
wmpiexec.exe 图形界面下的MPI运行器
wmpiregister.exe 图形界面下的MPICH服务注册器
首先还是把bin这个目录加到系统环境变量里面去,这是一般装开发环境时肯定要做的事。
然后测试smpd服务是否在运行了,没有的话就需要把它安装上并启动起来:
1 | smpd -install -phrase behappy |
-phrase
后面的这一串就是安装过程中输入的密码串。
确认已启动后继续。
启动wmpiregister.exe,这里需要把此时登录Windows系统的用户账户和密码输进去,因为MPICH需要调用管理员的底层权限。
比较坑的是当时在这里以及后面的测试这一步中卡了很久…
我现在用的是win10,从win8开始就使用了在线的微软账号进行登录。所以我把微软账号输入到register里面去,结果却死活没办法通过系统的验证。
后来才知道,如果采用微软账号登录系统,Windows在本地是还有另一个本地账号的用户名来对应的。一般是把登录微软账号前的最后一个本地账号直接作为对应。
我当时装机的时候应该是没有经过本地账号这一步,所以不知道它写在那里的本地用户名是什么。
于是切到本地账户,创建了一个本地账户的用户名,再切回微软账号。
然后用之前的本地账户用户名+微软账号的密码注册到register里面去。
注册完之后,可以用wmpiexec.exe测试一下,安装目录下example文件夹中有一个测试用的圆周率计算程序cpi.exe。
测试成功能运行即可。
不成功的话就需要检查smpd服务是不是正常运行,然后网络有没有被防火墙挡了,用户账户有没有注册到register里面去。
编译
网上提到MPI编译需要用到mpigcc之类的东西,然而我在MPICH2的安装目录下根本找不到这玩意的迹象。
官方文档中建议使用Visual Studio来作为MPI的IDE…然而,这货这么大,我是真心不太想用的感觉(尤其是VC6.0给我留下的印象太差了,不了解现在新版的VS套件的编译标准是不是跟GNU的一样)…
再仔细搜索之后,原来mpigcc就是调用了gcc的编译指令,这样事情就简单了。
看一下安装目录下面的文档,果然找到了gcc的说明:
README.winbin.rtf
1 | ... |
整个过程很简单,只要在gcc的编译指令后面加上-I
开关,把mpi的头文件include包括进来;-L
开关,把mpi的函数库lib包括进来;最后指定-lmpi
,使用mpi方式进行编译即可。
这样直接调用gcc和g++就可以对整个完成编译了,只不过运行必须调用mpiexec或者wmpiexec。
既然gcc的编译这一部分OK了,可以直接把编译命令绑进文本编辑神器Sublime2里面去。
Sublime2配置
配置部分跟以前已经记录过的一样:Sublime 2 配置
在sublime2中找到编译命令的配置文件:
Preference -> Bowser Packages -> /C++/C++.sublime-build
1 | { |
前面部分保持不变,最后加上一条命令,命名成BuildWithMPI
。
然后选一个没有被使用过的快捷键,加到快捷键注册文件里面去:
Preference -> Key Bindings – User
1 | [ |
保存好,之后就可以用alt+b
来调用附加了MPI编译命令的g++指令了。
Hello World~!
写个测试程序试试先:
1 | /* *********************************************** |
此时普通的编译指令会返回找不到头文件mpi.h,就算找到了也是编译失败。alt+b
可正常通过编译。
然后用wmpiexec来运行之,开了4个线程:
结果:
MPI我还没有真正开始学,不过也可以从这个简单的测试程序中稍微看出一些特点来:
从test这个变量的输出结果来看,4个线程的变量应该是完全独立的,并没有出现同一个变量反复加了4次这种事情。
我还特别调用了一下时间函数。从输出结果上来看,四个进程的时间居然真的是同步的!!结束时间和起始时间一样应该是因为中间运行的过程太少了。
关闭之后再运行,4个进程的输出的rank先后顺序可能会有些不同。
MPI初探:
把同一个过程分给多个线程独立执行,相互之间通过一些特殊的调用来进行通信,进程与进程之间是独立的。
并行编程与普通的编程之间看来应该是会有挺大的差别的,这一点上来看,编程的思路也需要发生挺多变化。
多机并行
MPICH除了可以在本地进行多线程并行的运算,还可以通过网络来进行远程多机多线程并行运算。
这个地方也挺坑的…
要求多台计算机上register的用户名和密码必须一致,要不然连不上。
我的两台win10都用的是微软账户,为了测试这个多机并行改了好久的本地账户。
再然后是要求如果是直接执行的本机的文件的话,要求对方的同样目录下必须有同样的文件,就是说文件也必须是同步的。
完成上面所有的设置之后,然后用wmpiexec调用:
或者用命令行调用:
1 | mpiexec -hosts 2 j-cf-yoga 2 j-cf-pc 2 "D:\mpitest.exe" |
如果网络和设置都是正常的,应该能得到这样的结果:
多机并行完成。
并行的效率问题
这里测试了一下多个线程之间的效率比较情况:
可以比较明显地看到同样对于9999999999
精度的求圆周率计算:
单线程花了10.7s,2线程5.41秒,4线程2.78秒,8线程以上效率就不会再怎么增加了
不知道是不是我的CPU只有4核的原因,还是与这个算圆周率的程序本身有关…进行到这里,已经非常能够体会到并行编程与普通程序之间的差别了:
并行程序必须要能够考虑到任务的划分、多线程之间的通讯等等,只是把原本的单线程程序拿来扔给多线程执行的话,效率根本不能增加,只是把相同的代码重复执行好多遍而已。
要想做到多线程,需要学的东西还很多。
然后是双机并行进行圆周率计算,两台电脑(Y480 i5-3210 以及 Yoga3_11 5Y10),双机8线程的时候能在1.7s左右完成上面的那个运算。
这里要再记一下的是,win10上面的防火墙太坑了…明明设了例外,还是会把通信线程给挡掉,发出指令的那一台机子需要关闭所有防火墙。回头再好好研究下。