📄 mpi312.htm
字号:
<P><TT>IN oldtype 旧数据类型(句柄) </TT></P>
<P><TT>OUT newtypr 新数据类型(句柄) </TT></P>
</UL>
<P><TT>int MPI_Type_hindexed(int count,int *array_of_blocklengths, MPI_Aint
*array_of_displacements, MPI_Datatype oldtype, MPI_Datatype *newtype) </TT></P>
<P><TT>MPI_TYPE_HINDEXED(COUNT,ARRAY_OF_BLOCKLENGTHS,ARRAY_OF_DISPLACEMENTS,OLDTYPE,NEWTYPE,IERROR)
</TT></P>
<UL>
<P><TT>INTEGER COUNT, ARRAY_OF_BLOCKLENGTHS(*), ARRAY_OF_DISPLACEMENTS(*),
OLDTYPE, NEWTYPE, IERROR </TT></P>
</UL>
<P>假设oldtype的类型映像为 </P>
<UL>
<P>{(type0, disp0), (typen-1,dispn-1 )}, </P>
</UL>
<P>extent = ex. 设B为array_of_blocklengths参数,D为array_of_displacements参数.新创建的数据类型有n.SUM(B[i],i=0,...,count-1)项,类型映像为
</P>
<UL>
<P>{(type0, disp0+D[0]),..., (typen-1,dispn-1 +D[0]),..., </P>
<P>(type0, disp0+(D[0]+B[0]-1).ex),..., </P>
<P>(typen-1, dispn-1+D[0]+(B[0]-1).ex),..., </P>
<P>(type0, disp0+D[count-1]),..., (typen-1, dispn-1+D[count-1]),..., </P>
<P>(type0, disp0+D[count-1]+(B[count-1]-1).ex),..., </P>
<P>(typen-1, dispn-1+D[count-1]+(B[count-1]-1).ex.)}. </P>
</UL>
<P>Struct(结构) </P>
<P>MPI_TYPE_STRUCT是最通用的类型生成器,它能够在上面介绍的基础上进一步允许每个块包含不同数据类型的拷贝。
</P>
<P><TT>MPI_TYPE_STRUCT(count,array_of_blocklengths,array_of_displacemets,array_of_types,newtype)
</TT></P>
<UL>
<P><TT>IN count 块的数量--同时也是array_of_displacements ,array_of_types和
array_of_blocklengths 中的项数(整数) </TT></P>
<P><TT>IN array_of_blocklengths 每个块中所含元素个数(整数数组) </TT></P>
<P><TT>IN array_of_displacements 各块偏移字节数(整数数组) </TT></P>
<P><TT>IN array_of_types 每个块中元素的类型(数据类型目标的句柄数组) </TT></P>
<P><TT>OUT newtypr 新数据类型(句柄) </TT></P>
</UL>
<P><TT>int MPI_Type_struct(int count,int *array_of_blocklengths, MPI_Aint
*array_of_displacements, MPI_Datatype array_of_types , MPI_Datatype *newtype)
</TT></P>
<P><TT>MPI_TYPE_STRUCT(COUNT,ARRAY_OF_BLOCKLENGTHS,ARRAY_OF_DISPLACEMENTS,
ARRAY_OF_TYPES (*),NEWTYPE,IERROR) </TT></P>
<UL>
<P><TT>INTEGER COUNT, ARRAY_OF_BLOCKLENGTHS(*), ARRAY_OF_DISPLACEMENTS(*),ARRAY_OF_TYPES
(*),NEWTYPE, IERROR </TT></P>
</UL>
<P>例 3.23 设type1的类型映像为 </P>
<UL>
<P>{(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)返回: </P>
<P>{(float,0),(float,4),(double,16),(char,24),(char,26),(char,27),(char,28)}.
</P>
</UL>
<P>即两个起始于0的MPI_FLOAT拷贝后面跟一个起始于16的type1,再跟三个起始于26的MPI_CHAR拷贝.(我们假设一个浮点数占4个字节).
</P>
<P>一般地,假设T是array_of_types参数, T[i]是一个句柄,指向 </P>
<UL>
<P>typemapi ={(type0, disp0), (typen-1,dispn-1 )}, </P>
</UL>
<P>extent = ex. 设B为array_of_blocklengths参数,D为array_of_displacements参数.新创建的数据类型有n.SUM(B[i],i=0,...,count-1)项,类型映像为
</P>
<UL>
<P>{(type0, disp0+D[0].ex),..., (typen-1,dispn-1 +D[0].ex),..., </P>
<P>(type0, disp0+(D[0]+B[0]-1).ex),..., (typen-1, dispn-1+(D[0]+B[0]-1).ex),...,
</P>
<P>(type0, disp0+D[count-1].ex),..., (typen-1, dispn-1+D[count-1].ex),...,
</P>
<P>(type0, disp0+(D[count-1]+B[count-1]-1).ex),..., </P>
<P>(typen-1, dispn-1+(D[count-1]+B[count-1]-1).ex.)}. </P>
<P>MPI_TYPE_HINDEXED(count,B,D,oldtype,newtype)`等价于调用MPI_TYPE_STRUCT(count,
B, D, T, newtype),其中T的每一项都等于oldtype.. </P>
</UL>
<P><A NAME="3.12.2"></A></P>
<P>3.12.2 地址和扩充函数 </P>
<P>一个通用数据类型的偏移量是相对一些初始缓冲区地址的,这些偏移的绝对地址可以被替换掉:我们可以把它看作是零地址的相对偏移量.这个初始零地址是由常量MPI_BOTTOM指明的.这样,一个数据类型可以说明通信缓冲区内元素的绝对地址,这时buf参数传递的是MPI_BOTTOM的值.
</P>
<P>一个位置在内存中的地址可以通过调用MPI_ADRESS获得.</P>
<P><TT>MPI_ADDRESS(location,address)</TT></P>
<UL>
<P><TT>IN location 调用者内存位置(选择)</TT></P>
<P><TT>OUT address 位置的对应地址(整型)</TT></P>
</UL>
<P><TT>int MPI_ADdress(void* location, MPI_Aint *address) </TT></P>
<P><TT>MPI_ADDRESS(LOCATION,ADDRESS,IERROR) <type> LOCATION(*)</TT></P>
<UL>
<P><TT>INTEGER ADDRESS,IERROR^M ^M 返回location的地址(字节).</TT> </P>
</UL>
<P>例 3.24 对一个数组使用MPI_ADDRESS. </P>
<UL>
<P><TT>REAL A(100,100) </TT></P>
<P><TT>INTEGER I1, I2, DIFF </TT></P>
<P><TT>CALL MPI_ADDRESS(A(1,1), I1, IERROR) </TT></P>
<P><TT>CALL MPI_ADDRESS(A(10,10), I2, IERROR) </TT></P>
<P><TT>DIFF = I2 - I1 </TT></P>
</UL>
<P>DIFF的值是909*sizeofreal;I1和I2的值依赖于具体执行. </P>
<P>##对用户的建议## </P>
<P>C的用户可能会试图避免使用MPI_ADDRESS而使用地址运算符&. 但是要注意&表达式是一个指针而不是地址.ANSI
C不要求指针的值是目标所指的实际地址--尽管通常总是这样的. .另外在使用段地址空间的机器上的参考定义可能不一致.使用MPI_ADDRESS来"参考"C变量也保证了在这样的机器上的方便性.
</P>
<P>以下的辅助函数提供一些派生数据类型的有用信息. </P>
<P><TT>MPI_TYPE_EXTENT(datatype,extent) </TT></P>
<UL>
<P><TT>IN datatype 数据类型(句柄) </TT></P>
<P><TT>OUT extent 数据类型extent(整型) </TT></P>
</UL>
<P><TT>int MPI_Type_extent(MPI_Datatype datatype, int *extent) </TT></P>
<P><TT>MPI_TYPE_EXTENT(DATATYPE,SIZE,IERROR) </TT></P>
<UL>
<P><TT>INTEGER DATATYPE,EXTENT,IERROR</TT> </P>
</UL>
<P>返回一个数据类型的extent,extent的定义在公式3.1. </P>
<P><TT>MPI_TYPE_SIZE(datatype,size) </TT></P>
<UL>
<P><TT>IN datatype 数据类型(句柄) </TT></P>
<P><TT>OUT size 数据类型大小(整型) </TT></P>
</UL>
<P><TT>int MPI_Type_size(MPI_Datatype datatype, int *size) </TT></P>
<P><TT>MPI_TYPE_SIZE(DATATYPE,SIZE,IERROR) </TT></P>
<UL>
<P><TT>INTEGER DATATYPE,SIZE,IERROR </TT></P>
</UL>
<P>MPI_TYPE_SIZE返回类型签名中和datatype相关的入口项总的字节;即一个消息中将用这种数据类型产生的数据的总和.数据类型中重复出现的项则计算其重复次数.
</P>
<P><TT>MPI_TYPE_COUNT(datatype,count) </TT></P>
<UL>
<P><TT>IN datatype 数据类型(句柄) </TT></P>
<P><TT>OUT count 数据类型计数(整型) </TT></P>
</UL>
<P><TT>int MPI_Type_count(MPI_Datatype datatype, int *count) </TT></P>
<P><TT>MPI_TYPE_COUNT(DATATYPE,COUNT,IERROR) </TT></P>
<UL>
<P><TT>INTEGER DATATYPE,COUNT,IERROR </TT></P>
</UL>
<P>返回指定数据类型中"顶层"项的个数. </P>
<P><A NAME="3.12.3"></A></P>
<P>3.12.3 下界和上界标记 </P>
<P>定义辅助的类型映像下界和上界并且覆盖公式3.1的定义经常是很方便的.它可以使用户定义开始或结束处留有"洞穴"的数据类型,
或者定义超越上,下界的数据类型. 这种应用的例子见3.12.7. 为了实现它,我们增加两个额外的"定型数据类型",MPI_LB和MPI_UB,
\他们可以分别用于标记一个数据类型的下界和上界.这些定型数据类型不占空间(extent(MPI_LB)
= extent(MPI_UB) =0 ).他们不影响数据类型的大小和数目,也不影响用该数据类型创建的消息的内容.可是他们影响数据类型定义的extent,
因此影响数据类型生成器复制数据类型的输出. </P>
<P>例 3.25 令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的新的数据类型,并且在偏移0处含有一个整数.这是序列{(lb,-3),(int,0),(ub,6)}定义的数据类型.如果该数据类型被MPI_TYPE_CONTIGUOUS(2,
type1,type2)调用复制两次,则新产生的数据类型可以用序列{(lb,-3),(int,0),(int,9),(ub,15)}来描述.(lb
或ub型的项可以被忽略掉,如果他们出现在数据类型两端以外的位置的话. </P>
<P>一般地,如果 </P>
<UL>
<P>typemap ={(type0, disp0),..., (typen-1,dispn-1 )}, </P>
</UL>
<P>当typemap的下界被定义为 </P>
<UL>
<P>minjdispj (如果没有类型为lb的项); </P>
<P>lb(typemap)= minj{dispj such that typej =lb } (否则 )</P>
</UL>
<P>类似地,typemap的上界定义为 </P>
<UL>
<P>maxjdispj + sizeof(typej) 如果没有类型为ub的项; ub(typemap)= maxj{dispj
such that typej=ub } 否则 则 extent(typemap) = ub(typemap)-lb(typemap)+e
</P>
</UL>
<P>如果typei 要求分配ki倍数的字节地址, 则e是使extent(typemap)进入(rount)下一个maxiki所需要的最小非负增长.
</P>
<P>至此我们给出了各种数据类型生成器的正式定义和修改了的extent的定义. </P>
<P>下面的两个函数用于寻找一个数据类型的下界和上界.</P>
<P><TT>MPI_TYPE_LB(datatype,displacement) </TT></P>
<UL>
<P><TT>IN datatype 数据类型(句柄) </TT></P>
<P><TT>OUT displacement 下界离原始位置的偏移字节(整数) </TT></P>
</UL>
<P><TT>int MPI_Type_lb (MPI_Datatype datatype, int *displacement) </TT></P>
<P><TT>MPI_TYPE_LB (DATATYPE,DISPLACEMENT,IERROR) </TT></P>
<UL>
<P><TT>INTEGER DATATYPE,DISPLACEMENT,IERROR </TT></P>
</UL>
<P><TT>MPI_TYPE_UB(datatype,displacement) </TT></P>
<UL>
<P><TT>IN datatype 数据类型(句柄) </TT></P>
<P><TT>OUT displacement 上界离原始位置的偏移字节(整数) </TT></P>
</UL>
<P><TT>int MPI_Type_ub (MPI_Datatype datatype, int *displacement) </TT></P>
<P><TT>MPI_TYPE_UB (DATATYPE,DISPLACEMENT,IERROR) </TT></P>
<UL>
<P><TT>INTEGER DATATYPE,DISPLACEMENT,IERROR </TT></P>
</UL>
<P>##基本原理## </P>
<P>注意3.12.6中给出的规则暗示使用包含绝对地址的数据类型参数调用MPI_TYPE_EXTENT,
MPI_TYPE_LB, MPI_TYPE_UB是错误的, 除非所有的地址在同一个顺序存储区内. 因此,C
在捆绑MPI_TYPE_UB时displacement是int型而不是MPI_Aint. </P>
<P><A NAME="3.12.4"></A></P>
<P>3.12.4 承诺(commit)和释放 </P>
<P>通信中的数据类型目标在使用之前必须被承诺.一个承诺的数据类型仍然可以被作为参数用在数据类型生成器中.
基本数据类型不需要承诺, 他们是"预承诺"了的. </P>
<P><TT>MPI_TYPE_COMMIT(datatype) </TT></P>
<UL>
<P><TT>INOUT datatype 承诺的数据类型(句柄) </TT></P>
</UL>
<P><TT>int MPI_Type_commit(MPI_Datatype *datatype) </TT></P>
<P><TT>MPI_TYPE_COMMIT(DATATYPE,IERROR) </TT></P>
<UL>
<P><TT>INTEGER DATATYPE,IERROR </TT></P>
</UL>
<P>承诺操作用于承诺数据类型,即它的通信缓冲区正式描述,而不是缓冲区的内容.这样,在一个数据类型被承诺以后,它能够被不断用不同的起始地址重复使用,传送不断改变的缓冲区内容,或者不同缓冲区的内容.
</P>
<P>##对执行者的建议## </P>
<P>系统可能在承诺时间为数据类型"编译"一个内部代理,例如,把一个密集的代理改变成一个稀疏代理,并选择最方便的通信机制.
</P>
<P><TT>MPI_TYPE_FREE(datatype) </TT></P>
<UL>
<P><TT>INOUT datatype 释放的数据类型(句柄) </TT></P>
</UL>
<P><TT>int MPI_Type_free(MPI_Datatype *datatype) </TT></P>
<P><TT>MPI_TYPE_FREE(DATATYPE,IERROR) </TT></P>
<UL>
<P><TT>INTEGER DATATYPE,IERROR </TT></P>
</UL>
<P>标记datatype相关的数据类型目标为解散并设datatype为MPI_DATATYPE_NULL.任何当前正在使用该数据类型的通信都将正常结束.由释放的数据类型派生的数据类型不受影响.
</P>
<P>例 3.26下面的程序段是一个使用MPI_TYPE_COMMIT的例子</P>
<P><TT>INTEGER type1, type2 </TT></P>
<P><TT>CALL MPI_TYPE_CNTIGUOUS(5, MPI_REAL, type1, ierr) </TT></P>
<UL>
<P><TT>! 创建新的类型目标 </TT></P>
</UL>
<P><TT>CALL MPI_TYPE_COMMIT(type1, ierr) </TT></P>
<UL>
<P><TT>! 此时type1可以用于通信 </TT></P>
</UL>
<P><TT>type2 = type1 </TT></P>
<UL>
<P><TT>! type2可以用于通信 </TT></P>
<P><TT>! (它是一个和type1指向同一个目标的句柄) </TT></P>
</UL>
<P><TT>CALL MPI_TYPE_VECTOR(3,5,4,MPI_REAL,type1,ierr) </TT></P>
<UL>
<P><TT>! 创建新的非专用类型目标 </TT></P>
</UL>
<P><TT>CALL MPI_TYPE_COMMIT(type1,ierr) </TT></P>
<UL>
<P><TT>! 此时type1可以用于再次通信 </TT></P>
</UL>
<P>释放一个数据类型并不影响另一个从这个被释放的数据类型中产生的数据类型.系统的表现就如同时输入给派生数据类型生成器的数据类型参数是用值传递的.
</P>
<P>##对执行者的建议##</P>
<P>执行时可能要保存一个使用该数据类型的活动通信的参考计数, 以便决定何时释放它.
同时用户可以执行派生数据类型生成器, 让他们指向他们的数据类型参数,而不是拷贝.
在这种情况下, 用户需要保留活动数据类型的参考定义的情况, 以便知道何时可以释放一个数据类型目标.
</P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -