MPI Hello World
▶《并行程序设计导论》第三章(用 MPI 进行分布式内存编程)的第一个程序样例。
● 代码
#include <stdio.h>
#include <string.h>
#include <mpi.h> const int maxSize = ; // 传输数据的最大尺寸,单位是个而不是字节 int main(int argc, char* argv[])
{
char greet[maxSize];
int size, rank;
MPI_Init(&argc, &argv); // MPI 初始化
MPI_Comm_size(MPI_COMM_WORLD, &size); // 获取通信子进程总数
MPI_Comm_rank(MPI_COMM_WORLD, &rank); // 获取当前通信子的编号 if (rank != ) // 非主进程
{
sprintf_s(greet, maxSize, "\nGreet from process %d of %d", rank, size);
MPI_Send(greet, strlen(greet) + , MPI_CHAR, , , MPI_COMM_WORLD); // 发送信息给 0 号通信子
}
else // 主进程
{
char name[maxSize];
int nameLength;
MPI_Get_processor_name(name, &nameLength); // 获取主机名
printf("\nGreet from process %d of %d in %s (length:%d)", rank, size, name, nameLength);
for (int q = ; q < size; q++)
{
MPI_Recv(greet, maxSize, MPI_CHAR, q, , MPI_COMM_WORLD, MPI_STATUS_IGNORE);// 按顺序接受来自其他通信子的信息
printf("%s", greet);
}
}
MPI_Finalize(); // MPI 资源释放
//getchar(); // 不用添加 getchar();,程序在命令提示符中用 mpiexec 命令运行
return ;
}
● 输出结果,使用 mpiexec 命令执行
// 使用 q 按顺序接收信息
D:\Code\MPI\MPIProjectTemp\x64\Debug>mpiexec MPIProjectTemp.exe -n Greet from process of in CUAN (length:)
Greet from process of
Greet from process of
Greet from process of
Greet from process of
Greet from process of
Greet from process of
Greet from process of // 使用 MPI_ANY_SOURCE 乱序接收信息
D:\Code\MPI\MPIProjectTemp\x64\Debug>mpiexec MPIProjectTemp.exe -n Greet from process of in CUAN (length:)
Greet from process of
Greet from process of
Greet from process of
Greet from process of
Greet from process of
Greet from process of
Greet from process of
▶ 涨姿势
● 函数 MPI_Init(),接收参数列表以初始化 MPI,使用的参数见后面的 mpiexec 用法部分。在使用默认参数初始化的时候可以用 MPI_Init(NULL, NULL);
MPI_Init(int *argc_p, ***argv_p);
● 函数 MPI_Comm_size() 和 MPI_Comm_rank(),指定通信子,并传入一个整数指针,返回该通信子的进程尺寸,或当前进程的编号。MPI_Comm 实际上是一个整形,见后面的宏定义部分。
MPI_METHOD MPI_Comm_size(_In_ MPI_Comm comm, _Out_ _Deref_out_range_(> , ) int* size); MPI_METHOD MPI_Comm_rank(_In_ MPI_Comm comm, _Out_ _Deref_out_range_(>= , ) int* rank);
● 函数 MPI_Send() 。采用两种实现,一种是将消息发送至缓冲区后函数返回,继续执行接下去的语句,如果缓冲区中的消息等待接收的时间超过阈值,再阻塞发送端,通常较少的消息使用这种模式;另一种是阻塞发送消息的函数,直到消息被接收为止。下面几种发送函数的参数都相同。
● 函数 MPI_Ssend()(同步通信模式)发送进程把缓冲区填充完毕,且接收进程开始接收时,发送函数返回。参考(https://blog.csdn.net/weixin_42742438/article/details/83104578)
● 函数 MPI_Bsend()(缓存通信模式)用户保证发送进程缓冲区可用,发送函数返回与接收进程无关
● 函数 MPI_Rsend()(就绪通信模式)接收进程开始接收时,发送进程才开始发送(填充缓冲区之前)
● 函数 MPI_Isend()(非阻塞通信模式)发送进程提交发送请求后立即返回,与缓冲区填充、接收进程无关,多一个 MPI_Request *request 参数用于标记任务
MPI_METHOD MPI_Send(
_In_opt_ const void* buf, // 指向发送数据的指针,转换为 void*
_In_range_(>= , ) int count, // 发送数据尺寸,1 表标量,超过 1 表数组长度
_In_ MPI_Datatype datatype, // 数据类型,注意使用 MPI 内建类型标志,见宏定义部分
_In_range_(>= , MPI_PROC_NULL) int dest,// 目标进程号
_In_range_(>= , ) int tag, // 数据标签,用于区分同一发送者和接受者之间传递的不同信息
_In_ MPI_Comm comm // 指定通信子
);
● 函数 MPI_Recv() 。其中,参数 source 可以使用 MPI_ANY_SOURCE,参数 tag 可以使用 MPI_ANY_TAG,以接收任意进程发送的,或带有任意标签的信息。在不需要使用参数 status 时可以将其设为默认值 MPI_STATUS_IGNORE。有类似的 MPI_Brecv(),MPI_Rrecv(),MPI_Irecv()
MPI_METHOD MPI_Recv(
_Out_opt_ void* buf, // 指向接收数据的指针,转换为 void*
_In_range_(>= , ) int count, // 接收数据尺寸,1 表标量,超过 1 表数组长度,可以大于发送的数据大小
_In_ MPI_Datatype datatype, // 数据类型,注意使用 MPI 内建类型标志
_In_range_(>= , MPI_ANY_SOURCE) int source, // 数据源进程号
_In_range_(>= , MPI_ANY_TAG) int tag, // 数据标签
_In_ MPI_Comm comm, // 指定通信子
_Out_ MPI_Status* status // 给定一个状态结构指针,包含传递数据的来源,大小,标签等信息,见宏定义部分
);
● 函数 MPI_Get_count() 。在函数 MPI_Recv() 使用 MPI_ANY_SOURCE 或 MPI_ANY_TAG 的情况下,完成消息传递后不知道发送来源、数据量大小、数据标签,这时可以使用状态结构指针来获取相关信息。
// 函数 MPI_Get_count() 的参数
MPI_METHOD MPI_Get_count(
_In_ const MPI_Status* status, // 状态结构指针
_In_ MPI_Datatype datatype, // 传递数据类型
_mpi_out_(count, MPI_UNDEFINED) int* count // 获取真实传递数据量
); // 使用范例
{
MPI_Status* status; // 创建一个状态结构指针
int count, source, tag, error;
MPI_Datatype dataType = MPI_INT; // 数据类型
MPI_Recv((void *)&data, , dataType, , , MPI_COMM_WORLD, status); // 接收数据
MPI_Get_count(status, dataType, &count); // 获得真实接受的数据量
source = status->MPI_SOURCE; // 获得数据来源进程号
tag = status->MPI_TAG; // 获得数据来源标签
error = status->MPI_ERROR; // 获得错误编号
}
● 用到的各种宏的定义
// mpi.h
typedef int MPI_Datatype; // MPI 传输数据类型(缓冲区类型)
#define MPI_DATATYPE_NULL ((MPI_Datatype)0x0c000000)
#define MPI_CHAR ((MPI_Datatype)0x4c000101)
#define MPI_UNSIGNED_CHAR ((MPI_Datatype)0x4c000102)
#define MPI_SHORT ((MPI_Datatype)0x4c000203)
#define MPI_UNSIGNED_SHORT ((MPI_Datatype)0x4c000204)
#define MPI_INT ((MPI_Datatype)0x4c000405)
#define MPI_UNSIGNED ((MPI_Datatype)0x4c000406)
#define MPI_LONG ((MPI_Datatype)0x4c000407)
#define MPI_UNSIGNED_LONG ((MPI_Datatype)0x4c000408)
#define MPI_LONG_LONG_INT ((MPI_Datatype)0x4c000809)
#define MPI_LONG_LONG MPI_LONG_LONG_INT
#define MPI_FLOAT ((MPI_Datatype)0x4c00040a)
#define MPI_DOUBLE ((MPI_Datatype)0x4c00080b)
#define MPI_LONG_DOUBLE ((MPI_Datatype)0x4c00080c)
#define MPI_BYTE ((MPI_Datatype)0x4c00010d)
#define MPI_WCHAR ((MPI_Datatype)0x4c00020e) typedef int MPI_Comm; // 通信子类型
#define MPI_COMM_NULL ((MPI_Comm)0x04000000)
#define MPI_COMM_WORLD ((MPI_Comm)0x44000000)
#define MPI_COMM_SELF ((MPI_Comm)0x44000001) typedef struct MPI_Status // 用于保存信息传递元数据的结构
{
int internal[]; int MPI_SOURCE;
int MPI_TAG;
int MPI_ERROR; } MPI_Status; // 状态结构指针默认参数和两个 ANY 的定义
#define MPI_STATUS_IGNORE ((MPI_Status*)(MPI_Aint)1) #define MPI_ANY_SOURCE (-2)
#define MPI_ANY_TAG (-1)
● 命令提示符中 mpiexec 的用法(关于 -a 和 -aa 的没看懂,以后补充)
mpiexec 的用法:
① mpiexec [options] executable [args] [ : [options] exe [args] : ... ]
② mpiexec -configfile <file name> 选项:
-configfile <file_name>
■ 从文件 <file_name> 中读取 mpiexec 的命令行,格式类似用法 ①,[options] executable [arguments],可用 '\' 转行,用 '#' 行注释 -optionfile <file_name>
■ 从文件 <file_name> 中读取 mpiexec 的选项,即作为命令行的一部分,格式 [option ] [option ] ... [option n],可用 '\' 转行,用 '#' 行注释 -n <num_processes>
-np <num_processes>
■ 指定运行的总进程数为 <num_processes> -n *
-np *
■ 指定运行的总进程数等于核心数,这是 -n -np 选项的默认参数。注意这里和下文中所有核心数均指逻辑核心数,而非物理核心数 -machinefile <file_name>
■ 运行主机的列表,格式为每行一个主机名,可选后跟该主机的核心数,用 '#' 行注释,-n * 默认使用的总进程数等于该列表中各主机核心数之和 -host <host_name>
■ 在名为 <host_name> 的主机上运行,-n * 默认使用一个核心 -hosts n host1 [m1][,mask[:group]] host2 [m2] ... hostn [mn]
■ 指定 n 台主机运行,并列出每台主机的名字和运行的进程数(默认为 ),同时可以使用 affinity masks 来指定每个核心上的进程数,参数 group 在大于 核心的系统中可用 -c <num_processes>
-cores <num_processes>
■ 指定每台主机上运行的核心数,该参数将覆盖选项 -hosts 或 -machinefile 指定的核心数数据 -a
-affinity
Set the affinity mask to a single core for each of the launched processes,
spreading them as far as possible throughout the available cores. This is the
equivalent of using the "-affinity_layout spr:L" option. -al <algo>[:<target>]
-al <algo>[:<stride>:<target>]
-affinity_layout <algo>[:<target>]
-affinity_layout <algo>[:<stride>:<target>]
Set the algorithm used to distribute launched processes to the compute cores,
and optionally specify the stride and the affinity target. The process
affinity is set to the specified target. Setting the stride in addition to
the target provides finer granularity (for example, "spr:P:L" will spread
processes across physical cores, and will bind each process to a single
logical core). If no stride is specified, it is assumed to be the same as the
target (for example, "seq:p" is the same as "seq:p:p"). Specifying affinity
with this option overrides any setting for the MPIEXEC_AFFINITY environment
variable. The following table lists the values for the <algo> parameter:
Value Description
-------- -----------------------------------------------------------------
No affinity (overrides any setting for MPIEXEC_AFFINITY).
or spr Spread: Distribute the processes as far as possible. (Default)
or seq Sequential: Distribute the processes sequentially.
or bal Balanced: Distribute the processes over the available NUMA nodes. The following table lists the values for the <target> and <stride> parameters:
Value Description
-------- -----------------------------------------------------------------
l or L Assign each process to a logical core. (Default)
p or P Assign each process to a physical core.
n or N Assign each process to a NUMA node. -aa
-affinity_auto
affinity_auto complements affinity_layout's behavior. It targets the
case where multiple jobs are running on the same node. When it is set, mpiexec
- Reads in the affinity settings which are published by other jobs running
on the same node, and determines the cores that are in use.
- Runs the specified MPIEXEC_AFFINITY algorithm avoiding the cores that are
in use, and calculates the affinity setting for this job.
- Publishes the calculated affinity settings so that upcoming jobs can avoid
the cores that are in use.
This way, multiple jobs on the same node can use the cores in a mutually exclusive
manner. -dir <working_directory>
-wdir <working_directory>
■ 指定工作空间,不超过 字符,可以使本地或者远端路径,包含需要的环境变量 -env <env_var_name> <env_var_value>
■ 指定环境变量 -genvlist <env_var_name1>[,env2,env3,...]
■ 将环境变量 <env_var_name1> 的值传递给 env2,env3 等环境变量,格式为逗号分隔。相当于统一环境变量 -exitcodes
■ 输出各进程的退出码 -priority {-}
■ 指定个进程额优先级, = idle, = below,=normal,=above,=high,默认为 -priority normal -p <port>
-port <port>
■ 指定 smpd 的监听端口 -path <path1>[;<path2>...]
■ 指定目标主机上的查找路径,多个路径之间用 ';' 分割,不影响环境变量 PATH 的值 -timeout <seconds>
■ 指定超时时限 -job <string>
■ 将应用程序与 Windows HPC 服务器创建的作业相关联 -l
-lines
■ 各进程输出时最前面写上进程号 -d [level]
-debug [level]
■ 将 debug 信息写入 stderr, = none, = error, = debug, = both,默认选项为 -d -genv, -gpath, -gdir, -gwdir, -ghost, -gmachinefile
■ 对应的无 g 选项的全局版本, -pwd <string>
■ 授权密码,仅当使用 MS-MPI Launch 服务时有效 -saveCreds
■ 保存密码凭据,在使用 -pwd 选项后可以保存密码,以后就不用再次授权密码,除非密码发生改变 -unicode
■ 要求运行输出支持 Unicode,可执行程序的路径等默认就支持 -?
-help
■ 列出简单的 mpiexec 的选项 -??
-help2
■ 列出帮助信息 -???
-help3
■ 列出环境变量
MPI Hello World的更多相关文章
- 查找素数Eratosthenes筛法的mpi程序
思路: 只保留奇数 (1)由输入的整数n确定存储奇数(不包括1)的数组大小: n=(n%2==0)?(n/2-1):((n-1)/2);//n为存储奇数的数组大小,不包括基数1 (2)由数组大小n.进 ...
- kmeans算法并行化的mpi程序
用c语言写了kmeans算法的串行程序,再用mpi来写并行版的,貌似参照着串行版来写并行版,效果不是很赏心悦目~ 并行化思路: 使用主从模式.由一个节点充当主节点负责数据的划分与分配,其他节点完成本地 ...
- MPI Maelstrom - POJ1502最短路
Time Limit: 1000MS Memory Limit: 10000K Description BIT has recently taken delivery of their new sup ...
- MPI之求和
// MPI1.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include "mpi.h" #include &l ...
- VS2012下配置MPI
并行处理结课实验,要用到MPI编程,我的电脑和VS2012都是64位的,以为MPICH也得是64位才行,结果饶了很大的弯——配置正确,添加引用之后,仍然无法识别MPI函数. 后来换了个32位的MPIC ...
- MPI+WIN10并行试运行
系统:2015 win10专业版 x64 MPI安装包:mpich2-1.4.1p1-win-x86-64.man 将后缀改为.msi 以管理员身份安装 安装过程一路默认,注意<behappy为 ...
- Parallel Computing–Cannon算法 (MPI 实现)
原理不解释,直接上代码 代码中被注释的源程序可用于打印中间结果,检查运算是否正确. #include "mpi.h" #include <math.h> #includ ...
- 基于MPI的并行计算—矩阵向量乘
以前没接触过MPI编程,对并行计算也没什么了解.朋友的期末课程作业让我帮忙写一写,哎,实现结果很一般啊.最终也没完整完成任务,惭愧惭愧. 问题大概是利用MPI完成矩阵和向量相乘.输入:Am×n,Bn× ...
- 大数据并行计算利器之MPI/OpenMP
大数据集群计算利器之MPI/OpenMP ---以连通域标记算法并行化为例 1 背景 图像连通域标记算法是从一幅栅格图像(通常为二值图像)中,将互相邻接(4邻接或8邻接)的具有非背景值的像素集合提取出 ...
- C++程序中调用MPI并行的批处理命令
问题来源:在使用MPI时,将程序并行实现了,运行时需要在dos窗口下输入批处理命令,以完成程序的执行. 如:mpiexec -localroot -n 6 d:/mpi/pro.exe 但每次这样挺麻 ...
随机推荐
- JavaScript 之call , apply 和prototype 介绍
1. 前言 为什么将这三个概念放在一起说.原因是这些是会在实现js 继承会需要使用到的 2. call 和 apply call 和 apply 的作用基本类似, 都是去执行function并将这个f ...
- 斐波那契数列的5种python实现写法
斐波那契数列的5种python写法 斐波那契数列(Fibonacci sequence),又称黄金分割数列.因数学家列昂纳多·斐波那契(Leonardoda Fibonacci)以兔子繁殖 ...
- JAVA解压文件
package com.chauvet.utils; import java.io.File; import java.io.FileOutputStream; import java.io.IOEx ...
- centos7下安装momgodb3
简介 MongoDB 是一个基于分布式 文件存储的NoSQL数据库 由C++语言编写,运行稳定,性能高 旨在为 WEB 应用提供可扩展的高性能数据存储解决方案 查看官方网站 MongoDB特点 模式自 ...
- POJ3276(遍历+区间修改)
http://poj.org/problem?id=3276 题意:n(n<=5000)头牛站成线,有朝前有朝后的的,然后每次可以选择大小为k的区间里的牛全部转向,会有一个最小操作m次使得它们全 ...
- javascript的单例模式
单例模式是javascript最基本,最有用的模式之一,它提供了一种将代码组织为一个逻辑单元的手段,这个逻辑单元中的代码通过单一的变量进行访问.我的理解是在这个作用域中,只有通过单一的变量来访问,不存 ...
- test20180921 手机信号
题意 分析 我们用形如(l, r, v) 的三元组描述一个区间,这个区间中从l 到r 每隔v 有一个信号站. 考虑一次construct 操作,会添加一个新的区间,并可能将一个已经存在的区间分裂为两个 ...
- Jmeter之JDBC
jdbc:mysql://ip:3306/test?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true
- ResourceBundle介绍
介绍: ResourceBundle类主要作用是读取属性文件,读取属性文件时可以直接指定属性文件的名称(指定名称时不需要文件的后缀),也可以根据Locale所指定的区域码来选取指定的资源文件: Res ...
- bzoj 4650(洛谷 1117) [Noi2016]优秀的拆分——枚举长度的关键点+后缀数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4650 https://www.luogu.org/problemnew/show/P1117 ...