您的位置:首页 > 其它

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 的偏移(整型)


与数据类型有关的调用


1. 返回一个数据类型的范围

以字节为单位返回一个数据类型的跨度extent

int 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数据类型需要的空间的大小。该调用返回的是上界, 而不是一个精确界,这是因为包装一个消息所需要的精确空间可能依赖于上下文。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