MPI学习六 具有不连续数据发送的MPI程序设计
2017-02-27 20:09
288 查看
处理不连续的数据基本方法
一是允许用户自定义新的数据类型 又称派生数据类型
二是数据的打包与解包
数据类型描述方法--类型图
类型图的二元组为如下形式 <基类型 偏移>,则类型图为
类型图={<基类型0 偏移0>,<基类型1 偏移1>,...,<基类型n-1 偏移n-1>}
基类型可以是预定义类型或派生类型
偏移可正可负,没有递增或递减的顺序要求。
数据类型的跨度被定义为该数据类型的类型图中从第一个基类型到最后一个基类型间的距离。
即如果某一个类型的类型图为
typemap={ (type0,disp0), ..., (typen-1,dispn-1)
},
则该类型图的下界定义为
lb(typemap)=min { dispj }, 0 =< j <= n-1
则该类型图的上界定义为
ub(typemap)=max (dispj+sizeof(typej)
), 0 =< j <= n-1
该类型图的跨度定义为
extent(typemap)=ub( typemap )-lb( typemap )+e
由于不同的类型有不同的对齐位置的要求, e 就是能够使类型图的跨度满足该类型的类型表中的所有的类型都能达到下一个对齐要求所需要的最小非负整数值。
得到的新类型是将一个已有的数据类型按顺序依次连续进行复制后的结果
int MPI_Type_contiguous(int count, MPI_Datatype oldtype, MPI_Datatype *newtype)
IN count 复制个数(非负整数)
IN oldtype 旧数据类型
OUT newtype 新数据类型
允许复制一个数据类型到含有相等大小块的空间 每个块通过连接相同数量的旧数据类型的拷贝来获得。块与块之间的空间是旧数据类型的extent的倍数
int MPI_Type_vector(int count,int blocklength, int stride, MPI_Datatype oldtype, MPI_Datatype *newtype)
IN count 块的数量(非负整数)
IN blocklength 每个块中所含元素个数(非负整数)
IN stride 各块第一个元素之间相隔的元素个数(整数)
IN oldtype 旧数据类型
OUT newtype新数据类型
函数 MPI_Type_hvector 和 MPI_Type_vector 基本相同,只是 stride 不再是元素个数,而是字节数
int MPI_Type_hvector(int count,int blocklength,MPI_Aint stride,MPI_Datatype oldtype, MPI_Datatype *newtype)
IN count 块的数量(非负整数)
IN blocklength 每个块中所含元素个数(非负整数)
IN stride 各块起始位置之间相隔的字节数(整数)
IN oldtype 旧数据类型
OUT newtype 新数据类型
允许复制一个旧数据类型到一个块序列中(每个块是旧数据类型的一个连接),每个块可以包含不同的拷贝数目和具有不同的偏移.所有的块偏移都是旧数据类型extent的倍数
int MPI_Type_indexed(int count, int array_of_blocklengths, int array_of_displacements, MPI_Datatype oldtype, MPI_Datatype *newtype)
IN count 块的数量 整型
IN array_of_blocklengths 每个块中所含元素个数(非负整数数组)
IN array_of_displacements 各块偏移值 (整数数组)
IN oldtype 旧数据类型
OUT newtype新数据类型
函数 MPI_Type_hindexed 和 MPI_Type_indexed 基本相同,只是 array_of_displacements 中的块偏移不再是旧数据类型 extent 的倍数,而是字节数
int MPI_Type_hindexed(int count,int array_of_blocklengths, MPI_Aint array_of_displacements, MPI_Datatype oldtype, MPI_Datatype *newtype)
IN count 块的数量 (整数)
IN array_of_blocklengths 每个块中所含元素个数(非负整数数组)
IN array_of_displacements 各块偏移字节数(整数数组)
IN oldtype 旧数据类型
OUT newtypr 新数据类型
能够在上面介绍的基础上进一步允许每个块包含不同数据类型的拷贝
int MPI_Type_struct(int count, int *array_of_blocklengths, MPI_Aint *array_of_displacements, MPI_Datatype array_of_types , MPI_Datatype *newtype)
IN count 块的数量 (整数)
IN array_of_blocklengths 每个块中所含元素个数(整数数组)
IN array_of_displacements 各块偏移字节数(整数数组)
IN array_of_types 每个块中元素的类型(句柄数组)
OUT newtype 新数据类型
新定义的数据类型在使用之前 必须先递交给MPI系统 一个递交后的数据类型 可以作为一个基本类型 用在数据类型生成器中产生新的数据类型。
int MPI_Type_commit(MPI_Datatype *datatype)
递交操作用于递交新定义的数据类型。注意这里的参数是指向该类型的指针,而不是定义该类型的缓冲区的内容。
int MPI_Type_free(MPI_Datatype *datatype)
MPI_TYPE_FREE调用将以前已递交的数据类型释放,并且设该数据类型指针为空MPI_DATATYPE_NULL,由该派生类型定义的新派生类型不受当前派生类型释放的影响
构造MPI派生类型时候,需要指定每个基类型相对于派生类型起始地址(MPI_BOTTOM)的偏移量。可以通过人工设定,MPI提供地址调用函数 MPI_Address, 可以返回某一个基类型在内存中相对于派生类型起始地址的偏移。
int MPI_Address(void* location, MPI_Aint *address)
IN location 内存地址(可选数据类型)
OUT address 相对于位置 MPI_BOTTOM 的偏移(整型)
以字节为单位返回一个数据类型的跨度extent
int MPI_Type_extent(MPI_Datatype datatype, int *extent)
IN datatype 数据类型
OUT extent 数据类型extent(整型)
以字节为单位 返回给定数据类型有用部分所占空间的大小,即跨度减去类型中的空隙后的空间大小
int MPI_Type_size(MPI_Datatype datatype, int *size)
IN datatype 数据类型(句柄)
OUT size 数据类型大小(整型)
和 MPI_Type_extent 相比 MPI_Type_size 不包括由于对齐等原因导致数据类型中的空隙所占的空间
返回的则是以给定数据类型中基本类型为单位的数据的个数
int MPI_Get_elements( MPI_Status status, MPI_Datatype datatype, int *count)
IN status 接收操作返回的状态(状态类型)
IN datatype 接收操作使用的数据类型
OUT count 接收到的基本元素个数(整型)
返回的是以给定数据类型中为单位,接收操作接收到的数据的个数。
int MPI_Get_count(MPI_Status * status, MPI_Datatype datatype, int * count)
IN status 接收操作返回的状态(状态类型)
IN datatype 接收操作使用的数据类型
OUT count 接收到的以指定的数据类型为单位的数据个数(整型)
伪数据类型:上界标记类型MPI_UB和下界标记类型MPI_LB。
这两个数据类型不占空间,即extent(MPI_LB)= extent(MPI_UB) =0), 他们主要是用来影响数据类型的跨度 从而对派生数据类型产生影响。
int MPI_Type_lb (MPI_Datatype datatype, int *displacement)
IN datatype 数据类型
OUT displacement 下界的偏移(整数)
int MPI_Type_ub (MPI_Datatype datatype, int *displacement)
IN datatype 数据类型
OUT displacement 上界的偏移(整数)
打包和解包操作是为了发送不连续的数据在发送前显式地把数据包装到一个连续的缓冲区,在接收之后从连续缓冲区中解包。
int MPI_Pack(void* inbuf, int incount, MPI_datatype, void *outbuf, int outcount, int *position, MPI_Comm comm)
IN inbuf 输入缓冲区起始地址(可选数据类型)
IN incount 输入数据项个数(整型)
IN datatype 每个输入数据项的类型
OUT outbuf 输出缓冲区开始地址(可选数据类型)
IN outcount 输出缓冲区大小(整型)
INOUT position 缓冲区当前位置(整型)
IN comm 通信域
int MPI_Unpack(void* inbuf, int insize, int *position, void *outbuf, int outcount, MPI_Datatype datatype, MPI_Comm comm)
IN inbuf 输入缓冲区起始(选择)
IN insize 输入数据项数目(整型)
INOUT position 缓冲区当前位置, 字节(整型)
OUT outbuf 输出缓冲区开始(选择)
IN outcount 输出缓冲区大小, 字节(整型)
IN datatype 每个输入数据项的类型
IN comm 打包的消息的通信域
一个打包单元可以用MPI_PACKED作为类型发送,发送类型可以是任何点到点通信或者组通信调用。用MPI_PACKED发送的数据可以用任意数据类型来接收, 只要它和实际接收到的消息的数据类型相匹配,以任何类型发送的消息(包括MPI_PACKED类型)都可以用MPI_PACKED类型接收。这样的消息于是就可以被调用MPI_UNPACK来解包。
int MPI_Pack_size(int incount, MPI_Datatype datatype, MPI_Comm comm, int *size)
IN incount 指定数据类型的个数(整型)
IN datatype 数据类型
IN comm 通信域
OUT size 以字节为单位 incount个datatype数据类型需要的空间(整型)
MPI_Pack_size 调用的返回值是size,表示incount个datatype数据类型需要的空间的大小。该调用返回的是上界, 而不是一个精确界,这是因为包装一个消息所需要的精确空间可能依赖于上下文。
一是允许用户自定义新的数据类型 又称派生数据类型
二是数据的打包与解包
派生数据类型
数据类型描述方法--类型图 类型图的二元组为如下形式 <基类型 偏移>,则类型图为
类型图={<基类型0 偏移0>,<基类型1 偏移1>,...,<基类型n-1 偏移n-1>}
基类型可以是预定义类型或派生类型
偏移可正可负,没有递增或递减的顺序要求。
数据类型的跨度被定义为该数据类型的类型图中从第一个基类型到最后一个基类型间的距离。
即如果某一个类型的类型图为
typemap={ (type0,disp0), ..., (typen-1,dispn-1)
},
则该类型图的下界定义为
lb(typemap)=min { dispj }, 0 =< j <= n-1
则该类型图的上界定义为
ub(typemap)=max (dispj+sizeof(typej)
), 0 =< j <= n-1
该类型图的跨度定义为
extent(typemap)=ub( typemap )-lb( typemap )+e
由于不同的类型有不同的对齐位置的要求, e 就是能够使类型图的跨度满足该类型的类型表中的所有的类型都能达到下一个对齐要求所需要的最小非负整数值。
新数据类型的定义
连续复制的类型生成
得到的新类型是将一个已有的数据类型按顺序依次连续进行复制后的结果
函数接口:
int MPI_Type_contiguous(int count, MPI_Datatype oldtype, MPI_Datatype *newtype) IN count 复制个数(非负整数)
IN oldtype 旧数据类型
OUT newtype 新数据类型
向量数据类型的生成
允许复制一个数据类型到含有相等大小块的空间 每个块通过连接相同数量的旧数据类型的拷贝来获得。块与块之间的空间是旧数据类型的extent的倍数
函数接口:
int MPI_Type_vector(int count,int blocklength, int stride, MPI_Datatype oldtype, MPI_Datatype *newtype) IN count 块的数量(非负整数)
IN blocklength 每个块中所含元素个数(非负整数)
IN stride 各块第一个元素之间相隔的元素个数(整数)
IN oldtype 旧数据类型
OUT newtype新数据类型
函数 MPI_Type_hvector 和 MPI_Type_vector 基本相同,只是 stride 不再是元素个数,而是字节数
int MPI_Type_hvector(int count,int blocklength,MPI_Aint stride,MPI_Datatype oldtype, MPI_Datatype *newtype)
IN count 块的数量(非负整数)
IN blocklength 每个块中所含元素个数(非负整数)
IN stride 各块起始位置之间相隔的字节数(整数)
IN oldtype 旧数据类型
OUT newtype 新数据类型
索引数据类型的生成
允许复制一个旧数据类型到一个块序列中(每个块是旧数据类型的一个连接),每个块可以包含不同的拷贝数目和具有不同的偏移.所有的块偏移都是旧数据类型extent的倍数
函数接口:
int MPI_Type_indexed(int count, int array_of_blocklengths, int array_of_displacements, MPI_Datatype oldtype, MPI_Datatype *newtype) IN count 块的数量 整型
IN array_of_blocklengths 每个块中所含元素个数(非负整数数组)
IN array_of_displacements 各块偏移值 (整数数组)
IN oldtype 旧数据类型
OUT newtype新数据类型
函数 MPI_Type_hindexed 和 MPI_Type_indexed 基本相同,只是 array_of_displacements 中的块偏移不再是旧数据类型 extent 的倍数,而是字节数
int MPI_Type_hindexed(int count,int array_of_blocklengths, MPI_Aint array_of_displacements, MPI_Datatype oldtype, MPI_Datatype *newtype)
IN count 块的数量 (整数)
IN array_of_blocklengths 每个块中所含元素个数(非负整数数组)
IN array_of_displacements 各块偏移字节数(整数数组)
IN oldtype 旧数据类型
OUT newtypr 新数据类型
结构数据类型的生成
能够在上面介绍的基础上进一步允许每个块包含不同数据类型的拷贝
函数接口:
int MPI_Type_struct(int count, int *array_of_blocklengths, MPI_Aint *array_of_displacements, MPI_Datatype array_of_types , MPI_Datatype *newtype) IN count 块的数量 (整数)
IN array_of_blocklengths 每个块中所含元素个数(整数数组)
IN array_of_displacements 各块偏移字节数(整数数组)
IN array_of_types 每个块中元素的类型(句柄数组)
OUT newtype 新数据类型
新类型递交和释放
新定义的数据类型在使用之前 必须先递交给MPI系统 一个递交后的数据类型 可以作为一个基本类型 用在数据类型生成器中产生新的数据类型。int MPI_Type_commit(MPI_Datatype *datatype)
递交操作用于递交新定义的数据类型。注意这里的参数是指向该类型的指针,而不是定义该类型的缓冲区的内容。
int MPI_Type_free(MPI_Datatype *datatype)
MPI_TYPE_FREE调用将以前已递交的数据类型释放,并且设该数据类型指针为空MPI_DATATYPE_NULL,由该派生类型定义的新派生类型不受当前派生类型释放的影响
地址函数
构造MPI派生类型时候,需要指定每个基类型相对于派生类型起始地址(MPI_BOTTOM)的偏移量。可以通过人工设定,MPI提供地址调用函数 MPI_Address, 可以返回某一个基类型在内存中相对于派生类型起始地址的偏移。int MPI_Address(void* location, MPI_Aint *address)
IN location 内存地址(可选数据类型)
OUT address 相对于位置 MPI_BOTTOM 的偏移(整型)
与数据类型有关的调用
1. 返回一个数据类型的范围
以字节为单位返回一个数据类型的跨度extentint MPI_Type_extent(MPI_Datatype datatype, int *extent)
IN datatype 数据类型
OUT extent 数据类型extent(整型)
2. 返回给定数据类型的大小
以字节为单位 返回给定数据类型有用部分所占空间的大小,即跨度减去类型中的空隙后的空间大小int MPI_Type_size(MPI_Datatype datatype, int *size)
IN datatype 数据类型(句柄)
OUT size 数据类型大小(整型)
和 MPI_Type_extent 相比 MPI_Type_size 不包括由于对齐等原因导致数据类型中的空隙所占的空间
3. 返回给定数据类型中基本元素的个数
返回的则是以给定数据类型中基本类型为单位的数据的个数int MPI_Get_elements( MPI_Status status, MPI_Datatype datatype, int *count)
IN status 接收操作返回的状态(状态类型)
IN datatype 接收操作使用的数据类型
OUT count 接收到的基本元素个数(整型)
4. 得到以给定数据类型为单位的数据的个数
返回的是以给定数据类型中为单位,接收操作接收到的数据的个数。int MPI_Get_count(MPI_Status * status, MPI_Datatype datatype, int * count)
IN status 接收操作返回的状态(状态类型)
IN datatype 接收操作使用的数据类型
OUT count 接收到的以指定的数据类型为单位的数据个数(整型)
MPI_Type_contiguous(2, MPI_REAL, Type2);
// 定义新类型
MPI_Type_commit(Type2);
...
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if(rank == 0)
{
MPI_Send(a, 2, MPI_REAL, 1, 0, MPI_COMM_WORLD);
// 向进程1发送2个实型数据
MPI_Send(a, 3, MPI_REAL, 1, 0, MPI_COMM_WORLD);
// 再向进程1发送3个实型数据
}
else
{
MPI_Recv(a, 2, Type2, 0, 0, MPI_COMM_WORLD, &stat);
// 从进程0接收Type2类型的数据
MPI_Get_count(&stat, Type2, &i);
// 计算收到的Type2类型数据的个数 这里i=1
MPI_Get_elements(&stat, Type2, &i);
// 计算按基本类型REAL计算收到的数据的个数 这里i=2
MPI_Recv(a, 2, Type2, 0, 0, MPI_COMM_WORLD, &stat)
// 再从进程0接收数据
MPI_Get_count(&stat, Type2, &i);
// 计算按Type2类型计算收到的数据的个数 这里i=MPI_UNDEFINED
// 因为3个REAL类型无法用Type2类型来度量
MPI_Get_elements(&stat, Type2, &i)
// 计算按基本类型REAL计算收到的数据的个数 这里i=3
}
下界标记类型和上界标记类型
伪数据类型:上界标记类型MPI_UB和下界标记类型MPI_LB。 这两个数据类型不占空间,即extent(MPI_LB)= extent(MPI_UB) =0), 他们主要是用来影响数据类型的跨度 从而对派生数据类型产生影响。
int MPI_Type_lb (MPI_Datatype datatype, int *displacement)
IN datatype 数据类型
OUT displacement 下界的偏移(整数)
int MPI_Type_ub (MPI_Datatype datatype, int *displacement)
IN datatype 数据类型
OUT displacement 上界的偏移(整数)
打包(Pack)和解包(Unpack)
打包和解包操作是为了发送不连续的数据在发送前显式地把数据包装到一个连续的缓冲区,在接收之后从连续缓冲区中解包。int MPI_Pack(void* inbuf, int incount, MPI_datatype, void *outbuf, int outcount, int *position, MPI_Comm comm)
IN inbuf 输入缓冲区起始地址(可选数据类型)
IN incount 输入数据项个数(整型)
IN datatype 每个输入数据项的类型
OUT outbuf 输出缓冲区开始地址(可选数据类型)
IN outcount 输出缓冲区大小(整型)
INOUT position 缓冲区当前位置(整型)
IN comm 通信域
int MPI_Unpack(void* inbuf, int insize, int *position, void *outbuf, int outcount, MPI_Datatype datatype, MPI_Comm comm)
IN inbuf 输入缓冲区起始(选择)
IN insize 输入数据项数目(整型)
INOUT position 缓冲区当前位置, 字节(整型)
OUT outbuf 输出缓冲区开始(选择)
IN outcount 输出缓冲区大小, 字节(整型)
IN datatype 每个输入数据项的类型
IN comm 打包的消息的通信域
一个打包单元可以用MPI_PACKED作为类型发送,发送类型可以是任何点到点通信或者组通信调用。用MPI_PACKED发送的数据可以用任意数据类型来接收, 只要它和实际接收到的消息的数据类型相匹配,以任何类型发送的消息(包括MPI_PACKED类型)都可以用MPI_PACKED类型接收。这样的消息于是就可以被调用MPI_UNPACK来解包。
int MPI_Pack_size(int incount, MPI_Datatype datatype, MPI_Comm comm, int *size)
IN incount 指定数据类型的个数(整型)
IN datatype 数据类型
IN comm 通信域
OUT size 以字节为单位 incount个datatype数据类型需要的空间(整型)
MPI_Pack_size 调用的返回值是size,表示incount个datatype数据类型需要的空间的大小。该调用返回的是上界, 而不是一个精确界,这是因为包装一个消息所需要的精确空间可能依赖于上下文。
相关文章推荐
- 【MPI学习6】MPI并行程序设计模式:具有不连续数据发送的MPI程序设计
- 【MPI学习6】MPI并行程序设计模式:具有不连续数据发送的MPI程序设计
- 【MPI学习6】MPI并行程序设计模式:具有不连续数据发送的MPI程序设计
- [MPI] MPI具有不连续数据发送的程序设计
- [MPI] 具有不连续数据发送的MPI程序设计
- C# socket 实现客户端连续发送数据
- javascript高级程序设计(第三版)-第三章 数据类型-学习笔记
- [MPI] 具有虚拟进程拓扑的 MPI 程序设计
- MPI 学习 -- 高性能计算之并行编程技术 --- MPI并行程序设计 都志辉编著
- iOS学习,蓝牙,iOS设备模拟BLE发送数据
- TinyOS学习笔记8-简单发送接收数据
- MPI 学习 -- 高性能计算之并行编程技术 --- MPI并行程序设计 都志辉编著
- 【学习心得】面向对象的程序设计中静态数据成员以及静态成员函数在统计中的作用
- android学习之 向网络中发送 XML格式数据
- Ext JS4 学习笔记之发送表单(Form)时也将表单下的表格(Grid)数据一同发送的方法
- Delphi-IOCP学习笔记<八>=======服务端的数据发送和JSonStreamObject的编码器
- JavaScript高级程序设计(第3版)学习笔记3 js简单数据类型
- FPGA学习心得及(flash读写,+lwip+数据发送等问题)
- C#MPI 第三课 MPI 发送图像数据
- 黑马程序员--Java基础学习之网络编程(TCP、UDP、Socket、模拟发送和接收数据)