MPI派生类型发送 [英] MPI Derived Type send

查看:68
本文介绍了MPI派生类型发送的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试将派生类型发送给处理器.该类型包含其他派生类型的对象.我从示例:结构派生数据类型开始了示例.我添加我的代码.该代码虽然很少,但是对于两种类型基本上相同.我有同时还有Particle对象的Part对象,我想发送Part.我得到的结果是在代码之后.

I try to send a derived type to processors. The type contains object from other derived type. I started the example from Examples: Struct Derived Data Type. I add my code. The code is little long but it basically same for two types. I have Part object that has also a Particle object and i want to send Part. The result that i have is after the code.

#include "mpi.h"
#include <stdio.h>
#define NELEM 25

main(int argc, char *argv[])  {
int numtasks, rank, source=0, dest, tag=1, i;

typedef struct {
 float x, y, z;
 float velocity;
 int  n, type;
 }          Particle;

// Another struct to send
typedef struct {
 char character;
 Particle part ;
} Part ;

MPI_Request send_req;
MPI_Status stat;


MPI_Init(&argc,&argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);

// Particle type 
Particle     particles;
MPI_Datatype particletype, oldtypes[2]; 
int          blockcounts[2];
MPI_Aint     offsets[2], extent;

offsets[0] = 0;
oldtypes[0] = MPI_FLOAT;
blockcounts[0] = 4;
MPI_Type_extent(MPI_FLOAT, &extent);
offsets[1] = 4 * extent;
oldtypes[1] = MPI_INT;
blockcounts[1] = 2;

MPI_Type_struct(2, blockcounts, offsets, oldtypes, &particletype);
MPI_Type_commit(&particletype);


// Part type 
Part party , party_received;
MPI_Datatype part_type,oldtype2[2];
int blockcount2[2];
MPI_Aint offset2[2],extent2; 

offset2[0] = 0;
oldtype2[0] = MPI_CHAR ;
blockcount2[0] = 1 ;

MPI_Type_extent(particletype,&extent);
offset2[1] = extent ;
oldtype2[1] = particletype ;
blockcount2[1] = 1 ;

MPI_Type_struct(2,blockcount2,offset2,oldtype2,&part_type);
MPI_Type_commit(&part_type);


party.character= 'a';

if (rank == 0) {

  particles.x = 1 * 1.0;
  particles.y = 1 * -1.0;
  particles.z = 1 * 1.0; 
  particles.velocity = 0.25;
  particles.n = 1;
  particles.type = 1 % 2; 

  party.part = particles;

  printf("Derived data type sending, character: %c \n",party.character);
  MPI_Isend(&party,1,part_type,1,tag,MPI_COMM_WORLD,&send_req);
  printf("particles sent %f %f %f %f %d %d \n", 
                        party.part.x,party.part.y,party.part.z,
                        party.part.velocity,party.part.n,party.part.type);
  }
if(rank == 1) {
  MPI_Recv(&party_received, 1, part_type, 0, tag, MPI_COMM_WORLD, &stat);
  printf("derived part type received character %c \n",party_received.character) ;
  printf("particles %f %f %f %f %d %d \n", 
           party_received.part.x,party_received.part.y,party_received.part.z,
           party_received.part.velocity,party_received.part.n,party_received.part.type);
 }
MPI_Type_free(&particletype);
MPI_Finalize();
}

结果每次都会更改.最后一个是:

The result changes every time. The last one is :

Derived data type sending, character: a 
particles sent 1.000000 -1.000000 1.000000 0.250000 1 1 
derived part type received character a 
particles 0.000000 -2686527813451776.000000 0.000000 0.000000 1 1 

虽然character为true,但为什么Particle对象不是?我该如何纠正?

While the character is true, why Particle object are not ? How can i correct it?

推荐答案

您错误地计算了偏移量.

You are computing the offsets wrongly.

offset2[0] = 0;
oldtype2[0] = MPI_CHAR ;
blockcount2[0] = 1 ;

MPI_Type_extent(particletype,&extent);
offset2[1] = extent ;  <--- WRONG
oldtype2[1] = particletype ;
blockcount2[1] = 1 ;

此处的偏移量不是结构第二个成员的范围.这是前一个的范围+可能是一些填充(在您的情况下为3个字节的填充).

The offset here is not the extent of the second member of the structure. It is the extent of the first one + possibly some padding (in your case - 3 bytes of padding).

为防止将来出现类似错误,我建议您改用offsetof():

To prevent similar error in the future, I would advise you to use offsetof() instead:

#include <stddef.h>

offset[0] = offsetof(Part, character);
offset[1] = offsetof(Part, part);

使用范围计算偏移量在概念上是错误的,因为不能保证在结构内部使用的填充与范围匹配.一个简单的示例:MPI_CHAR在大多数系统上的范围为1个字节,但是如果您具有struct { char a; int b; }之类的结构,由于对齐要求,在ab之间将有3个字节的填充.这同样适用于您的Part结构-由于Particle的第一个成员是浮点数,因此part成员使用填充对齐.

Computing offsets using extents is conceptually wrong since there is no guarantee that the padding used inside structures matches the extent. A simple example: MPI_CHAR has extent of 1 byte on most systems but if you have a structure like struct { char a; int b; }, because of alignment requirements, there will be 3 bytes of padding between a and b. The same applies to your Part structure - the part member is aligned using padding due to the first member of Particle being a float.

如果您的系统没有offsetof,则可以将其替换为MPI_Get_address:

If your system doesn't have offsetof, you can replace it with MPI_Get_address:

Part party;
MPI_Aint base, member_offset;

MPI_Get_address(&party, &base);

MPI_Get_address(&party.character, &member_offset);
offset[0] = member_offset - base;

MPI_Get_address(&party.part, &member_offset);
offset[1] = member_offset - base;

这篇关于MPI派生类型发送的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