博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MPI笔记:派生数据类型
阅读量:4137 次
发布时间:2019-05-25

本文共 9421 字,大约阅读时间需要 31 分钟。

派生数据类型

原理

目的

  • 传递含有不同数据类型值的信息(例如:int-float)
  • 传递非连续数据的用户(例如:矩阵的一个子块)

方法

  • 在发送端将非连续的数据打包到一个连续的缓冲区,在接收端再解包(缺点:接收端和发送端都需要额外的内存和内存拷贝操作)

类型图——通用的数据类型表述方法

  • 类型图:是一系列二元数组的集合,两个数据类型是否相同,取决于它们的类型图是否相同。将类型图和一个数据缓冲区的基地值结合起来,可以说明一个通信缓冲区的数据分布情况。

类型图={<基类型0, 偏移0>, <基类型1, 偏移1>, <基类型2, 偏移2>,…,<基类型n-1, 偏移n-1>}

基类型:指出该类型图中包含哪些基本的数据类型
偏移:指该基类型在整个类型图中的起始位置
例子:MPI_INT := {(int, 0)}

在这里插入图片描述

  • 类型图的相关量:

类型图:

typemap={( t y p e 0 type_0 type0, d i s p 0 disp_0 disp0),…,( t y p e n − 1 type_{n-1} typen1, d i s p n − 1 disp_{n-1} dispn1)}
类型图下界:
lb(typemap)=min{
d i s p j disp_j dispj}, 0 ≤ \leq j ≤ \leq n-1
类型图上界:
ub(typemap)=max{
d i s p j disp_j dispj+sizeof( t y p e j type_j typej)}, 0 ≤ \leq j ≤ \leq n-1
类型图的跨度:
extent(typemap)=ub(typemap)-lb(typemap)+ ϵ \epsilon ϵ
ϵ \epsilon ϵ: 由于不同的类型有不同的对其位置要求,是能够使类型图的跨度,满足类型图中所有的类型能达到下一个对齐要求,所需要的最小非负整数值
例子:
type={(double,0),(char,8)};假设double型的值必须严格分配到地址为8的倍数的存储空间,则该数据类型的extent是16

新数据类型的定义

连续复制的类型生成

  • 数据类型生成器:int MPI_Type_contiguous(int count,MPI_Datatype oldtype,MPI_Datatype *newtype)

IN count:复制个数(非负整数)

IN oldtype:旧数据类型(句柄)
OUT newtype:新数据类型(句柄)
RETURN int:返回1,0标志操作是否成功的

  • 例子:
    oldtype={(double,0),(char,8)}
    extent=16
    count=3
    MPI_TYPE_CONTIGUOUS返回的新的数据类型为:
    newtype={(double,0),(char,8),(double,16),(char,24),(double,32),(char,40)}

在这里插入图片描述

  • 更通用的表达:
    设旧类型oldtype的类型图为
    oldtype={( t y p e 0 type_0 type0, d i s p 0 disp_0 disp0),…,( t y p e n − 1 type_{n-1} typen1, d i s p n − 1 disp_{n-1} dispn1)},其跨度为extent=ex.
    新类型newtype将oldtype连续复制count次,则新类型newtype的类型图为

newtype={( t y p e 0 type_0 type0, d i s p 0 disp_0 disp0),…,( t y p e n − 1 type_{n-1} typen1, d i s p n − 1 disp_{n-1} dispn1),

( t y p e 0 type_0 type0, d i s p 0 + e x disp_0+ex disp0+ex),…,( t y p e n − 1 type_{n-1} typen1, d i s p n − 1 + e x disp_{n-1}+ex dispn1+ex),
…,
( t y p e 0 type_0 type0, d i s p 0 + e x ( c o u n t − 1 ) disp_0+ex(count-1) disp0+ex(count1)),…,( t y p e n − 1 type_{n-1} typen1, d i s p n − 1 + e x ( c o u n t − 1 ) disp_{n-1}+ex(count-1) dispn1+ex(count1))}
其类型的跨度为 c o u n t × e x count \times ex count×ex

