MPI 用户定义的数据类型,我所做的安全吗?
第一次在一些简单的练习应用程序之外使用 MPI,但有些事情不太顺利。
我有一个使用以下成员定义的类(为了可读性和节省屏幕空间而省略了方法):
class particle
{
public:
double _lastUpdate;
float _x, _y, _xvel, _yvel;
bool _isStatic;
bool _isForeign;
float _size;
private:
int _isStaticInt; // integer copy of _isStatic to be sent over MPI ( since there's no MPI_BOOL :C )
};
我想通过发送每个粒子的一些关键成员的值并在进程上复制其他成员来在进程之间发送粒子集。点。 为此,我定义了一个 MPI 数据类型; 正如你所看到的,成员 _lastUpdate、_isStatic 和 _isForeign 不包括在内:
MPI_Datatype types[] = { MPI_FLOAT, MPI_FLOAT, MPI_FLOAT, MPI_FLOAT, MPI_INTEGER, MPI_FLOAT };
std::vector<int> len(6, 1);
std::vector<MPI_Aint> disp(6, 0);
particle temp;
MPI_Aint base;
MPI_Address(&temp, &base);
MPI_Address(&temp._x, &disp[0]);
MPI_Address(&temp._y, &disp[1]);
MPI_Address(&temp._xvel, &disp[2]);
MPI_Address(&temp._yvel, &disp[3]);
MPI_Address(&temp._isStaticInt, &disp[4]);
MPI_Address(&temp._size, &disp[5]);
for (int i=0; i<6; ++i)
{
disp[i] = disp[i] - base;
}
MPI_Type_struct(6, &len[0], &disp[0], types, &_particleType);
MPI_Type_commit(&_particleType);
这就是我发送粒子的方式; “parts”是一个粒子*向量,其中包含指向我要发送的粒子对象的指针,“size”是parts.size()。
std::vector<int> len(size, 1);
std::vector<MPI_Aint> disp(size, 0);
MPI_Aint base;
MPI_Address(parts[0], &base); // datatype begins at the first selected object
for (int select = 1; select < size; ++select)
{
MPI_Address(parts[select], &disp[select]);
disp[select] = disp[select] - base;
}
MPI_Type_hindexed(size, &len[0], &disp[0], _particleType, &_sendType);
MPI_Type_commit(&_sendType);
MPI_Request payload_req;
MPI_Isend(parts[0], 1, _sendType, ngb, 0, _cartesian_comm, &payload_req);
接收过程类似,只是在这种情况下,“parts”是一个粒子*向量,它指向先前创建的“空白”粒子对象,其成员将用我们接收到的数据填充:
std::vector<int> len(size, 1);
std::vector<MPI_Aint> disp(size, 0);
MPI_Aint base;
MPI_Address(parts[0], &base); // datatype begins at the first newly inserted object
for (int part = 1; part < size; ++part)
{
MPI_Address(parts[part], &disp[part]);
disp[part] = disp[part] - base;
}
MPI_Type_hindexed(size, &len[0], &disp[0], _particleType, &_recvType);
MPI_Type_commit(&_recvType);
MPI_Status status;
MPI_Recv(parts[0], size, _particleType, ngb, 0, _cartesian_comm, &status);
问题是除了第一个在其成员中具有默认的“空白”值。 我之前编写了一个小型测试应用程序,做了类似的事情,并且工作完美,尽管它只传输了一些简单的值。 这让我相信,除非有一个我没有注意到的编码错误(完全有可能),否则这种数据类型欺骗并不能保证起作用,而且很少起作用只是偶然的。
任何人都可以确认/否认这种类型的内存操作是否安全并且应该依赖吗?
First time using MPI outside some simple practice apps, and something's not going right.
I have a class defined with the following members (methods omitted for the sake of readability and conserving screen space):
class particle
{
public:
double _lastUpdate;
float _x, _y, _xvel, _yvel;
bool _isStatic;
bool _isForeign;
float _size;
private:
int _isStaticInt; // integer copy of _isStatic to be sent over MPI ( since there's no MPI_BOOL :C )
};
I want to send sets of particles between processes by sending the values of some key members of each particle, and replicating the others on the spot. For that purpose, I define an MPI datatype as such; as you can see, members _lastUpdate, _isStatic and _isForeign are not included:
MPI_Datatype types[] = { MPI_FLOAT, MPI_FLOAT, MPI_FLOAT, MPI_FLOAT, MPI_INTEGER, MPI_FLOAT };
std::vector<int> len(6, 1);
std::vector<MPI_Aint> disp(6, 0);
particle temp;
MPI_Aint base;
MPI_Address(&temp, &base);
MPI_Address(&temp._x, &disp[0]);
MPI_Address(&temp._y, &disp[1]);
MPI_Address(&temp._xvel, &disp[2]);
MPI_Address(&temp._yvel, &disp[3]);
MPI_Address(&temp._isStaticInt, &disp[4]);
MPI_Address(&temp._size, &disp[5]);
for (int i=0; i<6; ++i)
{
disp[i] = disp[i] - base;
}
MPI_Type_struct(6, &len[0], &disp[0], types, &_particleType);
MPI_Type_commit(&_particleType);
This is how I send the particles; 'parts' is a vector of particle* that contains pointers to the particle objects I want to send, and 'size' is parts.size().
std::vector<int> len(size, 1);
std::vector<MPI_Aint> disp(size, 0);
MPI_Aint base;
MPI_Address(parts[0], &base); // datatype begins at the first selected object
for (int select = 1; select < size; ++select)
{
MPI_Address(parts[select], &disp[select]);
disp[select] = disp[select] - base;
}
MPI_Type_hindexed(size, &len[0], &disp[0], _particleType, &_sendType);
MPI_Type_commit(&_sendType);
MPI_Request payload_req;
MPI_Isend(parts[0], 1, _sendType, ngb, 0, _cartesian_comm, &payload_req);
Receiving happens similarly, only in this case, 'parts' is a vector of particle* that points to previously created "blank" particle objects, whose members are to be filled with the data we receive:
std::vector<int> len(size, 1);
std::vector<MPI_Aint> disp(size, 0);
MPI_Aint base;
MPI_Address(parts[0], &base); // datatype begins at the first newly inserted object
for (int part = 1; part < size; ++part)
{
MPI_Address(parts[part], &disp[part]);
disp[part] = disp[part] - base;
}
MPI_Type_hindexed(size, &len[0], &disp[0], _particleType, &_recvType);
MPI_Type_commit(&_recvType);
MPI_Status status;
MPI_Recv(parts[0], size, _particleType, ngb, 0, _cartesian_comm, &status);
The problem is that all the received particles except the first one have the default "blank" values in their members. I wrote a small test app before that did something similar, and that worked flawlessly, although it only transmitted a few simple values. This leads me to beleive that unless there's a coding mistake I'm not noticing here (entirely possible), this sort of datatype trickery is not guaranteed to work, and the little that works does so only by accident.
Can anyone confirm/deny if this type of memory manipulation is safe and should be relied upon?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
没关系,似乎只是简单地输入问题就让我意识到出了什么问题。
接收命令应该是:
Never mind, it seems that simply typing out the question made me realize what's wrong.
The receive command should be: