贡献者: addis
sudo apt install libmpich-dev,自动选择的版本是 3.3a2。安装完如果找不到 mpiexec,就退出 shell 再重新打开。
/etc/localhost 里面! 确保可以 ping,然后用 mpiexec -np 4 -host s0,s1,s2,s3 ./quad_mpi,不能用 localhost 注意 ./ 不能少。
mpiexec --version,目前是 4.1.x,mpicxx --version 只会给出 g++ 的版本号。
sudo apt install openmpi-bin libopenmpi-dev 然而 apt 的版本是非常老的,2.x.x,目前的版本是 4.1.4。笔者用 2.x.x 在多台机器上从来没成功过。其实 4.1.4 也没有成功12。
https://www.open-mpi.org/software/ompi/v4.1/ 里面的压缩包链接,用 wget 下载,然后解压如 tar -xzvf openmpi-4.1.4.tar.gz(要几分钟)。进入解压文件夹,./configure,make all -j20,sudo make install 即可。如果 mpicxx --version 说找不到 so 文件,就用 sudo ldconfig 即可。
sudo make uninstall 卸载
mpiexec -np 2 --host server1,server2 ./可执行文件
sudo ./install.sh 安装,过程和 MKL 差不多
~/.bashrc 中添加路径,即在文件最后加入命令 source /opt/intel/compilers_and_libraries_2020.1.217/linux/mpi/intel64/bin/mpivars.sh
mpicxx --help,如果进入帮助页面就说明成功了
mpicxx 或者 mpigxx 都是 g++ 的一个 wraper,和 g++ 一样使用即可。如果编译和链接分开也都要用。
# include <mpi.h>
mpiexec -np 4 ./main.x 指定进程数量。mpirun 也基本一样,但并不在 MPI 标准中。运行这个命令后,所有进程就都开始了。
mpiexec -np 4 ./main.x [参数1] [参数2] < 输入文件 即可。每一个进程都会获得完全一样的参数和独立的标准输入(不存在抢读输入文件的情况)。
MPI_Init(&argc, &argv); 开始 MPI,MPI_Finalize(); 结束。初始化会占用一些时间,可以留到程序中真的需要用到 MPI 的时候才使用,在这之前每个进程可以各自执行自己的事情(但是无法获取节点编号,所以一般在 init 前的计算都是完全相同的)。
MPI_Comm_size(MPI_Comm comm, &size); 获取指定 communicator 的进程数
MPI_Comm_rank(MPI_Comm comm, &rank); 获取当前进程的 id,称为 rank。
int MPI_Send(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm) 其中 dest 是进程 id,tag 是一个编号用于区分不同的消息(只需要区分来源和目标相同的多条消息),comm 一般是 MPI_COMM_WORLD(所有进程)。
MPI_Send 执行完以后,修改 buf 是安全的。
MPI_Datatype 有 MPI_CHAR,MPI_UNSIGNED_CHAR,MPI_INT,MPI_UNSIGNED,MPI_LONG,MPI_LONG_LONG,MPI_FLOAT,MPI_DOUBLE,MPI_LONG_DOUBLE,MPI_COMPLEX,MPI_REAL16,MPI_COMPLEX32。
count 是 buf 中有几个数据,即数组的长度。
int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status),接收信息。status 可以用于获取更多信息,其他参数同理。注意如果没有收到信息就会一直等待。
MPI_Send 和 MPI_Send 之前还是必须要 MPI_Bcast 让所有的节点都知道接收者是谁。如果信息量不大,还不如把信息和接收者一起直接广播。例如每个节点有一个数,要找到最大的数所在的节点并通知它,就直接用下面的 MPI_Allreduce 和 MPI_MAXLOC 即可。这样编程起来也会简单的多。
int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm) 从所有进程调用,把所有进程中的 buffer 同步为 root 的。这相当于分别对每个进程用 MPI_Send() 和 MPI_Recv()。注意如果 root 节点是运行时才确定的,那所有节点都要事先知道 root 是谁(要不然怎么确定自己要不要发送呢?)。
double MPI_Wtime() 返回当前进程的时间(从任意起点开始,单位秒)。
int MPI_Reduce(const void* send_buffer, void* receive_buffer, int count, MPI_Datatype datatype, MPI_Op operation, int root, MPI_Comm communicator); 把每个进程中的某个变量(或数组)相加或相乘等,赋值给 id 为 root 的某个变量(或数组,即每个元素分别相加)。其中 operation 可以是 MPI_MAX, MPI_MIN, MPI_SUM, MPI_PROD
int MPI_Allreduce(void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm); 和 MPI_Reduce 一样,但结果会返回到所有进程。
int MPI_Barrier(MPI_Comm comm) 可以同步所有的进程到某个点。
Scatter()(未完成)
Gather()(未完成)
MPI_Allgather(&my_number, 1, MPI_DOUBLE, all_numbers, 1, MPI_DOUBLE, MPI_COMM_WORLD); 其中 my_number 是双精度数字,all_numbers 是双精度数组的指针。
~/.ssh/config 或者 host 文件(给每个 ip 一个名称),设置免密码 ssh。
mpirun -np 5 -host localhost,worker1,worker2,... ./可执行文件。其中 localhost 是本机,worker1,worker2 是 ssh config 中的其他机器的名称。如果不指定 -host,所有进程将在本机运行。
-np 指定的是进程。
mpirun 依赖 ssh 在其他主机运行进程等,但在真正的通讯中一般使用 MPI 自己的通讯协议(基于 TCP/IP 或 InfiniBand 等)
slots):mpiexec -np 12 -machinefile machines.txt ./main.x
localhost slots=2
machine1 slots=4
machine2 slots=4
machine3 slots=2
其中也可以不包含 localhost,那么所有进程将远程运行。
1. ^ WARNING: Open MPI accepted a TCP connection from what appears to be a another Open MPI process but cannot find a corresponding process entry for that peer.
2. ^ WARNING: Open MPI failed to TCP connect to a peer MPI process. This should not happen. ... connect() to 10.0.2.4:1024 failed