向量数据类型的生成

  • 数据类型生成器1: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:新数据类型(句柄)

  • 数据类型生成器2:int MPI_Type_hvector(int count,int blocklength,int stride,MPI_Datatype oldtype,MPI_Datatype *newtype)

IN count:块的数目(非负整数)

IN blocklength:每个块中所含元素的个数(非负整数)
IN stride:各块第一个元素之间相隔的字节数(整数)
IN oldtype:旧数据类型(句柄)
OUT newtype:新数据类型(句柄)

  • 例子:
    oldtype={(double,0),(char,8)},extent=16
  1. MPI_TYPE_VECTOR(2,3,4,oldtype,newtype)生成的数据类型的类型图为:
    newtype={(double,0),(char,8),(double,16),(char,24),(double,32),(char,40),(double,64),(char 72),(double,80),(char,88),(double,96),(char,104)}

在这里插入图片描述

  1. MPI_TYPE_VECTOR(3,1,-2,oldtype,newtype)生成的数据类型的类型图为:
    newtype={(double,0),(char,8),(double,-32),(char,-24),(double,-64),(char,-56)}
  • 更通用的表达:
    假设oldtype={( t y p e 0 type_0 type0, d i s p 0 disp_0 disp0),…,( t y p e n − 1 type_{n-1} typen1, d i s p n − 1 disp_{n-1} dispn1)},其跨度extent=ex.
    设blocklength=bl,新建的数据类型有count*bl个入口项,类型图为:

block(offset)= { ( t y p e 0 , d i s p 0 + o f f s e t ) , . . . , ( t y p e n − 1 , d i s p n − 1 + o f f s e t ) , \{(type_0,disp_0+offset),...,(type_{n-1},disp_{n-1}+offset), {

(type0,disp0+offset),...,(typen1,dispn1+offset),
( t y p e 0 , d i s p 0 + e x + o f f s e t ) , . . . , ( t y p e n − 1 , d i s p n − 1 + e x + o f f s e t ) , (type_0,disp_0+ex+offset),...,(type_{n-1},disp_{n-1}+ex+offset), (type0,disp0+ex+offset),...,(typen1,dispn1+ex+offset),
. . . , ..., ...,
( t y p e 0 , d i s p 0 + e x ( b l − 1 ) + o f f s e t ) , . . . , ( t y p e n − 1 , d i s p n − 1 + e x ( b l − 1 ) + o f f s e t ) } (type_0,disp_0+ex(bl-1)+offset),...,(type_{n-1},disp_{n-1}+ex(bl-1)+offset)\} (type0,disp0+ex(bl1)+offset),...,(typen1,dispn1+ex(bl1)+offset)}
newtype= { b l o c k ( 0 ) , b l o c k ( s t r i d e ) , . . . , b l o c k ( s t r i d e ∗ ( c o u n t − 1 ) ) } \{block(0),block(stride),...,block(stride*(count-1))\} {
block(0),block(stride),...,block(stride
(count1))}

  • 注:MPI_TYPE_CONTIGUOUS(count,oldtype,newtype)等价于MPI_TYPE_VECTOR(count,1,1,oldtype,newtype)MPI_TYPE_VECTOR(1,count,n,oldtype,newtype)(n为升序)

