我有以下的结构。
typedef struct
{
int *Ai;
double *Ax;
int nz;
}column;
我想转移采用这种结构MPI_Send
和MPI_Receive
。 如何创建一个MPI_Datatype
这个结构呢?
我有以下的结构。
typedef struct
{
int *Ai;
double *Ax;
int nz;
}column;
我想转移采用这种结构MPI_Send
和MPI_Receive
。 如何创建一个MPI_Datatype
这个结构呢?
MPI的设计与阵列的结构,而该结构的阵列工作。
该MPI_Hindexed
@suszterpatt提出,是一个可怕的黑客。 这将只允许您发送用来定义MPI数据类型的结构类型,只有元素的一个元素。 对于相同的结构类型的其他变量它主要是保证计算的偏移量将是错误的。 除了Hindexed类型使用一个和所有元素相同MPI数据类型,因此不会让您同时发送整数和双打。
聪明的事情做的是改变你的程序使用结构数组:
typedef struct
{
int i;
double z;
} point;
typedef struct
{
point *A;
int nz;
} column;
现在,您可以创建一个MPI结构类型point_type
,并用它来发送nz
那种给人的元素column.A
作为缓冲地址:
int lens[3];
MPI_Aint base, disps[2];
MPI_Datatype oldtypes[2], point_struct, point_type;
MPI_Get_address(&point, disps);
MPI_Get_address(&point.z, disps+1);
base = disps[0];
lens[0] = 1; disps[0] = MPI_Aint_diff(disps[0], base); oldtypes[0] = MPI_INT;
lens[1] = 1; disps[1] = MPI_Aint_diff(disps[1], base); oldtypes[1] = MPI_DOUBLE;
MPI_Type_create_struct(2, lens, disps, oldtypes, &point_struct);
MPI_Type_create_resized(point_struct, 0, sizeof(point), &point_type);
MPI_Type_commit(&point_type);
MPI_Send(column.A, column.nz, point_type, ...);
这首先创建一个数据类型MPI point_struct
描述结构成员的布局,但不考虑在端部的任何填充,因此不能用于可靠地发送这种结构的阵列。 因此,第二数据类型point_type
与正确的程度是使用创建MPI_Type_create_resized
。
在接收器侧,你会偷看与消息MPI_Probe
,提取元件用的数量MPI_Get_count
与一种类型的point_type
(即直行到nz
字段),分配A
字段,并用它在MPI_Recv
接收所述nz
元素:
MPI_Status status;
MPI_Probe(source, tag, comm, &status);
MPI_Get_count(&status, point_type, &column.nz);
if (nz == MPI_UNDEFINED)
... non-integral message was received, do something
column.A = (point *)malloc(column.nz*sizeof(point));
MPI_Recv(column.A, column.nz, point_type, source, tag, comm, MPI_STATUS_IGNORE);
如果代码改变是不可能的,你仍然可以经过发送之前将您的结构的中间步骤,这个过程通常被称为(未)封送处理 。 在你的情况做这样的事情(我假设你存储在两个数组元素的数量Ai
和Ax
在nz
字段):
point *temp = (point *)malloc(nz*sizeof(point));
for (int i = 0; i < column.nz; i++)
{
temp[i].i = column.Ai[i];
temp[i].z = column.Az[i];
}
MPI_Send(temp, nz, point_type, ...);
free(temp);
在接收端必须做相反:分配一个足够大的缓冲区,可容纳的结构,它收到消息,然后做相反的转换。
再次,你并不需要发送的实际值nz
,因为它可以使用该消息的长度来容易地提取MPI_Get_count
。
发送指针到另一台机器是无意义的(不是双关语)。 由于虚拟寻址,指针可能会指向接收计算机上的无效的内存位置,即使没有,你有没有实际发送的是它指向的数据。
然而,正确使用MPI_Address()
和MPI_Hindexed
数据类型,它可以描述数据的内存布局(我假设你的指针指向动态数组)。 例如,如果Ai
点至3 int
秒, Ax
点到5 double
S,你需要一个Hindexed
类型有3块:3 MPI_INT
秒,5 MPI_DOUBLE
s和1个MPI_INT
,与偏移使用采集MPI_Address()
不要忘了重新定义和再犯的数据类型,如果你改变要发送的项目数或完全重新分配阵列。 如果你正在发送多个结构,你必须确定并提交此数据类型为每一个,因为你的MPI数据类型是专用于这些结构中的一个特定实例。
同时请记住,如果你想重建原始的结构,你必须做一些类似的棘手拆包在接收端。
“智者要做的是改变你的程序使用结构数组”
通常,这是概念上也比较好。
我想指出的另一种机制:使用MPI_Pack和MPI_Unpack。 例如,与原来的结构,你可以打包的第一个整数,然后包了两个数组。 接收器将解压的整数,然后知道有多少其他的一样的东西解压。
这也是一个很好的解决方案,如果你的对象是不能直接访问,但只能通过一个迭代左右进行访问。