索引数据类型的生成

  • 类型生成器1:int MPI_Type_indexed(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 newtype:新数据类型

  • 类型生成器2:int MPI_Type_hindexed(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:新数据类型

  • 例子:
    设oldtype= { ( d o u b l e , 0 ) , ( c h a r , 8 ) } \{(double,0),(char,8)\} {
    (double,0),(char,8)}
    ,extent=16,B=(3,1),D=(4,0),
    MPI_TYPE_INDEXED(2,B,D,oldtype,newtype)调用生成的数据类型图为:
    newtype={(double,64),(char,72),(double,80),(char,88),(double,96),(char,104),(double,0),(char,8)}

在这里插入图片描述

结构数据类型

  • 类型生成器: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:新数据类型(句柄)

  • 例子:
    设type1={(double,0),(char,8)},extent=16,B=(2,1,3),D=(0,16,26),T=(MPI_FLOAT,type1,MPI_CHAR).则MPI_TYPE_STRUCT(3,B,D,T,newtype)返回的新数据类型为:
    newtype={(float,0),(float,4),(double,16),(char,24),(char,26),(char,27),(char,28)}

在这里插入图片描述

  • 注:MPI_TYPE_HINDEXED(count,B,D,oldtype,newtype)等价于MPI_TYPE_STRUCT(count,B,D,T,newtype),其中T的每一项都是oldtype

新类型的交替和释放

新定义的数据类型在使用之前,必须先递交给MPI系统.递交之后的数据类型可以作为一个基本数据类型,用在数据类型生成器中产生新的数据类型.

  • 递交操作:int MPI_Type_commit(MPI_Datatype *datatype)

递交作用用于定义新的数据类型

  • 释放操作:int MPI_Type_free(MPI_Datatype *datatype)

释放操作用于释放已提交的数据类型,并且将该数据类型的指针或句柄设为空MPI_DATATYPE_NULL.由该派生类型定义的新派生类型不受当前派生类型释放的影响.

与数据类型相关的调用

  • int MPI_Type_extent(MPI_Datatype datatype, int *extent)

IN datatype:数据类型(句柄)

OUT extent:数据类型的extent(整型)
作用:MPI_TYPE_EXTENT以字节为单位返回一个数据类型的跨度extent

  • int MPI_Type_size(MPI_Datatype datatype, int *size)

IN datatype:数据类型(句柄)

OUT size:数据类型的大小(整型)
作用:MPI_TYPE_SIZE以字节为单位,返回一个数据类型有用部分所占空间的大小,即跨度减去类型中空隙后的空间的大小.

  • int MPI_Get_elements(MPI_Status status, MPI_Datatype datatype, int *count)

IN status:接受操作后返回的状态(状态类型)

IN datatype:接受操作后使用的数据类型(句柄)
OUT count:接收到的基本元素个数
作用:MPI_GET_ELEMENTS返回以基本数据类型为单位的个数

  • int MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int *int)

IN status:接受操作后返回的状态(状态类型)

IN datatype:接受操作后使用的数据类型(句柄)
OUT count:接受到的以指定的数据类型为单位的数据个数(整型)
MPI_GET_COUNT返回的是以指定的数据类型为单位,接受操作接收到的数据个数.

下界标记类型和上界标记类型

上下界标记类型的定义

MPI提供两个特殊的数据类型,称为伪数据类型,上界标记类型MPI_UB和下界标记类型MPI_LB.这两个数据类型不占空间,即extent(MPI_LB)=extent(MPI_UB)=0.

  • typemap的下界: l b ( T y p e m a p ) = { m i n j d i s p j 不 包 含 l b 类 型 m i n j { d i s p j ∣ t y p e j = l b } 若 含 有 l b 类 型 lb(Typemap) = \begin{cases} min_j disp_j \quad不包含lb类型 \\ min_j \{disp_j | type_j=lb\} \quad 若含有lb类型 \end{cases} lb(Typemap)={

    minjdispjlbminj{
    dispjtypej=lb}lb

  • typemap的上界: u b ( T y p e m a p ) = { m a x j d i s p j + s i z e o f ( t y p e j ) + ϵ 不 包 含 u b 类 型 m a x j { d i s p j ∣ t y p e j = u b } 若 含 有 u b 类 型 ub(Typemap) = \begin{cases} max_j disp_j+sizeof(type_j)+\epsilon \quad不包含ub类型 \\ max_j \{disp_j | type_j=ub\} \quad 若含有ub类型 \end{cases} ub(Typemap)={

    maxjdispj+sizeof(typej)+ϵubmaxj{
    dispjtypej=ub}ub

  • 数据类型typemap的跨度:

    e x t e n t ( t y p e m a p ) = u b ( t y p e m a p ) − l b ( t y p e m a p ) extent(typemap)=ub(typemap)-lb(typemap) extent(typemap)=ub(typemap)lb(typemap)

上下界标记类型的定义函数

  • 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:上界的位移(整数)

  • 例子:
    D=(-3,0,6);T=(MPI_LB,MPI_INT,MPI_UB);B=(1,1,1),则MPI_TYPE_STRUCT(3,B,D,T,type1)产生了一个extent=9的数据类型
    type1={(lb,-3),(int,0),(ub,6)}.如果该数据类型被MPI_TYPE_COUNTIGUOUS(2,type1,type2)复制两次,则新生成的序列为
    type2={(lb,3),(int,0),(int,9),(ub,15)}
    (如果lb或者ub出现在数据类型两端以外的位置,则它们可以被忽略)

打包和解包

打包和解包操作是为了发送不连续的数据,在发送前显式地把数据包装到一个连续的缓冲区,在接收之后从连续缓冲区中解包.

  • 打包:
    int MPI_Pack(void *inbuf, int incount, MPI_Datatype 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:打包的信息的通信域

  • 打包数据所需的空间:
    int MPI_Pack_size(int incount, MPI_Datatype datatype, MPI_Comm comm, int *size)

IN incount:指定数据类型的个数

IN datatype:数据类型
IN comm:通信域
OUT size:以字节为单位,incount个datatype数据类型打包需要的空间

  • 例子:
int position, i, j, a[2];char buff[1000];MPI_Comm_rank(MPI_COMM_WORLD, &myrank);// 进程0发送信息if(myrank==0){   position=0; // 打包的起始位置   MPI_Pack(&i, 1, MPI_INT, buff, 1000, &position, MPI_COMM_WORLD);// 将整数i打包   MPI_Pack(&j, 1, MPI_INT, buff, 1000, &position, MPI_COMM_WORLD);   // 将整数j打包   MPI_Send(buff, position, MPI_PACKED, 1, 0, MPI_COMM_WORLD);   // 将打包后的数据发送出去}else if(myrank==1){    MPI_Recv(a, 2, MPI_INT, 0, 0, MPI_COMM_WORLD);    // 以整型从进程0接收消息}

参考文献:《MPI并行程序设计》链接: https://pan.baidu.com/s/1mVKWmzc8AHT1Crxa5ZWArQ 密码: c49v

转载地址:http://hvxvi.baihongyu.com/

你可能感兴趣的文章
HDU 1579 Function Run Fun(记忆化搜索)
查看>>
HDU 1574 RP问题(01背包变形)
查看>>
HDU 5246 超级赛亚ACMer(贪心模拟)
查看>>
HDU 5247 找连续数(暴力)
查看>>
HDU 5256 序列变换(最长上升子序列)
查看>>
HDU 4841 圆桌问题(约瑟夫环队列模拟)
查看>>
HDU 1172 猜数字(暴力)
查看>>
HDU 1495 非常可乐(bfs+标记)
查看>>
HDU 2569 彼岸(递推)
查看>>
HDU 4503 湫湫系列故事——植树节(组合概率)
查看>>
HDU 4500 小Q系列故事——屌丝的逆袭(模拟枚举排序)
查看>>
HDU 4501 小明系列故事——买年货(三重背包)
查看>>
Php连接mysql实现注册信息和文件上传
查看>>
HDU 5253 连接的管道(最小生成树-Kruskal+并查集)
查看>>
HDU 5249 KPI(set+queue+二分查找)(转载)
查看>>
HDU 4502 吉哥系列故事——临时工计划(dp)
查看>>
Web Service调用
查看>>
微信公众号后台java开发实现自动回复机器人
查看>>
linux下shell显示-bash-4.1#不显示路径解决方法
查看>>
设计模式--单例模式
查看>>